CA and Certificates
Pigsty maintains a self-signed Certificate Authority (CA) on the admin node by default. It signs certificates for PostgreSQL, Patroni, etcd, Silo, Nginx, and other internal services. Public Nginx entries can use Certbot/Let’s Encrypt certificates configured through infra_portal.
files/pki/ca/ca.key is the trust-root private key for the entire deployment. Never print, commit, upload, or transmit it over an unprotected channel. Back it up with ca.crt. Encrypt the backup and tightly restrict read access.
Self-Signed CA
The ca stage of infra.yml creates or reuses the CA locally on the admin node running Ansible. It does not create the CA on a remote Infra node. The default layout is:
The core defaults match the v4.5.0 roles:
| Parameter | Default | Meaning |
|---|---|---|
ca_create | true | Allow creation when ca.key is missing |
ca_cn | pigsty-ca | Common Name of the CA certificate |
cert_validity | 7300d | Default internal service/client validity (20 years) |
nginx_cert_validity | 397d | Nginx self-signed HTTPS certificate validity |
The role hard-codes the CA certificate lifetime to 36500d (about 100 years). These long-lived certificates serve a controlled internal trust domain. Public browsers do not trust them by default. Clients must explicitly trust ca.crt. Public endpoints should use a publicly trusted CA.
Initialize the local CA stage:
Running ./infra.yml -t ca may create a missing key or certificate and therefore changes PKI state. Confirm the admin node, configuration, and existing CA backup first.
Use an External CA
To reuse an enterprise CA:
- Set
ca_create: falseinpigsty.yml. - Place a matching
files/pki/ca/ca.keyandfiles/pki/ca/ca.crtpair on the admin node. - Set permissions and verify that the public-key digests match.
ca_create: false prevents generation of a new private key only when ca.key is missing. If the key exists and ca.crt is missing, the role still creates a new self-signed CA certificate from the key. Always restore the pair together instead of relying on certificate regeneration.
Before running the CA stage, verify the files that will be used, the existing CA backup, and the admin node.
Back Up and Restore the CA
Retain at least:
files/pki/ca/ca.keyandca.crt- CA state such as
ca.srl,index.txt, and CRL files if issuance/revocation management uses them - backup time, the CA certificate SHA-256 fingerprint, and restoration instructions
Encrypt the backup and store it on controlled offline media or in a secrets-management system. Do not keep an unencrypted tar archive.
First, restore it to an isolated temporary directory. Before replacement, verify the file count, types, permissions, public-key match, and certificate fingerprint.
Loss of ca.key does not immediately prevent verification of existing certificates. Verification still works if clients trust ca.crt and the certificates remain valid and unrevoked.
You can no longer issue, renew, or revoke certificates with the original CA. Recovery usually requires a new CA, reissuance of every certificate, and deployment of a new trust chain.
Issue Certificates with cert.yml
cert.yml runs locally on the admin node and issues generic certificates with the Pigsty CA. Pass cn explicitly instead of relying on the generic script default:
Default outputs:
| Parameter | Default | Meaning |
|---|---|---|
cn | pigsty | Common Name; set explicitly in real use |
san | [DNS:localhost, IP:127.0.0.1] | Subject Alternative Names |
org | pigsty | Organization |
unit | pigsty | Organizational Unit |
expire | 7300d | Validity |
key | files/pki/misc/<cn>.key | Private-key output path |
crt | files/pki/misc/<cn>.crt | Certificate output path |
Advanced examples:
Verify the certificate without displaying or copying private-key content:
For PostgreSQL client certificates, cn must match the database role expected by HBA/cert authentication. Install the certificate, key, and root certificate on the client. Set the private key permissions to 0600. With sslmode=verify-full, the connection hostname must appear in the server certificate SAN.
Trust the CA Certificate
Distribute only the public ca.crt. Never distribute ca.key. Verify its SHA-256 fingerprint through a separate trusted channel before installation.
Debian / Ubuntu
RHEL / Rocky / AlmaLinux
macOS
Windows (Administrator PowerShell)
Infra Nginx normally exposes the public CA certificate at http://<infra_ip>/ca.crt. Verify the fingerprint after download. HTTP transport alone does not prove certificate authenticity.
Nginx and Let’s Encrypt
Each infra_portal entry can name a certbot certificate. Pigsty’s /etc/nginx/sign-cert uses Certbot webroot mode. It groups domain and domains entries that share a certificate name. Then /etc/nginx/link-cert links the resulting certificate into Nginx.
Prerequisites:
- Public DNS A/AAAA records resolve to the intended Infra node.
- Port 80 is publicly reachable for HTTP-01, and Nginx serves the ACME webroot.
certbot_emailis valid and the Certbot package is installed.- Portal domains, additional domains, and certificate names are exact.
Update the Nginx configuration and issue certificates:
In v4.5.0, the nginx_certbot task has ignore_errors: true. A playbook that continues or reports overall success does not prove certificate issuance. Inspect Certbot state, certificate files, Nginx configuration, and a real TLS handshake.
Renewal scheduling depends on the Certbot package for the operating system. Do not add a duplicate cron job before checking existing timers and cron configuration:
After Certbot replaces certificates on disk, Nginx still needs a reload to use them. Configure a renewal deploy hook, such as systemctl reload nginx, or an equivalent managed process. Verify that it works. Treat automatic renewal as proven only after a real or staging renewal exercise.
Troubleshooting and Acceptance
| Symptom | Check |
|---|---|
| Browser rejects an internal cert | Correct ca.crt, SAN hostname, and system time |
verify-full fails | Connection hostname, SAN, chain, and root certificate |
| Certbot HTTP-01 fails | DNS, port 80, ACME webroot, proxy/CDN, and rate limits |
| Playbook succeeds but old cert remains | Ignored nginx_certbot errors, link-cert, and Nginx reload |
| Permission denied | Private key 0600 (deployed Nginx key is 0640 root:nginx) |
| Trust breaks after CA rotation | Roll out client trust, then service certs, then reload services |
For final acceptance, verify each result separately:
- The certificate content and SANs are correct.
- Chain validation succeeds.
- The service has loaded the new certificate.
- Target clients trust the certificate.
- Renewal is configured and passes a dry run.
A generated file or successful playbook alone does not prove these results.
Was this page helpful?
Thanks—your feedback helps us improve this page.
What got in the way? (optional)