RDS Proxy created by DBCluster.addProxy() should have a depends on DBCluster in generated CloudFormation template
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
Deploying a stack with CloudFormation that has a RDS Proxy added with the `addProxy` method from the `DatabaseCluster` could possibly fail because the Proxy will attempt to be created before the DatabaseCluster. I had a stack with a Proxy that was able to deploy on one AWS account using the template but will consistently fail when trying to deploy to another AWS account.
### Reproduction Steps
Click to expand CDK Stack
This is a pared-down version of the stack I'm trying to deploy:
```
import { Construct, Stack, StackProps } from 'monocdk';
import {
AuroraPostgresEngineVersion,
Credentials,
DatabaseCluster,
DatabaseClusterEngine,
DatabaseSecret,
} from 'monocdk/aws-rds';
import {
SubnetType,
Vpc,
SecurityGroup,
Port,
} from 'monocdk/aws-ec2';
export class MyTestStack extends Stack {
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
/*
* Resources for VPC setup including security groups and bastion hosts
*/
const rdsVpc = new Vpc(this, 'myVpc');
// Security group assumed by AWS resources to allow access to RDS
const canReadRdsSecGroup = new SecurityGroup(
this,
'CanReadRdsSecGroup',
{
vpc: rdsVpc,
},
);
// Security group assumed by RDS, allow connections on default port for other sec groups
const rdsSecurityGroup = new SecurityGroup(this, 'RdsSecGroup', {
vpc: rdsVpc,
});
rdsSecurityGroup.connections.allowFrom(
canReadRdsSecGroup,
Port.tcp(5432),
'Security Group allowing RDS access from AWS resources',
);
/*
* Resources related to setting up the RDS instance
*/
const databaseName = 'db_name';
const username = 'postgres';
const rdsAdminSecret = new DatabaseSecret(
this,
'AdminSecret',
{
username,
},
);
// Create the Database cluster
const rdsCluster = new DatabaseCluster(this, 'myDatabase', {
engine: DatabaseClusterEngine.auroraPostgres({
version: AuroraPostgresEngineVersion.VER_11_8,
}),
credentials: Credentials.fromSecret(rdsAdminSecret),
instanceProps: {
vpc: rdsVpc,
vpcSubnets: {
subnetType: SubnetType.PRIVATE,
},
securityGroups: [rdsSecurityGroup],
},
storageEncrypted: true,
clusterIdentifier: 'myDatabase',
defaultDatabaseName: databaseName,
});
// Create the database secret for non-admin account
const user2Secret = new DatabaseSecret(this, 'User2Secret', {
username: 'user2',
masterSecret: rdsAdminSecret,
});
user2Secret.attach(rdsCluster);
// Add rotations for the secrets
rdsCluster.addRotationSingleUser();
// Create the Database Proxy
const rdsProxy = rdsCluster.addProxy('RdsProxy', {
secrets: [rdsAdminSecret,user2Secret],
vpc: rdsVpc,
securityGroups: [rdsSecurityGroup],
iamAuth: true,
});
rdsCluster.connections.allowDefaultPortFrom(
rdsProxy,
'Allow connections to the database cluster from the Proxy',
);
}
}
```
### What did you expect to happen?
Click to expand Partial CFN template
```
"myDatabaseRdsProxy3FC52F28": {
"Type": "AWS::RDS::DBProxy",
"Properties": {
"Auth": [
{
"AuthScheme": "SECRETS",
"IAMAuth": "REQUIRED",
"SecretArn": {
"Ref": "AdminSecretB9452750"
}
},
{
"AuthScheme": "SECRETS",
"IAMAuth": "REQUIRED",
"SecretArn": {
"Ref": "DataUploadDbSecret57F9A554"
}
}
],
"DBProxyName": "RdsProxy",
"EngineFamily": "POSTGRESQL",
"RoleArn": {
"Fn::GetAtt": [
"myDatabaseRdsProxyIAMRole8ADFED42",
"Arn"
]
},
"VpcSubnetIds": [
{
"Ref": "myVpcPrivateSubnet1SubnetDE1978C0"
},
{
"Ref": "myVpcPrivateSubnet2SubnetB7D01881"
}
],
"RequireTLS": true,
"VpcSecurityGroupIds": [
{
"Fn::GetAtt": [
"RdsSecGroup72BC67FD",
"GroupId"
]
}
]
},
"Metadata": {
"aws:cdk:path": "Infra-test/myDatabase/RdsProxy/Resource"
},
"DependsOn": [
"myDatabase6024D442"
]
},
```
### What actually happened?
Click to expand Partial CFN Template & Error
```
"myDatabaseRdsProxy3FC52F28": {
"Type": "AWS::RDS::DBProxy",
"Properties": {
"Auth": [
{
"AuthScheme": "SECRETS",
"IAMAuth": "REQUIRED",
"SecretArn": {
"Ref": "AdminSecretB9452750"
}
},
{
"AuthScheme": "SECRETS",
"IAMAuth": "REQUIRED",
"SecretArn": {
"Ref": "DataUploadDbSecret57F9A554"
}
}
],
"DBProxyName": "RdsProxy",
"EngineFamily": "POSTGRESQL",
"RoleArn": {
"Fn::GetAtt": [
"myDatabaseRdsProxyIAMRole8ADFED42",
"Arn"
]
},
"VpcSubnetIds": [
{
"Ref": "myVpcPrivateSubnet1SubnetDE1978C0"
},
{
"Ref": "myVpcPrivateSubnet2SubnetB7D01881"
}
],
"RequireTLS": true,
"VpcSecurityGroupIds": [
{
"Fn::GetAtt": [
"RdsSecGroup72BC67FD",
"GroupId"
]
}
]
},
"Metadata": {
"aws:cdk:path": "Infra-test/myDatabase/RdsProxy/Resource"
},
```
**This CFN lacks the `DependsOn` values**. When trying to deploy this to my 2nd AWS account in US-East-1, Cloudformation fails to deploy the stack with an error:
```
RDS is not authorized to assume service-linked role arn:aws:iam::[AWS ACCOUNT ID]:role/aws-service-role/rds.amazonaws.com/AWSServiceRoleForRDS (Service: AWSSecurityTokenService; Status Code: 403; Error Code: AccessDenied; Request ID: [REQUEST ID]; Proxy: null). Check your RDS service-linked role and try again.
```
### Environment
- **CDK CLI Version :** 1.97.0
- **Framework Version:** 1.97
- **Node.js Version:** v12.18.3
- **OS :** Amazon Linux 2
- **Language (Version):** TypeScript
### Other
- Adding a dependency on the DatabaseCluster using `dbProxy.node.addDependency()` does not work. While it does add the DBCluster as a dependency, it also adds other resources (such as the `DBProxyTargetGroup`) as a dependency to the proxy which creates circular dependencies.
- When creating a Proxy using the class [DatabaseProxy](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-rds.DatabaseProxy.html) and then adding a dependency to DBCluster works as intended
-
### Proposal
When adding a RDS proxy to a DBCluster using the `addProxy()` method, the generated CloudFormation resource for the DBProxy should have a `DependsOn` for the DBCluster.
---
This is :bug: Bug Report
Contributor guide
Research direction
Start at DatabaseCluster.addProxy() and compare its generated resource behavior with the separately constructed DatabaseProxy path. Inspect the generated CloudFormation for the DBProxy and the effects of dbProxy.node.addDependency(); done means the proxy depends on the DBCluster without introducing dependencies that create circular references.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- cloud, database, infrastructure
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100