Closed dan-lind closed 2 years ago
Because of this limitation, it looks like people have to resort to some workarounds as seen here until CFN supports it: https://stackoverflow.com/questions/42770067/how-do-you-associate-a-iam-role-with-an-aurora-cluster-using-cloudformation
Actually, this looks to be remedied with an update that came out back in August (as mentioned in an update to the StackOverflow answer):
As of August 29, 2019 this is finally supported! There is a new attribute named AssociatedRoles that takes an array of DBClusterRoles. These are basically an object with a RoleArn and an optional FeatureName which can currently only be s3Import per this reference showing SupportedFeatureNames.member.N.
AssociatedRoles seems to be what you are looking for, as a property of the AWS::RDS::DBCluster
resource type, which takes a list of the DBClusterRole property type.
This looks like you would need your CFN to create the IAM Role(s) first, and then reference them in AWS::RDS::DBCluster
Actually, this looks to be remedied with an update that came out back in August (as mentioned in an update to the StackOverflow answer):
As of August 29, 2019 this is finally supported! There is a new attribute named AssociatedRoles that takes an array of DBClusterRoles. These are basically an object with a RoleArn and an optional FeatureName which can currently only be s3Import per this reference showing SupportedFeatureNames.member.N.
AssociatedRoles seems to be what you are looking for, as a property of the
AWS::RDS::DBCluster
resource type, which takes a list of the DBClusterRole property type.This looks like you would need your CFN to create the IAM Role(s) first, and then reference them in
AWS::RDS::DBCluster
This is not the same thing. The description of AssociatedRoles reads "Provides a list of the AWS Identity and Access Management (IAM) roles that are associated with the DB cluster. IAM roles that are associated with a DB cluster grant permission for the DB cluster to access other AWS services on your behalf."
What I'm talking about is the opposite; creating roles that allows e.g. a Lambda to connect to an RDS instance using IAM Authentication. You need the DBClusterResourceId to be able to create that role.
I would like to get the cluster ARN for use with the aurora data API
@revmischa for the data API, you can recreate the ARN if you provide the DBClusterIdentifier property like https://github.com/smoketurner/serverless-vpc-plugin/blob/master/example/serverless.yml#L59
I believe in most cases we need CF return RDS cluster ARN, but in RDS IAM authentication case, we need CF able to return DBClusterResourceId, so that we could create IAM role for that RDS resource. Its really inconvenient and tricky that RDS IAM authentication require DBClusterResourceId instead of the common cluster ARN.
https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html To allow an IAM user or role to connect to your DB cluster, you must create an IAM policy. After that, you attach the policy to an IAM user or role.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "rds-db:connect" ], "Resource": [ "arn:aws:rds-db:us-east-2:1234567890:dbuser:cluster-ABCDEFGHIJKL01234/db_user" ] } ] }
Noticed that in sample rule above, currently there is no way to have "DBClusterResourceId", cluster-ABCDEFGHIJKL01234/
via CF....
Workaround to get the DB Clusters ARN in CloudFormation:
Value: Fn::Join: - "" - - !Sub "arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:" - !Select [0, !Split ['.', !GetAtt DBCluster.Endpoint.Address]].
Not relevant here. DBClusterResourceId (which is what this request is about) and DB cluster ARN is not the same thing
Workaround to get the DB Clusters ARN in CloudFormation:
Value: Fn::Join: - "" - - !Sub "arn:aws:rds:${AWS::Region}:${AWS::AccountId}:cluster:" - !Select [0, !Split ['.', !GetAtt DBCluster.Endpoint.Address]].
Not revlevant here. DBClusterResourceId (which is what this request is about) and DB cluster ARN is not the same thing
My bad - deleted comment
Please add this.
We desperately need this too.
Much needed. Thanks!
As a workaround I had to create a custom resource to retrieve this information:
Resources:
CustomLambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: RDSDescribe
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- rds:DescribeDBClusters
Resource: '*'
RDSUtilsLambda:
Type: 'AWS::Lambda::Function'
DeletionPolicy: Delete
Properties:
Code:
ZipFile: |
import boto3
import os
import cfnresponse
region = os.environ['AWS_REGION']
client = boto3.client('rds', region_name=region)
def handler(event, context):
responseData = {}
try:
rds_cluster = event['ResourceProperties']['rdsCluster']
clusters = client.describe_db_clusters(DBClusterIdentifier=rds_cluster)
responseData['DbClusterResourceId'] = clusters['DBClusters'][0]['DbClusterResourceId'] # Returns Cluster Resource Id
cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
except Exception as e:
cfnresponse.send(event, context, cfnresponse.FAILED, responseData)
Handler: index.handler
Runtime: python3.7
MemorySize: 128
Role: !GetAtt CustomLambdaRole.Arn
Timeout: 30
ClusterResourceIdOutput:
Type: Custom::RDSClusterResourceIdOutput
Properties:
rdsCluster: !Ref RDSCluster
ServiceToken: !GetAtt RDSUtilsLambda.Arn
Region: !Ref "AWS::Region"
UserIAMRole:
Type: AWS::IAM::Role
Properties:
Path: /
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
-
Effect: Allow
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- sts:AssumeRole
Policies:
- PolicyName: IAMDbAuthentication
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- rds-db:connect
Resource:
- !Sub "arn:aws:rds-db:${AWS::Region}:${AWS::AccountId}:dbuser:${ClusterResourceIdOutput.DbClusterResourceId}/my_nice_user"
It's two years since the initial request and a property that is easily available in AWS' APIs and necessary for a common configuration is still not available in cloudformation. Perhaps Cloudformation should allow a custom resource that returns the string output of a pseudo aws cli call - so that we can solve these problems ourselves without the convoluted (but inspired) workaround marcossantiago posted above.
I put in a pull request some time ago which I believe resolves this. There was a comment from the maintainers, but I don't think it's relevant because of how the code was written in the first place. If anyone can confirm that it works as is, tell me what needs to change, or make any other suggestions for the code, please do! It'd be great to get it merged in.
This is important if you're trying to set up IAM authentication with RDS clusters through CloudFormation.
@kara-uoy seems to have done all the work (see above), and it just needs to be reviewed. What's going on?
Updated the previous PR, as there had been some changes to the code in the meantime: https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-rds/pull/296
Can confirm this works now, I'm able to do
- Action: rds-db:connect
Effect: Allow
Resource: !Sub "arn:aws:rds-db:eu-west-1:112233445566:dbuser:${MyDb.DBClusterResourceId}/myUser"
Scope of request
New option for an existing attribute is desired
Expected behavior
Fn::GetAtt on a AWS::RDS::DBCluster resource returns DBClusterResourceId for the resource
Helpful Links to speed up research and evaluation
IAM Database Authentication https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html
IAM Policy for IAM Database Access https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/UsingWithRDS.IAMDBAuth.html
Category (required)
DB (RDS, DynamoDB...)
Any additional context (optional)
IAM Database Authentication requires us to create an IAM role, as per the link above. The resource ARN of the user policy needs to follow this pattern
arn:aws:rds-db:region:account-id:dbuser:DbClusterResourceId/db-user-name
Creating a role in CloudFormation is easy, however there is currently no way to extract DbClusterResourceId from a AWS::RDS::DBCluster resource, meaning we have to resort to custom resources.