Cloudformation-coverage-roadmap: AWS::RDS::DBCluster-DBClusterResourceId accessible via Fn::GetAtt

Created on 26 Sep 2019  路  12Comments  路  Source: aws-cloudformation/cloudformation-coverage-roadmap

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.

database

Most helpful comment

Please add this.

All 12 comments

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"
Was this page helpful?
0 / 5 - 0 ratings