Certificate Authority Service を使用して Cloud Service Mesh Ingress ゲートウェイの TLS 証明書管理を自動化する
このチュートリアルでは、プラットフォーム オペレーターが cert-manager ツールの Certificate Authority Service(CA Service)発行者を使用して、Cloud Service Mesh Ingress ゲートウェイの TLS 証明書の管理を自動化する方法について説明します。この証明書により、Ingress ゲートウェイは、Virtual Private Cloud(VPC)内でサービス メッシュの外部にあるクライアントから送信された HTTPS やその他の TLS、mTLS トラフィックを終端できます。このチュートリアルでは、Kubernetes と TLS 証明書について基本的な知識があることを前提としています。
はじめに
Cloud Service Meshh は、サービス メッシュ内のすべてのワークロードに TLS 証明書をプロビジョニングします。これらの証明書により、サービス メッシュ内のワークロード間で暗号化と相互認証 TLS(mTLS)通信が可能になります。サポートされている CA の 1 つが証明書を発行して署名します。
ただし、Cloud Service Mesh は、サービス メッシュに送信されるトラフィックに対して Ingress ゲートウェイに証明書を自動的にプロビジョニングしません。一般的な解決策は、オープンソースの cert-manager ツールを使用して、Ingress ゲートウェイでの証明書管理を自動化することです。
cert-manager ツールは、認証局(CA)を表す発行者の証明書をリクエストします。CA Service とは、独自のプライベート CA を作成できる Google Cloud サービスです。cert-manager ツールは、オープンソースの CA Service の外部発行者を使用して、CA Service の証明書をリクエストできます。
プライベート CA は、内部ネットワーク内でトラフィックを認証して暗号化する TLS 証明書を発行できます。多くの場合、Cloud Service Mesh の Ingress ゲートウェイは、VPC 内でサービス メッシュ外のクライアントからの受信トラフィックを許可するように設定されています。内部ネットワーク トラフィックに対しては、CA Service のプライベート CA を使用して Ingress ゲートウェイの証明書を発行できます。
このチュートリアルでは、Ingress ゲートウェイの TLS 証明書のプロビジョニングと更新を自動化するために、cert-manager ツールと CA Service 発行者を設定する方法について説明します。cert-manager ツールは、TLS タイプの Kubernetes Secret リソースとして証明書をプロビジョニングします。cert-manager ツールが証明書を更新すると、Secret リソースが新しい証明書で更新されます。Ingress ゲートウェイは Envoy プロキシを実行し、Envoy のシークレット検出サービス(SDS)をサポートします。SDS を使用すると、管理者がプロセスを再起動または再読み込みすることなく、Ingress ゲートウェイが新しい証明書を使用できるようになります。
メッシュの一部であるサイドカー プロキシは、CA Service または Cloud Service Mesh 認証局から TLS 証明書を取得できます。このチュートリアルでは、サイドカー プロキシと Ingress ゲートウェイの両方の証明書に CA Service を使用します。これにより、すべての TLS 証明書に 1 つのルート CA を使用できます。
次の図は、このチュートリアルでプロビジョニングするリソースを示しています。Ingress ゲートウェイに内部パススルー ネットワーク ロードバランサをプロビジョニングします。内部パススルー ネットワーク ロードバランサはプロキシではないため、TCP 接続の終端処理や TLS handshake は行いません。代わりに、istio-ingressgateway
Deployment の Pod に接続がルーティングされます。
hello-example-com-credential
Secret には証明書と秘密鍵が含まれています。hello
ゲートウェイは、この証明書と秘密鍵を使用してホスト名 hello.example.com
を持つリクエストに対して TLS handshake を実行するように istio-ingressgateway
Deployment の Pod を構成します。
cert-manager
Namespace 内の google-cas-issuer
Deployment の Pod が、CA Service で作成した CA の証明書をリクエストします。ca-service-isser
Pod が Workload Identity を使用して Google サービス アカウントの権限を借用できるようにする Identity and Access Management ポリシー バインディングを作成します。この Google サービス アカウントに CA Service の CA に証明書をリクエストする権限を付与するには、CA プールで IAM ポリシー バインディングを作成します。
目標
- CA Service の構成
- GKE クラスタを作成する
- Cloud Service Mesh コントロール プレーンをインストールする
- Ingress ゲートウェイをインストールする
- cert-manager ツールをインストールする
- CA Service 発行元コントローラをインストールする
- 証明書の発行者を作成する
- サンプル アプリケーションをデプロイする
- 問題の解決を確認する
- (オプション)CA 証明書をトラストストアに追加する
費用
このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。
このチュートリアルの終了後に作成したリソースを削除すれば、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
準備
Google Cloud コンソールでプロジェクト セレクタのページに移動し、プロジェクトを選択または作成します。
Google Cloud プロジェクトの課金が有効になっていることを確認します。
Google Cloud Console で、Cloud Shell に移動します。
Google Cloud コンソールの下部で Cloud Shell セッションが開き、コマンドライン プロンプトが表示されます。このチュートリアルでは、コマンドの実行はすべて Cloud Shell で行います。
このチュートリアルで使用する Google Cloud コンソール プロジェクトを設定します。
gcloud config set core/project PROJECT_ID
PROJECT_ID は、Cloud プロジェクト ID に置き換えます。
[Cloud Shell の承認] ダイアログで、[承認] をクリックします。[承認] をクリックすると、Cloud Shell で実行する
gcloud
コマンドで、ユーザー認証情報を使用して Google API に対する認証が可能となります。Resource Manager、GKE、GKE Hub、Cloud Service Mesh 認証局、CA Service の API を有効にします。
gcloud services enable \ cloudresourcemanager.googleapis.com \ container.googleapis.com \ gkehub.googleapis.com \ meshca.googleapis.com \ privateca.googleapis.com
CA Service の構成
このセクションでは、ルート CA と 2 つの下位 CA を CA サービスに作成します。1 つの下位 CA が Ingress ゲートウェイに証明書を発行し、もう 1 つの下位 CA がメッシュ内のサイドカー プロキシに証明書を発行します。
わかりやすくするため、このチュートリアルでは GKE クラスタ、ルート CA、下位 CA に同じプロジェクトを使用します。独自の環境では、GKE クラスタと CA に異なるプロジェクトを使用できます。
Cloud Shell で、ルート CA に使用する CA プールを作成します。
gcloud privateca pools create ROOT_CA_POOL \ --location CA_LOCATION \ --tier enterprise
- ROOT_CA_POOL は、CA プールの名前です。例:
root-ca-pool-tutorial
- CA_LOCATION は、CA プールのロケーションです。例:
us-central1
利用可能な CA Service のロケーションを一覧表示するには、
gcloud privateca locations list
コマンドを使用します。- ROOT_CA_POOL は、CA プールの名前です。例:
ルート CA を作成して有効にします。
gcloud privateca roots create ROOT_CA \ --auto-enable \ --key-algorithm ec-p384-sha384 \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --subject "CN=Example Root CA, O=Example Organization" \ --use-preset-profile root_unconstrained
- ROOT_CA は、ルート CA に使用する名前です。例:
root-ca-tutorial
- ROOT_CA は、ルート CA に使用する名前です。例:
Ingress ゲートウェイに証明書を発行する下位 CA に使用する CA プールを作成します。
gcloud privateca pools create SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --tier devops
- SUBORDINATE_CA_POOL_GATEWAYS は、CA プールの名前です。例:
subordinate-ca-mtls-pool-gateways-tutorial
- SUBORDINATE_CA_POOL_GATEWAYS は、CA プールの名前です。例:
Ingress ゲートウェイに証明書を発行する下位 CA を作成して有効にします。
gcloud privateca subordinates create SUBORDINATE_CA_GATEWAYS \ --auto-enable \ --issuer-location CA_LOCATION \ --issuer-pool ROOT_CA_POOL \ --key-algorithm ec-p256-sha256 \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_GATEWAYS \ --subject "CN=Example Gateway mTLS CA, O=Example Organization" \ --use-preset-profile subordinate_mtls_pathlen_0
- SUBORDINATE_CA_GATEWAYS は、下位 CA に使用する名前です。例:
subordinate-ca-mtls-gateways-tutorial
--use-preset-profile
フラグは、下位 mTLS 証明書プロファイルを使用するように下位 CA を構成します。このプロファイルにより、下位 CA は mTLS に対してクライアント TLS とサーバー TLS 証明書の両方を発行できます。
Ingress ゲートウェイで mTLS の代わりに単純な TLS を使用する場合は、下位 CA でサーバー TLS 証明書を発行するだけで済みます。この場合は、代わりに下位サーバーの TLS(
subordinate_server_tls_pathlen_0
)証明書プロファイルを使用できます。- SUBORDINATE_CA_GATEWAYS は、下位 CA に使用する名前です。例:
証明書の発行ポリシーを作成します。
cat << EOF > policy.yaml baselineValues: keyUsage: baseKeyUsage: digitalSignature: true keyEncipherment: true extendedKeyUsage: serverAuth: true clientAuth: true caOptions: isCa: false identityConstraints: allowSubjectPassthrough: false allowSubjectAltNamesPassthrough: true celExpression: expression: subject_alt_names.all(san, san.type == URI && san.value.startsWith("spiffe://PROJECT_ID.svc.id.goog/ns/") ) EOF
この発行ポリシーにより、CA はメッシュ内のワークロードの証明書のみを発行するように制限されます。
メッシュ内のサイドカー プロキシに証明書を発行する下位 CA に使用する CA プールを作成します。発行ポリシーを CA プールに適用します。
gcloud privateca pools create SUBORDINATE_CA_POOL_SIDECARS \ --issuance-policy policy.yaml \ --location CA_LOCATION \ --tier devops
- SUBORDINATE_CA_POOL_SIDECARS は、CA プールの名前です。例:
subordinate-ca-mtls-pool-sidecars-tutorial
- SUBORDINATE_CA_POOL_SIDECARS は、CA プールの名前です。例:
メッシュ内のサイドカー プロキシに証明書を発行する下位 CA を作成して有効にします。
gcloud privateca subordinates create SUBORDINATE_CA_SIDECARS \ --auto-enable \ --issuer-location CA_LOCATION \ --issuer-pool ROOT_CA_POOL \ --key-algorithm ec-p256-sha256 \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_SIDECARS \ --subject "CN=Example Sidecar mTLS CA, O=Example Organization" \ --use-preset-profile subordinate_mtls_pathlen_0
- SUBORDINATE_CA_GATEWAYS は、下位 CA に使用する名前です。例:
subordinate-ca-mtls-sidecars-tutorial
- SUBORDINATE_CA_GATEWAYS は、下位 CA に使用する名前です。例:
Google Kubernetes Engine クラスタを作成する
Cloud Shell で、GKE クラスタを作成します。
gcloud container clusters create CLUSTER_NAME \ --enable-ip-alias \ --num-nodes 4 \ --release-channel regular \ --scopes cloud-platform \ --workload-pool PROJECT_ID.svc.id.goog \ --zone ZONE
CLUSTER_NAME は、クラスタの名前に置き換えます。例:
asm-ingress-cert-manager-ca-service
ZONE は、クラスタに使用するゾーンに置き換えます。例:
us-central1-f
コマンドについて、次の点に注意してください。
--release-channel
フラグを指定すると、クラスタの GKE リリース チャンネルが選択されます。- Cloud Service Mesh と cert-manager ツールの CA Service 発行元の両方で、クラスタノードに
cloud-platform
スコープを設定する必要があります。 --workload-pool
引数を使用すると、Workload Identity が有効になり、CA サービス発行元の Kubernetes サービス アカウントが Google サービス アカウントになりすますことができます。この権限借用により、CA Service 発行元 Pod が Google サービス アカウントの鍵ファイルをダウンロードすることなく、CA Service API にアクセスできます。
ユーザー アカウントにクラスタ管理者の権限を付与します。
kubectl create clusterrolebinding cluster-admin-binding \ --clusterrole cluster-admin \ --user $(gcloud config get-value core/account)
Cloud Service Mesh のロールベース アクセス制御(RBAC)ルールを作成し、cert-manager ツールをインストールするには、Kubernetes
cluster-admin
ClusterRole によって提供される権限が必要です。
Anthos Service Mesh コントロール プレーンをインストールする
このチュートリアルでは、Google Cloud 上の GKE クラスタにマネージド Cloud Service Mesh をインストールし、すべてのリソースを 1 つのプロジェクトにまとめます。独自の環境では、このドキュメントで説明するソリューションはマネージド Cloud Service Mesh またはクラスタ内コントロール プレーンを使用して適用できます。
Cloud Service Mesh には、さまざまなシナリオに対応する各種のインストール オプションが用意されています。このチュートリアルを完了したら、インストール ガイドを確認して、実際の環境に最適なオプションを選択することをおすすめします。
Cloud Shell で、
asmcli
インストール ツールをダウンロードします。curl --location --output asmcli https://storage.googleapis.com/csm-artifacts/asm/asmcli_1.15 chmod +x asmcli
asmcli
を使用して Cloud Service Mesh コントロール プレーンをインストールします。Cloud Service Mesh コントロール プレーンをインストールします。
./asmcli install \ --ca gcp_cas \ --ca_pool projects/PROJECT_ID/locations/CA_LOCATION/caPools/SUBORDINATE_CA_POOL_SIDECARS \ --cluster_location ZONE \ --cluster_name CLUSTER_NAME \ --enable_all \ --enable_registration \ --fleet_id PROJECT_ID \ --managed \ --output_dir asm-files \ --project_id PROJECT_ID \ --verbose
--ca gcp_cas
フラグと--ca_pool
フラグを指定すると、CA Service のサイドカー CA プールを使用してメッシュ内のサイドカー プロキシに証明書を発行するように、Cloud Service Mesh コントロール プレーンを構成できます。--enable_registration
フラグを指定して、--fleet_id
フラグに指定したプロジェクトのフリートに GKE クラスタを登録します。このチュートリアルでは、GKE クラスタとフリートは同じプロジェクトを使用します。--managed
フラグは、マネージド Cloud Service Mesh コントロール プレーンを設定します。--output_dir
フラグには、Cloud Service Mesh のインストールに必要なファイルと構成をダウンロードする際にasmcli
が使用するディレクトリを指定します。これらのファイルは、チュートリアルの後半で使用します。
インストールには数分かかります。インストールが完了すると、次の出力が表示されます。
asmcli: Successfully installed ASM.
Ingress ゲートウェイをインストールする
Cloud Shell で、Ingress ゲートウェイの Kubernetes 名前空間を作成します。
kubectl create namespace GATEWAY_NAMESPACE
- GATEWAY_NAMESPACE は、Ingress ゲートウェイに使用する名前空間の名前です。例:
istio-ingress
- GATEWAY_NAMESPACE は、Ingress ゲートウェイに使用する名前空間の名前です。例:
Ingress ゲートウェイの内部パススルー ネットワーク ロードバランサに使用する静的内部 IP アドレスを予約します。
LOAD_BALANCER_IP=$(gcloud compute addresses create \ asm-ingress-gateway-ilb \ --region REGION \ --subnet default \ --format 'value(address)')
- REGION は、GKE クラスタノードが使用するゾーンを含むリージョンに置き換えます。たとえば、クラスタで
us-central1-f
ゾーンを使用する場合は、REGION をus-central1
に置き換えます。
このコマンドは、指定したリージョンのデフォルト サブネットの IP アドレスを予約します。
- REGION は、GKE クラスタノードが使用するゾーンを含むリージョンに置き換えます。たとえば、クラスタで
Ingress ゲートウェイのオペレータ マニフェストを作成します。
cat << EOF > ingressgateway-operator.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: ingressgateway-operator annotations: config.kubernetes.io/local-config: "true" spec: profile: empty revision: asm-managed components: ingressGateways: - name: istio-ingressgateway namespace: GATEWAY_NAMESPACE enabled: true k8s: overlays: - apiVersion: apps/v1 kind: Deployment name: istio-ingressgateway patches: - path: spec.template.metadata.annotations value: inject.istio.io/templates: gateway - path: spec.template.metadata.labels.sidecar\.istio\.io/inject value: "true" - path: spec.template.spec.containers[name:istio-proxy] value: name: istio-proxy image: auto service: loadBalancerIP: $LOAD_BALANCER_IP serviceAnnotations: networking.gke.io/load-balancer-type: Internal networking.gke.io/internal-load-balancer-allow-global-access: "true" EOF
オペレータ マニフェストについては、次の点に注意してください。
revision
フィールドには、データプレーンに使用するマネージド Cloud Service Mesh リリース チャンネルを指定します。コントロール プレーンに Rapid または Stable のリリース チャンネルを使用する場合は、このフィールドの値を変更します。overlays
セクションで指定したannotation
、label
、image
により、Ingress ゲートウェイ デプロイメントでプロキシ構成の自動挿入が有効になります。loadBalancerIP
フィールドには、ロードバランサに使用する IP アドレスを指定します。このフィールドをマニフェストから削除すると、ロードバランサはエフェメラル IP アドレスを使用します。Ingress ゲートウェイのサービス アノテーション
networking.gke.io/load-balancer-type: Internal
は、GKE が Ingress ゲートウェイ Pod の前に内部パススルー ネットワーク ロードバランサをプロビジョニングすることを意味します。このアノテーションを削除すると、GKE は代わりに外部パススルー ネットワーク ロードバランサをプロビジョニングします。オプションのサービス アノテーション
networking.gke.io/internal-load-balancer-allow-global-access: "true"
を使用すると、VPC の任意のリージョンのクライアントが内部パススルー ネットワーク ロードバランサにアクセスできます。このアノテーションを削除すると、内部パススルー ネットワーク ロードバランサは、VPC の同じリージョン内のクライアントから送信されたトラフィックのみを受信します。
オペレータ マニフェストと、コントロール プレーンのインストール時に
asmcli
スクリプトがダウンロードしたistioctl
ツールを使用して、Ingress ゲートウェイ インストール マニフェストを作成します。./asm-files/istioctl manifest generate \ --filename ingressgateway-operator.yaml \ --output ingressgateway
Ingress ゲートウェイをインストールします。
kubectl apply --recursive --filename ingressgateway/
cert-manager ツールをインストールする
Cloud Shell で、cert-manager ツールのインストール マニフェストをダウンロードして適用します。
CERT_MANAGER_VERSION=v1.5.4 curl --location --output cert-manager.yaml "https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml" kubectl apply --filename cert-manager.yaml
cert-manager ツールのインストールには 1 分ほどかかります。
CA Service 発行元コントローラをインストールする
CA Service 発行元コントローラを使用すると、cert-manager ツールは CA Service を使用して証明書をリクエストできます。コントローラは、cert-manager ツールの外部発行元の拡張メカニズムを使用します。
Cloud Shell で、Google サービス アカウントを作成します。
gcloud iam service-accounts create CAS_ISSUER_GSA \ --display-name "CA Service issuer for cert-manager"
- CAS_ISSUER_GSA は、Google サービス アカウントの名前です。例:
cert-manager-ca-service-issuer
Certificate Authority サービス発行元コントローラは、この Google サービス アカウントを使用して、Certificate Authority サービス API に対する認証を行います。
- CAS_ISSUER_GSA は、Google サービス アカウントの名前です。例:
Certificate Authority サービス発行元コントローラの Google サービス アカウントが下位 CA を含む CA プールの証明書をリクエストできるように、Identity and Access Management ポリシー バインディングを作成します。
gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester
Certificate Authority サービス発行元コントローラのインストール マニフェストをダウンロードします。
CAS_ISSUER_VERSION=v0.5.3 curl --location --output ca-service-issuer.yaml "https://github.com/jetstack/google-cas-issuer/releases/download/${CAS_ISSUER_VERSION}/google-cas-issuer-${CAS_ISSUER_VERSION}.yaml"
IAM ポリシー バインディングを作成して、
cert-manager
名前空間のksa-google-cas-issuer
Kubernetes サービス アカウントが Workload Identity を使用して Google サービス アカウント(GSA)になりすますことを許可します。gcloud iam service-accounts add-iam-policy-binding \ CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com \ --member "serviceAccount:PROJECT_ID.svc.id.goog[cert-manager/ksa-google-cas-issuer]" \ --role roles/iam.workloadIdentityUser
CA サービス発行元コントローラ Pod は、
ksa-google-cas-issuer
Kubernetes サービス アカウントを使用します。GKE クラスタに CA サービス発行元コントローラをインストールします。
kubectl apply --filename ca-service-issuer.yaml
Workload Identity アノテーション
iam.gke.io/gcp-service-account
を、CA サービス発行元コントローラ Pod が使用する Kubernetes サービス アカウントに追加します。kubectl annotate serviceaccount ksa-google-cas-issuer --namespace cert-manager \ "iam.gke.io/gcp-service-account=CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com"
このアノテーションは、Kubernetes サービス アカウントが Google サービス アカウントに成り代わって Google API にアクセスできることを GKE に通知します。
証明書の発行者を作成する
Cloud Shell で、GoogleCASIssuer マニフェストを作成して適用します。
cat << EOF > gateway-cas-issuer.yaml apiVersion: cas-issuer.jetstack.io/v1beta1 kind: GoogleCASIssuer metadata: name: gateway-cas-issuer namespace: GATEWAY_NAMESPACE spec: caPoolId: SUBORDINATE_CA_POOL_GATEWAYS location: CA_LOCATION project: PROJECT_ID EOF kubectl apply --filename gateway-cas-issuer.yaml
発行元により、cert-manager ツールで Ingress ゲートウェイ名前空間の下位 CA プールの証明書をプロビジョニングできます。
サンプル アプリケーションをデプロイする
このセクションでは、cert-manager ツールが CA サービス発行元を使用して CA サービスから証明書を取得できることを確認します。確認するために、リクエスト ルーティング構成と Ingress ゲートウェイの証明書を使用してサンプル アプリケーションをデプロイします。
Cloud Shell で、サンプル アプリケーション リソースの名前空間を作成します。
cat << EOF > sample-app-namespace.yaml apiVersion: v1 kind: Namespace metadata: name: APP_NAMESPACE annotations: mesh.cloud.google.com/proxy: '{"managed":"true"}' labels: istio.io/rev: asm-managed EOF kubectl apply --filename sample-app-namespace.yaml
- APP_NAMESPACE は、サンプル アプリケーションの名前空間の名前です。例:
sample-app
アノテーション
mesh.cloud.google.com/proxy
を使用すると、名前空間に対してマネージド データプレーンが有効になります。ラベル
istio.io/rev: asm-managed
は、サンプル アプリケーションの名前空間にあるマネージド データプレーンの Regular リリース チャンネルを選択します。Rapid または Stable のリリース チャンネルを使用している場合は、このラベルの値を変更します。- APP_NAMESPACE は、サンプル アプリケーションの名前空間の名前です。例:
サンプル アプリケーションの Deployment リソースを作成します。
cat << EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: hello namespace: APP_NAMESPACE labels: app: hello spec: replicas: 1 selector: matchLabels: app: hello template: metadata: labels: app: hello spec: containers: - image: gcr.io/google-samples/hello-app:1.0 name: hello-app ports: - containerPort: 8080 EOF kubectl apply --filename deployment.yaml
サンプル アプリケーションの Service リソースを作成します。
cat << EOF > service.yaml apiVersion: v1 kind: Service metadata: name: SERVICE_NAME namespace: APP_NAMESPACE spec: ports: - name: http-hello port: 8080 selector: app: hello type: ClusterIP EOF kubectl apply --filename service.yaml
- SERVICE_NAME は、サービスの名前です。例:
hello
- SERVICE_NAME は、サービスの名前です。例:
証明書の発行元を使用して、ドメイン名
hello.example.com
の Certificate リソースを作成します。cat << EOF > certificate.yaml apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: hello-example-com-certificate namespace: GATEWAY_NAMESPACE spec: secretName: hello-example-com-credential commonName: hello.example.com dnsNames: - hello.example.com duration: 24h renewBefore: 8h issuerRef: group: cas-issuer.jetstack.io kind: GoogleCASIssuer name: gateway-cas-issuer EOF kubectl apply --filename certificate.yaml
Certificate の名前空間が Ingress ゲートウェイの名前空間と一致する必要があります。サービス メッシュ全体に影響する可能性があるため、通常、この名前空間のリソースを変更できるのはプラットフォーム管理者のみです。cert-manager ツールにより、同じ名前空間に TLS 証明書の Secret リソースが作成されます。つまり、アプリケーション管理者は Ingress ゲートウェイ名前空間にアクセスする必要はありません。
Certificate の
dnsNames
リストで別のホスト名を追加できます。これらのホスト名は、サブジェクトの代替名(SAN)として証明書に含まれています。サンプル アプリケーションの Gateway リソースを作成します。
cat << EOF > gateway.yaml apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: GATEWAY_NAME namespace: GATEWAY_NAMESPACE spec: selector: istio: ingressgateway servers: - hosts: - APP_NAMESPACE/hello.example.com port: name: https-hello number: 443 protocol: HTTPS tls: credentialName: hello-example-com-credential mode: MUTUAL EOF kubectl apply --filename gateway.yaml
- GATEWAY_NAME はゲートウェイ名です。例:
hello
- ゲートウェイの
credentialName
フィールドは、証明書のsecretName
フィールドと一致します。cert-manager ツールにより、CA Service の TLS 証明書を使用して Kubernetes Secret が作成されます。この証明書により、Ingress ゲートウェイはhello.example.com
宛ての TLS トラフィックを終端できます。
Gateway マニフェストには、MUTUAL TLS(mTLS)を指定します。通常の TLS にゲートウェイを構成する場合は、代わりに Gateway の TLS モードを
SIMPLE
に設定します。- GATEWAY_NAME はゲートウェイ名です。例:
サンプル アプリケーションの VirtualService リソースを作成します。
cat << EOF > virtual-service.yaml apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: hello namespace: APP_NAMESPACE spec: hosts: - hello.example.com gateways: - GATEWAY_NAMESPACE/GATEWAY_NAME http: - route: - destination: host: SERVICE_NAME port: number: 8080 EOF kubectl apply --filename virtual-service.yaml
Gateway と VirtualService の名前空間は異なります。この共通パターンでは、Ingress ゲートウェイ名前空間内のリソースを変更する権限を持つプラットフォーム管理者にのみ、Gateway のホストベースのルーティングの変更が許可されます。
サンプル アプリケーションの名前空間で VirtualService を編集する権限を持つアプリケーション管理者は、プラットフォーム管理者と調整を行わずに、URL パスなどの他のリクエスト フィールドによるルーティングを変更できます。
他の構成オプションを確認する場合は、Certificate、Gateway、VirtualService リソースの API ドキュメントをご覧ください。
Ingress ゲートウェイを経由してサービス メッシュに到達するトラフィックに、認証ポリシーと認可ポリシーを適用できます。方法については、Istio PeerAuthentication API と AuthorizationPolicy API のドキュメントをご覧ください。
問題の解決を確認する
このセクションでは、サービス メッシュの外部からサンプル アプリケーションに mTLS を使用して HTTPS リクエストを送信できることを確認します。これを確認するには、Compute Engine VM インスタンスを作成して、CA Service からクライアント TLS 証明書をリクエストし、その証明書を使用してサンプル アプリケーションへのリクエストを認証します。
VM インスタンスへの SSH アクセスが必要です。デフォルト ネットワークには、SSH アクセスを許可するファイアウォール ルールが含まれています。SSH でアクセスできない場合は、ファイアウォール ルールのドキュメントに沿って、ポート 22 で受信 TCP 接続を許可するファイアウォール ルールを作成してください。
Cloud Shell で、Google サービス アカウントを作成します。
gcloud iam service-accounts create CLIENT_VM_GSA \ --display-name "CA Service tutorial VM instance service account"
- CLIENT_VM_GSA は、Google サービス アカウントの名前です。例:
cas-tutorial-client
この Google サービス アカウントを Compute Engine VM インスタンスに割り当てます。
- CLIENT_VM_GSA は、Google サービス アカウントの名前です。例:
Google サービス アカウントにゲートウェイの下位 CA プールの CA サービス証明書リクエスト元ロールを付与します。
gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester
このロールは、CA プールの証明書をリクエストする権限を付与します。
GKE クラスタと同じ VPC 内に Compute Engine VM インスタンスを作成します。
gcloud compute instances create cas-tutorial-client \ --scopes cloud-platform \ --service-account CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com \ --zone ZONE
VM インスタンスが CA Service API にアクセスするには、
cloud-platform
スコープが必要です。Ingress ゲートウェイの内部パススルー ネットワーク ロードバランサの IP アドレスをファイルに保存します。
kubectl get services istio-ingressgateway \ --namespace GATEWAY_NAMESPACE \ --output jsonpath='{.status.loadBalancer.ingress[0].ip}' > ilb-ip.txt
ルート CA の公開鍵証明書をファイルに保存します。
gcloud privateca roots describe ROOT_CA \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --format 'value(pemCaCertificates)' > root-ca-cert.pem
ルート CA 証明書と Ingress ゲートウェイの内部パススルー ネットワーク ロードバランサの IP アドレスを含むファイルを VM インスタンスにコピーします。
gcloud compute scp root-ca-cert.pem ilb-ip.txt cas-tutorial-client:~ \ --zone ZONE
SSH を使用して VM インスタンスに接続します。
gcloud compute ssh cas-tutorial-client --zone ZONE
このセクションの残りのコマンドは、SSH セッションから実行します。
ca-certificates
パッケージ、coreutils
パッケージ、curl
、openssl
、jq
コマンドライン ツールをインストールします。sudo apt-get update --yes sudo apt-get install --yes ca-certificates coreutils curl jq openssl
クライアント TLS 証明書の鍵ペアを作成します。
openssl genrsa -out private-key.pem 2048 openssl rsa -in private-key.pem -pubout -out public-key.pem
メタデータ サーバーにクエリを実行し、VM インスタンスに接続している Google サービス アカウント ID のメールアドレスを取得します。
GSA_EMAIL=$(curl --silent --header "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/email)
Certificate Authority サービス API からクライアント TLS 証明書をリクエストするときに、リクエスト本文として使用する JSON ファイルを作成します。
cat << EOF > request.json { "config": { "publicKey": { "format": "PEM", "key": "$(base64 --wrap 0 public-key.pem)" }, "subjectConfig": { "subject": { "commonName": "$(hostname --short)", "organization": "Example Organization" }, "subjectAltName": { "dnsNames": [ "$(hostname --fqdn)" ], "emailAddresses": [ "$GSA_EMAIL" ] } }, "x509Config": { "caOptions": { "isCa": false }, "keyUsage": { "baseKeyUsage": { "digitalSignature": true, "keyEncipherment": true }, "extendedKeyUsage": { "clientAuth": true } } } }, "lifetime": "86400s" } EOF
構成セクションのフィールドの詳細については、CA サービス API ドキュメントの
CertificateConfig
タイプをご覧ください。メタデータ サーバーの OAuth 2.0 アクセス トークンをリクエストします。
TOKEN=$(curl --silent --header "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token | jq --raw-output ".access_token")
このアクセス トークンにより、VM インスタンスに接続している Google サービス アカウントに付与された権限が提供されます。
CA サービス API のクライアント TLS 証明書をリクエストし、レスポンスの本文をファイルに保存します。
curl --silent --request POST \ --header "Authorization: Bearer $TOKEN" \ --header "Content-Type: application/json" \ --data @request.json \ --output response.json \ "https://privateca.googleapis.com/v1/projects/PROJECT_ID/locations/CA_LOCATION/caPools/SUBORDINATE_CA_POOL_GATEWAYS/certificates"
このコマンドでは、アクセス トークンを使用して API リクエストを認証しています。
クライアント証明書と証明書チェーンをファイルに保存します。
jq --raw-output --join-output ".pemCertificate , .pemCertificateChain[]" response.json > client-cert-chain.pem
curl
を使用して、VM インスタンスからサンプル アプリケーションに HTTPS リクエストを送信します。curl --cert client-cert-chain.pem --key private-key.pem \ --cacert root-ca-cert.pem \ --resolve hello.example.com:443:$(cat ilb-ip.txt) \ --silent https://hello.example.com | head -n1
出力は次のようになります。
Hello, world!
このレスポンスは、
curl
が mTLS を使用して HTTPS リクエストを送信したことを示しています。サンプル アプリケーションは、ターミナルの出力に表示されるメッセージで応答しています。curl
コマンドは、次のことを行います。--cert
フラグと--key
フラグを指定すると、curl
はクライアントの TLS 証明書と秘密鍵を使用してリクエストを認証します。クライアント証明書ファイルには、クライアント証明書からルート CA までの完全な証明書チェーンが含まれています。--cacert
フラグを指定すると、このチュートリアルで作成したルート CA またはその下位 CA のいずれかがサーバー証明書を発行したことをcurl
に確認するように指示します。このフラグを省略すると、
curl
は、オペレーティング システムのデフォルト CA バンドル(Debian のca-certificates
パッケージなど)を使用してサーバー証明書の検証を試みます。デフォルトの CA バンドルに、このチュートリアルで作成したルート CA が含まれていないため、検証は失敗します。--resolve
フラグは、ポート 443 でhello.example.com
をホストするリクエストの宛先として、内部パススルー ネットワーク ロードバランサの IP アドレスを使用するようにcurl
に指示します。このフラグを省略すると、
curl
は DNS を使用してhello.example.com
ホスト名を解決しようとします。このホスト名の DNS エントリがないため、DNS の解決は失敗します。独自の環境では、内部パススルー ネットワーク ロードバランサの IP アドレス(
$LOAD_BALANCER_IP
)を指す DNS A レコードを作成することをおすすめします。レコードの管理のドキュメントに従って、Cloud DNS を使用してこのレコードを作成します。--silent
フラグを指定すると、ターミナル出力でレスポンスのダウンロード進捗状況レポートが抑制されます。このコマンドは、curl 出力を
head -n1
にパイプします。その結果、ターミナルの出力にはレスポンスの本文の最初の行だけが含まれます。
SSH セッションを終了します。
exit
このセクションでは、クライアント TLS 証明書を CA サービス API から直接リクエストしました。クライアントが別の Kubernetes クラスタ内の別のサービス メッシュの下り(外向き)ゲートウェイである場合は、同じルート CA を持つ cert-manager ツールと Certificate Authority サービス発行元を使用して、Egress ゲートウェイにクライアント証明書を提供できます。
場合によっては、Hashicorp Vault、Terraform、gcloud
などのツールを使用して、サービス メッシュ外のワークロードのクライアント TLS 証明書をリクエストすることもできます。サンプル ソリューションの詳細については CA Service のドキュメントを、CA Service の詳細については gcloud
のドキュメントをご覧ください。
(オプション)CA 証明書をトラストストアに追加する
このセクション(オプション)では、Linux の Debian ディストリビューションの信頼できる CA 証明書のストアに CA 証明書を追加する方法を説明します。以下の手順は、Ubuntu などの Debian から生成されたディストリビューションにも適用されます。
このストアに CA 証明書を追加すると、curl
、Python、Go、Ruby を使用して HTTPS リクエストを送信する場合に、信頼できる CA 証明書のロケーションを指定する必要がなくなります。
SSH を使用して VM インスタンスに接続します。
gcloud compute ssh cas-tutorial-client --zone ZONE
このセクションの残りのコマンドは、SSH セッションから実行します。
ルート CA 証明書をディレクトリ
/usr/local/share/ca-certificates
にコピーし、ファイルの拡張子が.crt
であることを確認します。sudo cp root-ca-cert.pem /usr/local/share/ca-certificates/cas-rootca.crt
すべてのユーザーがルート CA 証明書ファイルを読み取れるように、ファイル権限を設定します。
sudo chmod 644 /usr/local/share/ca-certificates/cas-rootca.crt
update-ca-certificates
スクリプトを実行します。sudo update-ca-certificates
このスクリプトでは、ディレクトリ
/etc/ssl/certs
内の信頼できる証明書のセットとファイル/etc/ssl/certs/ca-certificates.crt
に証明書を追加します。次のような出力が表示されます。
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done. Running hooks in /etc/ca-certificates/update.d... done.
curl
を使用して、VM インスタンスからサンプル アプリケーションに HTTPS リクエストを送信します。curl --cert client-cert-chain.pem --key private-key.pem \ --resolve hello.example.com:443:$(cat ilb-ip.txt) \ --silent https://hello.example.com | head -n1
出力は次のようになります。
Hello, world!
このレスポンスは、
curl
が mTLS を使用して HTTPS リクエストを正常に送信し、デフォルトの CA 証明書ストアを使用して Ingress ゲートウェイのサーバー TLS 証明書を検証したことを示しています。SSH セッションを終了します。
exit
トラブルシューティング
CA サービス発行元コントローラが TLS 証明書のシークレットを作成しない場合は、CA サービス発行元コントローラのログを表示します。
kubectl logs deployment/google-cas-issuer --namespace cert-manager
Cloud Service Mesh のインストールで問題が発生した場合は、asmcli
ツールを使用して、Cloud プロジェクトと GKE クラスタを検証します。
このチュートリアルで他の問題が発生した場合は、次のドキュメントを確認することをおすすめします。
- CA Service のよくある質問
- Cloud Service Mesh の詳細なトラブルシューティング手順
- マネージド Cloud Service Mesh の問題の解決
- Istio オペレーションの一般的な問題
- GKE のトラブルシューティング
- Kubernetes クラスタのトラブルシューティング
クリーンアップ
このチュートリアルで使用したリソースについて、これ以降 Google Cloud アカウントに課金されないようにするには、プロジェクトを削除するか、個々のリソースを削除します。
プロジェクトの削除
Cloud Shell で、プロジェクトを削除します。
gcloud projects delete PROJECT_ID
リソースの削除
このチュートリアルで使用した Google Cloud プロジェクトを残しておく場合は、個々のリソースを削除します。
Cloud Shell で、GKE Hub から GKE クラスタの登録を解除します。
gcloud container hub memberships unregister CLUSTER_NAME \ --gke-cluster ZONE/CLUSTER_NAME
GKE クラスタを削除します。
gcloud container clusters delete CLUSTER_NAME \ --zone ZONE --async --quiet
下位 CA プールの IAM ポリシー バインディングを削除します。
gcloud privateca pools remove-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester gcloud privateca pools remove-iam-policy-binding SUBORDINATE_CA_POOL_GATEWAYS \ --location CA_LOCATION \ --member "serviceAccount:CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com" \ --role roles/privateca.certificateRequester
下位 CA とルート CA の無効化と削除のスケジュール設定を行います。
gcloud privateca subordinates disable SUBORDINATE_CA_GATEWAYS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_GATEWAYS \ --quiet gcloud privateca subordinates delete SUBORDINATE_CA_GATEWAYS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_GATEWAYS \ --ignore-active-certificates \ --quiet gcloud privateca subordinates disable SUBORDINATE_CA_SIDECARS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_SIDECARS \ --quiet gcloud privateca subordinates delete SUBORDINATE_CA_SIDECARS \ --location CA_LOCATION \ --pool SUBORDINATE_CA_POOL_SIDECARS \ --ignore-active-certificates \ --quiet gcloud privateca roots disable ROOT_CA \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --quiet gcloud privateca roots delete ROOT_CA \ --location CA_LOCATION \ --pool ROOT_CA_POOL \ --ignore-active-certificates \ --quiet
CA サービス発行元コントローラの Google サービス アカウントの IAM ポリシー バインディングを削除します。
gcloud iam service-accounts remove-iam-policy-binding \ CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com \ --member "serviceAccount:PROJECT_ID.svc.id.goog[cert-manager/ksa-google-cas-issuer]" \ --role roles/iam.workloadIdentityUser
Google サービス アカウントを削除します。
gcloud iam service-accounts delete --quiet \ CAS_ISSUER_GSA@PROJECT_ID.iam.gserviceaccount.com gcloud iam service-accounts delete --quiet \ CLIENT_VM_GSA@PROJECT_ID.iam.gserviceaccount.com
予約済みのロードバランサの IP アドレスを削除します。
gcloud compute addresses delete asm-ingress-gateway-ilb \ --region REGION --quiet
Compute Engine VM インスタンスを削除する:
gcloud compute instances delete cas-tutorial-client \ --zone ZONE --quiet
次のステップ
- 他の Certificate Authority Service 入門ガイドを確認する。
- Istio ベースのツールスイートである Cloud Service Mesh について学習する。このスイートを使用すると、オンプレミスと Google Cloud で信頼性の高いサービス メッシュのモニタリングと管理ができます。
- Cloud Service Mesh 入門ガイドを読む。