Gateway の保護


このページでは、次のようなセキュリティ機能を使用して Gateway を保護する方法について説明します。

  • SSL ポリシー。Gateway が必要な安全なプロトコルとアルゴリズムを使用していることを確認します。

  • 証明書。クライアントから Gateway へのトラフィックと Gateway からバックエンドへのトラフィックを TLS で保護するために使用します。

  • Google Cloud Armor セキュリティ ポリシー。DDoS 攻撃からサービスを保護します。

  • Identity-Aware Proxy(IAP)、Service へのアクセスを許可する前に認証と認可のレイヤを提供します。

Gateway のセキュリティの詳細については、Gateway のセキュリティをご覧ください。

始める前に

作業を始める前に、次のことを確認してください。

  • Google Kubernetes Engine API を有効にします。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得します。

GKE Gateway Controller の要件

  • Standard の場合は GKE バージョン 1.24 以降。
  • Autopilot の場合は GKE バージョン 1.26 以降。
  • Google Cloud CLI バージョン 407.0.0 以降。
  • Gateway API は、VPC ネイティブ クラスタでのみサポートされます。
  • 内部 GatewayClass を使用している場合は、プロキシ専用サブネットを有効にする必要があります。
  • クラスタで HttpLoadBalancing アドオンが有効になっている必要があります。
  • Istio を使用している場合は、Istio を次のいずれかのバージョンにアップグレードする必要があります。
    • 1.15.2 以降
    • 1.14.5 以降
    • 1.13.9 以降
  • 共有 VPC を使用している場合は、ホスト プロジェクトで、サービス プロジェクトの GKE サービス アカウントに Compute Network User ロールを割り当てる必要があります。

制限事項

GKE Gateway Controller の制限事項と制限に加えて、Gateway のセキュリティには次の制限があります。

  • Gateway で SSL 証明書または Certificate Manager を使用する TLS 構成は、GKE バージョン 1.28.4-gke.1083000 ではサポートされていません。この GKE バージョンでは、回避策として Kubernetes Secret を使用してください。
  • 同じ Gateway リソースに対して、tls.certificateRefsnetworking.gke.io/certmap アノテーションを使用することはできません。Gateway で CertificateMap を参照すると、GKE はこれをエラーとして扱います。
  • Certificate Manager はセルフマネージド証明書と Google マネージド証明書の両方をサポートしますが、リージョン Gateway とは互換性がありません。
  • Google マネージド SSL 証明書を使用する場合は、Gateway に接続する前に GKE の外部で SSL 証明書を作成する必要があります。

  • Google マネージド SSL 証明書にはリージョン Gateway との互換性がありません。各 GatewayClass の TLS 終端方法については、GatewayClass の TLS サポートをご覧ください。

  • Gateway Controller は ManagedCertificate リソースをサポートしていません。

  • Gateway Controller は networking.gke.io/managed-certificates アノテーションをサポートしていません。

  • サービス構成の appProtocol フィールドには、プロトコル値(HTTPHTTPSHTTP2)の大文字のみを使用できます。小文字を使用すると、バックエンドにプロトコルとして HTTP が使用されます。

Kubernetes Secret を使用して Gateway を保護する

この例では、Kubernetes Secret を使用して Gateway を構成します。

証明書を Kubernetes Secret に保存する

認証局(CA)によって発行および検証された証明書を使用するか、自己署名証明書を作成できます。次の手順では、自己署名証明書を使用します。

  1. 秘密鍵を作成する

    openssl genrsa -out PRIVATE_KEY_FILE 2048
    

    PRIVATE_KEY_FILE は、秘密鍵ファイルの名前(private-key.pem など)に置き換えます。詳細については、秘密鍵を選択または作成するをご覧ください。

  2. OpenSSL 構成ファイルを作成します。

    cat <<EOF >CONFIG_FILE
    [req]
    default_bits              = 2048
    req_extensions            = extension_requirements
    distinguished_name        = dn_requirements
    prompt                    = no
    
    [extension_requirements]
    basicConstraints          = CA:FALSE
    keyUsage                  = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName            = @sans_list
    
    [dn_requirements]
    0.organizationName        = example
    commonName                = store.example.com
    
    [sans_list]
    DNS.1                     = store.example.com
    EOF
    

    CONFIG_FILE は、新しい構成ファイルの名前(config-file.cnf など)に置き換えます。

  3. 証明書署名リクエスト(CSR)ファイルを作成するには、次の操作を行います。

    openssl req -new -key PRIVATE_KEY_FILE \
        -out CSR_FILE \
        -config CONFIG_FILE
    

    CSR_FILE は、新しい CSR ファイル(cert.pem など)の名前に置き換えます。詳細については、CSR を作成するをご覧ください。

  4. CSR に署名します。

    openssl x509 -req \
        -signkey PRIVATE_KEY_FILE \
        -in CSR_FILE \
        -out CERTIFICATE_FILE \
        -extfile CONFIG_FILE \
        -extensions extension_requirements \
        -days 30
    

    CERTIFICATE_FILE は、コマンドによって生成されたファイルのパスと名前(cert-file.pem など)に置き換えます。詳細については、CSR に署名するをご覧ください。

  5. 作成した鍵と証明書ファイルを使用して Kubernetes TLS Secret を作成します。

    kubectl create secret tls store-example-com \
        --cert=CERTIFICATE_FILE \
        --key=PRIVATE_KEY_FILE
    

    GKE は、Gateway に接続できる Kubernetes リソースとして証明書と鍵を保存します。

Gateway と HTTPRoute を作成する

  1. 次のマニフェストを external-gateway.yaml として保存します。

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          certificateRefs:
          - name: store-example-com
    

    このマニフェストでは、次のプロパティを持つ Gateway が記述されています。

    • gatewayClassName: gke-l7-global-external-managed: グローバル外部アプリケーション ロードバランサをデプロイします。
    • protocol: HTTPSport: 443: TLS を有効にするために必要です。
    • tls: 前の手順で作成した Kubernetes Secret を参照します。
  2. マニフェストをクラスタに適用します。

    kubectl apply -f external-gateway.yaml
    
  3. 次のマニフェストを store-external-route.yaml として保存します。

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    

    このマニフェストには、store.example.com へのトラフィックを照合して store-v1 Service に送信する HTTPRoute が記述されています。

  4. マニフェストをクラスタに適用します。

    kubectl apply -f store-external-route.yaml
    

Gateway を確認する

インターネット経由でリクエストを送信して、Gateway が動作することを確認します。

  1. Gateway の IP アドレスを取得します。

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    出力は次のようになります。

    203.0.113.12
    

    この出力はパブリック IP アドレスです。つまり、インターネットにアクセスできるクライアントであれば、このアドレスに接続できます。

  2. curl を使用して Gateway のドメインにアクセスします。

    curl https://store.example.com --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert CERTIFICATE_FILE -v
    

    次のように置き換えます。

    • GATEWAY_IP_ADDRESS: Gateway ロードバランサの IP アドレス。
    • CERTIFICATE_FILE: 生成した証明書ファイル。Gateway への接続に使用しているマシンに、このファイルを保存する必要があります。Gateway は自己署名証明書を使用するため、Gateway の認証には証明書が必要です。

    --resolve オプションは、ドメイン名を Gateway の IP アドレスに解決します。このドメインには DNS が構成されていないため、これは必須です。

    出力は次のようになります。

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08"
      # Several lines of output omitted here.
    }
    

    この出力には、TLS handshake が成功した後のアプリケーションからのレスポンスが含まれます。TLS 接続はゲートウェイで終端し、アプリケーションはクライアントに安全に応答します。

SSL 証明書を使用して Gateway を保護する

この例では、Google マネージド SSL 証明書を使用して Gateway を構成します。

SSL 証明書の作成

  1. Google マネージドのグローバル SslCertificate リソースを作成します。

    gcloud compute ssl-certificates create store-example-com \
        --domains=store.example.com \
        --global
    

Gateway と HTTPRoute を作成する

  1. 次のマニフェストを external-gateway.yaml として保存します。

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
        tls:
          mode: Terminate
          options:
            networking.gke.io/pre-shared-certs: store-example-com
    

    このマニフェストでは、次のプロパティを持つ Gateway が記述されています。

    • gatewayClassName: gke-l7-global-external-managed: グローバル外部アプリケーション ロードバランサをデプロイします。
    • protocol:HTTPSport:443: TLS を有効にするために必要です。
    • tls.mode:Terminate: SSL 証明書を使用して TLS を終端します。
  2. マニフェストをクラスタに適用します。

    kubectl apply -f external-gateway.yaml
    
  3. 次の HTTPRoute マニフェストを store-external-route.yaml として保存します。

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
      labels:
        gateway: external-http
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
    
  4. クラスタに HTTPRoute をデプロイします。

    kubectl apply -f store-external-route.yaml
    

    GKE が Gateway をデプロイするまでに数分かかることがあります。

Gateway を確認する

  1. Gateway の IP アドレスを取得します。

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    出力は次のようになります。

    203.0.113.12
    

    この出力はパブリック IP アドレスです。つまり、インターネットにアクセスできるクライアントであれば、このアドレスに接続できます。

  2. A レコードまたは AAAA レコードを更新して、ドメインをゲートウェイの IP アドレスにリダイレクトします。

    この手順は、Google マネージド SSL 証明書を構成する場合にのみ必要です。セルフマネージド証明書を構成する場合は、この手順をスキップできます。

    DNS レコードの更新後、ロードバランサが Google マネージド証明書の使用を開始するまでに最大で 10 分かかることがあります。

  3. curl を使用してインターネット経由でリクエストを送信し、Gateway が機能していることを確認します。

    curl https://store.example.com -v
    

    出力は次のようになります。

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    この出力には、TLS handshake が成功した後のアプリケーションからのレスポンスが含まれます。Gateway で TLS が正しく終端され、アプリケーションがクライアントに安全に応答します。

Certificate Manager を使用して Gateway を保護する

この例では、Certificate Manager を使用して Gateway を構成します。

CertificateMap の作成

  1. CertificateMap を作成します。

    gcloud certificate-manager maps create store-example-com-map
    
  2. セルフマネージド証明書と鍵を Certificate に読み込みます。

    gcloud certificate-manager certificates create store-example-com-cert \
        --certificate-file="cert.pem" \
        --private-key-file="PRIVATE_KEY_FILE"
    
  3. 証明書を CertificateMap に割り当てる CertificateMapEntry を作成します。

    gcloud certificate-manager maps entries create store-example-com-map-entry \
        --map=store-example-com-map \
        --hostname=store.example.com \
        --certificates=store-example-com-cert
    

Gateway と HTTPRoute を作成する

  1. 次のマニフェストを cert-map-gateway.yaml として保存します。

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      annotations:
        networking.gke.io/certmap: store-example-com-map
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
    

    このマニフェストでは、次のプロパティを持つ Gateway が記述されています。

    • gatewayClassName: gke-l7-global-external-managed: グローバル外部アプリケーション ロードバランサをデプロイします。
    • protocol: HTTPSport: 443: TLS を有効にするために必要です。

    TLS はアノテーション networking.gke.io/certmap を使用して Certificate Manager で構成されるため、TLS セクションはありません。

  2. マニフェストをクラスタに適用します。

    kubectl apply -f cert-map-gateway.yaml
    

    GKE が Gateway をデプロイするまでに数分かかることがあります。

  3. 次のマニフェストを cert-map-http-route.yaml として保存します。

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: foo
      namespace: default
    spec:
      parentRefs:
      - name: external-http
      hostnames:
      - foo.example.com
      rules:
      - matches:
        - path:
            value: /
        backendRefs:
        - name: foo-v1
          port: 8080
    
  4. マニフェストをクラスタに適用します。

    kubectl apply -f cert-map-http-route.yaml
    

Gateway を確認する

  1. Gateway の IP アドレスを取得します。

    kubectl get gateway external-http -o=jsonpath="{.status.addresses[0].value}"
    

    出力は次のようになります。

    203.0.113.12
    

    この出力はパブリック IP アドレスです。つまり、インターネットにアクセスできるクライアントであれば、このアドレスに接続できます。

  2. A レコードまたは AAAA レコードを更新して、ドメインをゲートウェイの IP アドレスにリダイレクトします。

    この手順は、Google マネージド SSL 証明書を構成する場合にのみ必要です。セルフマネージド証明書を構成する場合は、この手順をスキップできます。

    DNS レコードの更新後、ロードバランサが Google マネージド証明書の使用を開始するまでに最大で 10 分かかることがあります。

  3. curl を使用して Gateway のドメインにアクセスします。

    curl https://store.example.com -v
    

    出力は次のようになります。

    ...
    * TLSv1.2 (OUT), TLS handshake, Client hello (1):
    * TLSv1.2 (IN), TLS handshake, Server hello (2):
    * TLSv1.2 (IN), TLS handshake, Certificate (11):
    * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
    * TLSv1.2 (IN), TLS handshake, Server finished (14):
    * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
    * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (OUT), TLS handshake, Finished (20):
    * TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
    * TLSv1.2 (IN), TLS handshake, Finished (20):
    * SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
    * ALPN, server accepted to use h2
    * Server certificate:
    *  subject: O=example; CN=store.example.com
    *  start date: Apr 19 15:54:50 2021 GMT
    *  expire date: Apr 19 15:54:50 2022 GMT
    *  common name: store.example.com (matched)
    *  issuer: O=example; CN=store.example.com
    *  SSL certificate verify ok.
    ...
    {
      "cluster_name": "gw",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gw-default-pool-51ccbf30-yya8.c.agmsb-k8s.internal",
      "pod_name": "store-v1-84b47c7f58-tj5mn",
      "pod_name_emoji": "😍",
      "project_id": "agmsb-k8s",
      "timestamp": "2021-04-19T16:30:08",
      "zone": "us-west1-a"
    }
    

    この出力には、TLS handshake が成功した後のアプリケーションからのレスポンスが含まれます。Gateway で TLS が正しく終端され、アプリケーションがクライアントに安全に応答します。

TLS を使用してロードバランサからアプリケーションへのトラフィックを保護する

ports[].appProtocol フィールドを使用して、ロードバランサからバックエンド Pod へのトラフィックを暗号化できます。appProtocol でサポートされているフィールドは、HTTPHTTPSHTTP2 です。

次のマニフェストでは、HTTPS Pod を使用してバックエンド Pod と通信する必要があるロードバランサを指定する Service について説明します。

apiVersion: v1
kind: Service
metadata:
  name: store-v2
spec:
  selector:
    app: store
    version: v2
  ports:
  - port: 8080
    targetPort: 8080
    appProtocol: HTTPS

ロードバランサは、バックエンド Pod で使用される証明書を確認しません。バックエンド Pod で使用される証明書が有効であることの確認は、お客様の責任で行っていただきます。

SSL ポリシーを使用してクライアントからロードバランサへのトラフィックを保護する

アプリケーションが HTTPS を使用する外部ゲートウェイを介して公開される場合は、最新のプロトコルを使用するか、最小の SSL または TLS バージョンを指定することが重要です。SSL ポリシーを使用することで、クライアントからロードバランサのトラフィックを保護できます。

Gateway に接続できる SSL ポリシーとその作成方法の詳細については、クライアントからロードバランサのトラフィックを保護する SSL ポリシーの構成をご覧ください。

Google Cloud Armor を使用してバックエンドを保護する

Google Cloud Armor セキュリティ ポリシーは、ロード バランシンスされたアプリケーションをウェブベースの攻撃から保護するのに役立ちます。Google Cloud Armor セキュリティ ポリシーを構成すると、Kubernetes Service に適用される GCPBackendPolicy で参照できます。

Gateway で Google Cloud Armor ポリシーを構成するには、バックエンド サービスを保護する Google Cloud Armor セキュリティ ポリシーを構成するをご覧ください。

Identity-Aware Proxy を使用してバックエンドへのリクエストを認証する

Identity-Aware Proxy は、アプリケーションにリクエストを送信するクライアントを認証し、ロールベースのトラフィック認可を適用することで、不要なトラフィックからバックエンドを保護します。GKE 用 Identity-Aware Proxy を有効にすると、Kubernetes Service に適用された GCPBackendPolicy で OAuth 認証情報を参照できます。

Gateway を使用して Identity-Aware Proxy を構成するには、Identity-Aware Proxy を構成するをご覧ください。

次のステップ