[Terraform]別AWSアカウントにS3オブジェクトをコピー

# 別AWSアカウントのS3にオブジェクトをコピーしたい

特定のAWSアカウントのS3バケットにあるオブジェクトを
別AWSアカウントにコピーするTerraformコードの紹介になります。

## 実際のコード

copy_objectを使えばOKです。

- main.tf
ソースのS3バケットが存在するAWSアカウント設定

```hcl
provider "aws" {
  region = "ap-northeast-1"
  default_tags {
    tags = {
      IaC          = "Terraform"
    }
  }
}

# コピー対象のAWSアカウント設定
provider "aws" {
  profile = var.targetprofile
  alias   = "delegator"
  region  = "ap-northeast-1"

  default_tags {
    tags = {
      IaC          = "Terraform"
    }
  }
}
```

- data.tf

```hcl
data "aws_caller_identity" "current" {}
```

- variables.tf
TARGET_AWS_PROFILE : コピー先のAWSプロファイル名
TARGET_S3_BUCKETNAME : コピー先のS3バケット名
SOURCE_S3_BUCKETNAME : コピー元のS3バケット名

```hcl
variable "target_profile" {
  default     = TARGET_AWS_PROFILE
  description = "aws target_profile"
}


variable "region" {
  default     = "ap-northeast-1"
  description = "aws region"

}


variable "source_bucketname" {
  default     = TARGET_S3_BUCKETNAME
  description = "source s3 bucket name"
}

variable "target_bucketname" {
  default     = SOURCE_S3_BUCKETNAME
  description = "target s3 bucket name"
}
```

- s3_object_copy.tf

targetobject : コピー対象のオブジェクト名

```hcl
# Object S3 Copy
locals {
  targetobject = [
    "test.txt",
    "test/sample.txt"
  ]
}

# S3 Bucker Create
resource "aws_s3_bucket" "target" {
  provider = aws.delegator
  bucket   = var.target_bucketname
}

data "aws_iam_policy_document" "allow_access_from_another_account" {
  provider = aws.delegator
  statement {
    sid = "Example permissions"
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
    }

    actions = [
      "s3:GetObject",
      "s3:ListBucket",
      "s3:PutObject",
      "s3:PutObjectAcl",
      "s3:*"
    ]

    resources = [
      aws_s3_bucket.target.arn,
      "${aws_s3_bucket.target.arn}/*",
    ]
  }
}


resource "aws_s3_bucket_policy" "target" {
  provider = aws.delegator
  bucket   = aws_s3_bucket.target.bucket
  policy   = data.aws_iam_policy_document.allow_access_from_another_account.json
}



resource "aws_s3_object_copy" "copy_object" {
  for_each = toset(local.targetobject)
  bucket   = aws_s3_bucket.target.id
  key      = each.key
  source   = "${var.source_bucketname}/${each.key}"
  depends_on = [
    aws_s3_bucket_policy.target,
  ]
}


```

## 実行方法

- DryRun

```sh
terraform plan
```

- Apply

```sh
terraform apply
```

## 解説

aws_s3_object_copyでバケットポリシーを関連付けしておかないと
バケットポリシーの付与前にオブジェクトをコピーしようとしてしまうため
バケットポリシーの付与が完了してからコピーするようにdepends_onで指定しています。

尚、定義ファイルをシンプルにするためstateファイル管理にS3やDynamoDBを利用していません。
同じ理由でmodule化もしていません。

- 初回実行だとdefault_tagsが付与されない問題
Applyの内容をみるとtags_allで付与されるように見えるのですが、
実際には付与されず、再度実行する必要があります。

```hcl
  # aws_s3_object_copy.copy_object["test.txt"] will be updated in-place
  ~ resource "aws_s3_object_copy" "copy_object" {
        id                            = "test.txt"
        tags                          = {}
      ~ tags_all                      = {
          + "IaC" = "Terraform"
        }
        # (32 unchanged attributes hidden)
    }

  # aws_s3_object_copy.copy_object["test/sample.txt"] will be updated in-place
  ~ resource "aws_s3_object_copy" "copy_object" {
        id                            = "test/sample.txt"
        tags                          = {}
      ~ tags_all                      = {
          + "IaC" = "Terraform"
        }
        # (32 unchanged attributes hidden)
    }
```