Shared VPCs make plaintext HTTP between Lambdas and private ALBs feel “internal enough.” It is not. Any compromised ENI, over-broad security group, or curious sidecar can read tokens, PII, and tool payloads in flight. The unfair advantage is mutual TLS end-to-end: Lambda presents a client certificate from ACM Private CA, the ALB terminates and verifies it, and east-west traffic never travels as cleartext — even on RFC1918 links.
⚡ TL;DR: Issue short-lived client certs via ACM PCA (or short rotation from Secrets Manager). Mount them into Lambda with a cold-start refresh that fails closed. Configure the private ALB HTTPS listener with mTLS
verifymode and a trust store pointing at your PCA. Pin SAN/URI names per service identity. Pair with AI Coding in VPC: Private Bedrock Endpoints and Secure AI Sandboxes so agent backends inherit the same east-west posture.
Why security groups alone are not enough
SGs answer “who can open a TCP socket,” not “who proved cryptographic identity.” In a flat VPC with overlapping CIDRs across accounts, SG rules drift. mTLS binds the call to a named principal.
// BAD: plaintext east-west — anyone on the path can sniff Authorization
const resBad = await fetch("http://orders.internal:80/v1/quote", {
headers: { Authorization: `Bearer ${token}` },
});
// GOOD: HTTPS + client cert — ALB rejects callers without a trusted leaf
import https from "node:https";
import fs from "node:fs";
const agent = new https.Agent({
cert: fs.readFileSync(process.env.MTLS_CERT_PATH!),
key: fs.readFileSync(process.env.MTLS_KEY_PATH!),
ca: fs.readFileSync(process.env.MTLS_CA_PATH!), // PCA root/chain
keepAlive: true,
maxCachedSessions: 64,
});
const res = await fetch("https://orders.internal/v1/quote", {
// node fetch / undici agent wiring depends on runtime
dispatcher: undefined,
headers: { Authorization: `Bearer ${token}` },
});
void agent; void resBad;
✅ ALB listener policy requires present + valid client cert.
❌ Relying on “private subnet = encrypted.”
ALB trust store + PCA wiring
# illustrative listener shape
Listener:
Port: 443
Protocol: HTTPS
MutualAuthentication:
Mode: verify # not passthrough
TrustStoreArn: !Ref InternalTrustStore
Certificates:
- CertificateArn: !Ref ServerCertArn
TrustStore:
CaCertificatesBundleS3Bucket: pca-bundles
CaCertificatesBundleS3Key: internal-root.pem
Rotate the CA bundle with a dual-trust window. Snap the Lambda client CA env on the same schedule as the trust store update so you never brick invokes mid-rotation.
Cold-start cert refresh without leaking keys
import { SecretsManager } from "@aws-sdk/client-secrets-manager";
import { writeFileSync, chmodSync } from "node:fs";
const sm = new SecretsManager({});
let primed = false;
export async function ensureMtlsMaterial() {
if (primed) return;
const secret = await sm.getSecretValue({ SecretId: process.env.MTLS_SECRET! });
const { cert, key, ca } = JSON.parse(secret.SecretString!);
for (const [path, body] of [
[process.env.MTLS_CERT_PATH!, cert],
[process.env.MTLS_KEY_PATH!, key],
[process.env.MTLS_CA_PATH!, ca],
] as const) {
writeFileSync(path, body, { mode: 0o600 });
chmodSync(path, 0o600);
}
primed = true;
}
export const handler = async (_event: unknown) => {
await ensureMtlsMaterial();
// call private ALB with mTLS agent
};
Keep private keys out of image layers and out of CloudWatch. Prefer Secrets Manager + IAM condition keys over baking PEMs into the deployment zip. See Secret-Aware Context Filters for how AI editors must never echo these paths into PRs.
Identity per service, not one god cert
CN=orders-writer.lambda.prod.example
URI:spiffe://prod/ns/checkout/sa/orders-writer
Map ALB rules on SPIFFE/SAN when you graduate past “any trusted client.” One shared client cert across fifty functions is lateral-movement gift wrapping.
Closing checklist
- [ ] Private ALB HTTPS listener uses mTLS
verifywith PCA trust store - [ ] Lambda presents short-rotation client cert+key; CA chain pinned
- [ ] No plaintext HTTP listeners remain for the same target groups
- [ ] Cert material loaded at init from Secrets Manager, mode 0600
- [ ] Per-service SAN/SPIFFE — not one org-wide client cert
- [ ] Dual-trust CA rotation runbook tested in staging
Related reading
- AI Coding in VPC: Private Bedrock Endpoints and Secret Hygiene
- Secure AI Sandboxes: Ephemeral ECS Tasks for Agent Tool Execution
- Secret-Aware Context Filters: Stop AI Editors From Shipping Keys
- Agent Tool Allowlists: Least Privilege for Filesystem and Shell Access
Last updated on September 11, 2026
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
