Terraform で S3 を Backend に指定してステートファイルを管理したい。これを達成するため .tf ファイルに次のような記述をするとしよう。

terraform {
  ...
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.23.0"
    }
    ...
  }

  backend "s3" {
    bucket = "my-bucket-for-tfstate"
    key    = "terraform.tfstate"
    region = "ap-northeast-1"
  }
}

provider "aws" {
  region     = var.region
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  assume_role {
    role_arn = var.aws_role_arn
  }
}

次に S3my-buekct-for-tfstate バケットを作成して terraform init をするとしよう。次のようなエラーが表示されるだろう。

$ terraform init 
Initializing modules...

Initializing the backend...

Error: Error loading state:
    AccessDenied: Access Denied
        status code: 403, request id: xxxxxxxxxxxxxxxx, host id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Terraform failed to load the default state from the "s3" backend.
State migration cannot occur unless the state can be loaded. Backend
modification and state migration has been aborted. The state in both the
source and the destination remain unmodified. Please resolve the
above error and try again.

何が問題なのか? ここでは .tf ファイルで aws プロバイダに設定している assume_role が問題を起こしている。この例では、ある AWS アカウントに対して、あるロール (var.aws_role_arn で指定されているもの) を assume してプロビジョンしているので、S3 には assume する前のユーザーがバケットにアクセスする権限が付与されていなければならない。

具体的にはプロビジョンする対象の AWS アカウントに作る my-bucket-for-tfstate に次のような記述をする必要がある。

{
    "Version": "2012-10-17",
    "Statement": [
        {
           "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::012345678901:user/aws-terraform@example.com"
            },
            "Action": [
                "s3:DeleteObject",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::my-bucket-for-tfstate",
                "arn:aws:s3:::my-bucket-for-tfstate/*"
            ]
        }
    ]
}

ここで "arn:aws:iam::012345678901:user/aws-terraform@example.com" は AWS アカウント ID “012345678901” における IAM ユーザー “aws-terraform@example.com” の ARN であり、これが assume role 前のユーザーである。

この設定をすることで、最初の 403 エラーは解消できる。