Terraformの実行に必要な最小限のAWS IAMポリシーを調べる

2023年3月31日

Terraform

Terraform を実行するユーザの AWS IAM ポリシーを Administrator Access から最小限のポリシーに変更する機会があったので備忘録。

最小の権限を割り当てようとすると、その課程で AccessDenied エラーが数多く発生してなかなか大変です。どのようにして権限エラーを取り除き、最小の権限を決定したのかを紹介します。同じことを考えている方の参考になれば。この記事を書くために検証した Terraform のバージョンは 1.3.9、AWS Provider は 4.62.0 です。

目次

  1. アクセス権限の無い IAM ポリシーを用意する
  2. Terraform のログから実際に実行された API を調べる
  3. エラーがあった API を抽出する
  4. エンコードされたエラーメッセージからエラーの詳細を確認する
  5. CloudTrail を確認する
  6. 登録、更新、削除のパターンも確認する

アクセス権限の無い IAM ポリシーを用意する

まずはアクセス権のない IAM ポリシーを作成し、IAM Role にアタッチします。この IAM Role を使って Terraform を実行し、AccessDenied エラーを見ながら IAM ポリシーの Action と Resource を許可していきます。

手元の PC で Terraform を実行する場合は、AWS CLI の aws sts assume-role コマンドを使って、IAM Role の権限で Terraform を実行できるようにすると良いでしょう。やり方は過去に記事にしましたので参考にどうぞ。

AWS sts:AssumeRoleでIAMユーザからIAMロールになる

AWS サービスに設定する IAM ロールの権限が正しいかどうかを手元の PC 上で試したいことがあったので、IAM ユ ...

続きを見る

Terraform のログから実際に実行された API を調べる

Terraform 実行時に権限が足りないと、以下のように 400 系のエラーがでてきます。

$ terraform plan

...
│ Error: getting S3 Bucket encryption: AccessDenied: Access Denied
│       status code: 403, request id: AD5K2QH1NT937HXM, host id: F9pNxxxx
│ 
│   with aws_s3_bucket.bucket,
│   on main.tf line 33, in resource "aws_s3_bucket" "bucket":
│   33: resource "aws_s3_bucket" "bucket" {
...

上記のエラーは main.tf の aws_s3_bucket リソースで Access Denied エラーが起きたことを表しています。多くの場合はエラーが起きた API とエラーメッセージが出力されるので、どの権限が足りないのか分かるのですが、上記の例はそれが出力されておらず、IAM Policy で何の Action を許可すべきかは分かりません。

このような場合は、Terraform のログレベルを DEBUG にします。こうすると実行された API のレスポンスがログに出力されるので、具体的なエラー内容を確認できるようになります。以下はログの例です。エラーに出力されている request id AD5K2QH1NT937HXM をキーに探すと良いでしょう。

$ TF_LOG=DEBUG terraform plan

...
2023-04-09T12:25:09.356+0900 [DEBUG] provider.terraform-provider-aws_v4.62.0_x5: 
HTTP Response Received: ... 
http.status_code=403 ... 
aws.service=S3 ... 
aws.operation=GetBucketEncryption ... 
http.response.body="<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code><Message>Access Denied</Message>
<RequestId>AD5K2QH1NT937HXM</RequestId>
...
</Error>" 
...

上記の例では、ログの中でよく見るところを抜粋して、見やすいように改行を入れています。http.status_code=403, aws.service=S3, aws.operation=GetBucketEncryption のあたりをよく見ます。今回は S3 の GetBucketEncryptionの API で Access Denied エラーが出たことが分かります。

エラーがあった API を抽出する

ログは膨大な量があるので、エラーのあった API を抽出するとデバッグがやりやすくなります。ログの形式は Terraform のバージョンや API の種類によっても変わるようなので、ログの形式に応じて grep を微調整します。

$ TF_LOG=DEBUG terraform plan 2>&1 | tee -a tflogs.log

# 400 系のエラーがあった API 名を抽出
$ grep 'http.status_code=40[03]' tflogs.log | grep -o 'aws\.operation=[^ ]*' | sort | uniq

...
aws.operation=GetBucketEncryption
aws.operation=GetBucketLifecycleConfiguration
aws.operation=GetObjectLockConfiguration
...

# 400 系のエラーがあった API のサービス名を抽出
$ grep 'http.status_code=40[03]' tflogs.log | grep -o 'aws\.service=[^ ]*' | sort | uniq

...
aws.service=S3
...

後は、IAM Policy で必要な Action と Resource を許可していきます。API に対応した IAM Policy の探し方は別の記事にまとめたのでご確認ください。

AWS Connand Line Interface
AWS CLIやAPIに対応するIAMポリシーのActionを調べる

Amazon S3 を使うとき、AWS の API や AWS CLI の s3api のコマンドと、IAM Polic ...

続きを見る

エンコードされたエラーメッセージからエラーの詳細を確認する

Terraform でエラーが起きたとき、以下のようにエンコードされたエラーメッセージが出力されることがあります。

│ Error: creating EC2 Instance: UnauthorizedOperation: You are not authorized to perform this operation. Encoded authorization failure message: q0SFMTA5QSW9xxxxxxx
│       status code: 403, request id: 1a1dxxxx

以下のようにエラーメッセージをデコードすると、エラーの詳細を確認することができます。

aws sts decode-authorization-message --encoded-message q0SFMTA5QSW9xxxxxxx

CloudTrail を確認する

Terraform のログには request id が出力されています。これをもとに CloudTrail を確認して、どの API でエラーが起きているかを確認することもできます。

登録、更新、削除のパターンも確認する

terraform apply のときは更新系の API が呼ばれ、plan のときとは違う API が呼び出されます。通常の運用で想定されるパターンを洗い出して権限を付与します。通常は発生しないパターン、特にリソースの削除については、予期せぬ間違いを防ぐために権限を付与しないこともあります。特に DB やストレージなど状態をもったリソースの削除については、権限を与えないだけでなく、リソースの削除保護を有効にすることもご検討ください。

-技術ブログ
-