Search code examples
jsonamazon-web-servicesterraformaws-cloudformationterraform-provider-aws

How can I write a YAML Join Format of AWS Cloudformation to Terraform format?


I'm trying to convert an AWS Cloudformation Managed Policy document into a Terraform file to create policies. However, I'm having trouble with the Join format under the Resource section which it seems Terraform doesn't accept even when I tried wrapping it with ", ' or trying to convert it to JSON. May I seek some help o how do I format it the way terraform interpret it correctly? Below is the terraform file I'm working on. Many thanks in advance.

module "my_policy" {
  source = "../modules/policy"

  policy = {
    name        = "my_access"
    description = "my access account"
    path        = "/"
    document    = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "MyBeanstalkPermissions",
      "Effect": "Allow",
      "Action": [
        "elasticbeanstalk:CreateApplicationVersion",
        "elasticbeanstalk:DeleteApplicationVersion",
        "elasticbeanstalk:UpdateEnvironment",
        "elasticbeanstalk:CreateStorageLocation",
        "elasticbeanstalk:Check*",
        "elasticbeanstalk:Describe*",
        "elasticbeanstalk:List*",
        "elasticbeanstalk:RequestEnvironmentInfo",
        "elasticbeanstalk:RetrieveEnvironmentInfo",
        "elasticbeanstalk:RestartAppServer",
        "elasticbeanstalk:UpdateApplication",
        "elasticbeanstalk:UpdateApplicationVersion"
      ],
      "Resource": !Join ["", ["arn:aws:elasticbeanstalk:*:", !Ref "AWS::AccountId", ":*" ] ] 
    }
  ]
}
EOF
  }
}

I get this error:

"policy" contains an invalid JSON: invalid character '!' looking for beginning of value

Solution

  • Concatenating strings is a bit different in Terraform compared to CloudFormation as you might have noticed. The way you would usually do that is by referencing a resource attribute. If the ElasticBeanstalk attribute is available after creation, you could reference that value. If not, you can use interpolation that comes with Terraform [1]. So, in order to fix the error, you just have to use a different format for the value:

        document    = <<EOF
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "MyBeanstalkPermissions",
          "Effect": "Allow",
          "Action": [
            "elasticbeanstalk:CreateApplicationVersion",
            "elasticbeanstalk:DeleteApplicationVersion",
            "elasticbeanstalk:UpdateEnvironment",
            "elasticbeanstalk:CreateStorageLocation",
            "elasticbeanstalk:Check*",
            "elasticbeanstalk:Describe*",
            "elasticbeanstalk:List*",
            "elasticbeanstalk:RequestEnvironmentInfo",
            "elasticbeanstalk:RetrieveEnvironmentInfo",
            "elasticbeanstalk:RestartAppServer",
            "elasticbeanstalk:UpdateApplication",
            "elasticbeanstalk:UpdateApplicationVersion"
          ],
          "Resource": "arn:aws:elasticbeanstalk:*:<AWS account id>:*"
        }
      ]
    }
    EOF
    

    In order to get the account ID, you need to use a data source for that. The name of the data source is aws_caller_identity [2]. You would have to add the data source to a tf file:

    data "aws_caller_identity" "current" {}
    

    Then, instead of the <AWS account id> placeholder in the above snippet, you would use:

    data.aws_caller_identity.current.account_id
    

    Which then can be used to form the Elastic Beanstalk ARN:

    "arn:aws:elasticbeanstalk:*:${data.aws_caller_identity.current.account_id}:*"
    

    However, you might also consider using a data source for creating policies as it is much easier to fit in with Terraform way of thinking than JSON policies [3].

    Also note that the data source for AWS account ID will match only the current AWS account you are performing actions in. If you need to do that for another account, you need to provide a value instead of using the data source reference.


    [1] https://www.terraform.io/language/expressions/strings

    [2] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity

    [3] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document