GKE 限定公開クラスタの制限付きアクセスを構成する

このドキュメントでは、VPC Service Controls のサービス境界で Google Kubernetes Engine プライベート クラスタを使用するときに、制限付きの仮想 IP(VIP)を使用して pkg.dev および gcr.io ドメインにリクエストをルーティングするように DNS エントリを構成する方法について説明します。

レジストリ ドメインは通常、インターネット上のパブリック IP アドレスに解決されます。GKE 限定公開クラスタでは、ノードはデフォルトでインターネットから隔離されます。つまり、制限付き VIP への DNS ルーティングを構成していない場合、レジストリ ドメインへのリクエストは失敗します。

サポート対象サービスからサポート対象外サービスにデータが流出しないように、プライベート クラスタは、常に制限付き VIP を使用して Artifact Registry または Container Registry にアクセスする必要があります。

次のすべての条件に該当する場合は、GKE プライベート クラスタの制限付きアクセスを構成します。

  • GKE プライベート クラスタを使用している。
  • pkg.dev または gcr.io レジストリ ドメインの restricted.googleapis.com へのルーティングをまだ構成していない。

始める前に

サービス境界を作成する前に、新しい限定公開クラスタを設定するか、既存の限定公開クラスタの中から保護するクラスタを選択します。

また、ポート 443 で 199.36.153.4/30 への外向き(下り)を許可する必要があります。通常、VPC ネットワークには、任意の宛先へのすべての外向き(下り)トラフィックを許可する暗黙ルールがあります。ただし、このようなトラフィックを拒否するルールがある場合は、ポート 443 で 199.36.153.4/30 への TCP トラフィックを許可する外向き(下り)ファイアウォール ルールを作成する必要があります。

DNS の構成

レジストリ アドレスに対するリクエストが制限付き VIP の restricted.googleapis.com に解決されるように DNS サーバーを構成します。これを行うには、Cloud DNS の非公開 DNS ゾーンを使用します。

  1. 非公開のマネージド ゾーンを作成します。

    gcloud dns managed-zones create ZONE_NAME \
        --visibility=private \
        --networks=https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks/NETWORK \
        --description=DESCRIPTION \
        --dns-name=REGISTRY_DOMAIN \
        --project=PROJECT_ID
    

    説明:

    • ZONE_NAME は、作成するゾーンの名前です。例: registryこの名前は、以降のステップでも使用します。
    • PROJECT_ID は、GKE プライベート クラスタをホストするプロジェクトの ID です。
    • NETWORK は、リクエストのリダイレクト元のクラスタ ネットワークの名前のリストです(省略可)。
    • DESCRIPTION は、人間が読める形式のマネージド ゾーンの説明です。
    • REGISTRY_DOMAIN は、レジストリのドメインです。
      • pkg.dev(Artifact Registry の場合)
      • gcr.io(Container Registry の場合)または Artifact Registry でホストされている gcr.io リポジトリ
  2. トランザクションを開始します。

    gcloud dns record-sets transaction start \
      --zone=ZONE_NAME \
      --project=PROJECT_ID
    

    説明:

    • ZONE_NAME は、最初の手順で作成したゾーンの名前です。

    • PROJECT_ID は、GKE 限定公開クラスタをホストするプロジェクトの ID です。

  3. レジストリの CNAME レコードを追加します。

    gcloud dns record-sets transaction add \
      --name=*.REGISTRY_DOMAIN. \
      --type=CNAME REGISTRY_DOMAIN. \
      --zone=ZONE_NAME \
      --ttl=300 \
      --project=PROJECT_ID
    

    説明:

    • ZONE_NAME は、最初の手順で作成したゾーンの名前です。
    • PROJECT_ID は、GKE プライベート クラスタをホストするプロジェクトの ID です。
    • REGISTRY_DOMAIN は、レジストリのドメインです。
      • pkg.dev(Artifact Registry の場合)
      • gcr.io(Container Registry の場合)または Artifact Registry でホストされている gcr.io リポジトリ
  4. 制限付き VIP の A レコードを追加します。

    gcloud dns record-sets transaction add \
      --name=REGISTRY_DOMAIN. \
      --type=A 199.36.153.4 199.36.153.5 199.36.153.6 199.36.153.7 \
      --zone=ZONE_NAME \
      --ttl=300 \
      --project=PROJECT_ID
    

    説明:

    • ZONE_NAME は、最初の手順で作成したゾーンの名前です。
    • PROJECT_ID は、GKE プライベート クラスタをホストするプロジェクトの ID です。
    • REGISTRY_DOMAIN は、レジストリのドメインです。
      • pkg.dev(Artifact Registry の場合)
      • gcr.io(Container Registry の場合)または Artifact Registry でホストされている gcr.io リポジトリ
  5. トランザクションを実行します。

    gcloud dns record-sets transaction execute \
      --zone=ZONE_NAME \
      --project=PROJECT_ID
    

    説明:

    • ZONE_NAME は、最初の手順で作成したゾーンの名前です。

    • PROJECT_ID は、GKE 限定公開クラスタをホストするプロジェクトの ID です。

DNS ルーティングを構成したら、GKE、レジストリ、その他の必要なサービスが VPC Service Controls のサービス境界内にあることを確認します。サービス境界を構成するには、次のセクションをご覧ください。

サービス境界を構成する

DNS レコードを構成したら、次の操作を行います。

  1. 新しいサービス境界を作成するか、既存の境界を更新します。
  2. サービス境界を使用して保護するサービスのリストに Container Registry または Artifact Registry サービスを追加します。
  3. レジストリで使用するほかのサポート対象のサービスを Cloud Build、Artifact Analysis、Binary Authorization などのサービス境界に追加します。
  4. Container Registry にアクセスする必要がある場合は、Cloud Storage もサービス境界に追加する必要があります。

境界の動作を確認する

サービス境界を構成した後、サービス境界内のプロジェクトにイメージが保存されている場合、GKE プライベート クラスタのノードは Artifact Registry と Container Registry のコンテナ イメージにアクセスできます。

境界外のプロジェクトのコンテナ イメージには、いくつかの特定の読み取り専用公開リポジトリを除き、アクセスできません。

たとえば、google-samples プロジェクトがサービス境界にない場合、hello-app コンテナからデプロイを作成するコマンドを実行すると失敗します。

pkg.dev ドメイン

kubectl create deployment hello-server --image=us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0

gcr.io ドメイン

kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0

次のコマンドで Pod のステータスを確認します。

kubectl get pods

このコマンドは、次の例のようなテーブルを返します。Pod のステータス ErrImagePull は、pull が失敗したことを示します。

NAME                            READY   STATUS         RESTARTS   AGE
hello-server-dbd86c8c4-h5wsf    1/1     ErrImagePull   0          45s

kubectl describe pod コマンドを使用すると、Deployment の詳細が表示されます。前の例の Pod の場合、コマンドは次のようになります。

kubectl describe pod hello-server-dbd86c8c4-h5wsf