Connecting an AWS Apprunner instance to RDS using CDK

89 Views Asked by At

We decided to isolate each of our clients in their own AWS account. Each client will have their own resources, database, EC2 instances, subnets, etc.

My plan is to have a collection of CDK applications:

  • Tenant, which generates resources shared by other applications accessible to the client.
  • Simulations, the first 'module' that will need to connect to the database defined by Tenant.
  • Module 2.
  • Module 3.

In Tenant, I created my subnets and database:

const vpc = new ec2.Vpc(this, 'tenant-vpc', {
  natGateways: 1,
});

const rdsSecurityGroup = new ec2.SecurityGroup(this, 'RDSSecurityGroup', {
  vpc,
  securityGroupName: 'rds-security-group',
  description: 'Security group for RDS Cluster',
  allowAllOutbound: true,
});
rdsSecurityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(5432), 'Allow Database access from the internet');

const cluster = new rds.DatabaseCluster(this, 'Database', {
  vpc,
  engine: rds.DatabaseClusterEngine.auroraPostgres({ version: rds.AuroraPostgresEngineVersion.VER_15_4 }),
  credentials: rds.Credentials.fromSecret(dbSecret),
  writer: rds.ClusterInstance.serverlessV2('writer'),
  vpcSubnets: {
    subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
  },
  securityGroups: [rdsSecurityGroup],
});

Later, in my Simulations application, I have this:

import * as apprunner from '@aws-cdk/aws-apprunner-alpha';
const vpc = ec2.Vpc.fromLookup(this, 'VpcByName', { vpcName: 'TenantStack/tenant-vpc' });
const sg = new ec2.SecurityGroup(this, 'AppRunnerSecurityGroup', {
  vpc,
  allowAllOutbound: true,
})
sg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(5432), 'Allow Database access from the Rails apprunner instance');

const vpcConnector = new apprunner.VpcConnector(this, 'VpcConnector', {
  vpc,
  securityGroups: [sg],
  vpcSubnets: vpc.selectSubnets({ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }),
});

const rails = new apprunner.Service(this, 'Rails', {
  source: apprunner.Source.fromEcr({
    imageConfiguration: {
      port: 3000,
      environmentVariables: {
        COPILOT_APPLICATION_NAME: 'simulations',
        COPILOT_ENVIRONMENT_NAME: 'prototype'
      },
      environmentSecrets: {
        DB_SECRET: apprunner.Secret.fromSecretsManager(dbSecret),
      }
    },
    repository: ecr.Repository.fromRepositoryName(this, 'SimulationsRailsRepository', 'simulations/rails'),
    tagOrDigest: 'latest',
  }),
  vpcConnector
});

rails.addToRolePolicy(new iam.PolicyStatement({
  effect: iam.Effect.ALLOW,
  actions: ['ssm:*'],
  resources: ['arn:aws:ssm:us-east-1:127576463950:*'],
}))

But here's the issue.

When I use this configuration, my instance on Apprunner is not able to access the Internet. When I try to access secrets using aws-cli version, I get the error:

Could not connect to the endpoint URL: 'https://ssm.us-east-1.amazonaws.com/'

However, if I remove the vpcConnector parameter from the Service initialization, I correctly receive the ssm secrets, but then when running Rails, I get a timeout for the database.

Database migrations
connection to server at "10.0.171.111", port 5432 failed: Connection timed out
Is the server running on that host and accepting TCP/IP connections?
Couldn't create 'simulation_production' database. Please check your configuration.
rake aborted!

There is clearly a problem in my configuration, but I can't find it.

The aurora documentation describes Scenarios for accessing a DB cluster in a VPC but this is for an EC2 instance, but it seems impossible to assign a VPC directly to an Apprunner instance. The recommended option seems to be using a [vpcConnector][2] but I end up with the inability to access the secrets.

How should I proceed?

0

There are 0 best solutions below