I use a typescript CDK. Inside this I added a custome resource step. A sockerfile with a simple Javascript inside. It is working well until I want to receive the the connection string to my postgres database from SecretManager.
I use the following code in my stack:
this.urlSecret = new Secret(this, 'db-url-secret', {
secretStringValue: new SecretValue(
`postgres://${databaseUsername}:${password}@${
this.dbCluster.clusterEndpoint.hostname
}:${this.dbCluster.clusterEndpoint.port.toString()}/${props.databaseName}?schema=public`,
),
});
const initializer = new CdkResourceInitializer(this, 'MyRdsInit', {
config: this.urlSecret.secretName, //<-Name I use in docker to get secret.
fnLogRetention: RetentionDays.FIVE_MONTHS,
fnCode: DockerImageCode.fromImageAsset(`${__dirname}/rds-init-fn-code`, {}),
fnTimeout: Duration.minutes(2),
fnSecurityGroups: [],
vpc: props.vpc,
subnetsSelection: props.vpc.selectSubnets({
subnetType: cdk.aws_ec2.SubnetType.PUBLIC
}),
});
initializer.customResource.node.addDependency(this.dbCluster);
this.dbCluster.connections.allowFrom(initializer.function, Port.tcp(5432));
this.dbCluster.connections.allowDefaultPortFromAnyIpv4();
this.urlSecret.grantRead(initializer.function);
}
When I run the code with the fowlloing javascript inside the docker container:
const pg = require('pg');
const fs = require('fs');
const path = require('path')
const AWS = require('aws-sdk')
const secrets = new AWS.SecretsManager({})
exports.handler = async (e) => {
const { config } = e.params
var conString = "<connection string>";
//config is the secret Name;
console.log('#############DOCKER');
console.log(config);
const { conn } = await getSecretValue(config)
console.log(conn);
var client = new pg.Client(conString);
await client.connect();
const sql = fs.readFileSync(path.join(__dirname, 'script.sql')).toString()
var res = await client.query(sql);
await client.end();
return {
status: 'OK',
results: ''
}
}
function getSecretValue (secretId) {
return new Promise((resolve, reject) => {
secrets.getSecretValue({ SecretId: secretId }, (err, data) => {
if (err) return reject(err)
return resolve(JSON.parse(data.SecretString))
})
})
}
I get alsways a Timout error with the function: getSecretValue
.
I re-check everything a couple of times but it seems that the docker image cannot receive the SecretManager or connect to it.
2024-09-13T09:48:49.341Z 7d8d9575-d4c9-4510-992d-a997677a188f ERROR Invoke Error
{
"errorType": "TimeoutError",
"errorMessage": "connect ETIMEDOUT 18.179.209.155:443",
"code": "TimeoutError",
"message": "connect ETIMEDOUT 18.179.209.155:443",
"errno": -110,
"syscall": "connect",
"address": "18.179.209.155",
"port": 443,
"time": "2024-09-13T09:48:49.340Z",
"region": "ap-northeast-1",
"hostname": "secretsmanager.ap-northeast-1.amazonaws.com",
"retryable": true,
"stack": [
"Error: connect ETIMEDOUT 18.179.209.155:443",
" at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1159:16)"
]
}
BEcause I use a public subnet I assume that the docker can connect to the SecretManager.
Iam sure that I have missed something. Can anybody give me a hint or sample?
Ensure your VPC has an internet gateway attached. Verify that the public subnet has a route table that routes 0.0.0.0/0 traffic to the internet gateway.
Check IAM role associated with the container has proper permissions to access Secrets Manager, such as secretsmanager:GetSecretValue
.
if can’t resolve, I sugget you to add VPC Endpoint