CloudFormation: Return ARN of Subnet - aws-cloudformation

Is there another way to get ARN of created Subnet Resource AWS::EC2::Subnet via Fn::GetAtt intrinsic function. Subnet resource only returns AvailabilityZone, Ipv6CidrBlocks, NetworkAclAssociationId, VpcId.
Documentation: https://docs.aws.amazon.com/en_pv/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html#aws-resource-ec2-subnet-return-values

Since the ARN of a Subnet is in the format arn:aws:ec2:REGION:ACCOUNT_ID:subnet/SUBNET_ID. By using intrinsic function Fn::Join you can generate the ARN of the subnet.
Example: arn:aws:ec2:ap-southeast-1:767022272945:subnet/subnet-0d42d2235s3a2531d
!Join
- ''
- - 'arn:aws:ec2:'
- !Ref 'AWS::Region'
- ':'
- !Ref 'AWS::AccountId'
- ':subnet/'
- Fn::ImportValue:
Fn::Sub: VPC-SubnetId

A simpler solution, as noted in the comment by #sigpwned, is to just use !Sub
Even if the subnet you're referencing isn't local to your template, you can still pass it in as a parameter to the template or import it like in the original answer if it is available to the stack.
!Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:subnet/${Subnet}"

Related

is it possible to reuse existing route table in cloudformation template

I am writing one cft to connect dynamodb uisng vpcEndpoint.
DynamoDBEndpoint:
Type: "AWS::EC2::VPCEndpoint"
Properties:
RouteTableIds:
- !Ref PublicRouteTable
- !Ref Private0RouteTable
- !Ref Private1RouteTable
- !Ref Private2RouteTable
ServiceName:
!Sub "com.amazonaws.${AWS::Region}.dynamodb"
VpcId: !Ref VPC
Parameters:
vpcId:
Description: Choose the existing one
Type: AWS::EC2::VPC::Id
I am getting existing vpcId by using parameter ,is there any way I can ruse my existing routetable ,Please suggest me on this how could I define this ref PublicRouteTable and ref PrivateRouteTable .
Your parameter vpcId works because it uses AWS::EC2::VPC::Id type which belongs to Supported AWS-specific parameter types in CloudFormation.
Sadly, CloudFormation does not support similar type for route tables. You have to type out route tables IDs manually in console when you specify parameters.

What is the format to specify an external EDGE Gateway ApiId in CloudFormation templates?

I'm trying to create or update a stack with the following CloudFormation Template:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ApiGatewayId:
Type: String
ApiLayerArn:
Type: String
JarLocation:
Type: String
Resources:
Function:
Type: 'AWS::Lambda::Function'
Properties:
Handler: net.bitsandpaper.api.kiosk.PlatformChecker
Runtime: java11
Code:
S3Bucket: bnp-build-artifacts
S3Key: !Ref JarLocation
Description: ''
MemorySize: 128
Timeout: 5
Role: arn:aws:iam::479832603967:role/bnp-api-lambda-execution-role
Layers:
- !Ref ApiLayerArn
ApiIntegration:
Type: AWS::ApiGatewayV2::Integration
Properties:
ApiId: !Ref ApiGatewayId
IntegrationType: AWS_PROXY
IntegrationUri: !Join
- ''
- - 'arn:'
- !Ref 'AWS::Partition'
- ':apigateway:'
- !Ref 'AWS::Region'
- ':lambda:path/2015-03-31/functions/'
- !Ref Function
- /invocations
TimeoutInMillis: 6000
ApiRoute:
Type: AWS::ApiGatewayV2::Route
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'GET /kiosk/platform-check'
Target: !Join
- /
- - integrations
- !Ref ApiIntegration
The parameters are correctly passed by an external file, they look good in the Web Console, notably parameter ApiGatewayId has value 8548rqrsm5. Yet during deployment I have a CREATE_FAILED for ApiIntegration, with the message:
Invalid API identifier specified 479832603967:8548rqrsm5 (Service:
AmazonApiGatewayV2; Status Code: 404; Error Code: NotFoundException;
Request ID: 84918a83-cf9d-48d2-acf7-18d9d2e4d330; Proxy: null)
The API is an EDGE Rest API, in the same region than the CloudFormation stack. The ID is retrieved by the CLI with aws apigateway get-rest-apis.
Am I missing something in the ApiId format? The litterature is very scarce when not referencing an API in the same stack...
AWS::ApiGatewayV2 is only for WEBSOCKTES and HTTP types. From docs:
The API protocol. Valid values are WEBSOCKET or HTTP.
But since you are writing about Edge-optimized (not supported by HTTP api) it seems to that you are using REST API, rather then HTTP API. So you should be using AWS::ApiGateway resources, not AWS::ApiGatewayV2.
It seem's like the AWS::ApiGatewayV2::Route is created before the AWS::ApiGatewayV2::Integration. So When it trying to refer ApiIntegration it is not yet created.
So you should try to use DependsOn attribute.
With the DependsOn attribute you can specify that the creation of a
specific resource follows another. When you add a DependsOn attribute
to a resource, that resource is created only after the creation of the
resource specified in the DependsOn attribute.
Try this below CloudFormation code:
ApiRoute:
Type: AWS::ApiGatewayV2::Route
DependsOn: ApiIntegration
Properties:
ApiId: !Ref ApiGatewayId
RouteKey: 'GET /kiosk/platform-check'
Target: !Join
- /
- - integrations
- !Ref ApiIntegration
I hope this will help you out to resolve your problem.
Link: DependsOn Attribute UserGuide

Introduce a condition on a custom resource in CloudFormation

Another Engineer introduced a deploy date parameter into our AMIFInder Custom Resource in the prod stack which means we can no longer update the dev stack without attempting to recreate the EC2 instance.
Is it possible to introduce a condition purely based on the DeployDate parameter so I can still use one template for both stacks?
FindAmiResource:
Type: 'Custom::FindAmiFunction'
Properties:
ServiceToken:
Fn::ImportValue:
!Sub
- cfn:find-ami:${AWSAccount}:arn
- {AWSAccount: !FindInMap [AccountIDMap, Accounts, !Ref "AWS::AccountId"]}
AmiName: 'Corp_w2016_Std-*'
AmiOwner: '9999999999999'
DeployDate: !Ref AMIDeployDate
Assuming you have some information to key off (like a known AccountId or a parameter in the stack) you can create a condition that defines the stack as dev. Then you can use the 'Fn::If' function, like this:
FindAmiResource:
Type: 'Custom::FindAmiFunction'
Properties:
ServiceToken:
Fn::ImportValue:
!Sub
- cfn:find-ami:${AWSAccount}:arn
- {AWSAccount: !FindInMap [AccountIDMap, Accounts, !Ref "AWS::AccountId"]}
AmiName: 'Corp_w2016_Std-*'
AmiOwner: '9999999999999'
DeployDate:
Fn::If:
- DevCondition
- !Ref AWS::NoValue
- !Ref AMIDeployDate

Transforming a CommaDelimitedList of Roles to list of Arns in Cloudformation

I have a cloudformation template generating a kms key with a policy document to grant roles access to the key. Now I want the roles to be a CommaDelimitedList Parameter of the Cloudformation template and I do not know the size in advanced. So I have input like this:
["role1", "role2", ...]
and have to generate this:
Principal:
AWS:
- !Sub "arn:aws:iam::${AWS::AccountId}:role/role1",
- !Sub "arn:aws:iam::${AWS::AccountId}:role/role2",
...
Is this transformation possible in cloudformation?
Not possible.
What you need to do is to pass the ARNs list. For example:
SomeParam:
"Fn::Join":
- ","
-
- !GetAtt "role1.Arn"
- !GetAtt "role2.Arn"
And just use it directly, CommaDelimitedList is automatically transformed into list by CloudFormation when passed as a parameter:
Principal:
AWS: !Ref "RolesParameter"
If you have just role names, you need to build the ARNs on your own, like in your question, but before passing as an argument:
SomeParam:
"Fn::Join":
- ","
-
- !Sub "arn:aws:iam::${AWS::AccountId}:role/role1"
- !Sub "arn:aws:iam::${AWS::AccountId}:role/role2"

Output a list in cloud formation

I have a parameter:
ClusterSubnets:
Description: Subnets where cluster will reside.
Typically private. Use mutiples, each in a different AZ for HA.
ConstraintDescription: comma separated list of valid Subnet IDs
Type: List<AWS::EC2::Subnet::Id>
I'm trying to output this:
ClusterSubnets:
Description: Subnets used by cluster
Value: !Ref ClusterSubnets
Export:
Name: !Sub "${AWS::StackName}-ClusterSubnets"
But I get this error: Template format error: The Value field of every Outputs member must evaluate to a String.
How can I export a list?
You need to join the elements of the list into a string. Try something like this:
ClusterSubnets:
Description: Subnets used by cluster
Value: !Join
- ','
- !Ref ClusterSubnets
Export:
Name: !Sub "${AWS::StackName}-ClusterSubnets"
Here is the relevant AWS documentation.