Functions nest, and the engine evaluates them from the inside out. Both values below build the same URL for an SSM parameter from a website bucket's WebsiteURL minus its http://; deployed on LocalStack 63,725 , both returned https://<bucket>.s3-website.localhost.localstack.cloud:4566/dev/books (with the container's port 4566, not the host port 31566):
# Nested
Value: !Join
- ""
- - "https://"
- !Select [1, !Split ["//", !GetAtt FrontEndBucket.WebsiteURL]]
- !Sub "/${Stage}/books"
# Flattened
Value: !Sub
- https://${Host}/${Stage}/books
- Host: !Select [1, !Split ["//", !GetAtt FrontEndBucket.WebsiteURL]]
Prefer Fn::Sub to Fn::Join with an empty delimiter: the string then looks like its result.
Name inner expressions in Fn::Sub's variable map, one expression per variable.
YAML cannot stack two short tags: Value: !Base64 !Sub "..." is a parse error (cfn-lint 2,641 E0000 did not find expected key); write Fn::Base64: !Sub "...".
A !Sub without variables is noise; cfn-lint reports W1020 'Fn::Sub' isn't needed.
Beyond three levels, move the value into a parameter, a mapping or another stack's output.