管理项目的即时特权访问权限

Last reviewed 2024-07-22 UTC

本文档介绍了如何使用开源工具实现对 Google Cloud 项目的即时特权访问。即时特权访问权限允许您仅在需要访问权限时向一组有限的用户授予对项目的临时访问权限。

本文档适用于管理用户对 Google Cloud 资源的访问权限的管理员。本文假定您熟悉 Google Cloud、Identity and Access Management (IAM) 和相关概念。

即时特权访问权限管理概览

当您遵循最小权限原则时,您将为用户授予使他们能够执行日常活动所需的足够访问权限,但无法执行任何操作。遵循此原则有助于降低风险。但是,当用户偶尔需要执行特权操作(例如处理意外突发事件)时,可能会造成麻烦。例如,排查生产系统中的问题或涉及敏感数据的问题。

解决此问题的一种方法是提供即时特权访问权限,即仅在需要时提供特权访问权限。即时特权访问权限管理的一个关键理念是区分永久访问权限和符合条件的访问权限:

  • 永久访问权限在撤消之前都适用。在遵循最小权限原则的情况下,最好限制永久访问权限,仅将其授予必须拥有它的少数用户。
  • 符合条件的访问权限不会立即应用。相反,被授予项目符合条件的访问权限的用户必须先明确激活该访问权限,然后才能访问该项目。他们还必须提供正当理由。用户访问权限激活后,访问权限会在短时间后自动过期。

使用即时特权访问权限管理可以帮助您执行以下操作:

  • 降低有人意外修改或删除资源的风险。例如,如果用户仅在需要时具有特权访问权限,则有助于防止其他用户在其他时间运行脚本,以免无意中影响他们不应更改的资源。
  • 创建审核跟踪,以指明激活权限的原因。
  • 进行审核和复核,以分析过去的活动。

使用 Just-in-Time Access 来实现特权访问权限

Just-in-Time Access 是一个开源应用,设计为在 App Engine 或 Cloud Run 上运行,允许您实现对 Google Cloud 资源的即时特权访问权限。该应用允许管理员、用户和审核人员执行以下任务:

  • 管理员可以通过添加以下 IAM 条件向用户或群组授予角色并使得角色符合条件:

    has({}.jitAccessConstraint)
    
  • 用户可以使用即时访问应用搜索他们有权访问的项目和角色。

    即时访问应用中的以下屏幕截图显示了用户在项目中有资格的角色列表:

    即时访问应用的屏幕截图,其中显示了 2 个符合条件的角色和 1 个已激活的角色。

    然后,他们可以激活一个或多个角色,并提供获取访问权限的理由:

    来自即时访问应用的屏幕截图,显示了用于输入理由的表单。

    用户激活角色后,Just-In-Time Access 会向用户授予项目临时访问权限

  • 审核人员可以使用 Cloud Logging 查看用户激活有效角色的时间和原因。

为了保护应用免遭未经授权的访问,只能通过 Identity-Aware Proxy (IAP) 访问 Just-In-Time Access 应用。使用 IAP,管理员可以控制哪些用户可以访问 Just-In-Time Access,以及这些用户必须满足哪些其他条件才能获得访问权限。

准备工作

在部署 Just-In-Time Access 应用之前,您必须确定您要管理其即时特权访问权限的资源层次结构的哪些部分。您可以管理以下资源的访问权限:

  • 单个项目
  • 包含多个项目的文件夹
  • 您的组织的所有项目

如需完成部署,您需要以下各项:

  • 对与您使用的 Google Cloud 组织相对应的 Cloud Identity 或 Google Workspace 账号的超级用户访问权限。
  • 针对要使用 Just-In-Time Access 管理的项目、文件夹或组织的 IAM 政策的修改权限。
  • 可用于测试访问权限的第二个 Cloud Identity 或 Google Workspace 用户。

您还需要一个 Google Cloud 项目来部署 Just-In-Time Access 应用。

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

部署即时访问

本部分介绍如何将 Just-In-Time Access 应用部署到 App Engine 或 Cloud Run。

将 Just-In-Time Access 应用部署到 Cloud Run 所需的配置比将应用部署到 App Engine 更复杂。因此,除非您在不支持 App Engine 的区域进行部署,或者由于其他原因无法使用 App Engine,否则我们建议您使用 App Engine。

Just-In-Time Access 的代码位于 GitHub 代码库中。

本部分假定您是管理员。

配置 Google Cloud 项目

  1. 在 Google Cloud 控制台中,切换到您的项目并启用所需的 API:

    App Engine

    Enable the Cloud Asset Inventory, Resource Manager, Identity-Aware Proxy, Container Registry, Cloud Build, Identity and Access Management, and Directory APIs.

    Enable the APIs

    Cloud Run

    Enable the Cloud Asset Inventory, Resource Manager, Identity-Aware Proxy, Container Registry, Cloud Run, Compute Engine, Identity and Access Management, and Directory APIs.

    Enable the APIs

  2. 打开 Cloud Shell。

    打开 Cloud Shell

  3. 设置一个环境变量,以包含您的项目 ID

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替换为您的项目 ID。

  4. 为 Just-In-Time Access 应用创建服务账号:

    SERVICE_ACCOUNT=$(gcloud iam service-accounts create jitaccess --display-name "Just-In-Time Access" --format "value(email)")
    
  5. 通过向应用授予 Service Account Token Creator 角色 (roles/iam.serviceAccountTokenCreator),允许应用使用其服务账号创建令牌:

    gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT \
      --member "serviceAccount:$SERVICE_ACCOUNT" \
      --role "roles/iam.serviceAccountTokenCreator"
    

    应用使用创建令牌的权限来访问 Directory API,并视情况处理多方审批工作流

授予 Just-In-Time Access 应用权限以管理 IAM 绑定

您现在可以向应用的服务账号授予 Project IAM Admin 角色。此角色允许 Just-In-Time Access 应用创建必须授予即时访问的临时 IAM 绑定。

由于 Project IAM Admin 角色具有高度特权,因此您必须限制对应用的服务账号及其所属项目的访问权限。

请遵循以下准则:

  • 限制可访问项目的用户数,并避免向任何用户授予 OwnerEditor 角色。
  • 限制可模拟服务账号的用户数。应该能够执行此模拟的用户包括具有 Service Account User 角色或 Service Account Token Creator 角色的用户。

如需向服务账号授予 Project IAM Admin 角色,请执行以下操作:

  1. Project IAM Admin 角色 (roles/resourcemanager.projectIamAdmin) 和 Cloud Asset Viewer 角色 (roles/cloudasset.viewer) 授予您希望管理即时特权访问权限的资源层次结构部分:

    项目

    SCOPE_ID=RESOURCE_PROJECT_ID
    SCOPE_TYPE=projects
    
    gcloud projects add-iam-policy-binding $SCOPE_ID \
        --member "serviceAccount:$SERVICE_ACCOUNT" \
        --role "roles/resourcemanager.projectIamAdmin" \
        --condition None
    
    gcloud projects add-iam-policy-binding $SCOPE_ID \
        --member "serviceAccount:$SERVICE_ACCOUNT" \
        --role "roles/cloudasset.viewer" \
        --condition None
    

    RESOURCE_PROJECT_ID 替换为您要管理其访问权限的 Google Cloud 项目的 ID。此项目与您部署了 Just-In-Time Access 的项目不同。

    文件夹

    SCOPE_ID=RESOURCE_FOLDER_ID
    SCOPE_TYPE=folders
    
    gcloud resource-manager folders add-iam-policy-binding $SCOPE_ID \
        --member "serviceAccount:$SERVICE_ACCOUNT" \
        --role "roles/resourcemanager.projectIamAdmin" \
        --condition None
    gcloud resource-manager folders add-iam-policy-binding $SCOPE_ID \
        --member "serviceAccount:$SERVICE_ACCOUNT" \
        --role "roles/cloudasset.viewer" \
        --condition None
    

    RESOURCE_FOLDER_ID 替换为包含要管理其访问权限的项目的文件夹 ID。

    组织

    SCOPE_ID=ORGANIZATION_ID
    SCOPE_TYPE=organizations
    
    gcloud organizations add-iam-policy-binding $SCOPE_ID \
        --member "serviceAccount:$SERVICE_ACCOUNT" \
        --role "roles/resourcemanager.projectIamAdmin" \
        --condition None
    gcloud organizations add-iam-policy-binding $SCOPE_ID \
        --member "serviceAccount:$SERVICE_ACCOUNT" \
        --role "roles/cloudasset.viewer" \
        --condition None
    

    ORGANIZATION_ID 替换为您的组织的 ID

授予访问权限以允许应用解决群组成员资格

借助 Just-In-Time Access 应用,您可以向特定用户或整个群组授予符合条件的访问权限。如需评估群组成员资格,应用必须有权从 Cloud Identity 或 Google Workspace 账号读取群组成员资格信息。

如需向应用的服务账号授予访问权限以读取群组成员资格,请执行以下操作:

  1. 打开 Google 管理控制台,然后以超级用户身份登录。

  2. 转到账号 > 管理员角色

    转到管理员角色

  3. 点击 Groups Reader > 管理员

  4. 点击分配服务账号

  5. 输入以下电子邮件地址:

    jitaccess@PROJECT_ID.iam.gserviceaccount.com
    

    PROJECT_ID 替换为您的 Google Cloud 项目的 ID。

  6. 点击添加

  7. 点击分配角色

查找您的 Cloud Identity 或 Google Workspace 账号的客户 ID

如需使用 Directory API 评估群组成员资格,Just-In-Time Access 应用需要您的 Cloud Identity 或 Google Workspace 账号的客户 ID。如需查找此 ID,请执行以下操作:

  1. 在 Google 管理控制台中,转到账号 > 账号设置

    转到账号设置

  2. 复制账号的客户 ID。客户 ID 以 C 开头。

    在后续步骤中,您需要客户 ID。

  3. 关闭管理控制台。

部署应用

您现在可以将 Just-In-Time Access 应用部署到 App Engine 或 Cloud Run 了。

App Engine

如需将 Just-In-Time Access 应用部署到 App Engine,请执行以下步骤。

  1. 在 Cloud Shell 中,设置环境变量以包含您的 Cloud Identity 或 Google Workspace 账号的客户 ID:

    ACCOUNT_CUSTOMER_ID=CUSTOMER_ID
    

    CUSTOMER_ID 替换为您之前查找的客户 ID。

  2. 创建 App Engine 应用:

    gcloud app create --region LOCATION
    

    LOCATION 替换为受支持的 App Engine 位置

  3. 为 App Engine 默认服务账号授予 Artifact Registry Create-on-push Writer (roles/artifactregistry.createOnPushWriter) 和 Storage Admin (roles/storage.admin) 角色,以允许 App Engine 使用 Artifact Registry。

    PROJECT_ID=$(gcloud config get-value core/project)
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member "serviceAccount:$PROJECT_ID@appspot.gserviceaccount.com" \
        --role "roles/artifactregistry.createOnPushWriter" \
        --condition None
    gcloud projects add-iam-policy-binding $PROJECT_ID\
        --member "serviceAccount:$PROJECT_ID@appspot.gserviceaccount.com" \
        --role "roles/storage.admin" \
        --condition None
    
  4. 克隆 GitHub 代码库并切换到 latest 分支:

    git clone https://github.com/GoogleCloudPlatform/jit-groups.git
    cd jit-access/sources
    git checkout latest
    
  5. 为 Just-In-Time Access 应用创建配置文件:

    cat << EOF > app.yaml
    
    runtime: java17
    instance_class: F2
    service_account: $SERVICE_ACCOUNT
    env_variables:
        RESOURCE_SCOPE: $SCOPE_TYPE/$SCOPE_ID
        RESOURCE_CATALOG: AssetInventory
        RESOURCE_CUSTOMER_ID: $ACCOUNT_CUSTOMER_ID
        ACTIVATION_TIMEOUT: 60
        JUSTIFICATION_HINT: "Bug or case number"
        JUSTIFICATION_PATTERN: ".*"
    EOF
    

    在此配置文件中,您可以自定义变量的值。如需查看设置列表,请参阅关联的 GitHub 代码库中的配置选项页面。

  6. 部署应用:

    gcloud app deploy --appyaml app.yaml
    

    记下输出中的 target url。这将是 Just-In-Time Access 应用的公开网址。

    如果您看到错误消息 NOT_FOUND: Unable to retrieve P4SA,请重试该命令。

Cloud Run

如需将 Just-In-Time Access 应用部署到 Cloud Run,请执行以下步骤。

  1. 在 Cloud Shell 中,设置环境变量以包含您的 Cloud Identity 或 Google Workspace 账号的客户 ID:

    ACCOUNT_CUSTOMER_ID=CUSTOMER_ID
    

    CUSTOMER_ID 替换为您之前查找的客户 ID。

  2. 选择要部署到的区域:

    gcloud config set run/region REGION
    

    REGION 替换为支持 Cloud Run 的区域。

  3. 创建后端服务

    gcloud compute backend-services create jitaccess-backend \
      --load-balancing-scheme=EXTERNAL \
      --global
    

    您稍后使用此后端服务配置负载均衡器和 IAP。

  4. 克隆 GitHub 代码库并切换到 latest 分支:

    git clone https://github.com/GoogleCloudPlatform/jit-groups.git
    cd jit-access/sources
    git checkout latest
    
  5. 构建应用并将容器映像推送到 Container Registry:

    PROJECT_ID=$(gcloud config get-value core/project)
    
    docker build -t gcr.io/$PROJECT_ID/jitaccess:latest .
    docker push gcr.io/$PROJECT_ID/jitaccess:latest
    
  6. 为 Just-In-Time Access 应用创建配置文件:

    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'value(projectNumber)')
    REGION=$(gcloud config get-value run/region)
    IAP_BACKEND_SERVICE_ID=$(gcloud compute backend-services describe jitaccess-backend --global --format 'value(id)')
    
    cat << EOF > app.yaml
    
    apiVersion: serving.knative.dev/v1
    kind: Service
    metadata:
      name: jitaccess
      namespace: $PROJECT_NUMBER
      labels:
        cloud.googleapis.com/location: $REGION
      annotations:
        run.googleapis.com/ingress: internal-and-cloud-load-balancing
    spec:
      template:
        spec:
          serviceAccountName: $SERVICE_ACCOUNT
          containers:
          - image: gcr.io/$PROJECT_ID/jitaccess:latest
            env:
            - name: RESOURCE_SCOPE
              value: "$SCOPE_TYPE/$SCOPE_ID"
            - name: RESOURCE_CATALOG
              value: "AssetInventory"
            - name: RESOURCE_CUSTOMER_ID
              value: "$ACCOUNT_CUSTOMER_ID"
            - name: ACTIVATION_TIMEOUT
              value: "60"
            - name: JUSTIFICATION_HINT
              value: "Bug or case number"
            - name: JUSTIFICATION_PATTERN
              value: ".*"
            - name: IAP_BACKEND_SERVICE_ID
              value: "$IAP_BACKEND_SERVICE_ID"
    EOF
    

    在此配置文件中,您可以自定义变量的值。如需查看设置列表,请参阅关联的 GitHub 代码库中的配置选项页面。

  7. 部署应用:

    gcloud run services replace app.yaml
    

配置负载均衡器

您现在可以为 Just-In-Time Access 应用配置负载均衡器。

App Engine

App Engine 会自动为您配置负载均衡器。

Cloud Run

为您的 Cloud Run 服务配置 HTTPS 负载均衡器:

  1. 为负载均衡器预留静态外部 IP 地址

    gcloud compute addresses create jitaccess-ip --global
    
  2. 为负载均衡器创建托管式 SSL 证书

    gcloud compute ssl-certificates create jitaccess \
      --domains PUBLIC_FQDN \
      --global
    

    其中,PUBLIC_FQDN 是您要使用的公共完全限定域名 (FQDN),例如 jitaccess.example.com

  3. 查找负载均衡器的 IP 地址:

    gcloud compute addresses describe jitaccess-ip \
      --global \
      --format=value\(address\)
    
  4. 在您的公共 DNS 区域中创建指向负载均衡器的 IP 地址的 DNS A 记录。DNS 记录的完全限定名称必须与您用于 SSL 证书的名称一致。

  5. 为 Cloud Run 服务创建无服务器网络端点组,并将其连接到后端服务:

    gcloud compute network-endpoint-groups create jitaccess \
      --region $(gcloud config get-value run/region) \
      --network-endpoint-type=serverless  \
      --cloud-run-service jitaccess
    gcloud compute backend-services add-backend jitaccess-backend \
      --global \
      --network-endpoint-group jitaccess \
      --network-endpoint-group-region $(gcloud config get-value run/region)
    
  6. 创建使用外部 IP 地址并将流量转发到后端服务的负载均衡器前端:

    gcloud compute url-maps create jitaccess \
      --default-service jitaccess-backend
    gcloud compute target-https-proxies create jitaccess-proxy \
      --ssl-certificates jitaccess \
      --url-map jitaccess
    gcloud compute forwarding-rules create jitaccess-https \
      --load-balancing-scheme EXTERNAL \
      --address jitaccess-ip \
      --target-https-proxy jitaccess-proxy \
      --global \
      --ports=443
    

配置 Identity-Aware Proxy

现在,您可以为即时访问应用配置 IAP。

  1. 在 Cloud Shell 中,配置 OAuth 权限请求页面

    gcloud iap oauth-brands create \
        --application_title "Just-In-Time Access" \
        --support_email=$(gcloud config get core/account)
    
  2. 在 Google Cloud 控制台中,转到安全性> Identity-Aware Proxy

    转到 IAP

  3. IAP 设置为IAP

现在,您必须定义哪些用户可以访问 Just-In-Time Access 应用。您可以向个别用户、群组或整个网域授予访问权限。

  1. 在 Google Cloud 控制台中,转到 IAM 和管理 > IAM

    转到 IAM

  2. 点击授予访问权限,然后设置以下值:

    1. 在主账号列表中,选择用户、群组或网域。
    2. 在角色列表中,选择 IAP-secured Web app user

    IAP-secured Web app user 角色可让用户打开 Just-In-Time Access 应用,但该角色未向他们提供对任何其他资源的访问权限。

  3. 点击保存

角色绑定可能需要几分钟才能生效。

App Engine

IAP 配置现已完成。

Cloud Run

为了完成 IAP 配置,请向 IAP 使用的服务代理授予 Cloud Run Invoker 角色 (roles/run.invoker):

PROJECT_NUMBER=$(gcloud projects list \
  --filter $(gcloud config get-value project) \
  --format "value(PROJECT_NUMBER)")

gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
  --member "serviceAccount:service-$PROJECT_NUMBER@gcp-sa-iap.iam.gserviceaccount.com" \
  --role "roles/run.invoker"

测试 Just-in-Time Access

现在,您可以测试授予符合条件的访问权限的过程以及使用即时访问应用激活符合条件的访问权限的过程。

授予符合条件的访问权限

首先,您需要向第二个 Cloud Identity 或 Google Workspace 用户授予符合条件的访问权限。

  1. 在 Google Cloud 控制台中,使用项目列表选择由 Just-In-Time Access 应用管理的资源层次结构中的项目。
  2. 在 IAM 页面上,点击授予访问权限
  3. 输入第二个 Cloud Identity 或 Google Workspace 用户的电子邮件地址,然后选择一个角色,例如 Project > Browser
  4. 点击添加条件
  5. 输入标题,例如 Eligible for JIT access
  6. 选择条件编辑器,然后输入以下 CEL 表达式:

    has({}.jitAccessConstraint)
    
  7. 保存更改。

激活访问权限

现在,您可以切换用户并请求对资源的临时访问权限。

  1. 打开无痕模式浏览器窗口并导航到您之前记下的 Just-In-Time Access 应用的网址。
  2. 以您已授予访问权限的用户身份登录。
  3. 在 Just-In-Time Access 应用中,选择要为其激活访问权限的角色和资源。
  4. 输入理由(例如 testing),然后点击申请访问权限

    在下一页上,请注意您的访问权限已暂时激活。

分析日志

现在,您可以切换回管理员用户并查看日志。

  1. 在 Google Cloud 控制台中,转到 Logging > Logs Explorer

    转到 Logs Explorer

  2. 显示查询设置为已启用

  3. 输入以下查询:

    labels.event="api.activateRole"
    
  4. 点击运行查询

    输出内容类似如下:

    {
    "textPayload": "User EMAIL activated role 'ROLE' on '//cloudresourcemanager.googleapis.com/projects/PROJECT_ID' for themselves",
    "severity": "INFO",
    "labels": {
        "resource": "//cloudresourcemanager.googleapis.com/projects/PROJECT_ID",
        "event": "api.activateRole",
        "role": "ROLE",
        "clone_id": "00c6...",
        "user": "EMAIL",
        "justification": "testing",
        ...
      },
    ...
    }
    

    请注意,已为激活的每个角色创建日志记录。日志记录包含一组标签,可用于创建自定义过滤条件。

升级即时访问

本部分介绍如何升级现有的即时访问部署以使用新版应用,或使用其他配置。

本部分假定您是管理员。

  1. 在 Google Cloud 控制台中,切换到您的项目,然后打开 Cloud Shell。

    打开 Cloud Shell

  2. 设置一个环境变量,以包含您的项目 ID

    gcloud config set project PROJECT_ID
    

    PROJECT_ID 替换为您的项目 ID。

  3. 克隆 GitHub 代码库并切换到 latest 分支:

    git clone https://github.com/GoogleCloudPlatform/jit-groups.git
    cd jit-access/sources
    git checkout latest
    
  4. 下载您之前用于部署应用的配置文件,并将其保存到文件 app.yaml 中:

    App Engine

    APPENGINE_VERSION=$(gcloud app versions list --service default --hide-no-traffic --format "value(version.id)")
    APPENGINE_APPYAML_URL=$(gcloud app versions describe $APPENGINE_VERSION --service default --format "value(deployment.files.'app.yaml'.sourceUrl)")
    
    curl -H "Authorization: Bearer $(gcloud auth print-access-token)" $APPENGINE_APPYAML_URL -o app.yaml
    cat app.yaml
    

    如果 app.yaml 文件下载失败,您可以在 Google Cloud 控制台中下载当前配置。

    Cloud Run

    gcloud config set run/region REGION
    gcloud run services describe jitaccess --format yaml > app.yaml
    

    REGION 替换为包含现有 Cloud Run 部署的区域。

  5. 如果要更改配置,请修改 app.yaml 文件。如需查看设置列表,请参阅关联的 GitHub 代码库中的配置选项页面。

  6. 部署应用:

    App Engine

    sed -i 's/java11/java17/g' app.yaml
    gcloud app deploy --appyaml app.yaml
    

    Cloud Run

    PROJECT_ID=$(gcloud config get-value core/project)
    
    docker build -t gcr.io/$PROJECT_ID/jitaccess:latest .
    docker push gcr.io/$PROJECT_ID/jitaccess:latest
    
    IMAGE=$(docker inspect --format='{{index .RepoDigests 0}}'  gcr.io/$PROJECT_ID/jitaccess)
    sed -i "s|image:.*|image: $IMAGE|g" app.yaml
    
    gcloud run services replace app.yaml
    

后续步骤