Hi
I try to use the CDK to create infrastructure with AppSync and Aurora serverless.
Unfortunately I cannot get the ARN from the CfnDBCluster which is needed for the Data source and I AM role.
getAtt for Arn is also not working for CfnDBCluster
Is there another way to get the ARN?
Is there a general strategy for getting the ARN of a construct? If so, we should document it in the guide.
This is a limitation of CF, not of CDK. Unfortunately CDK does not expose it, so you will have to assemble it manually:
https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Tagging.ARN.html
let arn = `arn:aws:rds:${this.region}:${this.accountId}:clusterIdentifier:${cluster.clusterIdentifier}`
@fimbulvetr Thanks for the info but CfnDBCluster also doesn't expose the clusterIdentifier
How do you get around this?
Basically I need the ARN of the newly created cluster to create the access role for the appsync datasource.
const cluster = new CfnDBCluster(this, 'DBCluster', {
databaseName: 'myDb',
engine: 'aurora',
engineMode: 'serverless',
masterUsername: 'master',
masterUserPassword: 'password',
port: 3306,
scalingConfiguration: {
autoPause: true,
maxCapacity: 2,
minCapacity: 2,
secondsUntilAutoPause: 300,
},
});
// cluster.clusterIdentifier is undefined
let clusterArn = `arn:aws:rds:${this.region}:${this.accountId}:clusterIdentifier:${cluster.clusterIdentifier}`;
const role = new Role(this, 'GrantAppsyncAcessToClusterAndSecret', {
assumedBy: new ServicePrincipal('appsync.amazonaws.com'),
});
role.addToPolicy(new PolicyStatement()
.addAction('secretsmanager:GetSecretValue')
.addResources(secret.secretArn)
);
role.addToPolicy(new PolicyStatement()
.addActions('rds-data:DeleteItems',
'rds-data:ExecuteSql',
'rds-data:GetItems',
'rds-data:InsertItems',
'rds-data:UpdateItems')
.addResources(
"arn:aws:rds:us-east-1:123456789012:cluster:cdktrialstack-dbcluster-?????????????",
"arn:aws:rds:us-east-1:123456789012:cluster:cdktrialstack-dbcluster-?????????????:*",
)
);
@BerndWessels Apologies, I made two mistakes:
cluster.dbClusterName property.Like so:
let arn = `arn:aws:rds:${this.region}:${this.accountId}:cluster:${cluster.dbClusterName}`
@fimbulvetr Thanks, I am trying this out now.
I am slightly confused about the execution order within the CDK. Will the CfnDBCluster be created first, then the let arn ='arn:aws:rds:${this.region}:${this.accountId}:cluster:${cluster.dbClusterName}'; statement executed to receive the correct value to be used in the Role that has the secret.node.addDependency(cluster); ?
So basically what is the magic that puts the correct cluster.dbClusterName into the let clusterArn = 'arn:aws:rds:${this.region}:${this.accountId}:cluster:${cluster.dbClusterName}'; - since the cluster needs to be created before the value will be available ?
Wow, that works.
I think I understand how - so actually the CDK is clever enough to turn string templates like
let arn =`arn:aws:rds:${this.region}:${this.accountId}:cluster:${cluster.dbClusterName}`;
into
yml
Fn::Join:
- ""
- - "arn:aws:rds:"
- Ref: AWS::Region
- ":"
- Ref: AWS::AccountId
- ":cluster:"
- Ref: DBCluster
which is resolved at the "right" time within the flow of the CloudFormation Stack.
Pretty cool ;)
I would still prefer if all resources would give easy strongly typed access to all necessary properties without workarounds, but anyways cool that there is a workaround for now - thanks to @fimbulvetr
@BerndWessels If you're familiar with standard CF, you'll know that you can set up a resource, say a cluster with a name of FooBar, you can refer to it later when setting something else (Like an IAM role or something) up by using the !Ref FooBar and CF will know that it has to evaluate that "later" (i.e. not right now).
Basically, CDK behind the scenes is adding !Ref FooBar to your template.
See this page (or google "cloudformation ref" for more examples:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-ref.html
The tricky part is knowing that there are in general two ways to refer to an object - either GetAtt or Ref. Depending on the resource Type (AWS::Lambda::Function, AWS::SNS::Queue, etc.) , Ref might return an ARN, a Name, a UUID, etc. Also depending on the resource type, you may or may not have the ability to use GetAtt. In general, you can get an ARN from a resource using either GetAtt or Ref. Some resources (Such as RDS Cluster) inexplicably don't have the ability to get an ARN. Some resource types give you the ability to get a lot of useful things from GetAtt, some give you none.
I suggest always browsing the docs, it's what I do and it's how was able to get the RDS ARN to work for my usecase.
Just go to the Resource Type, and on the right click "Return Types". It will tell you what the "Ref" returns and if applicable, what GetAtts are available and what they return. For example:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-account.html#aws-resource-apigateway-account-returnvalues
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-graphqlapi.html#aws-resource-appsync-graphqlapi-returnvalues
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-certificatemanager-certificate.html#aws-resource-certificatemanager-certificate-return-values
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-distribution.html#aws-resource-cloudfront-distribution-ref
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-dynamodb-table.html#w2ab1c21c10d110c14c15
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance.html#aws-properties-ec2-instance-returnvalues
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#w2ab1c21c10d183c21b9
Just browse to those and see the variations of what Ref returns and if/what GetAtts are available.
@fimbulvetr Thank you, great advice - will do.
@fimbulvetr Oh, one last thing - this document says
Fn::GetAtt
Fn::GetAtt returns a value for a specified attribute of this type. The following are the available attributes and sample return values.
ClusterResourceId
The resource id for the DB cluster; for example: cluster-ABCD1234EFGH5678IJKL90MNOP. The cluster ID uniquely identifies the cluster and is used in things like IAM authentication policies.
But if I use cluster.getAtt('ClusterResourceId') I get this error
CdkTrialStack failed: ValidationError: Template error: resource DBCluster does not support attribute type ClusterResourceId in Fn::GetAtt
Template error: resource DBCluster does not support attribute type ClusterResourceId in Fn::GetAtt
Any ideas if I am doing something wrong or if there is another way to get the ClusterResourceId ?
Oh it's because you were on the DocDB::DBCluster:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-docdb-dbcluster.html
You want to be on RDS::DBCluster:
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-rds-dbcluster.html
testing with 1.4.0 version and arn that works now is:
let arn =arn:aws:rds:${this.region}:${this.account}:cluster:${cluster.ref};
so, instead of cluster.dbClusterName use cluster.ref
Thanks @goranopacic ! Closing this issue but please reopen it if you want to discuss things further.
Most helpful comment
Is there a general strategy for getting the ARN of a construct? If so, we should document it in the guide.