NGINX レイヤ 7 ロード バランシングのリファレンス実装

Google Distributed Cloud(GDC)エアギャップには、組み込みのマネージド レイヤ 4(L4)ロードバランサが用意されていますが、多くのエンタープライズ アプリケーションでは、ホストベースのルーティング、一元化された TLS 管理、複雑なトラフィック分割など、高度なレイヤ 7(L7)機能が必要です。これまで、これは Ingress API を使用して実現されてきましたが、Kubernetes コミュニティでは現在、機能がフリーズされています。

このリファレンス アーキテクチャは、セルフマネージド レイヤ 7 ロード バランシング ソリューションを提供します。一般的な NGINX Gateway Fabric オープンソース コントローラを GDC Standard クラスタにデプロイすることで、L7 トラフィックをハイブリッド環境にシームレスにルーティングできます。このアーキテクチャでは、TLS 終端(HTTPRoute)を使用して、Server Name Indication(SNI)に基づいて、組み込みのコンテナ化された Pod と外部仮想マシンでホストされているアプリケーションの両方にトラフィックをルーティングします。

アーキテクチャ

GDC エアギャップでの NGINX レイヤ 7 ロード バランシングのアーキテクチャ図。

ソリューションの主なコンポーネントは次のとおりです。

  • クライアント: アプリケーションとやり取りするために HTTPS リクエストを開始するエンティティ。
  • GDC Standard クラスタ: GDC には、Kubernetes Vanilla クラスタを作成する組み込みの方法が用意されています。このソリューションでは、クラスタは L7 LB とそのコントローラ、ワークロード、外部 VM のヘッドレス サービスをホストします。
  • GDC L4 ロードバランサ: エントリ ポイントとして機能する組み込みの L4 ロードバランサ。TCP/443 トラフィックを Gateway コントローラを実行する Kubernetes Pod に直接配信します。
  • Gateway コントローラ: Standard クラスタで実行されている NGINX オペレータ。 Gateway API リソース(GatewayHTTPRoute など)をモニタリングし、基盤となるプロキシを動的に更新します。このソリューションでは、Nginx Gateway Fabric が使用されます。
  • Gateway(HTTPRoute を使用): 物理リスニング ポート(443)と、TLS 終端を使用した SNI ベースのホスト ルーティング ルールを定義する標準化された Kubernetes リソース。
  • コンテナ化されたワークロード(Pod): 通常の Kubernetes Service を使用して内部的に公開される標準の Kubernetes Deployment。
  • VM ベースのワークロード(外部): プロジェクト ネットワーク上の外部 VM でホストされるワークロード。ヘッドレス Kubernetes Service と、VM の直接 IP を含むカスタム エンドポイントを使用してプロキシに公開されます。
  • Harbor Registry: エアギャップ環境でプロキシとアプリケーション イメージを保存して提供するために使用されるプライベート コンテナ レジストリ。

Standard クラスタで、次の 4 つの Namespace を作成します。

  • Nginx Gateway Fabric リソースをホストする nginx-gateway Namespace:

    nginx-gateway Namespace のリソース。

  • Gateway リソースをホストする load-balancer Namespace:

    ロードバランサの Namespace リソース。

  • vm-app Namespace は、外部 VM IP vm-app、ヘッドレス サービス、外部 IP を指す EndpointSliceGatewayHTTPRoute をホストします。

    vm-app Namespace リソース。

  • hello-app Namespace は、デモ コンテナ ワークロードの DeploymentServiceHTTPRouteGateway をホストします。

    hello-app Namespace のリソース。

始める前に

このソリューションをデプロイする前に、次の前提条件を満たしていることを確認してください。

  • 必要なソフトウェア: helm、docker、kubectl
  • CLI ログインとローカル設定: GDC コンソールから gdcloud CLI をダウンロードし、ローカルで環境を設定します。

    export USER_NAME="USER_NAME"
    export PROJECT_ID="PROJECT_ID"
    export ZONE="ZONE"
    export ORG_NAME="ORG_NAME"
    export GDCH_URL="GDC_URL"
    
    gdcloud components install gdcloud-k8s-auth-plugin
    
    gdcloud config set core/organization_console_url \
      https://console.$ORG_NAME.$ZONE.$GDC_URL
    gdcloud config set core/zone $ZONE
    gdcloud config set core/project ${PROJECT_ID}
    
    gdcloud auth login # use --login-config-cert option in case of TLS error
    
  • プロジェクトの設定: GDC エアギャップ環境に プロジェクトを作成して、リソースを保持します。

    gdcloud projects create $PROJECT_ID
    
  • IAM ロール: Kubernetes リソースを管理する クラスタ管理者 ロールと Standard クラスタ管理者 ロール、イメージを push する Harbor インスタンス管理者 ロールをユーザーに付与します。

    # Grant standard cluster and cluster admin roles
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=cluster-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=standard-cluster-admin
    
    # Grant Harbor instance admin role
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=harbor-instance-admin
    

標準クラスタを作成する

このセクションでは、GDC エアギャップ環境内に標準の Kubernetes クラスタを設定するプロセスについて説明します。Standard クラスタは、Nginx Gateway Controller やカスタム アプリケーションなど、さまざまなワークロードをデプロイするための柔軟で堅牢な基盤を提供します。 次の手順では、クラスタが適切に構成され、以降のデプロイでアクセス可能であることを確認します。

  1. 次のコマンドを実行して、使用可能な仮想マシン イメージタイプを特定します。

    gdcloud compute machine-types list
    
  2. クラスタ ワーカーノードに適したマシンタイプを選択します。このチュートリアルでは、 4 つ以上の vCPU を備えたマシンタイプをおすすめします。

    export MACHINE_TYPE="MACHINE_TYPE"
    
  3. 管理 API サーバーの kubeconfig を取得して、エイリアスを設定します。

    export CLUSTER_NAME="CLUSTER_NAME"
    
    KUBECONFIG=kubeconfig-admin.yaml gdcloud clusters \
      get-credentials ${ORG_NAME}-admin
    
    alias km="kubectl --kubeconfig kubeconfig-admin.yaml"
    
  4. 2 つのワーカーノードを含む Standard クラスタを作成します。

    km create -f - <<EOF
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: ${CLUSTER_NAME}
      namespace: ${PROJECT_ID}
    spec:
      nodePools:
      - machineTypeName: ${MACHINE_TYPE}
        nodeCount: 2
        name: ${CLUSTER_NAME}-node-pool
    EOF
    

    使用可能なオプションの詳細については、 ドキュメントをご覧ください。

    Standard クラスタの作成には最長で 60 分ほどかかることがあります。ステータスを確認するには、次のコマンドを使用します。

    km get clusters/${CLUSTER_NAME} \
      -n ${PROJECT_ID} \
      --watch
    

    クラスタの準備ができると、出力に Running の状態が表示されます。

    NAME         STATE     K8S VERSION
    my-cluster   Running   1.30.12-gke.300
    
  5. クラスタの準備ができたら、認証情報を取得します。

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \
      get-credentials ${CLUSTER_NAME} \
      --standard \
      --project ${PROJECT_ID} \
      --zone ${ZONE}
    
  6. このガイドの残りの部分で kubectl コマンドを簡潔にするために、エイリアスを作成します。このエイリアスは、Standard クラスタとのやり取りに使用されます。

    alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"
    
  7. コントローラ、デモ コンテナ化アプリ「hello-app」、VM ベースのデモアプリの Namespace を作成します。

    kk create namespace load-balancer
    kk create namespace hello-app
    kk create namespace vm-app
    

Harbor Registry を作成して統合する

Harbor は、GDC エアギャップに組み込みのサポートを備えたコンテナ イメージ レジストリです。このセクションでは、イメージの安全な pull と push を有効にするための認証情報と Secret の構成など、Harbor Registry を Standard クラスタと統合する手順について説明します。

  1. プロジェクトに Harbor インスタンス を作成します。
  2. Harbor インスタンスに Harbor プロジェクト を作成します。
  3. 環境変数を設定します。

    export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL"
    export HARBOR_PROJECT="HARBOR_INSTANCE_PROJECT"
    export IMAGE_PULL_SECRET_NAME="harbor-secret"
    
  4. ロボット アカウントを使用して Harbor インスタンスにログインします。

    docker --config=./docker login ${HARBOR_INSTANCE_URL}
    
  5. Standard クラスタに Secret を作成します。

    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n load-balancer
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n hello-app
    

デモ コンテナ化アプリをデプロイする

このセクションでは、GDC エアギャップ Kubernetes クラスタ内にデモ コンテナ化アプリケーション(hello-app)をデプロイする方法について説明します。hello-app を実行してクラスタ内で内部的に公開するために必要な Kubernetes Deployment リソースと Service リソースを作成し、L7 ロードバランサを使用してアクセスできるように準備します。

  1. デモ コンテナ化アプリのサンプル イメージを Harbor にアップロードします。

    docker pull gcr.io/google-samples/hello-app:1.0 \
      --platform linux/amd64
    docker tag gcr.io/google-samples/hello-app:1.0 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    
  2. 次のマニフェストを Standard クラスタにデプロイします。

    cat << EOF > hello-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: hello-app
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-server
            image: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
            ports:
            - containerPort: 8080
          imagePullSecrets:
          - name: ${IMAGE_PULL_SECRET_NAME}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      type: ClusterIP
      selector:
        app: hello-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
    EOF
    
    kk apply -f hello-app.yaml
    

次に、Deployment と Service が存在することを確認します。

kk get svc,deploy -n hello-app

VM にデモアプリをデプロイする

このセクションでは、Kubernetes クラスタ外の仮想マシン(VM)にデモ アプリケーションをデプロイする方法について説明します。VM に HTTP サーバーを設定することで、ロードバランサが公開できる外部アプリケーションをシミュレートし、クラスタの内外のリソースへのトラフィックを管理する機能を示します。

まず、デモアプリ用の VM を作成します。

  1. ウェブブラウザで GDC コンソールを開きます。
  2. Standard Kubernetes クラスタを作成したのと同じプロジェクトを選択します。
  3. メニューを開き、[仮想マシン] をクリックします。
  4. [インスタンスを作成] をクリックします。
  5. VM に vm-workload という名前を付けます。この例では、2 つの vCPU イメージで十分です。
  6. ブートディスク イメージには、Python がプリインストールされている Ubuntu 22.04 ディストリビューションを選択します。
  7. [作成] をクリックします。
  8. VM の準備が整うまで数分待ちます。
  9. VM への SSH 接続を確立します。
    1. GDC コンソールで、VM をクリックします。
    2. [SSH で接続] をクリックします。

SSH コンソールに接続したら、次のコマンドを実行します。

mkdir ~/simple-server
cd ~/simple-server
echo 'Welcome to my VM!' > index.html
python3 -m http.server --bind 0.0.0.0 8080 &

VM にトラフィックをルーティングするには、ヘッドレス Service(セレクタなし)を作成します。これは、EndpointSlice リソースを使用して VM の内部 IP アドレスに手動でマッピングされます。

kk apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: vm-app-svc
  namespace: vm-app
spec:
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
EOF

次のコマンドを実行して、vm-workload VM の IP アドレスを取得します。

gdcloud compute instances list --project ${PROJECT_ID} \
  | grep workload-vm | awk '{print $3}'

出力は、EndpointSlice リソースの設定に必要な VM の IP アドレスになります。

VM-app セレクタなし Service に接続し、トラフィックをルーティングする VM の IP アドレスを指定するリソース EndpointSlice を作成します。

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: vm-app-endpoints
  namespace: vm-app
  labels:
    kubernetes.io/service-name: vm-app-svc
addressType: IPv4
ports:
  - port: 8080
endpoints:
  - addresses:
    - "VM_IP"
    conditions:
      ready: true

自己署名証明書を作成する

このセクションでは、アプリケーションの自己署名 TLS 証明書を生成するプロセスについて説明します。このガイドでは、便宜上自己署名証明書を使用しますが、本番環境では、省略可: プロダクション レディ(な)証明書を使用するで説明されているように、プロダクション レディ(な)証明書を使用する必要があります。これらの証明書は、Nginx Gateway で HTTPS 終端を有効にし、コンテナ化されたワークロードと VM ベースのワークロードの両方で、クライアントとロードバランサ間の暗号化された通信を確保するために不可欠です。

  1. コンテナ化されたアプリの証明書を作成します。

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-containerized.key \
      -out tls-containerized.crt \
      -subj "/CN=k8s-app.example.com" \
      -days 365
    
    kk create secret tls tls-containerized \
      --namespace load-balancer \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
    kk create secret tls tls-containerized \
      --namespace hello-app \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
  2. VM アプリの証明書を作成します。

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-vm.key \
      -out tls-vm.crt \
      -subj "/CN=vm-app.example.com" \
      -days 365
    
    kk create secret tls tls-vm \
      --namespace load-balancer \
      --key tls-vm.key \
      --cert tls-vm.crt
    
    kk create secret tls tls-vm \
      --namespace vm-app \
      --key tls-vm.key \
      --cert tls-vm.crt
    

NGINX をデプロイする

このセクションでは、Gateway API カスタム リソース定義(CRD)のインストール、Helm を使用した Nginx Gateway Fabric の設定、Standard クラスタ内でのインストールの確認など、Nginx Gateway Controller をデプロイする手順について説明します。これにより、高度なレイヤ 7 ルーティングのインフラストラクチャが準備されます。

Gateway API CRD をインストールする

Gateway API では、コントローラをデプロイする前に、カスタム リソース定義(CRD)をクラスタにインストールする必要があります。Gateway API プロジェクトの公式の試験運用版カスタム リソース定義(CRD)を使用します(このガイドではバージョン 1.2.0 を使用します)。

  1. 試験運用版の CRD をインストールします。

    kk apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml
    
  2. kk get crd gateways.gateway.networking.k8s.io を実行して、CRD が正常にインストールされていることを確認します。

NGINX Gateway Fabric をインストールする

Helm を使用して NGINX Gateway Fabric コントローラをデプロイします。このコントローラは Gateway API リソースを監視し、トラフィックを処理するように NGINX を構成します。

  1. NGINX イメージタグを設定します。

    helm template nfg oci://ghcr.io/nginx/charts/nginx-gateway-fabric | grep "image:" # get the tag of the nginx-gateway-fabric (in following case 2.4.2)
    
    export NGINX_TAG="2.4.2"
    
  2. NGINX Gateway Fabric イメージと NGINX イメージを pull して、Harbor レジストリに push します。

    docker pull ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG}
    docker tag ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG} \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    
    docker pull nginx:1.27.3
    docker tag nginx:1.27.3 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    
  3. nginx-gateway Namespace を作成し、Harbor イメージ pull Secret を追加します。

    kk create namespace nginx-gateway
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n nginx-gateway
    
  4. Harbor レジストリのイメージを参照して、Helm で NGINX Gateway Fabric をデプロイします。

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml helm upgrade --install ngf \
      oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
      --create-namespace -n nginx-gateway \
      --set nginxGateway.image.tag="${NGINX_TAG}" \
      --set nginxGateway.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric" \
      --set nginx.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx" \
      --set nginxGateway.serviceAccount.imagePullSecret="${IMAGE_PULL_SECRET_NAME}" \
      --set nginx.imagePullSecret="${IMAGE_PULL_SECRET_NAME}"
    

    Kubernetes Deployment は、Harbor ロボット アカウントの認証情報を含む、指定された Secret(${IMAGE_PULL_SECRET_NAME})を使用して、Harbor からイメージを安全に pull します。

  5. GatewayClass リソースが受け入れられていることを確認します。

    kk get gatewayclass
    

    nginxACCEPTED = True で表示されます。

Gateway インスタンスを作成する

ポート 443 でリッスンする論理ロードバランサ インスタンスを定義します。Terminate モードで構成します。つまり、Gateway は TLS 終端を実行し、トラフィックを復号してから通過させます。

gateway.yaml を作成して適用します。

cat << EOF > gateway.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: load-balancer
spec:
  gatewayClassName: nginx
  listeners:
  - name: https-k8s-workload
    hostname: "k8s-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-containerized 
  - name: https-vm-workload
    hostname: "vm-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-vm 
EOF

kk apply -f gateway.yaml

PROGRAMMEDTrue かどうかを確認して、Gateway が正常にデプロイされていることを確認します。

kk get gateway my-gateway --n load-balancer

マネージド GDC L4 ロードバランサが Gateway とともに Service としてデプロイされていることを確認します。

kk get services -n load-balancer

Nginx Service が作成されて構成されていることを確認します。出力は次のようになります。

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)         AGE
my-gateway-nginx   LoadBalancer   10.252.19.148   10.200.32.43   443:30649/TCP   45h

L7 ルーティング ロジック(HTTPRoute)を定義する

HTTPRoute を Gateway にバインドして、リクエストされたホスト名(SNI)に基づいてトラフィックを分散する方法を定義します。

routing.yaml を作成して適用します。

cat << EOF > routing.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: k8s-http-route
  namespace: hello-app
spec:
  parentRefs:
  - name: my-gateway 
    namespace: load-balancer
  hostnames:
  - "k8s-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: hello-app 
      namespace: hello-app
      port: 80          
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: vm-http-route
  namespace: vm-app
spec:
  parentRefs:
  - name: my-gateway
    namespace: load-balancer
  hostnames:
  - "vm-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: vm-app-svc  
      namespace: vm-app
      port: 443       
EOF

kk apply -f routing.yaml   

ロードバランサの IP を取得する

コマンドを実行して、Nginx ロードバランサの IP を取得します。

kk get services/my-gateway-nginx \
  -n load-balancer \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

これは、アプリへのアクセスを確認するときに必要になります。これは LOAD_BALANCER_IP と呼ばれます。

クライアント VM を作成する

手順に沿ってクライアント VM を作成します。

  1. ウェブブラウザで GDC コンソールを開きます。
  2. メニューを開き、[仮想マシン] をクリックします。
  3. [インスタンスを作成] をクリックします。
  4. client という名前の VM を作成し、小規模なマシンタイプを選択して、Rocky Linux または Ubuntu を選択します。これらには curl がプリインストールされています。
  5. [作成] をクリックします。
  6. VM の準備が整うまで数分待ちます。
  7. VM の準備ができたら、VM への SSH 接続を確立します。
    1. GDC コンソールで、VM をクリックします。
    2. [SSH で接続] をクリックします。

アクセスとルーティングを確認する

ルーティングをテストするには、クライアント VM から curl コマンドを実行します。ロードバランサの IP アドレスを使用して、定義されたホスト名で両方のアプリケーションに接続できます。

curl で --resolve フラグを渡すと、ドメイン名を GDC エアギャップ L4 ロードバランサの IP アドレスに強制的に解決できます。 自己署名証明書を信頼するために -k フラグを渡します。

Kubernetes コンテナ化アプリをテストします。

curl -k --resolve k8s-app.example.com:443:$LOAD_BALANCER_IP https://k8s-app.example.com -v

外部 VM アプリをテストします。

curl -k --resolve vm-app.example.com:443:$LOAD_BALANCER_IP https://vm-app.example.com -v

正しく構成されている場合、Gateway コントローラは TLS 終端としてシームレスに機能し、トラフィックを宛先に通過させます。

省略可: プロダクション レディ(な)証明書を使用する

このセクションでは、GDC エアギャップ CA Service を活用してプライベート ルート認証局(CA)を作成し、ワークロードの署名付き証明書を発行して、GDC エアギャップ Standard クラスタとクライアント VM を安全に更新する方法について説明します。

このセクションでは、GDC エアギャップ CA Service を使用して プライベート ルート認証局(CA)を作成し、アプリケーションの 有効な証明書を発行する方法について説明します。このルート CA をクライアント VM にインストールすると、SSL 警告を回避しなくても(curl -k を使用するなど)、信頼できる証明書で TLS 終端がシームレスに機能することを確認できます。

必要な権限を付与して認証情報を取得する

CA Service を管理して証明書を発行するには、プロジェクトに適切な IAM ロールが必要です。

  1. certificate-authority-service-admin ロールと certificate-requester ロールを付与します。

    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-authority-service-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-requester
    
  2. 管理 API サーバーの認証情報を取得します。

    gdcloud clusters get-credentials ${ORG_NAME}-admin
    

ルート CA を作成する

プロジェクト Namespace 内の管理 API サーバーに認証局を作成します。

  1. CertificateAuthority リソースを適用します。

    km apply -f - <<EOF
    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: my-root-ca
      namespace: ${PROJECT_ID}
    spec:
      caProfile:
        commonName: "My Root CA"
        duration: 87600h # 10 years
        keyAlgorithm: RSA_2048
        maxChainLength: 1
      caType: ROOT
      keyLocation: HSM
      rotationPolicy:
        cronTime: 0 0 1 1 *
    EOF
    
    km -n ${PROJECT_ID} get \
    certificateauthority.pki.security.gdc.goog/my-root-ca -ojson \
    | jq -r '
    .status.conditions[] | select( .type as $id | "Ready" | index($id)) .status'
    

証明書を発行してデプロイする

CA の準備ができたら、コンテナ化されたアプリと VM ベースのアプリの両方の証明書をリクエストします。これらのリクエストは管理 API サーバーで行われ、結果の鍵は Standard クラスタに移動する必要があります。

両方のドメインのリクエストを作成します。

km apply -f - <<EOF
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-containerized-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "k8s-app.example.com"
      dnsNames:
      - "k8s-app.example.com"
  signedCertificateSecret: tls-containerized-signed
---
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-vm-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "vm-app.example.com"
      dnsNames:
      - "vm-app.example.com"
  signedCertificateSecret: tls-vm-signed
EOF

証明書が発行されるまでしばらく待ちます。Ready 条件が True の場合は、準備が完了しています。

km get certificaterequests -n ${PROJECT_ID}

Standard クラスタを更新する

このガイドの前のセクションの手順に沿って操作した場合は、Standard クラスタに自己署名 Secret があります。新しい署名付きバージョンを作成する前に、これらを削除する必要があります。

kk delete secret tls-containerized -n load-balancer
kk delete secret tls-vm -n load-balancer

kk delete secret tls-containerized -n hello-app
kk delete secret tls-vm -n vm-app

次に、署名付き証明書を管理 API サーバーから抽出し、Standard クラスタに新しい Secret を作成します。

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-containerized.key

kk create secret tls tls-containerized \
  --namespace load-balancer \
  --key tls-containerized.key \
  --cert tls-containerized.crt

kk create secret tls tls-containerized \
  --namespace hello-app \
  --key tls-containerized.key \
  --cert tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-vm.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-vm.key

kk create secret tls tls-vm \
  --namespace load-balancer \
  --key tls-vm.key \
  --cert tls-vm.crt

kk create secret tls tls-vm \
  --namespace vm-app \
  --key tls-vm.key \
  --cert tls-vm.crt

新しい Secret は自動的に取得され、ロードバランサによって更新されます。

クライアントの信頼を構成する

設定を確認するには、新しいルート CA を信頼するようにクライアント VM に指示する必要があります。

ルート CA 証明書をファイルに抽出します。

km get secret -n ${PROJECT_ID} my-root-ca-secret \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > my-root-ca.crt

証明書をクライアント VM に転送します。(my-root-ca.crt の内容をコピーして、クライアント VM 上のファイルに貼り付けることができます)。

クライアント VM で、トラスト ストアを更新します。

client VM が Ubuntu の場合:

sudo cp my-root-ca.crt /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates

client VM が Rocky Linux の場合:

sudo cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

アクセス権の確認

-k フラグを使用せずに、curl を使用してアプリケーションにアクセスできるようになりました。接続は完全に信頼されます。

Kubernetes コンテナ化アプリをテストします。

curl -v --resolve k8s-app.example.com:443:LOAD_BALANDER_IP https://k8s-app.example.com

VM アプリをテストします。

curl -v --resolve vm.example.com:443:LOAD_BALANDER_IP https://vm-app.example.com

成功すると、SSL 証明書の警告が表示されずに、アプリケーションの出力がすぐに表示されます。