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
CodePudding user response:
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