AWS Cloudformation Get Hosted Zone Name from Hosted Zone ID - amazon-web-services

When taking a parameter of type AWS::Route53::HostedZone::Id is there a way to get the HostedZone name?
The hosted zone already exists but was not created with Cloudformation so there is no way for me to reference the name from another template.
Using type AWS::Route53::HostedZone::Id allows the user to select from a drop down, but the ID is chosen not the name.
Is there a way to get the name from the ID so that a record set can be created?
Here is the template I am using, notice the Name of the record set entry where we need the name of the hosted zone to create the record set.
AWSTemplateFormatVersion: '2010-09-09'
Description: Route53
Parameters:
HostedZone:
Type: AWS::Route53::HostedZone::Id
Description: The Hosted Zone for the Record Set
RecordSetName:
Type: String
Description: The name of the record set (all lowercase)
Resources:
Route53:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref HostedZone
Comment: DNS name
Name: !Sub ${RecordSetName}.??????
Type: A
TTL: '60'
ResourceRecords:
- 10.1.1.1

Given the problem you appear to be trying to solve (add an A record for your apex domain) you don't actually need the drop down parameter selector of type AWS::Route53::HostedZone::Id. Instead you can just use your String input and use HostedZoneName instead of HostedZoneId in the AWS::Route53::RecordSet as shown below:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
DomainName:
Type: String
Description: apex domain name
Resources:
Route53:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Sub '${DomainName}.'
Comment: DNS name
Name: !Ref DomainName
Type: A
TTL: '60'
ResourceRecords:
- 10.1.1.1
(note that you need to add the extra period . onto the end of the DomainName for the HostedZoneName).
If you wanted a sub-domain you could do something like:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
DomainName:
Type: String
Description: apex domain name
DomainPrefix:
Type: String
Description: sub domain prefix
Resources:
Route53:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: !Sub '${DomainName}.'
Comment: DNS name
Name: !Sub '${DomainPrefix}.${DomainName}'
Type: A
TTL: '60'
ResourceRecords:
- 10.1.1.2
With reference to Fn::GetAtt, you would use these when creating cloudformation exports for your resources, not when using the resources as in this question.
You can if you wish create exports containing the apex domain name and hosted zone ids, which is what I prefer to do to keep things tidy. However, exports are region specific, so if you deploy across multiple regions (which might be forced on you if you are using CloudFront and wants APIs deployed to other than us-east-1) you will need some faking up the exports in some of the regions.

Hosted Zone ID is displayed in Route 53 console UI and looks like Z1AVC899B05E2Y

Fn::GetAtt
The Fn::GetAtt intrinsic function returns a value for a specified attribute of this type. The following are the available attributes and sample return values.
For more information about using the Fn::GetAtt intrinsic function, see Fn::GetAtt.
NameServers
Returns the set of name servers for the specific hosted zone. For example: ns1.example.com.
This attribute is not supported for private hosted zones.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-route53-hostedzone.html

Related

How to reference Cognito UserPoolDomain alias target within CloudFormation template?

I want to create A record for Cognito UserPoolDomain alias target (Cognito auto-generated Cloudfront distribution) within CloudFormation template.
I didn't find in docs how to reference alias target of UserPoolDomain?
Should I create a Cloudfront distribution and then somehow pass it to Cognito?
This is snippet of my CloudFormation template and what I try to achieve:
...
AuthUserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
UserPoolId: !Ref AuthUserPool
Domain: auth.example.com
CustomDomainConfig:
CertificateArn: !Ref CertificateArn
AuthRecordSets:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneName: example.com.
RecordSets:
- Name: auth.example.com
Type: A
AliasTarget:
DNSName: ???
EvaluateTargetHealth: false
HostedZoneId: Z2FDTNDATAQYW2 # This is always the hosted zone ID when you create an alias record that routes traffic to a CloudFront distribution.
...
Please help!
As a workaround solution I've created a new CloudFormation template that accept Cognito target alias as a parameter (CognitoDistribution).
After Cognitio UserPoolDoman is created I run this to find distribution
aws cognito-idp describe-user-pool-domain --domain auth.example.com \
| jq -r '.DomainDescription.CloudFrontDistribution'
and then I create DNS record with this template
AWSTemplateFormatVersion: 2010-09-09
Description: >-
Add CNAME record for Cognito UserPoolDomain alias target (CloudFront distribution).
It is not part of same template as AWS::Cognito::UserPoolDomain because UserPoolDomain does not return distribution ref.
Parameters:
HostedZoneName:
Type: String
UserPoolDomain:
Type: String
CognitoTargetAlias:
Type: String
Resources:
AuthRecordSets:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneName: !Sub "${HostedZoneName}."
RecordSets:
- Name: !Ref UserPoolDomain
Type: A
AliasTarget:
DNSName: !Ref CognitoTargetAlias
EvaluateTargetHealth: false
# This is always the hosted zone ID when you create an alias record that routes traffic to a CloudFront distribution.
HostedZoneId: Z2FDTNDATAQYW2
not clean solution but at least I don't need to do it in console

Is there a way to fetch HostedZoneId from DNS name in CFT?

In CloudFormation Template, can we fetch HostedZoneId from DNS name? One way is we check the resource and look for the HostedZoneId and insert it. Can we also use GetAtt or any other function to get the id.
I want to do something like this on HostedZoneId but this is incorrect. Is there any other way to do this?
Parameter:
VPCEDNS:
Description: VPCe DNS target
Type: String
Resources:
PrimaryRecord:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
HostedZoneId: !GetAtt (!Ref "VPCEDNS").HostedZoneId
DNSName: !Ref "VPCEDNS"
EvaluateTargetHealth: true
Failover: PRIMARY
HostedZoneName: example.com
Name: service.example.com
Type: A
Sadly, in plain CFN there is no such way. If you really would need such functionality, you would have to use custom resource.
The resource would be in the form of a lambda function, which would take your DNS name as input parameter. Then using AWS SDK (e.g. boto3), it would find and match the corresponding hosted zone, and return its ID into your CFN stack for further use.

AWS ApiGateway: Unable to retrieve DistributionHostedZoneId attribute for AWS::ApiGateway::DomainName

We are using AWS API Gateway, and I'm using CloudFormation to register a domain and an A record, as follows:
Domain:
Type: AWS::ApiGateway::DomainName
Properties:
# EnvironmentName starts with an upper case letter, but the domain is created anyway
DomainName: !Sub "${EnvironmentName}.mycompany.com"
# this is a single certificate, used for all envs, and must be in virginia
CertificateArn: !ImportValue DomainCertificateArn
SecurityPolicy: TLS_1_2
EndpointConfiguration:
Types:
- EDGE
ARecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: Fn::ImportValue !Sub "${EnvironmentName}-HostedZoneId"
# resolves to Z032215012YHJZINBEW
Type: A
Name: !Ref Domain
AliasTarget:
DNSName: !GetAtt Domain.DistributionDomainName
HostedZoneId: !GetAtt Domain.DistributionHostedZoneId
However, I'm seeing the following error when running this against my environment:
Unable to retrieve DistributionHostedZoneId attribute for AWS::ApiGateway::DomainName
I've looked in the API Gateway console to check on this domain entry, and it does exist, with type EDGE, and all the other params present. The Hosted zone id however is not the same value as that used in the template.
According to the documentation you should be able to get this value from the distributionHostedZoneId attribute of your AWS::ApiGateway::DomainName resource.
Based on the documentation and your file nothing appears to be configured incorrectly, there is also this line in the documentation regarding the DistributionHostedZoneId.
The only valid value is Z2FDTNDATAQYW2 for all regions.
This is the CloudFront distribution ID (as you're using regional) so you could set this value specifically. Otherwise validate that it gets created as a EDGE custom domain.

How can I link my AWS Managed AD to my FSx resources in cloudformation?

I am quite new in cloudformation. Trying to create a template for AWS FSx with joining my AWS Managed AD. Here is what I did so far, when I execute in AWS CF console, it shows Failed to retrieve external values for AWS AD and seems like other options, I am able to select with dropdown; the AD one, I don't get a drop-down way to select my AWS managed Microsft AD.
AWSTemplateFormatVersion: 2010-09-09
Parameters:
MyAWSManagedADServiceID:
Description: "AWS Managed Active Directoy Service ID, (e.g d-90670817d3)"
Type: 'AWS::DirectoryService::MicrosoftAD'
# Type: String
StorageCapacity:
Description: "Type the Storage Capacity value in TB, default '2TB' storage"
Type: Number
Default: 2000
MyFSxVPC:
Description: "VPC to operate FSx file FileSystem, (e.g vpc-05f3704057d6dce71)"
Type: AWS::EC2::VPC::Id
MyPrivateSubnet01:
Description: "The ID of Private Subnet 1 in Availability Zone 1 (e.g., subnet-a0246dcd)"
Type: AWS::EC2::Subnet::Id
MyPrivateSubnet02:
Description: "The ID of the Private Subnet 2 in Availability Zone 2 (e.g., subnet-a0246dcd)"
Type: AWS::EC2::Subnet::Id
WindowsIngressSecurityGroupId:
Description: "SecurityGroup ID for AWS FSx, (e.g sg-0fa88a05af8a49e03)"
Type: AWS::EC2::SecurityGroup::Id
Resources:
WindowsMadFileSystemWithAllConfigs:
Type: 'AWS::FSx::FileSystem'
Properties:
FileSystemType: WINDOWS
StorageCapacity: !Ref StorageCapacity
StorageType: SSD
SubnetIds:
- !Ref MyPrivateSubnet01
- !Ref MyPrivateSubnet02
SecurityGroupIds:
- !Ref WindowsIngressSecurityGroupId
Tags:
- Key: Name
Value: my-fsx-multi-az
WindowsConfiguration:
ActiveDirectoryId: !Ref MyAWSManagedADServiceID
ThroughputCapacity: 8
WeeklyMaintenanceStartTime: '4:16:30'
DailyAutomaticBackupStartTime: '01:00'
AutomaticBackupRetentionDays: 2
DeploymentType: MULTI_AZ_1
PreferredSubnetId: !Ref PrivateSubnet01
CopyTagsToBackups: false
Outputs:
FileSystemId:
Value: !Ref WindowsMadFileSystemWithAllConfigs
How can I get rid-off this error for AD and how can I select AWS Managed AD out of that drop-down menu?
Ah, I figured that "Type: 'AWS::DirectoryService::MicrosoftAD'" is not one of the parameters accepted by CF template. Refer: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html
Finally solved with using string type, however we can do ssm and use that.

AWS cloudformation recordset creation failing

I am trying to deploy an AWS cloudformation template with the following section
APIDns:
Type: 'AWS::Route53::RecordSet'
Properties:
HostedZoneId: myzoneid
HostedZoneName: myhost.com
AliasTarget:
DNSName: !Join [ '', [ !Ref RestApi, '.execute-api.',!Ref 'AWS::Region','.amazonaws.com/',!Ref 'Stage'] ]
EvaluateTargetHealth: false
Type: A
Name: api.myhost.com
I've have real string values instead of myzoneid and myhost
However creation of the recordset always fails with
CREATE_FAILED AWS::Route53::RecordSet APIDns Property HostedZoneId cannot be empty.
Any clues on what is causing the failure? Cloudformation spec is at https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html and I suspect that AliasTarget might have some error. I'm trying to create an alias to another API gateway v2 API (ie type AWS::ApiGatewayV2::Api)
I don't think you want to specify both the HostedZoneName AND HostedZoneId.
From https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html:
"Specify either HostedZoneName or HostedZoneId, but not both. If you have multiple hosted zones with the same domain name, you must specify the hosted zone using HostedZoneId."
For anyone else trying to create an Alias record to a CloudFront and not making it through, you'll need to have a specific hard-coded value for AliasTarget.HostedZoneId as mentioned in the documentations here
So, effectively, here's how your CloudFormation will look like:
CloudFront:
....
....
CloudFrontDnsRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: CHANGE_THIS
Name: example.com
Type: A
AliasTarget:
HostedZoneId: "Z2FDTNDATAQYW2" # this is hard-coded value
DNSName: !GetAtt Cloudfront.DomainName