TLS Setup¶
The SentriKat API ships with HTTP enabled by default for ease of first install, but production deployments must serve all API traffic over HTTPS. Agents send API keys and software inventories over the wire: without TLS, anyone with network visibility can read them.
This page walks through the three TLS topologies SentriKat supports out of the box and the cert-acquisition flow for each.
Why TLS is required¶
- API keys travel as bearer tokens. Every agent call carries its organization API key in the
Authorizationheader. Without TLS the key can be read from a single packet capture and used until it is rotated. - Inventory data is sensitive. Agents post software inventories (versions, paths, container images, dependency manifests). Keep that traffic encrypted.
- Session cookies and sign-ins also travel over the same connection. Serve the web interface over HTTPS only.
- The Windows installer has a
-AllowHttpoption for plain HTTP in labs (see Windows agent). Do not use it in production.
Quick path: built-in nginx with TLS template¶
The on-prem image ships two nginx config templates: the default nginx.conf.template (HTTP-only, listens on :80) and nginx-ssl.conf.template (HTTPS on :443, HTTP redirect on :80). Switching to the TLS template is a 4-step flip:
cd /opt/sentrikat # or wherever you put the deploy
# 1. Disable the HTTP-only template
mv nginx/nginx.conf.template nginx/nginx.conf.template.disabled
# 2. Activate the TLS template
mv nginx/nginx-ssl.conf.template nginx/nginx.conf.template
# 3. Drop your cert + key into ./ssl/
mkdir -p ssl
cp /path/to/your/fullchain.pem ssl/cert.pem
cp /path/to/your/privkey.pem ssl/key.pem
chmod 600 ssl/key.pem
# 4. Recycle the stack
docker compose down
docker compose up -d
Verify with:
The cert.pem filename must contain the full chain (leaf + any intermediate certs concatenated). A bare leaf cert will pass curl -k but fail strict validation from agents and from public CT log monitors.
Cert acquisition¶
Three paths, pick the one that matches your network position.
Option A: Let's Encrypt via certbot (internet-facing deployments)¶
Free, automated, 90-day rotation. Runs on the host, not inside the container.
# One-time install
sudo apt install certbot python3-certbot-nginx # Debian / Ubuntu
sudo dnf install certbot python3-certbot-nginx # RHEL / Rocky / Alma
# Stop the proxy so certbot can claim port 80 for the HTTP-01 challenge
docker compose stop sentrikat-nginx
sudo certbot certonly --standalone \
-d sentrikat.example.com \
--email [email protected] --agree-tos --no-eff-email
# Wire the resulting files into ./ssl/
sudo cp /etc/letsencrypt/live/sentrikat.example.com/fullchain.pem ssl/cert.pem
sudo cp /etc/letsencrypt/live/sentrikat.example.com/privkey.pem ssl/key.pem
sudo chown $USER:$USER ssl/*.pem
chmod 600 ssl/key.pem
docker compose up -d
Use this when SentriKat is reachable from the public internet on port 80 (HTTP-01) or via DNS API (DNS-01, see certbot plugins for Cloudflare, Route53, etc.).
Option B: Internal CA (corporate / air-gapped)¶
Most enterprises run an AD CS / Vault / step-ca / private CA. The flow is:
-
Generate a key + CSR on the SentriKat host:
-
Submit the CSR to your internal CA (the exact mechanism is CA-specific: AD CS web enrollment,
step ca certificate, Vault PKI, etc.). -
Receive
cert.pem(with the full chain) from the CA and drop it into./ssl/cert.pem. -
Distribute the internal CA root to agent hosts so they trust the cert. Three cases:
- On Windows agents:
Import-CertificateintoLocalMachine\Root. - On Debian/Ubuntu agents: copy the CA certificate to
/usr/local/share/ca-certificates/as a.crtfile and runupdate-ca-certificates. - For the SentriKat container itself if it needs to talk to other internally-issued endpoints (e.g. an internal SMTP relay), mount the CA bundle into
/app/custom-certs. See the Container User & Privilege Model page for the bind-mount setup.
- On Windows agents:
Option C: Self-signed (dev / lab only)¶
Acceptable for short-lived test installs. Agents will not trust the cert unless the certificate is installed in their trust store (see Option B, step 4). Do not use self-signed in any environment that holds real inventory data.
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
-keyout ssl/key.pem -out ssl/cert.pem \
-subj "/CN=sentrikat.local"
chmod 600 ssl/key.pem
docker compose down && docker compose up -d
Cert renewal automation¶
Let's Encrypt certs expire every 90 days. Inside the container is the wrong place to renew. Use a host-level cron / systemd timer that:
- Runs
certbot renew(which is a no-op if the cert is more than 30 days from expiry). The certificate above was issued with--standalone, so renewal needs port 80 free: stop the proxy before the challenge and start it after. - Copies
fullchain.pemandprivkey.peminto./ssl/if they changed. - Sends nginx a
SIGHUPto pick up the new cert without dropping connections.
A complete /etc/cron.daily/sentrikat-cert-renew script:
#!/bin/bash
set -e
cd /opt/sentrikat
certbot renew --quiet --no-self-upgrade \
--pre-hook "docker compose -f /opt/sentrikat/docker-compose.yml stop sentrikat-nginx" \
--post-hook "docker compose -f /opt/sentrikat/docker-compose.yml start sentrikat-nginx"
LIVE=/etc/letsencrypt/live/sentrikat.example.com
if [ "$LIVE/fullchain.pem" -nt ssl/cert.pem ]; then
cp "$LIVE/fullchain.pem" ssl/cert.pem
cp "$LIVE/privkey.pem" ssl/key.pem
chown $(stat -c '%u:%g' .) ssl/*.pem
chmod 600 ssl/key.pem
docker compose kill -s SIGHUP sentrikat-nginx
fi
For internal-CA certs the analogous job invokes whatever your CA's renewal command is (step ca renew, Vault PKI auto-renew, scheduled CSR submission, etc.): same cp + SIGHUP afterwards.
Troubleshooting¶
SSL handshake failed from curl -v¶
Almost always one of:
cert.pemorkey.pemhas wrong permissions or wrong owner. The proxy must be able to read both files. Fix:chmod 644 ssl/cert.pem(the certificate is public). For the key, keep it private (chmod 600) when the proxy reads it as the file owner; if the proxy runs as a different user, give that user's group read access (chgrp <proxy-group> ssl/key.pemandchmod 640 ssl/key.pem). Never make the key world-readable.cert.pemis the leaf only, not the full chain. Some clients (browsers) tolerate this because they fetch missing intermediates; agents do not. Fix: concatenateleaf.pem+intermediate.pemintocert.pem(leaf first).- Wrong file format: DER instead of PEM, or PKCS#12 instead of PEM. Run
openssl x509 -in ssl/cert.pem -noout -textandopenssl rsa -in ssl/key.pem -check. Both must succeed and print parseable content.
cert verification failed from agents¶
The agent reaches the API but rejects the cert. Means the agent's local trust store doesn't contain the issuing CA. Pick one:
- Public CA (Let's Encrypt, DigiCert, Sectigo, etc.): already in every OS trust store. If verification fails with a public CA, the cert chain on the server is incomplete (see "wrong chain" above).
- Internal CA: add the CA root to the agent host's trust store (per-OS instructions in the agent docs).
- Self-signed: install the certificate in the agent host's trust store (lab use only).
If the SentriKat container itself talks to your internal CA-signed endpoints (LDAP, SMTP relay, Jira, etc.), mount the CA bundle into /app/custom-certs and the container's entrypoint will append it to the system trust store at boot. See Container User & Privilege Model for the bind-mount layout.
nginx logs show SSL_CTX_use_PrivateKey_file error¶
Key and cert don't match. Confirm with:
openssl x509 -in ssl/cert.pem -noout -modulus | openssl md5
openssl rsa -in ssl/key.pem -noout -modulus | openssl md5
# the two MD5 values must be identical
If they differ you've mixed certs from different issuance batches, re-issue or copy the right pair.
Related¶
- Container User & Privilege Model, the
/app/custom-certsCA-bundle path. - External Postgres,
sslmode=verify-fullfor the DB connection (separate TLS layer from the API). - Windows agent, where the
-AllowHttpoption is listed. - Updating: keep
./ssl/and your renamed nginx template when you move to a new bundle.