Error putting S3 policy: MalformedPolicy: Invalid policy syntax

Viewed 1322

I am trying to set up an S3 bucket policy in Terraform. I have written the following code in a module core/main.tf:

resource "aws_s3_bucket_policy" "access_to_bucket" {

  bucket = aws_s3_bucket.some_bucket.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action    = ["s3:GetObject", "s3:GetObjectAcl", "s3:ListBucket"]
        Effect    = "Allow"
        Principal = "${var.some_variable_name}"
        Resource = [
          "${aws_s3_bucket.some_bucket.arn}",
          "${aws_s3_bucket.some_bucket.arn}/*"
        ]
      },
    ]
  })
}

Which then gets instantiated in a local module which uses localstack to run locally.

This is the plan generated:

Terraform will perform the following actions:

  # module.local.aws_s3_bucket_policy.access_to_bucket will be created
  + resource "aws_s3_bucket_policy" "access_to_bucket" {
      + bucket = "some_bucket"
      + id     = (known after apply)
      + policy = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = [
                          + "s3:GetObject",
                          + "s3:GetObjectAcl",
                          + "s3:ListBucket",
                        ]
                      + Effect    = "Allow"
                      + Principal = "arn:aws:iam::000000000000:role/test_role"
                      + Resource  = [
                          + "arn:aws:s3:::some-bucket/*",
                          + "arn:aws:s3:::some-bucket",
                        ]
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
    }
╷
│ Error: Error putting S3 policy: MalformedPolicy: Invalid policy syntax.
│       status code: 400, request id, host id
│ 
│   with module.local.aws_s3_bucket_policy.access_to_bucket,
│   on ../core/main.tf line 55, in resource "aws_s3_bucket_policy" "access_to_bucket":
│   55: resource "aws_s3_bucket_policy" "access_to_bucket" {
│ 

Running it both locally and in AWS ends up with this error. I am guessing it's a syntax error somewhere but AFAIK this is correct. Any clue what's wrong?

1 Answers

Your Principal isn't valid. If you look at the IAM user guide (S3 bucket policies share the same syntax but are limited to actions on the bucket and combine to form a least privilege access control) on the Principal element you should see examples such as this:

"Principal" : { 
"AWS": [ 
  "arn:aws:iam::123456789012:root",
  "arn:aws:iam::555555555555:root" 
  ]
}

This allows the IAM action to happen only for users or roles in the two AWS accounts with IDs 123456789012 and 555555555555.

In your case you want to allow an IAM role so your policy should look like this:

{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Effect": "Allow",
      "Principal": {"AWS": "arn:aws:iam::000000000000:role/test_role"},
      "Action": ["s3:GetObject", "s3:GetObjectAcl", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::some-bucket/*", "arn:aws:s3:::some-bucket"]
    }
  ]
}

Terraform allows you to write the JSON for your IAM policies yourself, which can be easier to compare to examples across the internet, or you can use the aws_iam_policy_document data source which will give you more plan time validation as Terraform can better understand the structure you are giving it.

The equivalent policy document as above but as an aws_iam_policy_document data source looks like this:

data "aws_iam_policy_document" "bucket_policy" {
  statement {
    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::000000000000:role/test_role"]
    }

    actions = [
      "s3:GetObject",
      "s3:GetObjectAcl",
      "s3:ListBucket",
    ]

    resources = [
      "arn:aws:s3:::some-bucket",
      "arn:aws:s3:::some-bucket/*",
    ]
  }
}

resource "aws_s3_bucket_policy" "access_to_bucket" {
  bucket = aws_s3_bucket.some_bucket.id
  policy = data.aws_iam_policy_document.bucket_policy.json
}
Related