6
votes

I have seen several links, but I have to see an example. I have:

resource "aws_iam_role" "role" {
  name = "role"

  assume_role_policy = <<-EOF
{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "Stmt1590217939125",
        "Action": "s3:*",
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::wwe"
      },
      {
        "Sid": "Stmt1590217939125",
        "Action": "s3:*",
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::wwe/*"
      },
      {
        "Sid": "Stmt1577967806846",
        "Action": [
          "secretsmanager:DescribeSecret",
          "secretsmanager:GetRandomPassword",
          "secretsmanager:GetResourcePolicy",
          "secretsmanager:GetSecretValue",
          "secretsmanager:ListSecretVersionIds",
          "secretsmanager:ListSecrets"
        ],
        "Effect": "Allow",
        "Resource": "*"
      }
    ]
}
  EOF
  tags = {
    Name        = wwe
    Environment = STAGE
  }
}

When I am making,

terraform apply

I see this:

  # aws_iam_role.role will be created
  + resource "aws_iam_role" "role" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = "s3:*"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:s3:::wwe"
                      + Sid      = "Stmt1590217939125"
                    },
                  + {
                      + Action   = "s3:*"
                      + Effect   = "Allow"
                      + Resource = "arn:aws:s3:::wwe/*"
                      + Sid      = "Stmt1590217939125"
                    },
                  + {
                      + Action   = [
                          + "secretsmanager:DescribeSecret",
                          + "secretsmanager:GetRandomPassword",
                          + "secretsmanager:GetResourcePolicy",
                          + "secretsmanager:GetSecretValue",
                          + "secretsmanager:ListSecretVersionIds",
                          + "secretsmanager:ListSecrets",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                      + Sid      = "Stmt1577967806846"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + max_session_duration  = 3600
      + name                  = "role"
      + path                  = "/"
      + tags                  = {
          + "Environment" = "STAGE"
          + "Name"        = "wwe"
        }
      + unique_id             = (known after apply)
    }

After, when I am writing yes, I see:

Error: Error creating IAM Role role: MalformedPolicyDocument: Has prohibited field Resource
        status code: 400

Where, I have an error ? Please don't post links, to the same questions. I don't understand, where I have an error, Could You please write an example, where I have an error, If it possible. Thanks for Your attention.

2
Something similar, which may help: stackoverflow.com/questions/44565879/…BishalG

2 Answers

4
votes

One issue is that you have two statements with the same Sid: Stmt1590217939125.

Sids must be unique. From the docs:

In IAM, the Sid value must be unique within a JSON policy.

The second issue is that assume_role_policy is for a trust policy. Trust policies do not have Resource. They have different form. For instance:

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

To add your policies to the role, have to use aws_iam_role_policy_attachment. For example, you could do:

resource "aws_iam_policy" "policy" {
  name = "my-role"
   description = "My policy"

  policy = <<-EOF
{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "Stmt1590217939128",
        "Action": "s3:*",
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::wwe"
      },
      {
        "Sid": "Stmt1590217939125",
        "Action": "s3:*",
        "Effect": "Allow",
        "Resource": "arn:aws:s3:::wwe/*"
      },
      {
        "Sid": "Stmt1577967806846",
        "Action": [
          "secretsmanager:DescribeSecret",
          "secretsmanager:GetRandomPassword",
          "secretsmanager:GetResourcePolicy",
          "secretsmanager:GetSecretValue",
          "secretsmanager:ListSecretVersionIds",
          "secretsmanager:ListSecrets"
        ],
        "Effect": "Allow",
        "Resource": "*"
      }
    ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "test-attach" {
  role       = "${aws_iam_role.role.name}"
  policy_arn = "${aws_iam_policy.policy.arn}"
}
4
votes

What's wrong with the existing code?

The assume_role_policy attribute of the aws_iam_role resource, is not for granting permissions to calls APIs other than sts:AssumeRole:

assume_role_policy - (Required) The policy that grants an entity permission to assume the role.

NOTE: This assume_role_policy is very similar but slightly different than just a standard IAM policy and cannot use an aws_iam_policy resource. It can however, use an aws_iam_policy_document data source, see example below for how this could work.

How do I fix it?

So, assuming you want this role to be assumable by EC2, you would use an aws_iam_role to declare the IAM Role and its assume_role_policy:

resource "aws_iam_role" "role" {
  name = "role"

  assume_role_policy = <<-EOF
  EOF
  tags = {
    Name        = wwe
    Environment = STAGE
  }
}

And then use an aws_iam_role_policy to attach an inline policy with the IAM actions you wish to grant that role (along with resources and possible conditions):

resource "aws_iam_role_policy" "policy" {
  name = "policy"
  role = aws_iam_role.role.id

  policy = <<-EOF
  {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": "s3:*",
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::wwe"
        },
        {
          "Action": "s3:*",
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::wwe/*"
        },
        {
          "Action": [
            "secretsmanager:DescribeSecret",
            "secretsmanager:GetRandomPassword",
            "secretsmanager:GetResourcePolicy",
            "secretsmanager:GetSecretValue",
            "secretsmanager:ListSecretVersionIds",
            "secretsmanager:ListSecrets"
          ],
          "Effect": "Allow",
          "Resource": "*"
        }
      ]
  }
  EOF
}

You don't need to tuck your JSON along the margin, it can be indented for improved readability:

Terraform also accepts an indented heredoc string variant that is introduced by the <<- sequence:

block {
  value = <<-EOT
  hello
    world
  EOT
}

I recommend using an aws_iam_policy_document data source to build your IAM policies. It's avoids annoying quirks of JSON (like no trailing commas) and better supports scenarios where you need to use variables in building your policies (really difficult to escape them properly in all cases):

resource "aws_iam_role_policy" "policy" {
  name = "policy"
  policy = data.aws_iam_policy_document.policy_doc.json
}

data "aws_iam_policy_document" "policy_doc" {
  statement {
    actions = [
      "s3:*",
    ]

    resources = [
      "arn:aws:s3:::wwe",
    ]
  }

  statement {
    actions = [
      "s3:*",
    ]

    resources = [
      "arn:aws:s3:::wwe/*",
    ]
  }

  statement {
    actions = [
      "secretsmanager:DescribeSecret",
      "secretsmanager:GetRandomPassword",
      "secretsmanager:GetResourcePolicy",
      "secretsmanager:GetSecretValue",
      "secretsmanager:ListSecretVersionIds",
      "secretsmanager:ListSecrets",
    ]

    resources = [
      "*",
    ]
  }
}