cloudformation-coverage-roadmap icon indicating copy to clipboard operation
cloudformation-coverage-roadmap copied to clipboard

AWS::RDS::DBCluster - DBClusterResourceId accessible via Fn::GetAtt

Open dan-lind opened this issue 4 years ago • 16 comments

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.

dan-lind avatar Sep 26 '19 07:09 dan-lind

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

ScriptAutomate avatar Nov 18 '19 07:11 ScriptAutomate

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

ScriptAutomate avatar Nov 27 '19 22:11 ScriptAutomate

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.

dan-lind avatar Nov 28 '19 06:11 dan-lind

I would like to get the cluster ARN for use with the aurora data API

revmischa avatar Nov 28 '19 08:11 revmischa

@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

jplock avatar Nov 28 '19 12:11 jplock

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....

kuanhung-chen avatar Feb 04 '20 16:02 kuanhung-chen

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

dan-lind avatar Mar 30 '20 16:03 dan-lind

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

thkapasi avatar Mar 30 '20 16:03 thkapasi

Please add this.

BenSmith avatar Apr 10 '20 15:04 BenSmith

We desperately need this too.

qoomon avatar Apr 30 '20 05:04 qoomon

Much needed. Thanks!

mmahmood avatar Jun 30 '20 11:06 mmahmood

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"

marcossantiago avatar Jul 16 '20 13:07 marcossantiago

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.

jebcolesd avatar Sep 24 '21 05:09 jebcolesd

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.

ghost avatar Sep 25 '21 09:09 ghost

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?

iainb123 avatar Aug 24 '22 07:08 iainb123

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

karaken12 avatar Sep 01 '22 10:09 karaken12

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"

kabo avatar Sep 23 '22 03:09 kabo