aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.62k stars 3.91k forks source link

RDS: add support for creating Proxy endpoints #14186

Open aalam-tu opened 3 years ago

aalam-tu commented 3 years ago

I have created a rds cluster: image

I am trying to create a rds proxy with both reader and read/write endpoints using AWS CDK

Reproduction Steps

I have created a rds proxy using:

    this.rdsCluster = new DatabaseCluster(this, clusterName, {
      clusterIdentifier: clusterName,
      engine: clusterEngine,
      credentials: {
        username: ResourcePropsConstants.RDS_MASTER_USER,
        excludeCharacters: ';',
      },
      instanceProps: {
        instanceType: new InstanceType(RdsUtils.determineInstanceSize(envName)),
        vpc: this.iVpc,
        vpcSubnets: {
          subnetType: SubnetType.PRIVATE,
        },
        securityGroups: [this.iRdsSG],
      },
      storageEncrypted: true,
      backup: {
        retention: Duration.days(RdsUtils.determineRetentionPeriod(envName)),
      },
      parameterGroup: this.parameterGroup,
      deletionProtection: isHigherEnv,
    });

    this.rdsProxy = this.rdsCluster.addProxy(dbProxyName, {
      dbProxyName,
      borrowTimeout: Duration.minutes(3),
      maxConnectionsPercent: 85,
      maxIdleConnectionsPercent: 10,
      idleClientTimeout: Duration.minutes(15),
      requireTLS: true,
      secrets: [this.rdsSecret],
      securityGroups: [this.iRdsProxySG],
      vpcSubnets: {
        subnetType: SubnetType.PRIVATE,
      },
      vpc: this.iVpc,
    });

What did you expect to happen?

I am expecting two endpoints to be created in the proxy - one with Read/Write and the other with Read target role. When I manually create a proxy using AWS Console a proxy is created with two endpoints

What actually happened?

Only one endpoint was created with Read/Write target role

Environment

Other


This is :bug: Bug Report

skinny85 commented 3 years ago

Thanks for opening the issue @aalam-tu. I don't think it's a bug. What you probably want is to have a Proxy TargetGroup that points to both instances of the Cluster.

We don't support that in the ProxyTarget class yet, so I'm changing this to a feature request. You could probably use the low-level CfnDBProxyTargetGroup class to achieve that today, you just have to take out the Instances from a Cluster. Perhaps something like this?

this.rdsCluster.node.children.forEach(child => {
  if (child instanceof rds.CfnDBInstance) {
    // do something with `child`

Hope this helps!

Thanks, Adam

aalam-tu commented 3 years ago

Thanks for the reply @skinny85.

Also, Initially I tried using this bit of code to generate the proxy and it created only one endpoint.

    this.rdsProxy = new DatabaseProxy(this, dbProxyName, {
      proxyTarget: ProxyTarget.fromCluster(dbCluster),
      dbProxyName,
      maxConnectionsPercent: 85,
      maxIdleConnectionsPercent: 1,
      borrowTimeout: Duration.minutes(3),
      secret: this.rdsCluster.secret,
      iamAuth: false,
      securityGroups: [this.iRdsProxySG],
      vpcSubnets: {
        subnetType: SubnetType.PRIVATE,
      },
      vpc: this.iVpc,
      idleClientTimeout: Duration.minutes(15),
      requireTLS: true,
    });

    // https://github.com/aws/aws-cdk/issues/8885
    const targetGroup = this.rdsProxy.node.findChild('ProxyTargetGroup') as CfnDBProxyTargetGroup;
    targetGroup.addOverride('Properties.TargetGroupName', 'default');
    targetGroup.addOverride('Properties.DBClusterIdentifiers', [this.rdsCluster.clusterIdentifier]);
    targetGroup.addOverride('Properties.DBInstanceIdentifiers', []);

I tried to override the DBInstanceIdentifiers :

    const targetGroup = this.rdsProxy.node.findChild('ProxyTargetGroup') as CfnDBProxyTargetGroup;
    targetGroup.addOverride('Properties.DBInstanceIdentifiers', [`${this.rdsCluster.clusterIdentifier}instance1`,
      `${this.rdsCluster.clusterIdentifier}instance2`]);

But, I got an exception: Resource handler returned message: "Only one DB instance is supported but 2 instances are provided (Service: AmazonRDS; Status Code: 400; Error Code: InvalidParameterValue; Request ID: ad46eb41-0dfe-4333-8030-3dafa5739d83; Proxy: null)" (RequestToken: 7b497dd9-e910-4b14-904d-1dbd76f02d2e, HandlerErrorCode: GeneralServiceException)

skinny85 commented 3 years ago

Ok... So, given that limitation, I wonder what does the setup in the Console that you mentioned do. Does it create two separate Proxies? One Proxy, but two ProxyTargetGroups? Or something else?

aalam-tu commented 3 years ago

When I created a proxy via aws console referencing the rds cluster, it creates one proxy with two endpoints - Read and Read/Write

In the prompt, I get asked if I want a reader endpoint. I believe in the .addProxy() we should get a boolean attribute like 'includeReaderEndpoint' to cater for this

image

Once the proxy is created it generates two endpoints

image

skinny85 commented 3 years ago

Ok. Looks like there's a resource called AWS::RDS::DBProxyEndpoint. This is probably what's missing from the DatabaseProxy class today.

You can create them today by using the CfnDBProxyEndpoint from the CDK. I'll keep this issue open as a feature request to add support for Proxy endpoints to our DatabaseProxy class.

yeti-g commented 2 years ago

@ericzbeard @skinny85 It's been over a year and this issue is still unassigned. 😞 Can you add the read-only endpoint creation as a boolean in DatabaseProxyProps to match the console functionality?

skinny85 commented 2 years ago

Sorry @yeti-g, we haven't prioritized this issue yet. Feel free to +1 it (we use +1s to help us prioritize).

We also encourage community contributions, so if you'd like to open us a Pull Request adding this feature, that would be fantastic! Our "Contributing" guide: https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md.

Thanks, Adam

ekeyser commented 2 years ago

@skinny85 You should know that whenever someone from AWS suggests that people freely submit PRs to a company with tens of billions of dollars a year in net profits and has a market cap approaching 2 trillion dollars it sounds a bit obtuse. Just so you're aware. Most of us either personally and out of our own pocket spend thousands of dollars a year on AWS services or we work for organizations that spend orders of magnitude more. This is not an isolated incident and quite frankly the tone of some of the other devs in this project have been very contemptuous borderline rude. If I were you I would perhaps hold back on that suggestion. We, the ones that use aws-cdk, are the ones that pay your salary either directly or indirectly. Just a little bit of feedback.

skinny85 commented 2 years ago

That's fair @ekeyser. I just want to underscore that we're a relatively small team, so we will always lag behind all AWS features in one area or another. So, given that, if a particular feature is very valuable to your project, the quickest way to get it to CDK is often contributing a PR for it. But of course, that is completely voluntary, and there is no expectation on anyone in the community about opening a PR.

Jacco commented 2 years ago

I am considering making a PR for this. Should I go for an includeReadOnlyEndpoint or for an addEndpoint interface?

Jacco commented 2 years ago

I am going for the following approach:

On DatabaseProxy:

  public addEndpoint(options: DatabaseProxyEndpointOptions): IDatabaseProxyEndpoint {
    const endpoint = new DatabaseProxyEndpoint(this, 'EndPoint', {
      ...options,
      dbProxy: this,
    });
    this.endpoints.push(endpoint.endpoint);
    return endpoint;
  }

Note to self: I need to add an index to the id to make it unique in the scope

Jacco commented 2 years ago

@skinny85 I created a PR for this, happy to process some feedback :-)

skinny85 commented 2 years ago

@Jacco thanks for the contribution! Unfortunately, I'm not with the CDK team anymore, so I can't review the PR.

Jacco commented 2 years ago

@Jacco thanks for the contribution! Unfortunately, I'm not with the CDK team anymore, so I can't review the PR.

@skinny85 do you know who of the team I should ping?

skinny85 commented 2 years ago

I'm not sure - perhaps Cory (Hall)?

Jacco commented 2 years ago

@corymhall are you able to review my PR?

Jacco commented 2 years ago

Sorry for letting the PR go stale. Was busy, will come back to it. @corymhall

0x-jj commented 1 year ago

Can this be prioritized? We can't actually create a read-only proxy endpoint via CDK.

wilhen01 commented 1 year ago

+1 for doing this - CDK should have first class support for read-only proxy endpoints.

In the meantime, anyone looking to achieve it should be able to do so via the Level 1 constructs as follows (this has worked correctly in our setup):

const proxy = new DatabaseProxy(this, 'Proxy', {
  ...
});

const readerEndpoint = new CfnDBProxyEndpoint(this, 'ProxyReaderEndpoint', {
  dbProxyName: proxy.dbProxyName,
  targetRole: 'READ_ONLY',
  ...
});
readerEndpoint.node.addDependency(proxy);
github-actions[bot] commented 4 months ago

This issue has received a significant amount of attention so we are automatically upgrading its priority. A member of the community will see the re-prioritization and provide an update on the issue.