1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オンプレKubernetesからGCPのWorkload Identity連携を使えるようにした話

Posted at

はじめに

前回は GCP のリソースを Terraform で管理できるようにしました。今回は、GCP のリソースを Kubernetes 上の Pod から、サービスアカウントキーを使わずに利用できるようにしていきます。

動機

GCP のリソースにアクセスする方法で、最もシンプルなのはサービスアカウントキーを発行する方法です。
しかし、サービスアカウントキーは次のようなデメリットがあります。

  • 漏洩のリスクがある
  • 有効期限切れになる前に再発行する必要があり、管理が大変

そこで、GCP の Workload Identity 連携を使って、Kubernetes 上の Pod から GCP のリソースにアクセスできるようにしようと思いました。

実装

Kubernetes の情報を取得

Kubernetes に接続して、issuer URL を確認します。

kubectl get --raw /.well-known/openid-configuration | jq -r .issuer

クラスタの JSON Web Key Set (JWKS) を確認します。

kubectl get --raw /openid/v1/jwks > cluster-jwks.json

ダウンロードして、terraform プロジェクトのディレクトリに配置します。

GCP の設定

基本的には公式ドキュメントに従って設定します。

まず、まだ作成していない場合は Workload Identity Pool を作成します。

resource "google_iam_workload_identity_pool" "default" {
  workload_identity_pool_id = "pool"
}

先程ダウンロードした JWKS を terraform から使えるようにします。

data "local_file" "cluster_jwks" {
  filename = "${path.module}/cluster-jwks.json"
}

Kubernetes の Workload Identity Pool Provider を作成します。

resource "google_iam_workload_identity_pool_provider" "home_kubernetes" {
  workload_identity_pool_id          = google_iam_workload_identity_pool.default.workload_identity_pool_id.workload_identity_pool_id
  workload_identity_pool_provider_id = "home-kubernetes"
  display_name                       = "Home Kubernetes"
  description                        = "for Kubernetes in the home"
  attribute_mapping = {
    "google.subject" = "assertion.sub"
  }
  oidc {
    issuer_uri = "{issuer URL}"
    jwks_json  = data.local_file.cluster_jwks.content
  }
}

使用するサービスアカウントを作成します。

resource "google_service_account" "sa" {
  account_id                   = "sa"
  create_ignore_already_exists = true
}

与えたいロールを作成します。Workload Identity 連携をするためには、roles/iam.workloadIdentityUser が必要です。

resource "google_project_iam_member" "clubroom_storage_object_user" {
  project = var.project
  member  = "serviceAccount:${google_service_account.clubroom.email}"
  role    = "roles/storage.objectUser"
}
resource "google_project_iam_member" "clubroom_service_account_token_creator" {
  project = var.project
  member  = "serviceAccount:${google_service_account.clubroom.email}"
  role    = "roles/iam.workloadIdentityUser"
}

最後に、サービスアカウントを Kubernetes から使用できるようにします。

resource "google_service_account_iam_member" "ksa_workload_identity_user" {
  service_account_id = google_service_account.clubroom.id
  role               = "roles/iam.workloadIdentityUser"
  member             = "principal://iam.googleapis.com/projects/${var.project_number}/locations/global/workloadIdentityPools/${google_iam_workload_identity_pool.default.workload_identity_pool_id}/subject/system:serviceaccount:default:{ksa-name}"
}

Kubernetes 側の設定

まず、次のような JSON を作成します。

{
  "universe_domain": "googleapis.com",
  "type": "external_account",
  "audience": "//iam.googleapis.com/projects/{project_number}/locations/global/workloadIdentityPools/{pool_id}/providers/{provider_id}",
  "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
  "token_url": "https://sts.googleapis.com/v1/token",
  "credential_source": {
    "file": "/var/run/service-account/token",
    "format": {
      "type": "text"
    }
  },
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/{gsa_email}:generateAccessToken"
}

この JSON をもとに ConfigMap を作成します。

# kustomization.yaml
- name: workload-identity-credential-configuration
  files:
    - gcp-credential-configuration.json

Deployment に以下の 2 つの Volume を作成します。

volumes:
  - name: token
    projected:
      sources:
        - serviceAccountToken:
            audience: https://iam.googleapis.com/projects/{project_number}/locations/global/workloadIdentityPools/{pool_id}/providers/{provider_id}
            expirationSeconds: 3600
            path: token
  - name: workload-identity-credential-configuration
    configMap:
      name: workload-identity-credential-configuration

Volume をマウントします。

volumeMounts:
  - name: token
    mountPath: /var/run/service-account
    readOnly: true
  - name: workload-identity-credential-configuration
    mountPath: /etc/workload-identity
    readOnly: true

環境変数で作成した設定へのパスを指定します。

env:
  - name: GOOGLE_APPLICATION_CREDENTIALS
    value: /etc/workload-identity/gcp-credential-configuration.json

以上で、Kubernetes 上の Pod から GCP のリソースにアクセスできるようになります。

まとめ

今回は、GCP のリソースにアクセスする方法として、Workload Identity 連携を使う方法を紹介しました。
サービスアカウントキーを発行せずに GCP を使えるようになって、かなり便利になったと感じています。

今後は Kubernetes 側の設定を自動でやってくれる Custom Controller なんかを作ってみたいなと感じています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?