Crossplane で GKE の Workload Identity による認証方法
クラウドエース北野です。
GKE の Workload Identity によって、Crossplane の認証させる方法を紹介します。
概要
Crossplane で Google Kubernetes Engine (以降 GKE と呼びます)で Workload Identity を使うには、以下のようにします。
-
ControllerConfig
に Workload Identity により関連づける Google Cloud のサービスアカウントと Kubernetes のサービスアカウントの定義 -
ProviderConfig
の spec.credentials.source にInjectedIdentity
の定義
上記の内容のマニフェストは以下の通りです。
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: sa-k8s-crossplane
annotations:
iam.gke.io/gcp-service-account: <GOOGLE_SERVICEACCOUNT_EMAIL>
spec:
serviceAccountName: <KUBERNETES_SERVICEACCOUNT_ID>
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: pc-workload-identity
spec:
credentials:
source: InjectedIdentity
projectID: <PROJECT_ID>
この ProviderConfig を参照するように ManagedResource を定義すると、Crossplane の gcp-provider Provider を Google Cloud のサービスアカウントで認証させることができます。
はじめに
Crossplane は Google Cloud や AWS といった Kubernetes ではないリソースを Kubernetes リソースとして扱う OSS の Kubernetes 拡張機能です。Crossplane は Upbound 社により開発された CNCF プロジェクトのソフトウェアで、あらゆるものを Kubernetes から管理することを目的としたソフトウェアです。
Crossplane は Google Cloud や AWS などの操作する Kubernetes 外のプラットフォームごとに Provider を作成します。この Provider が、Kubernetes のマニフェストや API コールを外部プラットフォームの API に変換して、外部プラットフォーム上のリソースを管理します。
また、Provider は作成したリソースを Kubernetes 上で ManagedResource というオブジェクトで管理します。この ManagedResource を Kubernetes 上で作成、削除、更新すると、外部のプラットフォームのオブジェクトにも同じ処理がなされます。
Provider に外部リソースを操作させるためには、Provider を認証させる必要があります。Google Cloud の Provider を使って、Cloud Storage バケットを作成するクイックスタートでは、サービスアカウント鍵を使って認証しています。この方法はサービスアカウント鍵を作成する必要があり、セキュリティ上の問題があります。
そこで、本記事では GKE の Workload Identity を使って、Google Cloud のサービスアカウントで Provider を認証させる方法を紹介します。
Crossplane の認証方法
Crossplane は Google Cloud の Provider の認証に以下の 5 つの方法を提供しています。
- Workload Identity
- サービスアカウントキー
- サービスアカウント権限の借用
- OAuth2 Access Key
- Upbound クラウドによる認証 (OIDC)
Crossplane を GKE 上で動かす場合、Workload Identity を使って認証させる方法が最もセキュアな方法となっています。
Crossplane の実行
以下のシステムの構成で Crossplane を実行して、Google Cloud の VPC Network を作成してみます。
Crossplane を GKE 上で実行し、Crossplane のデフォルト Namespace crossplane-system
上に作成します。この Namespace のサービスアカウントと Google Cloud で作成したサービスアカウントを Workload Identity の機能で紐つけます。
Crossplane で Google Cloud の VPC Network を作成する gcp-provider をインストールし、Workload Identity で認証するための ProviderConfig と ControllerConfig を作成します。
そして、作成する VPC Network の ManagedResource を作成します。この ManagedResource に ControllerConfig を紐つけて、Workload Identity で Provider を Google Cloud に認証させます。
この構成でシステムを構築する Terraform コードと、Kubernetes マニフェストを紹介します。<>
で囲まれた部分は環境に合わせて読み替えてください。
事前準備
GKE と Service Account を作成する Terraform コードは以下の通りです。
resource "google_compute_network" "main" {
name = "gke-single"
project = var.project
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "main" {
name = "gke-platform-tyo"
project = var.project
ip_cidr_range = "192.168.0.0/24"
network = google_compute_network.main.self_link
region = "asia-northeast1"
}
resource "google_service_account" "main" {
depends_on = [
google_container_cluster.primary
]
account_id = "<GOOGLE_SERVICEACCOUNT>"
project = var.project
}
resource "google_service_account_iam_member" "workload_identity_argocd-server" {
service_account_id = google_service_account.main.id
role = "roles/iam.workloadIdentityUser"
member = format("serviceAccount:%s.svc.id.goog[%s/%s]", var.project, "crossplane-system", "<KUBERNETES_SERVICEACCOUNT>")
}
resource "google_project_iam_member" "main" {
member = google_service_account.main.member
project = var.project
role = "roles/editor"
}
今回、Autopilot の GKE を使うため、Terraform コードは以下のようになります。
resource "google_container_cluster" "main" {
name = "platform"
project = var.project
location = "asia-northeast1"
enable_autopilot = true
network = google_compute_network.main.id
subnetwork = google_compute_subnetwork.main.id
}
Crossplane の操作
Crossplane を以下のように Helm でインストールします。
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane \
crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace
インストールすると、以下の2つの Deployment が作成されます。
kubectl get deployment -n crossplane-system
NAME READY UP-TO-DATE AVAILABLE AGE
crossplane 1/1 1 1 4m1s
crossplane-rbac-manager 1/1 1 1 4m1s
VPC Network を作成する compute の gcp-provider をインストールするマニフェストは以下のようになります。
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-family-gcp
spec:
package: xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v1.12.1
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-gcp-compute
spec:
package: xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v1.12.1
controllerConfigRef:
name: sa-k8s-crossplane
Workload Identity を Kubernetes のサービスアカウントと Google Cloud のサービスアカウントの紐つけを以下の ControllerConfig で定義します。
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: sa-k8s-crossplane
annotations:
iam.gke.io/gcp-service-account: <GOOGLE_SERVICEACCOUNT_EMAIL>
spec:
serviceAccountName: <KUBERNETES_SERVICEACCOUNT>
ここで、ControllerConfig と Provider 作成します。
kubectl apply -f controller_config.yaml
kubectl apply -f provider.yaml
暫くすると、gcp-provider がインストールされ、HEALTHY が True になります。
kubectl get provider
NAME INSTALLED HEALTHY PACKAGE AGE
provider-family-gcp True True xpkg.crossplane.io/crossplane-contrib/provider-family-gcp:v1.12.1 3m56s
provider-gcp-compute True True xpkg.crossplane.io/crossplane-contrib/provider-gcp-compute:v1.12.1 3m56s
続いて、ProviderConfig を定義し、Provider を Workload Identity で認証するようにします。
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: pc-workload-identity
spec:
credentials:
source: InjectedIdentity
projectID: <PROJECT_ID>
次に実際に Network の ManagedResource を作って、VPC Network を作成してみます。
事前に作成する VPC Network がないことを確認します。
gcloud compute networks describe crossplane-sample --project <PROJECT ID>
ERROR: (gcloud.compute.networks.describe) Could not fetch resource:
- The resource 'projects/<PROJECT ID>/global/networks/crossplane-sample' was not found
Network の ManagedResource を次のように定義します。
apiVersion: compute.gcp.upbound.io/v1beta1
kind: Network
metadata:
name: crossplane-sample
spec:
forProvider:
autoCreateSubnetworks: false
project: <PROJECT ID>
description: "Created By Crossplane"
providerConfigRef:
name: pc-workload-identity
マニフェストを実行して、暫くすると ManagedResource の SYNCED と READY が True になると、Google Cloud 側にリソースが作成されます。
kubectl apply -f network.yaml
kubectl get network
NAME SYNCED READY EXTERNAL-NAME AGE
crossplane-sample True True crossplane-sample 39s
作成された VPC Network を確認すると、作成されていること ManagedResource の内容が作成されていることが分かります。
gcloud compute networks describe crossplane-sample --project <PROJECT ID>
autoCreateSubnetworks: false
creationTimestamp: '2025-03-20T01:37:59.560-07:00'
description: Created By Crossplane
id: '8027351178494242056'
kind: compute#network
name: crossplane-sample
networkFirewallPolicyEnforcementOrder: AFTER_CLASSIC_FIREWALL
routingConfig:
bgpBestPathSelectionMode: LEGACY
routingMode: REGIONAL
selfLink: https://www.googleapis.com/compute/v1/projects/<PROJECT ID>/global/networks/crossplane-sample
selfLinkWithId: https://www.googleapis.com/compute/v1/projects/<PROJECT ID>/global/networks/8027351178494242056
x_gcloud_bgp_routing_mode: REGIONAL
x_gcloud_subnet_mode: CUSTOM
ManagedResource を削除して、Google Cloud 側のリソースが Crossplane により削除されるか確認します。
kubectl delete network crossplane-sample
network.compute.gcp.upbound.io "crossplane-sample" deleted
kubectl get network
No resources found
gcloud compute networks describe crossplane-sample --project <PROJECT ID>
ERROR: (gcloud.compute.networks.describe) Could not fetch resource:
- The resource 'projects/<PROJECT ID>/global/networks/crossplane-sample' was not found
ManagedResource を削除すると、実際の Google Cloud 上でも対応するリソースが削除されていることが分かります。
さいごに
Workload Identity を使って、gcp-provider を Google Cloud に認証させる方法を紹介しました。Workload Identity を使うと、安全に Google Cloud に認証させられるので、GKE で Crossplane を使う場合は導入を検討してみてください。
Discussion