Aws cloudformation join and sub together - amazon-web-services

I'm trying to generate list of ARNs using list of account ids. Below is the code ,
Principal:
Service: lambda.amazonaws.com
AWS:
!Split
- ','
- !Sub
- 'arn:${AWS::Partition}:iam::${acc_id}:root'
- acc_id: !Join
- !Sub ':root,arn:${AWS::Partition}:iam::'
- !Ref AccountIds
But getting an error "botocore.exceptions.ClientError: An error occurred (ValidationError) when calling the UpdateStack operation: Template error: every Fn::Join object requires two parameters, (1) a string delimiter and (2) a list of strings to be joined or a function that returns a list of strings (such as Fn::GetAZs) to be joined."
I'm not understanding what's wrong in above code. Can someone help ?

Related

Cloudformation: Create array of log ARNs from comma delimited list of log names

I have parameter LogNames - comma delimited list of log names:
LogNames:
Type: String
Default: >-
/aws/my-custom-log-1,/aws/my-custom-log-1
I want to use it in the IAM policy definition - Resource field:
Resource:
<array of allowed log ARNs created from LogNames parameter>
Any idea how to use functions e.g. Split, Join, Sub, ... to generate correct array of log ARNs? Single log ARN have syntax:
- !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${LogName}:*'
Its not possible without a macro or a custom resource. The only way to do it without these, is to hardcode your region and accountid and use combo of Split, Join, Sub:
Parameters:
LogNames:
Type: CommaDelimitedList
Default: >-
/aws/my-custom-log-1,/aws/my-custom-log-2,/aws/my-custom-log-3
Resource:
!Split:
- ","
- !Sub
- "arn:aws:logs:us-east-1:234234234234:log-group:${logname}"
- logname: !Join
- ",arn:aws:logs:us-east-1:234234234234:log-group:"
- !Ref LogNames

Template validation failed when using SAM syntax instead of CloudFormation syntax for step function

I have the following step function in my AWS SAM template, it was defined using the syntax in the documentation. I'm using intrinsic functions to get some pseudoparameters but something is going wrong with them.
SfdcOrderEventsStepFunction:
Type: AWS::Serverless::StateMachine
Properties:
DefinitionSubstitutions:
Region: !Ref "AWS::Region"
AccountId: !Ref "AWS::AccountId"
EventBusPublishTarget: "order-events"
DefinitionUri: sfn-definition.asl.yml
Events:
EventBridgeEvent:
Type: EventBridgeRule
Properties:
EventBusName: sfdc-events
Pattern:
# TODO: Update pattern when the salesforce service is ready
source:
- prefix: salesforce.com
detail-type:
- Order
detail:
Payload__c:
attributes:
type:
- order
InputPath: $.detail
Name: sfdc-order-events
Role: !Sub 'arn:aws:iam::${AWS::AccountId}:role/stepfunction_execution_role'
Tracing:
Enabled: true
when I try to deploy it shows me the following error:
Resource template validation failed for resource
SfdcOrderEventsStepFunction as the template has invalid properties.
Please refer to the resource documentation to fix the template.
Properties validation failed for resource SfdcOrderEventsStepFunction
with message:
#/De finitionSubstitutions/ AccountId: 2 subschemas matched instead of one
#/DefinitionSubstitutions/AccountId: expected type: Boolean, found: String
At the end it deploys without problems. The step function and all of its components run as expected and without errors, but I wanted to know if there if something I can do to fix the template.

Use Gett Function inside Sub in cloudformation

I am trying to get the value of my RDS endpoint and use it as a value in a secret-manager I am creating.
I know how to get the endpoint in the outputs:
DB1ConnectionString:
Condition: Launch1Engine
Description: The First db Connection String
Value: {"Fn::GetAtt": ["RDSDBInstance1","Endpoint.Address"]}
But I can not use output inside my current stack, so I want to use the same way I got the Endpoint and use it in the secret manager.
This is what I tried:
DBStringSecret1:
Condition: Launch1Engine
Type: 'AWS::SecretsManager::Secret'
Properties:
Name: !Ref DBStringSecret1Name
SecretString: !Sub '{"repository":!GetAtt RDSDBInstance1.Endpoint.Address,"username":"MasterUsername","password":"${SafeMineDBPassword1}"}'
But I get a literal string as the "repository value and not the RDS endpoint,
Is there a way to use the "!GetAtt" inside the "!Sub"?
Or am I doing it all wrong and I can define a new parameter that will build the value I want using Join?
!Sub 'jdbc://{!GetAtt RDSDBInstance1.Endpoint.Address}:3306/<SCHEMA>?'
Expected result:
jdbc://endpoint:3306/?
You have to use join function in this case:
SecretString: !Join
- ''
- - '{"repository": "'
- !GetAtt RDSDBInstance1.Endpoint.Address
- '","username":"MasterUsername","password":"'
- !Ref SafeMineDBPassword1
- '"}'

Cloudformation Combine Sub and Join to get a list

I am trying to create a list in my Cloudformation template.
Inspired by this post: Sub and Join on Comma-Delimited List I have gotten to this idea but it doesnt work as the !Sub line has to be a string...
Error is:
Error: Failed to create changeset for the stack: STACKNAME, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state: For expression "Status" we matched expected path: "FAILED" Status: FAILED. Reason: Template error: every Fn::Join object requires two parameters, (1) a string delimiter and (2) a list of strings to be joined or a function that returns a list of strings (such as Fn::GetAZs) to be joined.
Any thoughts? Is this even possible?
Accounts:
Type: CommaDelimitedList
Default: Acc1,Acc2,Acc3
pRedshiftUser:
Type: String
Default: arn:redshiftperson
...
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Split
- ','
- !Sub
- '${pRedshiftUser}/${user}'
- user: !Join
- !Sub ',${pRedshiftUser}/'
- Ref: "Accounts"
The idea being I'm trying to create this as the output:
Action: sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId:
- arn:redshiftperson/user1
- arn:redshiftperson/user2
Sadly you can't do this. Delimiter in Join must be explicit string.
For the Fn::Join delimiter, you can't use any functions. You must specify a string value.
So you can't use Sub in Delimiter.
The only way would to create a custom macro or a custom resource in CloudFormation. In both ways, you would need to develop a lambda function to handle the transformation of your data to desired format.

Template format error: Every Mappings attribute must be a String or a List

I wanted to have some quick references at the top of my CloudFormation template, so that I don't have to write out a complex reference every time i need it throughout the template.
So I wrote this:
Mappings:
StandardResourcesMap:
AWSExecuteApi:
string: !Join [ ':' , ['arn', !Sub '${AWS::Partition}', 'execute-api', !Sub '${AWS::Region}', !Sub '${AWS::AccountId}'] ]
AWSLambdaFunctions:
string: !Join [ ':' , ['arn', !Sub '${AWS::Partition}', 'apigateway', !Sub '${AWS::Region}', 'lambda:path/2015-03-31/functions/'] ]
The rest of the CloudFormation template follows this, and, without the lines above, the template deploys (an S3 bucket, DynamoDB table and a python 3.7-based Lambda).
The hope was that I could then just use:
!FindInMap [StandardResourcesMap,AWSExecuteApi,string]
whenever i needed the long-winded value, however the template fails validation with:
An error occurred (ValidationError) when calling the CreateChangeSet operation: Template format error: Every Mappings attribute must be a String or a List.
as the title says.
I have tried a number of variations on the Mappings such as using the !Ref variant:
Mappings:
StandardResourcesMap:
AWSExecuteApi:
string: !Join [ ':' , ['arn', !Ref 'AWS::Partition', 'execute-api', !Ref 'AWS::Region', !Ref 'AWS::AccountId'] ]
AWSLambdaFunctions:
string: !Join [ ':' , ['arn', !Ref 'AWS::Partition', 'apigateway', !Ref 'AWS::Region', 'lambda:path/2015-03-31/functions/'] ]
and I just get pulled up on various validation errors, centring on the one presented above.
any help would be greatly appreciated.
The problem is this: You cannot include parameters, pseudo parameters, or intrinsic functions in the Mappings section. Mappings