Security Hardening Guide
This guide covers the security controls required for a production jitsudo deployment. Implementing all recommendations in this guide is strongly advised before exposing jitsudo to production workloads.
Network Architecture
Section titled “Network Architecture”Do NOT expose jitsudod to the internet
Section titled “Do NOT expose jitsudod to the internet”jitsudod should run inside a private network segment, reachable only by:
- Engineers connecting through a VPN or zero-trust network access tool
- Automated clients (CI/CD pipelines, MCP agents) on private networks
- The cloud provider’s internal network (for provider callbacks)
A public-facing jitsudod dramatically increases the attack surface. Even with mTLS, a public endpoint invites brute-force, DDoS, and credential stuffing attempts.
Recommended architecture:
Internet │ ▼ VPN / ZTNA (Tailscale, Teleport, Cloudflare Access) │ ▼Internal Load Balancer (private subnet) │ ▼jitsudod instances (private subnet, no public IP) │ ▼PostgreSQL (private subnet, jitsudo service account only)Firewall rules
Section titled “Firewall rules”Inbound to jitsudod:
- Allow TCP 443 (gRPC/REST) from VPN/ZTNA subnet only
- Allow TCP 8080 (health check endpoint) from internal monitoring only
- Deny all other inbound
Outbound from jitsudod:
- Allow HTTPS to cloud provider APIs (AWS STS, Azure ARM, GCP IAM, Kubernetes API)
- Allow TCP 5432 to PostgreSQL
- Allow HTTPS to IdP JWKS endpoint (for token verification)
- Allow HTTPS to Slack/webhook/SIEM HTTP endpoints (for notifications)
- Allow TCP/UDP to syslog server (if using syslog SIEM forwarding)
TLS and mTLS
Section titled “TLS and mTLS”Enable mTLS for production
Section titled “Enable mTLS for production”jitsudod supports three TLS modes. Use mTLS for any production deployment:
| Mode | Config | Use case |
|---|---|---|
| Insecure | No TLS config | Local development only |
| Server TLS | cert_file + key_file | Internal deployments with trusted CA |
| mTLS | cert_file + key_file + ca_file | Recommended for production |
With mTLS, the server verifies client certificates on every connection. Unauthorized clients — even those on the internal network — cannot communicate with jitsudod.
tls: cert_file: /etc/jitsudo/tls/server.crt key_file: /etc/jitsudo/tls/server.key ca_file: /etc/jitsudo/tls/ca.crt # enables mTLSSee Configuration Reference for the full TLS configuration schema.
Certificate management
Section titled “Certificate management”- Use a private CA (Vault PKI, cert-manager, AWS ACM Private CA) — do not use a public CA for internal services
- Set certificate TTLs to 90 days or less; automate rotation
- Store private keys in a secrets manager (Vault, Kubernetes Secrets with encryption at rest, AWS Secrets Manager) — never on disk unencrypted
PostgreSQL Hardening
Section titled “PostgreSQL Hardening”PostgreSQL holds all jitsudo state: requests, policies, audit events, and credentials for connected providers. It must be treated as a high-value target.
Access controls
Section titled “Access controls”Create a dedicated PostgreSQL role for jitsudo with the minimum required permissions:
-- Create dedicated roleCREATE ROLE jitsudo_app LOGIN PASSWORD '<strong-password>';
-- Grant access to the databaseGRANT CONNECT ON DATABASE jitsudo TO jitsudo_app;GRANT USAGE ON SCHEMA public TO jitsudo_app;
-- Grant SELECT + INSERT on all tables (normal operation)GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA public TO jitsudo_app;GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO jitsudo_app;
-- Critical: explicitly deny UPDATE and DELETE on the audit log-- This enforces append-only at the database layerREVOKE UPDATE, DELETE ON audit_events FROM jitsudo_app;Encryption
Section titled “Encryption”- Encryption at rest: Enable PostgreSQL transparent data encryption, or use encrypted storage volumes (AWS EBS encryption, GCP Persistent Disk encryption). This protects against physical media theft.
- Encryption in transit: Always use TLS for the PostgreSQL connection. Set
sslmode=require(orverify-fullwith a CA cert) in the jitsudod database connection string. - Credentials: Never store the PostgreSQL password in the jitsudod config file. Use environment variables:
export JITSUDOD_DATABASE_URL="postgres://jitsudo_app:<password>@db-host:5432/jitsudo?sslmode=require"Backups
Section titled “Backups”- Take daily snapshots of the PostgreSQL database
- Test restore procedures quarterly
- Encrypted backups should be stored in a separate account/project from the primary database
- After a restore, verify the audit log hash chain integrity:
jitsudo audit verify --from-backupCredential and Secret Management
Section titled “Credential and Secret Management”Provider credentials
Section titled “Provider credentials”jitsudo needs credentials to call cloud provider APIs (STS AssumeRole for AWS, ARM API for Azure, IAM API for GCP). These are high-privilege credentials.
Never store provider credentials in the jitsudod config file. Use environment variables or a secrets manager:
# AWS: prefer IAM roles for EC2/EKS (no static credentials needed)# If static credentials are required:export AWS_ACCESS_KEY_ID="..."export AWS_SECRET_ACCESS_KEY="..."
# Azure: prefer Workload Identity for AKS# If client secret is required:export AZURE_CLIENT_SECRET="..."
# GCP: prefer Workload Identity Federation# If service account key is required:export GOOGLE_APPLICATION_CREDENTIALS="/var/secrets/gcp-sa-key.json"Prefer workload identity over static credentials wherever possible. IAM Roles for Service Accounts (IRSA) on EKS, Azure Workload Identity on AKS, and GCP Workload Identity Federation all eliminate the need to manage long-lived static credentials.
Notification secrets
Section titled “Notification secrets”Slack webhook URLs, SMTP passwords, and SIEM tokens should be set via environment variables rather than the config file:
export JITSUDOD_SLACK_WEBHOOK_URL="https://hooks.slack.com/..."export JITSUDOD_SMTP_PASSWORD="..."export JITSUDOD_SIEM_JSON_URL="https://siem.example.com/api/v1/ingest"export JITSUDOD_SIEM_SYSLOG_ADDRESS="syslog.example.com:514"Audit Log Integrity
Section titled “Audit Log Integrity”The jitsudo audit log uses SHA-256 hash chaining: each entry includes the SHA-256 hash of the previous entry. This creates a tamper-evident chain that makes retroactive modification detectable.
Database-layer enforcement
Section titled “Database-layer enforcement”The REVOKE UPDATE, DELETE ON audit_events database permission (described above) enforces append-only at the storage layer, independent of the application.
Verify the hash chain
Section titled “Verify the hash chain”# Verify the full audit log chainjitsudo audit verify
# Export and verify offlinejitsudo audit export --output audit-backup.jsonpython3 verify_audit_chain.py audit-backup.jsonSee Audit Log for the verification script and chain format.
Current limitations
Section titled “Current limitations”The hash chain protects against undetected modification of entries, but does not prevent deletion of entries (truncation). For stronger guarantees — write-once storage, cryptographic anchoring, WORM sinks — see the roadmap. In the interim, the combination of hash chaining, database role restrictions, and external SIEM forwarding provides defense in depth.
Break-Glass Recovery
Section titled “Break-Glass Recovery”If jitsudod itself is compromised:
- Revoke all active provider credentials immediately via the cloud provider’s IAM console — do not wait for TTL expiry
- Rotate all provider credentials used by jitsudod (AWS role, Azure client secret, GCP service account)
- Rotate the PostgreSQL password and TLS certificates
- Restore from a known-good database backup if the database was modified out-of-band
- Verify audit log integrity on the restored database:
jitsudo audit verify - Review all audit log entries since the last verified backup for unauthorized grants
- Rebuild jitsudod from source or a verified container image before restarting
The hash chain in the audit log will reveal any entries that were modified or inserted out-of-band during the compromise window.
Key Rotation
Section titled “Key Rotation”TLS certificate rotation
Section titled “TLS certificate rotation”jitsudod reads TLS certificates from disk at startup. To rotate without downtime on Kubernetes:
- Update the Kubernetes Secret containing the TLS cert/key
- Perform a rolling restart:
kubectl rollout restart deployment/jitsudod - Verify the new certificate is in use:
openssl s_client -connect jitsudod:443
Database credential rotation
Section titled “Database credential rotation”- Create a new PostgreSQL role or update the password
- Update the
JITSUDOD_DATABASE_URLenvironment variable in the deployment (Kubernetes Secret or Vault) - Perform a rolling restart
- Drop the old credential after confirming the new one works
Provider credential rotation
Section titled “Provider credential rotation”Follow each cloud provider’s credential rotation procedure, then update the corresponding environment variable and perform a rolling restart of jitsudod.