amplify-backend icon indicating copy to clipboard operation
amplify-backend copied to clipboard

ampx generate schema-from-database emits vpcConfig even when RDS is public, creating unnecessary VPC Endpoints and cost

Open BugeezS opened this issue 3 months ago • 2 comments

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

  1. Create/use an RDS PostgreSQL instance in eu-west-1 with Public access = Yes.

  2. Store a secret SQL_CONNECTION_STRING pointing to that public endpoint.

  3. 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... */ });

BugeezS avatar Sep 05 '25 07:09 BugeezS