Ingress ゲートウェイで TLS 終端を設定する

概要

このページでは、Cloud Service Mesh の Ingress ゲートウェイで TLS 終端を設定して、サービスへの外部 HTTPS トラフィックを管理する方法について説明します。ゲートウェイの設定方法のより基本的な説明については、ゲートウェイ ガイドをご覧ください。TLS を使用して安全な通信を行うようにゲートウェイを構成し、アプリケーションへの暗号化されたアクセスを有効にする方法についても学習します。このプロセスでは、Cloud Service Mesh の機能を活用してサービスを安全に公開します。

始める前に

このドキュメントの手順を完了するには、次のリソースが必要です。

  • Cloud Service Mesh がインストールされている Kubernetes クラスタ。Cloud Service Mesh のインストール方法については、インストール ガイドをご覧ください。

環境を設定する

使用するクラスタにアクセスできるワークステーションから次のコマンドを実行します。クラスタに固有のクラスタ コンテキストを使用するように、kubectl ツールが構成されていることを確認します。

  1. 環境変数を設定します。

    export CSM_INGRESSGATEWAY_NAMESPACE=CSM_INGRESSGATEWAY_NAMESPACE
    export CSM_INGRESSGATEWAY_DEPLOYMENT_NAME=CSM_INGRESSGATEWAY_DEPLOYMENT_NAME
    export CSM_INGRESSGATEWAY_SERVICE_NAME=CSM_INGRESSGATEWAY_SERVICE_NAME
    
  2. foo アプリケーションをクラスタにデプロイします。次の yaml を使用してインストールします。

    apiVersion: v1
    kind: Service
    metadata:
      name: foo
      namespace: foo
    spec:
      selector:
        app: test-backend
      ports:
      - port: 8080
        targetPort: 8080
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: foo
      namespace: foo
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: test-backend
      template:
        metadata:
          labels:
            app: test-backend
        spec:
          containers:
          - name: whereami
            image: gcr.io/google-samples/whereami:v1.2.23
            ports:
            - containerPort: 8080
    EOF
    
  3. 証明書と鍵を生成します。

    Ingress ゲートウェイを保護するには、TLS 証明書と鍵が必要です。任意の証明書生成ツールを使用することも、次の手順で openssl を使用して必要な認証情報を作成することもできます。

    • ルート CA 証明書と鍵を作成する
    mkdir example_certs
    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=Example Corp/CN=example.com' \
      -keyout example.com.key -out example.com.crt
    
    • Ingress の証明書と鍵を生成する
    openssl req -out foo.example.com.csr -newkey rsa:2048 -nodes \
      -keyout foo.example.com.key -subj "/CN=foo.example.com/O=Foo Org"
    
    openssl x509 -req -sha256 -days 365 -CA example.com.crt \
      -CAkey example.com.key -set_serial 0 \
      -in foo.example.com.csr -out foo.example.com.crt
    

TLS 証明書を保存する

TLS 証明書を Secret として保存します。

  1. Namespace を作成します。この Namespace は、Ingress ゲートウェイのデプロイに使用されます。

    kubectl create namespace ${CSM_INGRESSGATEWAY_NAMESPACE}
    
  2. デフォルトのインジェクション ラベルを Namespace に適用します。

    kubectl label namespace ${CSM_INGRESSGATEWAY_NAMESPACE} \
        istio.io/rev- istio-injection=enabled --overwrite
    
  3. TLS 認証情報を Kubernetes Secret に保存します。

    kubectl create -n ${CSM_INGRESSGATEWAY_NAMESPACE} secret tls foo-credential \
      --key=example_certs/foo.example.com.key \
      --cert=example_certs/foo.example.com.crt
    

TLS 証明書をゲートウェイに適用する

新しく作成した TLS 証明書をゲートウェイで使用する方法は 2 つあります。

マウントされた認証情報ありでデプロイする(推奨)

  1. デフォルトの Ingress ゲートウェイ マニフェストをローカル ファイルにコピーします。

    curl https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-samples/main/docs/ingress-gateway-external-lb/ingress-gateway.yaml > ingress-gateway.yaml
    
  2. ingress-gateway.yaml のデプロイ仕様を変更して、TLS シークレット認証情報をマウントします。

    apiVersion: apps/v1
    kind: Deployment
    ...
    spec:
      ...
        spec:
            ...
            volumeMounts:
            - name: foo-credential # Add new volume mount specifying mount path.
              mountPath: /etc/secrets/foo-credential 
              readOnly: true
          volumes:
          - name: foo-credential # Point volume mount to the Kubernetes secret holding the TLS certificate and keys.
            secret:
              secretName: foo-credential
    

    次に、Ingress ゲートウェイに関連するリソースを作成します。

    kubectl --namespace ${CSM_INGRESSGATEWAY_NAMESPACE} apply --filename ingress-gateway.yaml 
    
  3. Ingress ゲートウェイを定義する

    マウントされたシークレットを参照するポート 443 の HTTPS トラフィックを処理するゲートウェイ リソースを作成します。

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1
    kind: Gateway
    metadata:
      name: secure-gateway
      namespace: ${CSM_INGRESSGATEWAY_NAMESPACE}
    spec:
      selector:
        app: asm-ingressgateway
        istio: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        tls:
          mode: SIMPLE
          serverCertificate: /etc/secrets/foo-credential/foo.example.com.crt
          privateKey: /etc/secrets/foo-credential/foo.example.com.key
        hosts:
        - "foo.example.com"
    EOF
    

マウントされた認証情報なしでデプロイする

  1. Ingress ゲートウェイ マニフェスト ファイルを適用します。

    kubectl --namespace ${CSM_INGRESSGATEWAY_NAMESPACE} apply --filename https://raw.githubusercontent.com/GoogleCloudPlatform/anthos-service-mesh-samples/main/docs/ingress-gateway-external-lb/ingress-gateway.yaml
    

    予想される出力:

    serviceaccount/asm-ingressgateway created
    role.rbac.authorization.k8s.io/asm-ingressgateway created
    rolebinding.rbac.authorization.k8s.io/asm-ingressgateway created
    deployment.apps/asm-ingressgateway created
    service/asm-ingressgateway created
    poddisruptionbudget.policy/asm-ingressgateway created
    horizontalpodautoscaler.autoscaling/asm-ingressgateway created
    
  2. Ingress ゲートウェイを定義する

    ポート 443 の HTTPS トラフィックを処理するゲートウェイ リソースを作成します。

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1
    kind: Gateway
    metadata:
      name: secure-gateway
      namespace: ${CSM_INGRESSGATEWAY_NAMESPACE}
    spec:
      selector:
        app: asm-ingressgateway
        istio: ingressgateway
      servers:
      - port:
          number: 443
          name: https
          protocol: HTTPS
        tls:
          mode: SIMPLE
          credentialName: foo-credential
        hosts:
        - "foo.example.com"
    EOF
    

デプロイの最適化

認証情報がマウントされていないデプロイを使用する場合、Ingress ゲートウェイ Pod は認証情報が更新されているかどうかを定期的にチェックします。デフォルトでは、最大 60 分かかります。ポーリング頻度を変更するには、Ingress ゲートウェイ Pod のデプロイに CSM_MIN_K8S_SECRET_REFRESH_INTERVAL 環境変数と CSM_MAX_K8S_SECRET_REFRESH_INTERVAL 環境変数を設定します。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: asm-ingressgateway
  ...
spec:
  ...
  template:
    ...
    spec:
      containers:
      - name: istio-proxy
        image: auto
        env:
        - name: CSM_MIN_K8S_SECRET_REFRESH_INTERVAL
          value: "15m" # Half of the default minimum interval
        - name: CSM_MAX_K8S_SECRET_REFRESH_INTERVAL
          value: "30m" # Half of the default maximum interval
      ...

トラフィックをテストする

  1. トラフィックを foo サービスにルーティングします。

    トラフィックを foo デプロイに転送する VirtualService を定義します。

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1
    kind: VirtualService
    metadata:
      name: foo-routing
      namespace: ${CSM_INGRESSGATEWAY_NAMESPACE}
    spec:
      hosts:
      - "foo.example.com"
      gateways:
      - secure-gateway
      http:
      - match:
        - uri:
            prefix: /status
        - uri:
            prefix: /delay
        route:
        - destination:
            host: foo
            port:
              number: 8080
    EOF
    
  2. クラスタから Ingress ゲートウェイに接続するように外部ロードバランサを設定します

  3. 安全な接続をテストします。

    次の curl コマンドを使用して設定を確認します。

    export EXTERNAL_LB_IP_ADDRESS=EXTERNAL_LB_IP_ADDRESS
    curl -v -H "Host: foo.example.com" --resolve "foo.example.com:443:$EXTERNAL_LB_IP_ADDRESS" \
      --cacert example_certs/example.com.crt "https://foo.example.com:443/ping"
    

    EXTERNAL_LB_IP_ADDRESS は、外部ロードバランサの IP に置き換えます。

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

      {
        "cluster_name": "gke-us",
        "host_header": "34.120.175.141",
        "pod_name": "whereami-deployment-954cbf78-mtlpf",
        "pod_name_emoji": "😎",
        "project_id": "my-project",
        "timestamp": "2021-11-29T17:01:59",
        "zone": "us-central1-b"
      }
    

次のステップ