Terraform-provider-aws: Configuring source KMS keys for replicating encrypted objects

Created on 2 Oct 2018  ·  6Comments  ·  Source: hashicorp/terraform-provider-aws

_This issue was originally opened by @ChairmanTubeAmp as hashicorp/terraform#18966. It was migrated here as a result of the provider split. The original body of the issue is below._


Terraform Version

Terraform v0.11.8
+ provider.aws v1.38.0

Terraform Configuration Files

replication_configuration {
  role = "${aws_iam_role.replication.arn}"

  rules {
    id     = "${var.service}"
    prefix = "${var.replication_bucket_prefix}"
    status = "Enabled"

    destination {
      bucket        = "${aws_s3_bucket.replication_bucket.arn}"
      storage_class = "STANDARD"
      replica_kms_key_id = "xxxxx"
    }

    source_selection_criteria {
      sse_kms_encrypted_objects {
        enabled = true
      }
    }
  }
}

Debug Output

Terraform applies normally

Crash Output

No crash output

Expected Behavior

With sse_kms_encrypted_objects, Terraform should've required a source kms key for the replication source bucket. Or defaulted to the aws kms master key.

Actual Behavior

Terraform does not give AWS a kms key to decrypt the source bucket's objects during replication. Replication is marked as FAILED.

After setting up replication with Terraform, if you use the AWS console to specify a source bucket decryption key for the replication rule, it will replicate properly.

needs-triage servics3

Most helpful comment

When you set up replication in the console, it is actually creating permissions for you. Go to IAM > Policies > Filter Policies > Used for Permissions and look for something like s3crr_kms_v2_for__to_. There is no need to specify the key, but you do need to add permissions for it.

The policy should look something like what is presented here: https://docs.aws.amazon.com/AmazonS3/latest/dev/crr-walkthrough-4.html

Here is some example .tf:

resource "aws_iam_role" "s3_backup_replication" {
  name = "backup_replication"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
POLICY
}

data "aws_kms_key" "s3" {
  key_id = "alias/aws/s3"
}

variable "s3_backup_key" {
  default = "arn:aws:kms:${var.backup_region}:${var.account_id}:${var.backup_s3_kms_key_id}"
}

resource "aws_s3_bucket" "source_bucket" {
  bucket        = "source-bucket.cap-rx.com"
  acl           = "private"
  region        = "${var.region}"
  force_destroy = true

  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "aws:kms"
      }
    }
  }

  versioning {
    enabled = true
  }

  lifecycle_rule {
    enabled = true

    noncurrent_version_expiration {
      days = 90
    }
  }

  replication_configuration {
    role = "${aws_iam_role.s3_backup_replication.arn}"

    rules {
      id     = "all"
      prefix = ""
      status = "Enabled"

      destination {
        bucket        = "${data.terraform_remote_state.backup_s3.source_bucket_backup_arn}"
        storage_class = "STANDARD"
        replica_kms_key_id = "${var.s3_backup_key}"
      }

      source_selection_criteria {
        sse_kms_encrypted_objects {
          enabled = true
        }
      }
    }
  }
}


resource "aws_iam_policy" "s3_backup_replication" {
  name = "s3_backup_replication"

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:GetReplicationConfiguration",
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_s3_bucket.source_bucket.arn}"
      ]
    },
    {
      "Action": [
        "s3:GetObjectVersion",
        "s3:GetObjectVersionAcl",
        "s3:GetObjectVersionForReplication"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_s3_bucket.source_bucket.arn}/*"
      ]
    },
    {
      "Action": [
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ReplicateTags",
        "s3:GetObjectVersionTagging"
      ],
      "Effect": "Allow",
      "Resource": [
        "${data.terraform_remote_state.backup_s3.source_bucket_backup_arn}/*"
      ]
    },
    {
      "Action":[
        "kms:Decrypt"
      ],
      "Effect":"Allow",
      "Condition": {
        "StringLike": {
          "kms:ViaService":"s3.${var.region}.amazonaws.com",
          "kms:EncryptionContext:aws:s3:arn": [
            "${aws_s3_bucket.source_bucket.arn}/*"
          ]
        }
      },
      "Resource":[
        "${data.aws_kms_key.s3.arn}"
      ]
    },
    {
      "Action":[
        "kms:Encrypt"
      ],
      "Effect":"Allow",
      "Condition": {
        "StringLike": {
          "kms:ViaService": "s3.${var.backup_region}.amazonaws.com",
          "kms:EncryptionContext:aws:s3:arn": [
            "${data.terraform_remote_state.backup_s3.source_bucket_backup_arn}/*"
          ]
        }
      },
      "Resource":[
        "${var.s3_backup_key}"
      ]
    }
  ]
}
POLICY
}

resource "aws_iam_policy_attachment" "s3_backup_replication" {
  name       = "s3_backup_replication"
  roles      = ["${aws_iam_role.s3_backup_replication.name}"]
  policy_arn = "${aws_iam_policy.s3_backup_replication.arn}"
}

All 6 comments

When you set up replication in the console, it is actually creating permissions for you. Go to IAM > Policies > Filter Policies > Used for Permissions and look for something like s3crr_kms_v2_for__to_. There is no need to specify the key, but you do need to add permissions for it.

The policy should look something like what is presented here: https://docs.aws.amazon.com/AmazonS3/latest/dev/crr-walkthrough-4.html

Here is some example .tf:

resource "aws_iam_role" "s3_backup_replication" {
  name = "backup_replication"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
POLICY
}

data "aws_kms_key" "s3" {
  key_id = "alias/aws/s3"
}

variable "s3_backup_key" {
  default = "arn:aws:kms:${var.backup_region}:${var.account_id}:${var.backup_s3_kms_key_id}"
}

resource "aws_s3_bucket" "source_bucket" {
  bucket        = "source-bucket.cap-rx.com"
  acl           = "private"
  region        = "${var.region}"
  force_destroy = true

  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "aws:kms"
      }
    }
  }

  versioning {
    enabled = true
  }

  lifecycle_rule {
    enabled = true

    noncurrent_version_expiration {
      days = 90
    }
  }

  replication_configuration {
    role = "${aws_iam_role.s3_backup_replication.arn}"

    rules {
      id     = "all"
      prefix = ""
      status = "Enabled"

      destination {
        bucket        = "${data.terraform_remote_state.backup_s3.source_bucket_backup_arn}"
        storage_class = "STANDARD"
        replica_kms_key_id = "${var.s3_backup_key}"
      }

      source_selection_criteria {
        sse_kms_encrypted_objects {
          enabled = true
        }
      }
    }
  }
}


resource "aws_iam_policy" "s3_backup_replication" {
  name = "s3_backup_replication"

  policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:GetReplicationConfiguration",
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_s3_bucket.source_bucket.arn}"
      ]
    },
    {
      "Action": [
        "s3:GetObjectVersion",
        "s3:GetObjectVersionAcl",
        "s3:GetObjectVersionForReplication"
      ],
      "Effect": "Allow",
      "Resource": [
        "${aws_s3_bucket.source_bucket.arn}/*"
      ]
    },
    {
      "Action": [
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ReplicateTags",
        "s3:GetObjectVersionTagging"
      ],
      "Effect": "Allow",
      "Resource": [
        "${data.terraform_remote_state.backup_s3.source_bucket_backup_arn}/*"
      ]
    },
    {
      "Action":[
        "kms:Decrypt"
      ],
      "Effect":"Allow",
      "Condition": {
        "StringLike": {
          "kms:ViaService":"s3.${var.region}.amazonaws.com",
          "kms:EncryptionContext:aws:s3:arn": [
            "${aws_s3_bucket.source_bucket.arn}/*"
          ]
        }
      },
      "Resource":[
        "${data.aws_kms_key.s3.arn}"
      ]
    },
    {
      "Action":[
        "kms:Encrypt"
      ],
      "Effect":"Allow",
      "Condition": {
        "StringLike": {
          "kms:ViaService": "s3.${var.backup_region}.amazonaws.com",
          "kms:EncryptionContext:aws:s3:arn": [
            "${data.terraform_remote_state.backup_s3.source_bucket_backup_arn}/*"
          ]
        }
      },
      "Resource":[
        "${var.s3_backup_key}"
      ]
    }
  ]
}
POLICY
}

resource "aws_iam_policy_attachment" "s3_backup_replication" {
  name       = "s3_backup_replication"
  roles      = ["${aws_iam_role.s3_backup_replication.name}"]
  policy_arn = "${aws_iam_policy.s3_backup_replication.arn}"
}

@ChairmanTubeAmp ^^

Hello,

I've exactly the same problem.
When terraform (provider aws 2.25) create the replication rule, the replication doesn't work.
But, if I go trough the console and I edit the replication rule, I can see that the box "Replicate objects encrypted with AWS KMS" is checked but in the keys list, no key are selected. If I select the default key , replication start to work. After that, if I lauch again a terraform run, nothing is modified and the replication continue to work. I also did an aws s3api get-bucket-replication --bucket my-logs-bucket before and after the console modification (the key selection), and there is absolutely no difference before and after.
My IAM policy is good (like @f0rk proposition) and had never been modified after I select the key in the console.
I think there is something behind the scenes when we use the console that we cannot see through the API.

Thanks

Adrien

Hi folks 👋 It appears the answer to the original report was solved with this comment: https://github.com/terraform-providers/terraform-provider-aws/issues/6046#issuecomment-427960842

There is also additional information in this related issue: https://github.com/terraform-providers/terraform-provider-aws/issues/3993

Since Terraform seems to be doing what it is should be doing (we would not attempt to perform additional API actions outside the given configuration), we are going to opt to close this issue. If you have suggestions for how to improve the documentation for handling S3 Bucket replication, please feel free to submit a new GitHub issue. Thanks!

the documentation on this topic is not clear with regards to the proper configuration in the .tf file for KMS replication - specifically the source selection criteria

source_selection_criteria {
sse_kms_encrypted_objects {
enabled = true
}
}

I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

Was this page helpful?
0 / 5 - 0 ratings