GC環境でサービスアカウントのキーダウンロードをなるべくしないために



# はじめに
AWSではRoleから一時認証を払い出すなどでAWSのAPIへアクセスする認証情報を得ます。
IAMでクレデンシャルを払い出しそれを利用することも可能ですが、クレデンシャルのローテートされることが望ましくちょっと面倒です。
では、GCではどうしたらいいのか調べてみました。

# 概要
答えはほぼここに書いてありました。
Google Cloud のサービス アカウント キーを安全に管理する

https://cloud.google.com/blog/ja/products/gcp/help-keep-your-google-cloud-service-account-keys-safe

インフラ担当の場合、使いそうなのはTerraformやAWSからのGCへのアクセスなので、それについても調べてみました。

https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds#generate-automatic

https://cloud.google.com/blog/ja/topics/developers-practitioners/using-google-cloud-service-account-impersonation-your-terraform-code

これらについて記載された概要としては以下でした。

- リソースに紐づくサービスアカウントがある場合、キーをダウンロードするのではなく、リソースのサービスアカウントを使う
- サービスアカウントキーをダウンロードする場合は定期的にローテートする仕組みを入れて、同じキーで長い期間継続的に使えないようにする
- 外部IDプロバイダを利用した一時認証の払い出しや、自身のGCのIAMからさらにサービスアカウントの権限を借用し、実行する
    - AWSでいうSAML認証からのRoleの一時認証の払い出し、Roleからの一時認証の払い出し、、のようなイメージです

では順番に見ていきたいと思います。

## リソースに紐づくサービスアカウントがあリソースのサービスアカウントを使う
AWSでいう、クレデンシャルをダウンロードするのではなく、EC2であればインスタンスロールを使いましょうって感じでして、
GCEであればサービス側にRoleを紐付けて、他サービスへのアクセスなどを行いましょう、というものです、GCEのサービスアカウントだと以下のような形で、設定することが可能です。特にCloud Storageにアクセスしたいなどあると思うので、そういった場合、キーダウンロードではなく、添付の通りGCEのサービスアカウント設定を行います。
![スクリーンショット 2023-01-12 16.55.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720034/e29adf42-44cf-32f7-2431-4b87775ce961.png)

## サービスアカウントキーを定期的にローテートする
ざっくり記載すると以下のような形でした。
サービスアカウントのキーをアクセスを制限したCloudStorageに配置し、
そのCloudStorageのキーを一定期間でローテートしています。
それの方法として、Keyrotatorが紹介されておりましたが、記載した時点ですでにGithub上でPublicArchiveとなっていました。

https://github.com/Googlecloudplatform/keyrotator

普段利用になられている方は、どうしているか、軽く検索してみましたが、Goで実装されている方がいたり、必要なときに払い出して、消すって運用をしてる人もいました。
そもそもこういう運用をしない方針であり、事例としても少なそうで、どうしても必要な場合、Cloud Functions などで実装しても良いかなと思いました。

## 一時認証の払い出しや、IAMからさらにサービスアカウントの権限を借用する
こちらについては、インフラ担当として1番利用ケースが多そうなTerraformを例にし、実際に試してみました。

### Terraform コードにおける サービス アカウントの権限借用
以下に記載されていますが、改めて以下からかいつまんで記載します。

https://cloud.google.com/blog/ja/topics/developers-practitioners/using-google-cloud-service-account-impersonation-your-terraform-code

以下、手順を纏めてみました、特に難しくもないので、キーをダウンロードしてファイル配置するより、よっぽどいいかな、と思いました。

※前提
・すでに自分のIAMユーザがあること
・Terraform実行用のサービスアカウントがあること
・gcloud CLIが導入済みであること

1.自身のIAMに以下の権限を付与する
　・サービス アカウント トークン作成者

2.Terraformのコードのprovider.tfに入れる
コメント箇所で何をしている挙動か記載しています
```
# サービスアカウントの情報外だし
locals {
 terraform_service_account = "サービスアカウントのメールアドレス"
}

# アクセストークン取得のプロバイダ作成
provider "google" {
 alias = "impersonation"
 scopes = [
   "https://www.googleapis.com/auth/cloud-platform",
   "https://www.googleapis.com/auth/userinfo.email",
 ]
}

# サービスアカウントの認証で利用するアクセストークンの取得
data "google_service_account_access_token" "default" {
 provider               	= google.impersonation
 target_service_account 	= local.terraform_service_account
 scopes                 	= ["userinfo-email", "cloud-platform"]
 lifetime               	= "1200s"
}

# ここのブロックでアクセストークンを利用する
provider "google" {
 project 		= "プロジェクトID"
 access_token	= data.google_service_account_access_token.default.access_token
 request_timeout 	= "60s"
}
```

3.実行するときの事前の手順

3-1.以下のコマンドをローカル端末で実施する
※gcloud CLIを利用する準備が整っていない場合、config作成する
```
gcloud config configurations create config名
gcloud config set project 実行するプロジェクト名
gcloud config set account 自身のIAMメアド
```

3-2.認証コマンドを実行する
```
gcloud auth login
```
実行するとブラウザが起動し承認画面がでますので、承認します。

4.Terraformを実行する

5.サービスアカウントが利用されているのか確認する
対象サービスアカウントの指標を確認し、サービスアカウントの利用状況が確認できますので、こちらで画面描画されていれば正常に利用されており、キーを利用せずともサービスアカウントが利用できたことが確認できます。
![スクリーンショット 2023-01-12 16.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720034/48a52def-9e37-8a77-7377-34b7f30f0cd9.png)

また、キーあたりの認証トラフィックというのがありますが、もしかしたらキーを利用した認証をすると、ここに画面描画されるのかな、と思いました。
![スクリーンショット 2023-01-12 16.52.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720034/d3bf53a5-b03d-0976-947d-733574871b11.png)


## 所感
改めてサービスアカウントの利用について確認しました。
Terraform利用を例にしても、ブログなどの記事でキーをダウンロードしているケースはよく見受けられますが、ダウンロードしなくても良いことを再確認できました。
自身で改めて意識するとともに、周囲にも注意喚起していこうと思いました。
記載した以外でも以下を気にしておいてもいいかと思いました。

https://cloud.google.com/docs/authentication/provide-credentials-adc