为 Application Load Balancer 设置授权政策

在应用负载均衡器中,授权政策是在评估路线扩展、网络安全政策(由 Google Cloud Armor 评估)、跨域资源共享 (CORS) 政策和 Identity-Aware Proxy (IAP) 之后,但在执行流量管理操作之前调用的。

本页介绍了如何为应用负载均衡器设置授权政策。

准备工作

设置负载均衡器

如果您尚未创建负载均衡器,请参阅以下页面,设置首选的应用负载均衡器:

创建和配置安全代码或服务账号

使用内部应用负载均衡器时,您可以选择性地根据附加到客户端虚拟机的安全标记和服务账号来应用授权政策。如果您打算应用基于标记的授权政策,请使用 Resource Manager 创建标记。

如果您使用的是外部应用负载均衡器,则无需创建和配置安全标记。

如需了解详情,请参阅使用防火墙标记服务账号

将服务账号附加到客户端虚拟机

如需了解如何将服务账号关联到虚拟机实例的分步说明,请参阅以下文档:

创建安全的标记键和标记值

在将安全标记与实例组模板绑定之前,您必须先创建标记键和值。创建代码时,请为其指定 GCE_FIREWALL 用途。Google Cloud 网络功能(包括安全 Web 代理和授权政策)需要使用 GCE_FIREWALL 用途来应用代码。

如需创建安全标记,您需要拥有 Tag Administrator 角色 (roles/resourcemanager.tagAdmin)。

控制台

  1. 在 Google Cloud 控制台中,前往标记页面。

    前往“标记”

  2. 点击 创建

  3. 标记键说明字段中,输入说明。

  4. 选中与网络防火墙搭配使用复选框。

  5. 项目列表中,选择您要在其中创建代码的 Google Cloud 项目。

  6. 网络字段中,选择 LB_NETWORK

  7. 点击 添加值

  8. 标记值字段中,输入 TAG_VALUE。该值必须是数字值。

  9. 标记值说明字段中,输入说明。

  10. 添加完标记值后,点击创建标记键

gcloud

  1. 创建安全的标记键。

    gcloud resource-manager tags keys create TAG_KEY \
        --parent=organizations/ORG_ID \
        --purpose=GCE_FIREWALL \
        --purpose-data=network=LB_NETWORK
    

    替换以下内容:

    • TAG_KEY:安全标记键的名称。
    • ORG_ID:您的组织的 ID。
    • LB_NETWORK:您的 VPC 网络的名称。
  2. 将安全标记值添加到数字标记键。

    gcloud resource-manager tags values create TAG_VALUE \
        --parent=ORG_ID/TAG_KEY
    

    TAG_VALUE 替换为数字标记值。

将安全标记绑定到实例组模板

标记管理员可以将安全标记绑定到各个虚拟机实例或实例组模板,并将标记的值附加到虚拟机或模板的后端。

如需绑定安全标记,您需要拥有 Tag User 角色 (roles/resourcemanager.tagUser)。

  1. 定义项目和可用区的完整名称前缀:

    FULL_NAME_PREFIX=//compute.googleapis.com/projects/PROJECT_ID/zones/ZONE/instances/
    

    替换以下内容:

    • PROJECT_ID:您的项目的 ID。
    • ZONE:托管式实例组所在的可用区。
  2. 获取实例组模板 ID:

    TEMPLATE_ID=$(gcloud compute instance-templates describe TEMPLATE_NAME --region=LOCATION --format='value(id)')
    

    替换以下内容:

    • TEMPLATE_NAME:实例组模板的名称。
    • LOCATION:您的 Google Cloud 区域。
  3. 串联 FULL_NAME_PREFIXTEMPLATE_ID 的值:

    PARENT="$FULL_NAME_PREFIX$TEMPLATE_ID"
    echo $PARENT
    
  4. 创建绑定。

    gcloud resource-manager tags bindings create \
        --location LOCATION \
        --tag-value ORG_ID/TAG_KEY/TAG_VALUE \
        --parent PARENT
    

    替换以下内容:

    • ORG_ID:您的组织的 ID。
    • LOCATION:您的 Google Cloud 区域。
    • TAG_KEY:安全标记键的名称。
    • TAG_VALUE:数字标记值。

创建授权政策

如需创建授权政策,您需要创建一个用于定义目标和规则的 YAML 文件,然后使用 gcloud beta network-security authz-policies 命令导入该文件。

本部分介绍了如何创建附加到负载均衡器转发规则的不同类型的授权政策。

用于拒绝请求的授权政策

全球和跨区域

如果您使用的是全球外部应用负载均衡器或跨区域内部应用负载均衡器,请按以下步骤创建和导入授权政策:

  1. 创建授权政策文件以拒绝特定请求。

    以下示例在 global 位置为转发规则 LB_FORWARDING_RULE 创建 authz-policy-deny.yaml 文件。该政策会禁止 *.hello.com 客户端访问 /api/payments 网址路径。

    $ cat >authz-policy-deny.yaml <<EOF
    name: my-authz-policy-deny
    target:
      loadBalancingScheme: LB_SCHEME
      resources:
      - "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules/LB_FORWARDING_RULE"
    httpRules:
    - from:
        sources:
        - principals:
          - suffix: ".hello.com"
      to:
        operations:
        - paths:
          - prefix: "/api/payments"
    action: DENY
    EOF
    

    替换以下内容:

    • LB_SCHEME:您的负载均衡方案。对于全球外部应用负载均衡器,请将架构设置为 EXTERNAL_MANAGED。对于跨区域内部应用负载均衡器,请将架构设置为 INTERNAL_MANAGED
    • PROJECT_ID:您的 Google Cloud 项目的 ID。
    • LB_FORWARDING_RULE:负载均衡器的转发规则的名称。
  2. 创建授权政策并导入 YAML 文件。

    以下示例命令会导入之前创建的政策文件并创建授权政策:

    gcloud beta network-security authz-policies import my-authz-policy-deny \
        --source=authz-policy-deny.yaml \
        --location=global
    

区域

如果您使用的是区域级外部应用负载均衡器或区域级内部应用负载均衡器,请按照以下步骤创建和导入授权政策:

  1. 创建授权政策文件以允许特定请求。

    以下示例在 Google Cloud 区域中为转发规则 LB_FORWARDING_RULE 创建 authz-policy-deny.yaml 文件。该政策会禁止与 *.hello.com 匹配的身份的客户端访问 /api/payments 网址路径。此外,该政策还会禁止使用服务账号 my-sa-123@PROJECT_ID.iam.gserviceaccount.com 访问 /api/payments 网址的任何客户端虚拟机。

    $ cat >authz-policy-deny.yaml <<EOF
    name: my-authz-policy-deny
    target:
      loadBalancingScheme: LB_SCHEME
      resources:
      - "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/LOCATION/forwardingRules/LB_FORWARDING_RULE"
    httpRules:
    - from:
        sources:
        - principals:
          - suffix: ".hello.com"
      to:
        operations:
        - paths:
          - prefix: "/api/payments"
    - from:
        sources:
        - resources:
           - iamServiceAccount:
               exact: "my-sa-123@PROJECT_ID.iam.gserviceaccount.com"
      to:
        operations:
        - paths:
          - prefix: "/api/payments"
    action: DENY
    EOF
    

    替换以下内容:

    • LB_SCHEME:您的负载均衡方案。对于区域级外部应用负载均衡器,请将架构设置为 EXTERNAL_MANAGED。对于区域级内部应用负载均衡器,请将架构设置为 INTERNAL_MANAGED
    • PROJECT_ID:您的 Google Cloud 项目的 ID。
    • LOCATION:您的 Google Cloud 区域。
    • LB_FORWARDING_RULE:负载均衡器的转发规则的名称。
  2. 创建授权政策并导入 YAML 文件。

    以下示例命令会导入之前创建的政策文件,并在 LOCATION 区域中创建授权政策:

    gcloud beta network-security authz-policies import my-authz-policy-deny \
        --source=authz-policy-deny.yaml \
        --location=LOCATION
    

用于允许请求的授权政策

全球和跨区域

如果您使用的是全球外部应用负载均衡器或跨区域内部应用负载均衡器,请按以下步骤创建和导入授权政策:

  1. 创建授权政策文件以允许特定请求。

    以下示例在 global 位置为转发规则 LB_FORWARDING_RULE 创建 authz-policy-allow.yaml 文件。该政策仅允许来自 *.example.com 的客户端访问 /api/payments 网址路径。

    $ cat >authz-policy-allow.yaml <<EOF
    name: my-authz-policy-allow
    target:
      loadBalancingScheme: LB_SCHEME
      resources:
      - "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules/LB_FORWARDING_RULE"
    httpRules:
    - from:
      sources:
      - principals:
        - suffix: ".example.com"
      to:
        operations:
        - paths:
          - exact: "/api/payments"
    action: ALLOW
    EOF
    

    替换以下内容:

    • LB_SCHEME:您的负载均衡方案。对于全球外部应用负载均衡器,请将架构设置为 EXTERNAL_MANAGED。对于跨区域内部应用负载均衡器,请将架构设置为 INTERNAL_MANAGED
    • PROJECT_ID:您的 Google Cloud 项目的 ID。
    • LB_FORWARDING_RULE:负载均衡器的转发规则的名称。
  2. 创建授权政策并导入 YAML 文件。

    以下示例命令会导入之前创建的政策文件并创建授权政策:

    gcloud beta network-security authz-policies import my-authz-policy-allow \
        --source=authz-policy-allow.yaml \
        --location=global
    

区域

如果您使用的是区域级外部应用负载均衡器或区域级内部应用负载均衡器,请按照以下步骤创建和导入授权政策:

  1. 创建授权政策文件以允许特定请求。

    以下示例为区域级内部应用负载均衡器的 Google Cloud 区域中的转发规则 LB_FORWARDING_RULE 创建了一个 authz-policy-allow.yaml 文件。该政策规定,只有来自 *.example.com 的客户端可以在请求来自具有资源标记 TAG_VALUE 的虚拟机时访问 /api/payments 网址路径。

    $ cat >authz-policy-allow.yaml <<EOF
    name: my-authz-policy-allow
    target:
      loadBalancingScheme: LB_SCHEME
      resources:
      - "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/LOCATION/forwardingRules/LB_FORWARDING_RULE"
    httpRules:
    - from:
      sources:
      - principals:
        - suffix: ".example.com"
        resources:
        - tagValueIdSet:
          - ids: "TAG_VALUE"
      to:
        operations:
        - paths:
          - exact: "/api/payments"
    action: ALLOW
    EOF
    

    替换以下内容:

    • LB_SCHEME:您的负载均衡方案。如果您使用的是区域级外部应用负载均衡器,请将方案设置为 EXTERNAL_MANAGED。如果您使用的是区域级内部应用负载均衡器,请将架构设置为 INTERNAL_MANAGED
    • PROJECT_ID:您的 Google Cloud 项目的 ID。
    • LOCATION:您的 Google Cloud 区域。
    • LB_FORWARDING_RULE:负载均衡器的转发规则的名称。
  2. 创建授权政策并导入 YAML 文件。

    以下示例命令会导入之前创建的政策文件,并在 LOCATION 区域中创建授权政策:

    gcloud beta network-security authz-policies import my-authz-policy-allow \
        --source=authz-policy-allow.yaml \
        --location=LOCATION
    

要委托给服务扩展程序的授权政策

开始之前,请先设置外部授权引擎。如需详细了解服务扩展,请参阅 Cloud Load Balancing 宣传信息概览

全球和跨区域

如果您使用的是全球外部应用负载均衡器或跨区域内部应用负载均衡器,请按以下步骤创建和导入授权政策:

  1. 创建授权政策文件,以将某些请求委托给外部服务。

    以下示例会在 global 位置为转发规则 LB_FORWARDING_RULE 创建 authz-policy-custom.yaml 文件。当请求包含不为空的 Authorization 标头时,该政策会针对指向 /api/payments 网址路径的所有流量调用 AUTHZ_EXTENSION 扩展程序。

    $ cat >authz-policy-custom.yaml <<EOF
    name: my-authz-policy-custom
    target:
      loadBalancingScheme: LB_SCHEME
      resources:
      - "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/forwardingRules/LB_FORWARDING_RULE"
    httpRules:
    - to:
        operations:
        - paths:
          - exact: "/api/payments"
      when: 'request.headers["Authorization"] != ""'
    action: CUSTOM
    customProvider:
      authzExtension:
        resources:
        - "https://networkservices.googleapis.com/v1/projects/PROJECT_ID/locations/global/authzExtensions/AUTHZ_EXTENSION"
    EOF
    

    替换以下内容:

    • LB_SCHEME:您的负载均衡方案。对于全球外部应用负载均衡器,请将架构设置为 EXTERNAL_MANAGED。对于跨区域内部应用负载均衡器,请将架构设置为 INTERNAL_MANAGED
    • PROJECT_ID:您的 Google Cloud 项目的 ID。
    • LB_FORWARDING_RULE:负载均衡器的转发规则的名称。
    • AUTHZ_EXTENSION:授权扩展程序的名称。
  2. 创建授权政策并导入 YAML 文件。

    以下示例命令会导入之前创建的政策文件并创建授权政策:

    gcloud beta network-security authz-policies import my-authz-policy-custom \
        --source=authz-policy-custom.yaml \
        --location=global
    

区域

如果您使用的是区域级外部应用负载均衡器或区域级内部应用负载均衡器,请按照以下步骤创建和导入授权政策:

  1. 创建授权政策文件,以将某些请求委托给外部服务。

    以下示例在区域级内部应用负载均衡器的 Google Cloud 区域中为转发规则 LB_FORWARDING_RULE 创建 authz-policy-custom.yaml 文件。当请求包含不为空的 Authorization 标头时,该政策会针对指向 /api/payments 网址路径的所有流量调用 AUTHZ_EXTENSION 扩展程序。

    $ cat >authz-policy-custom.yaml <<EOF
    name: my-authz-policy-custom
    target:
      loadBalancingScheme: LB_SCHEME
      resources:
      - "https://www.googleapis.com/compute/v1/projects/PROJECT_ID/regions/LOCATION/forwardingRules/LB_FORWARDING_RULE"
    httpRules:
    - to:
        operations:
        - paths:
          - exact: "/api/payments"
      when: 'request.headers["Authorization"] != ""'
    action: CUSTOM
    customProvider:
      authzExtension:
        resources:
        - "https://networkservices.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/authzExtensions/AUTHZ_EXTENSION"
    EOF
    

    替换以下内容:

    • LB_SCHEME:您的负载均衡方案。对于区域级外部应用负载均衡器,请将架构设置为 EXTERNAL_MANAGED。对于区域级内部应用负载均衡器,请将架构设置为 INTERNAL_MANAGED
    • PROJECT_ID:您的 Google Cloud 项目的 ID。
    • LOCATION:您的 Google Cloud 区域。
    • LB_FORWARDING_RULE:负载均衡器的转发规则的名称。
    • AUTHZ_EXTENSION:授权扩展程序的名称。
  2. 创建授权政策并导入 YAML 文件。

    以下示例命令会导入之前创建的政策文件,并在 LOCATION 区域中创建授权政策:

    gcloud beta network-security authz-policies import my-authz-policy-custom \
        --source=authz-policy-custom.yaml \
        --location=LOCATION
    

测试授权政策

如需测试授权政策,请将一些流量发送到负载均衡器。如需了解详情,请参阅以下页面:

了解 Cloud Logging 中的授权政策日志

如需了解在允许或拒绝请求时如何记录授权政策,请参阅以下内容:

  • 如果请求与 ALLOW 政策和 DENY 政策都不匹配,则 DENY 政策会允许该请求,并将其记录为 allowed_as_no_deny_policies_matched_request。反之,ALLOW 政策会拒绝请求并将其记录为 denied_as_no_allow_policies_matched_request。由于其中一个政策拒绝了请求,因此请求被拒绝。

    如果您使用的是全球外部应用负载平衡器,则日志中的 statusDetails 会设置为 denied_by_authz_policy。请参阅以下示例:

      {
        httpRequest: {8}
        insertId: "example-id"
        jsonPayload: {
          @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
          authzPolicyInfo: {
            policies: [
              0: {
                details: "allowed_as_no_deny_policies_matched_request"
                result: "ALLOWED"
              }
              1: {
                details: "denied_as_no_allow_policies_matched_request"
                result: "DENIED"
              }
            ]
            result: "DENIED"
          }
          backendTargetProjectNumber: "projects/12345567"
          remoteIp: "00.100.11.104"
          proxyStatus: "error=\"http_request_error\"; details=\"denied_by_authz_policy\""
        }
        logName: "projects/example-project/logs/requests"
        receiveTimestamp: "2024-08-28T15:33:56.046651035Z"
        resource: {2}
        severity: "WARNING"
        spanId: "3e1a09a8e5e3e14d"
        timestamp: "2024-08-28T15:33:55.355042Z"
        trace: "projects/example-project/traces/8c8b3dbf9a19c85954d0fa2d958ca509"
      }
    

    如果您使用的是区域级内部应用负载均衡器、区域级外部应用负载均衡器或跨区域内部应用负载均衡器,则日志中的 proxyStatus 会设置为 error=\"http_request_error\"; details=\"denied_by_authz_policy\"。请参阅以下示例:

      {
        httpRequest: {8}
        insertId: "example-id"
        jsonPayload: {
          @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
          authzPolicyInfo: {
            policies: [
              0: {
                details: "allowed_as_no_deny_policies_matched_request"
                result: "ALLOWED"
              }
              1: {
                details: "denied_as_no_allow_policies_matched_request"
                result: "DENIED"
              }
            ]
            result: "DENIED"
          }
          backendTargetProjectNumber: "projects/12345567"
          remoteIp: "00.100.11.104"
          proxyStatus: "error=\"http_request_error\"; details=\"denied_by_authz_policy\""
        }
        logName: "projects/example-project/logs/requests"
        receiveTimestamp: "2024-08-28T15:33:56.046651035Z"
        resource: {2}
        severity: "WARNING"
        spanId: "3e1a09a8e5e3e14d"
        timestamp: "2024-08-28T15:33:55.355042Z"
        trace: "projects/example-project/traces/8c8b3dbf9a19c85954d0fa2d958ca509"
      }
    
  • 如果请求与 DENY 政策匹配,系统会拒绝该请求,并记录拒绝该请求的政策。

    如果您使用的是全球外部应用负载均衡器,则日志中的 statusDetails 会设置为 denied_by_authz_policy,而拒绝请求的政策名称会记录在 policies 中。请参阅以下示例:

      {
        httpRequest: {8}
        insertId: "example-id"
        jsonPayload: {
          @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
          authzPolicyInfo: {
            policies: [
              0: {
                details: "name: "projects/12345567/locations/global/authzPolicies/deny-authz-policy-test""
                result: "DENIED"
              }
            ]
            result: "DENIED"
          }
          backendTargetProjectNumber: "projects/12345567"
          cacheDecision: [2]
          remoteIp: "00.100.11.104"
          statusDetails: "denied_by_authz_policy"
        }
        logName: "projects/example-project/logs/requests"
        receiveTimestamp: "2024-08-28T15:33:56.046651035Z"
        resource: {2}
        severity: "WARNING"
        spanId: "3e1a09a8e5e3e14d"
        timestamp: "2024-08-28T15:33:55.355042Z"
        trace: "projects/example-project/traces/8c8b3dbf9a19c85954d0fa2d958ca509"
      }
    

    如果您使用的是区域级内部应用负载平衡器、区域级外部应用负载平衡器或跨区域内部应用负载平衡器,则 proxyStatus 会设置为 error=\"http_request_error\"; details=\"denied_by_authz_policy\",并且政策名称会记录在 policies 中。请参阅以下示例:

      {
        httpRequest: {8}
        insertId: "example-id"
        jsonPayload: {
          @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
          authzPolicyInfo: {
            policies: [
              0: {
                details: "name: "projects/12345567/locations/$REGION/authzPolicies/deny-authz-policy-test""
                result: "DENIED"
              }
            ]
            result: "DENIED"
          }
          backendTargetProjectNumber: "projects/12345567"
          remoteIp: "00.100.11.104"
          proxyStatus: "error=\"http_request_error\"; details=\"denied_by_authz_policy\""
        }
        logName: "projects/example-project/logs/requests"
        receiveTimestamp: "2024-08-28T15:33:56.046651035Z"
        resource: {2}
        severity: "WARNING"
        spanId: "3e1a09a8e5e3e14d"
        timestamp: "2024-08-28T15:33:55.355042Z"
        trace: "projects/example-project/traces/8c8b3dbf9a19c85954d0fa2d958ca509"
      }
    
  • 如果请求与 DENY 政策不匹配,但与 ALLOW 政策匹配,则允许该请求。在日志中,此操作会针对 DENY 政策记录为 allowed_as_no_deny_policies_matched_request。系统还会记录允许该请求的政策。

    如果您使用的是全球外部应用负载均衡器,日志中不会包含 statusDetails。允许请求的政策也会记录在 policies 中。请参阅以下示例:

      {
        httpRequest: {8}
        insertId: "example-id"
        jsonPayload: {
          @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
          authzPolicyInfo: {
            policies: [
              0: {
                details: "allowed_as_no_deny_policies_matched_request"
                result: "ALLOWED"
              }
              1: {
                details: "name: "projects/12345567/locations/global/authzPolicies/allow-authz-policy-test""
                result: "ALLOWED"
              }
            ]
            result: "ALLOWED"
          }
          backendTargetProjectNumber: "projects/12345567"
          cacheDecision: [2]
          remoteIp: "00.100.11.104"
        }
        logName: "projects/example-project/logs/requests"
        receiveTimestamp: "2024-08-28T15:33:56.046651035Z"
        resource: {2}
        severity: "WARNING"
        spanId: "3e1a09a8e5e3e14d"
        timestamp: "2024-08-28T15:33:55.355042Z"
        trace: "projects/example-project/traces/8c8b3dbf9a19c85954d0fa2d958ca509"
      }
    

    如果您使用的是区域级内部应用负载均衡器、区域级外部应用负载均衡器或跨区域内部应用负载均衡器,日志中将不包含 proxyStatus 字段。允许请求的政策也会记录在 policies 中。请参阅以下示例:

      {
        httpRequest: {8}
        insertId: "example-id"
        jsonPayload: {
          @type: "type.googleapis.com/google.cloud.loadbalancing.type.LoadBalancerLogEntry"
          authzPolicyInfo: {
            policies: [
              0: {
                details: "allowed_as_no_deny_policies_matched_request"
                result: "ALLOWED"
              }
              1: {
                details: "name: "projects/12345567/locations/$REGION/authzPolicies/allow-authz-policy-test""
                result: "ALLOWED"
              }
            ]
            result: "ALLOWED"
          }
          backendTargetProjectNumber: "projects/12345567"
          cacheDecision: [2]
          remoteIp: "00.100.11.104"
        }
        logName: "projects/example-project/logs/requests"
        receiveTimestamp: "2024-08-28T15:33:56.046651035Z"
        resource: {2}
        severity: "WARNING"
        spanId: "3e1a09a8e5e3e14d"
        timestamp: "2024-08-28T15:33:55.355042Z"
        trace: "projects/example-project/traces/8c8b3dbf9a19c85954d0fa2d958ca509"
      }
    

后续步骤