Home > Mobile >  "jsonencode" expects only 1 argument(s)
"jsonencode" expects only 1 argument(s)

Time:10-26

I am trying to terraform an AWS role. I followed this example where they had only attached one json policy:

resource "aws_iam_policy" "policy" {
  name        = "test_policy"
  path        = "/"
  description = "My test policy"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "ec2:Describe*",
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}

However, I want to attach two policies. I tried this with a comma in between the two:

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

  assume_role_policy = jsonencode(

    {
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Effect" : "Allow",
          "Action" : [
            "s3:*",
            "s3-object-lambda:*"
          ],
          "Resource" : "*"
        }
      ]
    },
    {
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Effect" : "Allow",
          "Action" : [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents"
          ],
          "Resource" : "*"
        }
      ]
    }

  )

However, this gives an error that:

Function "jsonencode" expects only 1 argument(s).

How else can I attach more than one policy?

CodePudding user response:

It is because your policies are in wrong json format. You need to wrap the two policies in an array as follows.

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

  assume_role_policy = jsonencode(
    [
      {
        "Version" : "2012-10-17",
        "Statement" : [
          {
            "Effect" : "Allow",
            "Action" : [
              "s3:*",
              "s3-object-lambda:*"
            ],
            "Resource" : "*"
          }
        ]
      },
      {
        "Version" : "2012-10-17",
        "Statement" : [
          {
            "Effect" : "Allow",
            "Action" : [
              "logs:CreateLogGroup",
              "logs:CreateLogStream",
              "logs:PutLogEvents"
            ],
            "Resource" : "*"
          }
        ]
      }
    ]
  )

CodePudding user response:

The assume_role_policy argument expects only a single IAM policy document, but that document can potentially contain multiple statements if you need to declare multiple effects on different resources.

Note though that assume_role_policy is only used to specify which other IAM principals are allowed to assume the role. It does not specify what access the role itself grants. Therefore it's not useful to declare policies for actions other than sts:AssumeRole, sts:AssumeRoleWithSAML, and sts:AssumeRoleWithWebIdentity in an assume role policy.

(I wrote more detail about AssumeRole in an answer to an earlier question.)

Given the policy content you shared, I expect your intent is to associate a policy with two statements with the role such that assuming the role will grant that access. To do that you'll need to use the aws_iam_role_policy resource type alongside aws_iam_role, to first declare the role and then declare the policy to associate with it:

resource "aws_iam_role" "example" {
  name = "name"

  # You will also need to set assume_role_policy to declare
  # what can assume this role, but there isn't enough
  # information in your question to know what policy would
  # be appropriate for that.
}

resource "aws_iam_role_policy" "example" {
  name = aws_iam_role.example.name

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect   = "Allow"
        Action   = [
          "s3:*",
          "s3-object-lambda:*",
        ]
        Resource = "*"
      },
      {
        Effect   = "Allow"
        Action   = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents",
        ]
        Resource = "*"
      },
    ]
  })
}

output "role_arn" {
  value = aws_iam_role.example.arn

  # The role ARN won't be fully usable until
  # the policy is attached to it, so we must
  # declare this additional dependency to get
  # correct ordering of operations.
  depends_on = [aws_iam_role_policy.example]
}

Notice that the policy expression in aws_iam_role_policy.example has only one policy document, but that document has two statements that each independently allow a set of actions. In this case it would be equivalent to put all of these actions together into a single statement, but I assume you have them separated because in practice they are not so similar to each other.

It's also valid to declare more than one aws_iam_role_policy for the same role, which can be useful if you want to split the declaration of the role from granting different policies to it, but in this case (where the same module is declaring both anyway) there's little reason to add that complexity.

  • Related