2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWSでterraformするときにinstance-profileからassume-roleする

Posted at

AWSで terraform apply するにはAWSの操作権限の全てを与えておくのが現実的である。さもないと、未利用だったサービス・新しいサービスを使おうとする度にpolicy修正が必要になってしまう。

terraform 作業専用の instanceを用意する場合でも、強すぎる権限を常時全開にするわけにはいかないだろう。instance-profileとしては ReadOnlyAccess などもっと軽い権限だけにして、 terraform コマンドのときだけ全権を与えたい。そうおもってやってみたらはまりポイントがあったのでここに記録する。

※terraformオペレータのIAMユーザをMFA必須にして、そのユーザからの assume-roleをするのが、たぶんベストバランスだろう。この記事はその一歩手前のところである。assume-roleするための方法としては共通のはず。

role/ReadOnly-Role

  • Usecase: EC2
    • instance-profile として使える role
    • これを terraform作業用instance のIAM roleとして割り当てる
  • ReadOnlyAccess AWS 管理ポリシー
  • ProfileOnlyPolicy
    • instance-profile:ReadOnly-Role の instanceでの利用でなければ何もさせない
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Resource": "*",
            "Action": "*",
            "Effect": "Deny",
            "Condition": {
                "ArnEquals": {
                    "ec2:InstanceProfile": "arn:aws:iam::<account-id>:role/ReadOnly-Role"
                }
            }
        }
    ]
}

role/Terraform-Role

  • AdministratorAccess AWS 管理ポリシー
    • Terraform用に原則全部の操作を可能とする
  • ProfileOnlyPolicy
    • instance-profile:ReadOnly-Role の instanceでの利用でなければ何もさせない
  • PolicyDocument
    • role/ReadOnly-Role からの switch だけを許す
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<account-id>:role/ReadOnly-Role"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

provider.tf

provider "aws" {
  region  = "ap-northeast-1"
  version = ">1.56.0"
  profile = "terraform-role"
}

terraform {
  backend "s3" {
    bucket = "foo-terraform"
    key    = "bar/terraform.tfstate"
    region = "ap-northeast-1"
    skip_metadata_api_check = true
    profile = "terraform-role"
  }
}

~/.aws/credentials

[terraform-role]
role_arn = arn:aws:iam::<account-id>:role/Terraform-Role
credential_source = Ec2InstanceMetadata

policy/role/credentials の動作検証

terraform抜きで確認できる範囲をまずは検証する。

$ aws sts get-caller-identity
{
    "Account": <account-id>,
    "UserId": "xxxx:<instance-id>",
    "Arn": "arn:aws:sts::<account-id>:assumed-role/ReadOnly-Role/<instance-id>"
}
$ aws sts get-caller-identity --profile terraform-role
{
    "Account": <account-id>,
    "UserId": "xxxx:botocore-session-1598506181",
    "Arn": "arn:aws:sts::<account-id>:assumed-role/Terraform-Role/botocore-session-1598506181"
}

terraform apply

既存のリソースに新規Tagを追加するとか、注記用のTagの文字列を少し変えるとかで、terraform apply

はまりポイント

terraform state を S3保存するための backend "s3" ブロックが難物だった。

terraformオペレータが複数になることや、terraform作業instanceが障害や誤操作で失われることを想定すると、S3保存は外せない。

しかし provider ブロックで profile 指定しても export AWS_PROFILE= の環境変数指定しても、エラーになる。

Failed to save state: failed to upload state: AccessDenied: Access Denied

検証用に追加したTagやTag文字列はリソースに反映されているので、assume-roleはできているはずなのに。

コードブロックにあるように、backend ブロックにも profile 指定が要るのだった。 backend 保存処理は provider ブロックとは独立の credential設定になっているようだ。おまけにこちらには、skip_metadata_api_check = true オプションが必要だった。

参照した issue
terraform-providers/terraform-provider-aws#5018

The s3 backend does not use the provider block.

次にはまったときはこれも試そう

I run terraform init with TF_LOG=DEBUG

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?