How-to guide
Harden the deployment
Image verification, runtime hardening, and authentication.
Image verification
Every published image is signed with Cosign using keyless GitHub OIDC. Verify before deploying to confirm the image was built by the Elevarq GitHub Actions workflow and has not been tampered with.
cosign verify elevarq/pgagroal:1.4.3 \
--certificate-identity-regexp "https://github.com/Elevarq/pgAgroal/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"A successful verification confirms:
- The image was built by GitHub Actions from the Elevarq/pgAgroal repository
- The signature is tied to a specific commit and workflow run
- The image has not been modified since signing
Supply chain attestations
Each image includes two attestations attached at build time:
| Attestation | What it provides |
|---|---|
| SBOM | Software bill of materials — lists every package in the image |
| SLSA Provenance | Build metadata — source repo, commit, workflow, builder identity |
Inspect attestations:
docker buildx imagetools inspect elevarq/pgagroal:1.4.3Runtime hardening
The container is hardened by default. These protections are built into the image and the Helm chart — no configuration needed.
- Non-root execution — runs as UID 1000, never root
- No capabilities — all Linux capabilities dropped
- No privilege escalation —
allowPrivilegeEscalation: false - Read-only root filesystem — only
/tmpand/etc/pgagroalare writable (via emptyDir in K8s) - Seccomp profile — RuntimeDefault restricts system calls
- Multi-stage build — compilers and build tools are not present in the runtime image
Authentication
Registered users (default)
The container ships with allow_unknown_users = false. Unknown users are rejected at the pooler; register users withPG_USERNAME and PG_PASSWORD, or provide the equivalent existing Secret through Helm.
To restore transparent passthrough, setPGAGROAL_ALLOW_UNKNOWN_USERS=true (Helm:pgagroal.allowUnknownUsers=true). PostgreSQL then becomes the sole user-authentication gate.
Supplying credentials
Set PG_USERNAME and PG_PASSWORD to register a user at startup. The entrypoint writes a hashed credential file that pgagroal uses for initial authentication before forwarding to the backend.
PG_USERNAME and PG_PASSWORD, then setcredentials.existingSecret.Source-address allowlist
At startup the container generates pgagroal_hba.conf fromPGAGROAL_HBA_SOURCE (Helm:pgagroal.hbaSource). The default admits RFC1918 private ranges and requires scram-sha-256. Set your actual client CIDR when it falls outside RFC1918; use all only to restore the legacy any-source behavior.
Network considerations
pgagroal speaks the PostgreSQL wire protocol. Anything that can connect to PostgreSQL can connect to pgagroal. This also means pgagroal inherits the same exposure risks.
- Do not expose to the public internet. pgagroal should only be reachable from application networks. Use Kubernetes NetworkPolicies, security groups, or firewall rules.
- Use ClusterIP services in Kubernetes. The Helm chart defaults to ClusterIP. Do not change this to LoadBalancer or NodePort unless you have a specific reason and additional access controls.
- Restrict backend connectivity. The pooler needs to reach PostgreSQL on port 5432. It does not need outbound internet access.
- TLS to the backend. If your PostgreSQL server requires TLS, configure it in pgagroal. The container supports TLS via pgagroal's built-in TLS settings.
The Helm NetworkPolicy is enabled by default. It allows same-namespace clients and denies cross-namespace ingress unless you addnetworkPolicy.ingressNamespaceSelectors or pod selectors. Egress remains open by default; enablenetworkPolicy.restrictEgress=true only with the correct backend and kube-DNS CIDRs. Disable the policy entirely withnetworkPolicy.enabled=false when required by your CNI.
Compliance alignment
The build and release process is aligned with SOC 2 and ISO 27001 expectations: CI-only publishing, signed images, SBOM and provenance attestations, non-root execution, and auditable build-to-deployment traceability.