Reputation: 523
I've got a nested CloudFormation template which accepts a number of parameters from its root template to configure it. At the moment I'm only passing simple string parameters but now I need to pass a list of S3 bucket ARNs onto the child template.
ChildLambdaStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
AwsRegion: !Ref AwsRegion
Environment: !Ref Environment
Product: !Ref Product
S3Buckets: "arn:aws:s3:::bucket1,arn:aws:s3:::bucket2"
TemplateURL: "https://s3.amazonaws.com/child-template.yml"
And then in the child template I have this
AWSTemplateFormatVersion: "2010-09-09"
Description: "Child Lambda"
Parameters:
AwsRegion:
Type: String
Environment:
Type: String
Product:
Type: String
S3Buckets:
Type: String
Resources:
DeployerPolicy:
Type: AWS::IAM::ManagedPolicy
Properties:
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:GetObject
- s3:DeleteObject
- s3:CreateBucket
- s3:DeleteBucket
- s3:ListBucket
- s3:PutBucketNotification
Resource:
- Fn::Split:
- ","
- !Ref S3Buckets
My idea is that that list of S3 bucket ARNs that I'm inputting is expanded in the child template like this
Resource:
- arn:aws:s3:::bucket1
- arn:aws:s3:::bucket2
But when I run the template in, it just errors out
Syntax errors in policy. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument)
I've tried other variations like using a CommaDelimitedList
parameter type, but none work. Is there a simple way to pass in a list of strings as a parameter?
Upvotes: 29
Views: 62588
Reputation: 426
There is actually a much better way. You can use the type List<String>
in your CloudFormation Parameters:
# ...
Parameters:
S3Buckets:
Type: List<String>
# ...
Then pass the S3 Bucket list just like you did as comma separated values:
# ...
ChildLambdaStack:
Type: AWS::CloudFormation::Stack
Properties:
Parameters:
AwsRegion: !Ref AwsRegion
Environment: !Ref Environment
Product: !Ref Product
# Next line will be interpreted as a list
S3Buckets: "arn:aws:s3:::bucket1,arn:aws:s3:::bucket2"
TemplateURL: "https://s3.amazonaws.com/child-template.yml"
# ...
You can then assume that the type of the referenced Parameter is a list. So instead of:
# ...
Resource: !Split [",", !Ref S3Buckets]
# ...
You can just use:
# ...
Resource: !Ref S3Buckets
# ...
Upvotes: 13
Reputation: 2073
As @MaiKaY points out, the flaw in @Liam Mayfair's code is that Fn::Split
is preceded by -
which results in a list containing a single element which is a list. The fixed code would look like
...
Resource:
Fn::Split:
- ","
- !Ref S3Buckets
On a more general note, you must make sure to use a Parameter type of String
not CommaDelimitedList
when using Fn::Split
as it won't split a CommaDelimitedList
.
CommaDelimitedList
with Fn::Split
you'll get the error Template error: every Fn::Split object requires two parameters, (1) a string delimiter and (2) a string to be split or a function that returns a string to be split
CommaDelimitedList
with no Fn::Split
you'll get the error Syntax errors in policy
Upvotes: 20
Reputation: 4482
Because the return value of !Split
is A list of string values.
I would do it in the following way:
[...]
Resource: !Split [",", !Ref S3Buckets]
[...]
Upvotes: 26