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?