amplify-backend
amplify-backend copied to clipboard
ampx generate schema-from-database emits vpcConfig even when RDS is public, creating unnecessary VPC Endpoints and cost
Environment information
❯ npx ampx info
System:
OS: macOS 15.6.1
CPU: (10) arm64 Apple M1 Max
Memory: 9.77 GB / 64.00 GB
Shell: /bin/zsh
Binaries:
Node: 22.12.0 - ~/.nvm/versions/node/v22.12.0/bin/node
Yarn: 1.22.22 - /usr/local/bin/yarn
npm: 10.9.0 - ~/.nvm/versions/node/v22.12.0/bin/npm
pnpm: undefined - undefined
NPM Packages:
@aws-amplify/auth-construct: 1.6.0
@aws-amplify/backend: 1.14.1
@aws-amplify/backend-ai: Not Found
@aws-amplify/backend-auth: 1.5.0
@aws-amplify/backend-cli: 1.4.11
@aws-amplify/backend-data: 1.4.0
@aws-amplify/backend-deployer: 1.1.18
@aws-amplify/backend-function: 1.12.2
@aws-amplify/backend-output-schemas: 1.4.0
@aws-amplify/backend-output-storage: 1.1.4
@aws-amplify/backend-secret: 1.1.6
@aws-amplify/backend-storage: 1.2.4
@aws-amplify/cli-core: 1.3.0
@aws-amplify/client-config: 1.5.7
@aws-amplify/data-construct: 1.15.0
@aws-amplify/data-schema: 1.18.0
@aws-amplify/deployed-backend-client: 1.5.1
@aws-amplify/form-generator: 1.0.4
@aws-amplify/model-generator: 1.0.12
@aws-amplify/platform-core: 1.6.3
@aws-amplify/plugin-types: 1.8.0
@aws-amplify/sandbox: 1.2.11
@aws-amplify/schema-generator: 1.2.7
aws-amplify: 6.13.2
aws-cdk: 2.1001.0
aws-cdk-lib: 2.181.1
typescript: 5.7.3
No AWS environment variables
No CDK environment variables
Describe the bug
When generating an Amplify Data schema from a publicly accessible RDS PostgreSQL using:
npx ampx generate schema-from-database \
--connection-uri-secret SQL_CONNECTION_STRING \
--out amplify/data/schema.sql.ts
the generated file always includes a vpcConfig block. Deploying this creates Interface VPC Endpoints (SSM, SSMMessages, EC2Messages, EC2, KMS) via CloudFormation—even though the DB is reachable over the public internet with TLS—leading to avoidable cost (~$15/day for us across multiple AZs).
Expected: If the target DB endpoint is public (or external Postgres), the generator should omit vpcConfig by default, or provide an explicit flag to disable VPC plumbing (e.g., --no-vpc / --prefer-public-endpoint).
Actual: vpcConfig is injected unconditionally by the generator; subsequent deploys create/maintain multiple AWS::EC2::VPCEndpoint resources.
Impact: Unnecessary spend (fixed hourly + data), extra networking resources to manage, and high risk of re-introducing costs whenever the file is regenerated in CI.
Workarounds:
Don’t run schema-from-database in CI; manually remove vpcConfig once and avoid regenerating.
Use an external Postgres provider (no vpcConfig generated).
Skip Amplify Data SQL and access RDS through an API in the VPC.
Proposed fixes:
Detect public endpoints / PubliclyAccessible=true and do not emit vpcConfig.
Add explicit CLI controls: --no-vpc (never emit), or --vpc-id/--subnets/--security-groups (emit only when provided).
Preserve existing choice on re-generation (if file has no vpcConfig, don’t add it unless requested).
Evidence (cleanup events):
AWS::EC2::VPCEndpoint .../SQLVpcEndpoint...ec2 DELETE_COMPLETE
AWS::EC2::VPCEndpoint .../SQLVpcEndpoint...ssmmessages DELETE_COMPLETE
AWS::EC2::VPCEndpoint .../SQLVpcEndpoint...ec2messages DELETE_COMPLETE
AWS::EC2::VPCEndpoint .../SQLVpcEndpoint...kms DELETE_COMPLETE
Reproduction steps
-
Create/use an RDS PostgreSQL instance in eu-west-1 with Public access = Yes.
-
Store a secret SQL_CONNECTION_STRING pointing to that public endpoint.
-
Run:
npx ampx generate schema-from-database \
--connection-uri-secret SQL_CONNECTION_STRING \
--out amplify/data/schema.sql.ts
Open the generated file and observe a vpcConfig block is present.
Deploy (npx ampx pipeline-deploy …).
In CloudFormation/VPC, observe creation of Interface VPC Endpoints: ssm, ssmmessages, ec2messages, ec2, kms.
In Cost Explorer, see VPCE-Hours / VPCE-Bytes charges start accruing.
Minimal generated snippet (redacted):
export const schema = configure({
database: {
identifier: "…",
engine: "postgresql",
connectionUri: secret("SQL_CONNECTION_STRING"),
vpcConfig: { /* injected even though DB is public */ }
}
}).schema({ /* models... */ });