Terraform を実行するユーザの AWS IAM ポリシーを Administrator Access
から最小限のポリシーに変更する機会があったので備忘録。
最小の権限を割り当てようとすると、その課程で AccessDenied エラーが数多く発生してなかなか大変です。どのようにして権限エラーを取り除き、最小の権限を決定したのかを紹介します。同じことを考えている方の参考になれば。この記事を書くために検証した Terraform のバージョンは 1.3.9、AWS Provider は 4.62.0 です。
目次
- アクセス権限の無い IAM ポリシーを用意する
- Terraform のログから実際に実行された API を調べる
- エラーがあった API を抽出する
- エンコードされたエラーメッセージからエラーの詳細を確認する
- CloudTrail を確認する
- 登録、更新、削除のパターンも確認する
アクセス権限の無い 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 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 やストレージなど状態をもったリソースの削除については、権限を与えないだけでなく、リソースの削除保護を有効にすることもご検討ください。