Repository navigation
[Security] PostgreSQL accepts any cluster pod-identity certificate for unauthenticated superuser login #2071
Description
This is a result of an internal vuln finding run. Many of these are known issues, but don't appear to have tracking issues, so I'm filing them anyway.
[Security] PostgreSQL Superuser Login via Pod Identity mTLS
Severity: CRITICAL (5.12) | CWE: CWE-287 / CWE-306
Problem Description
The podidentity signer (podidentity.podcert.ate.dev/identity) issues a client-authentication certificate for every PodCertificateRequest (PCR) that references it, regardless of the requesting namespace or ServiceAccount:
signercontroller.handlePCRfilters solely onsignerNameand explicitly relies onkube-apiserverfor node isolation (signercontroller.go:173-180).podidentitysigner.MakeCertchecks only that the pod UID matches, then signs a certificate with SPIFFE URIspiffe://cluster.local/ns/<ns>/sa/<sa>andExtKeyUsageClientAuth(podidentitysigner.go:95-164).- Kubelet creates the PCR for any pod declaring a
podCertificateprojected volume with thissignerName. Any principal permitted to create a pod in any namespace receives a certificate chaining to the pod-identity CA.
Database Trust Configuration
The ate-system PostgreSQL instance backing ate-api uses this exact pod-identity CA as its ssl_ca_file (postgres.yaml:26), with pg_hba.conf configured as:
hostssl all all all trust clientcert=verify-ca
(postgres.yaml:35). Any client presenting a certificate that chains to the pod-identity CA can log in as any database user, including the postgres superuser, with no password and no cert-to-user mapping (the certificate CN is random per podidentitysigner.go:136-138, so verify-full / cert mapping is not enforced).
Furthermore, PostgreSQL listens on 0.0.0.0 (*, postgres.yaml:22) behind a ClusterIP Service in ate-system without a NetworkPolicy, allowing any pod in the cluster to reach postgres.ate-system.svc:5432.
Attack Vector
- Attacker creates a pod in any tenant namespace with a
podCertificateprojected volume referencingsignerName: podidentity.podcert.ate.dev/identity. - Attacker retrieves
credential-bundle.pemfrom the projected volume. - Attacker connects directly to
postgres.ate-system.svc:5432using:psql "sslmode=verify-ca sslcert=credential-bundle.pem sslkey=credential-bundle.pem user=postgres host=postgres.ate-system.svc" - Attacker gains immediate superuser access without authentication.
Impact
Full compromise of the ate-api control-plane database by any low-privileged cluster tenant:
- Read, modify, or delete all atespaces, actors, templates, egress policies, workers, and assignments across tenants.
- Forge state acted upon by
ate-api(e.g., redirecting actor placement or snapshot URIs). - Achieve remote command execution in the
postgrescontainer inate-systemvia PostgreSQL superuserCOPY ... PROGRAM.
Proposed Remediation
- Restrict PostgreSQL authentication in
pg_hba.confto specific client CNs or usernames usingclientcert=verify-fullwith explicit identity mapping instead of blankettrust. - Use a dedicated database client CA rather than the cluster-wide pod-identity CA.
- Apply Kubernetes
NetworkPolicyobjects restricting port 5432 ingress toate-apipods only. - Enforce namespace and ServiceAccount authorization checks in
podcertcontrollerbefore signing client-auth certificates.
Activity
destijl commentedon Oct 1, 2026
Taahir Ahmed (@ahmedtd) Eitan Yarmush (@EItanya) This is likely one of you. Eitan this is highly related to the separate admin for Postgres issue you were already working on.
EItanya commentedon Oct 1, 2026
Agreed this is M3 worthy, Jeremy Alvis (@iplay88keys) for reference
iplay88keys commentedon Oct 6, 2026
This issue specifically affects bundled PostgreSQL. The bootstrap changes that merged in #2025 already block the superuser-login attack by making it so that user can only be used on local socket connections (remote postgres connections are rejected) and requiring passwords for application logins.
The certificate-auth change in #2266 further addressed the underlying trust model by introducing a dedicated PostgreSQL client CA, restricting issuance to
ate-system/ate-api-server, and issuing separate certificates whose CNs match the owner and read/write login users. PostgreSQL then requires that certificate-to-username match.The proposed ingress NetworkPolicy remains separate hardening work, but the reported authentication bypass is addressed without it.
zlammerts-svg commentedon Oct 13, 2026
Eitan Yarmush (@EItanya) Jeremy Alvis (@iplay88keys) Are there more planned changes for this one? Can we consider the security issue is sufficiently mitigated via #2266?
iplay88keys commentedon Oct 13, 2026
I don't have plans to implement the NetworkPolicy changes at the moment. I believe #2266 covers the primary issues here.
destijl commentedon Oct 13, 2026
I'm doing the network policy. Status update on the findings in this issue:
Unauthenticated superuser login (
trust+postgresover TCP) — Fixed in Set up bundled PostgreSQL identities in ate-setup #2025 (dc5aba96)manifests/ate-install/postgres/postgres.yamlnow setshostssl all postgres all reject, restricting thepostgressuperuser strictly to the pod-local Unix domain socket.pkg/postgressetup/setup.sqlprovisions non-superuser rolessubstrate_owner_user(DDL migrations) andsubstrate_readwrite_user(runtime DML) with defaultpublicschema privileges revoked.Cluster-wide
podidentity.podcert.ate.devCA & missing CN verification — Fixed in Authenticate bundled PostgreSQL logins with separate pod certificates #2266 (df788825)podidentity.podcert.ate.dev/identitytrust bundle on PostgreSQL with a dedicated signer and CA (postgres.podcert.ate.dev/identity).cmd/podcertcontroller/internal/postgressigner/postgressigner.gorestricts issuance strictly to ServiceAccountate-api-serverinate-system, allows onlysubstrate_owner_userandsubstrate_readwrite_userviapostgres.podcert.ate.dev/username, and setsSubject.CommonName = username.pg_hba.confnow enforceshostssl atepg substrate_owner_user,substrate_readwrite_user all cert, requiring both a valid cert from the dedicated Postgres CA and an exactCN == database_usermatch.Ingress
NetworkPolicyonpostgres:5432— In review in ate-system now denies ingress by default; in-cluster API clients must label their namespace ate.dev/api-access=true #2522 (tracking Provide default-deny ingress NetworkPolicies for ate-system control plane #2278)ate-systemand restricts TCP/5432 onpostgresstrictly toapp: ate-api-serverpods.Once #2522 merges, all items in this issue are resolved, so I'm going to close it now.