Cerbos provides official Docker images for easy deployment in containerized environments.
Docker Images
Official Cerbos images are available on GitHub Container Registry:
Image : ghcr.io/cerbos/cerbos
Tags : Version tags (e.g., 0.52.0), latest, dev
Architecture : AMD64 and ARM64
Quick Start
Basic Container
Run Cerbos with default configuration:
docker run -d \
--name cerbos \
-p 3592:3592 \
-p 3593:3593 \
ghcr.io/cerbos/cerbos:latest
With Custom Policies
Mount a local policies directory:
docker run -d \
--name cerbos \
-p 3592:3592 \
-p 3593:3593 \
-v $( pwd ) /policies:/policies \
-e CERBOS_CONFIG=__default__ \
ghcr.io/cerbos/cerbos:latest
With Custom Configuration
Mount a configuration file:
docker run -d \
--name cerbos \
-p 3592:3592 \
-p 3593:3593 \
-v $( pwd ) /config/.cerbos.yaml:/config/.cerbos.yaml \
ghcr.io/cerbos/cerbos:latest server --config=/config/.cerbos.yaml
Dockerfile Details
The official Cerbos Dockerfile:
FROM alpine:3.16 AS base
RUN apk add -U --no-cache ca-certificates && update-ca-certificates
FROM scratch
ARG TARGETPLATFORM
EXPOSE 3592 3593
ENV CERBOS_CONFIG= "__default__"
VOLUME [ "/policies" , "/tmp" , "/.cache" ]
ENTRYpoint [ "/cerbos" ]
CMD [ "server" ]
HEALTHCHECK --interval=10s --timeout=2s --retries=2 CMD [ "/cerbos" , "healthcheck" ]
COPY --from=base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY ${TARGETPLATFORM}/cerbos /cerbos
Key features:
Minimal scratch-based image for security
Multi-architecture support (AMD64, ARM64)
Built-in health check every 10 seconds
Exposed ports: 3592 (HTTP), 3593 (gRPC)
Default volumes for policies, temp, and cache
Ports and Volumes
Exposed Ports
3592 : HTTP API (REST endpoints, health checks, metrics)
3593 : gRPC API (recommended for production)
Volumes
/policies: Policy files directory
/tmp: Temporary files and caches
/.cache: Bundle cache directory (for Hub/remote bundles)
Environment Variables
Default Configuration
When CERBOS_CONFIG=__default__, Cerbos uses:
server :
httpListenAddr : ":3592"
grpcListenAddr : ":3593"
storage :
driver : "disk"
disk :
directory : /policies
watchForChanges : false
Common Variables
Configuration
Storage
Audit
Schema
CERBOS_CONFIG = __default__ # Use default config
CERBOS_LOG_LEVEL = info # Log level: debug, info, warn, error
Docker Compose
Basic Setup
Create docker-compose.yml:
services :
cerbos :
image : ghcr.io/cerbos/cerbos:latest
container_name : cerbos
restart : unless-stopped
ports :
- "3592:3592"
- "3593:3593"
volumes :
- ./policies:/policies
- ./config/.cerbos.yaml:/config/.cerbos.yaml
command : [ "server" , "--config=/config/.cerbos.yaml" ]
healthcheck :
test : [ "/cerbos" , "healthcheck" ]
interval : 10s
timeout : 2s
retries : 3
Start the service:
Production Setup
A production-ready configuration with monitoring:
services :
cerbos :
image : ghcr.io/cerbos/cerbos:0.52.0
container_name : cerbos
restart : always
ports :
- "3592:3592"
- "3593:3593"
volumes :
- ./config:/conf:ro
- ./policies:/policies:ro
- ./audit:/audit
- cerbos-cache:/.cache
command :
- "server"
- "--config=/conf/.cerbos.yaml"
- "--log-level=info"
environment :
- AUDIT_ENABLED=true
- SCHEMA_ENFORCEMENT=reject
deploy :
resources :
limits :
cpus : '2.0'
memory : 512M
reservations :
cpus : '0.5'
memory : 128M
healthcheck :
test : [ "/cerbos" , "healthcheck" ]
interval : 10s
timeout : 2s
retries : 3
start_period : 5s
networks :
- cerbos-network
prometheus :
image : prom/prometheus:latest
container_name : prometheus
ports :
- "9090:9090"
volumes :
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
command :
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
networks :
- cerbos-network
depends_on :
- cerbos
grafana :
image : grafana/grafana:latest
container_name : grafana
ports :
- "3000:3000"
volumes :
- ./grafana/dashboards.yaml:/etc/grafana/provisioning/dashboards/dashboards.yaml:ro
- ./grafana/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:ro
- ./grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana-data:/var/lib/grafana
environment :
- GF_SECURITY_ADMIN_PASSWORD=admin
networks :
- cerbos-network
depends_on :
- prometheus
volumes :
cerbos-cache :
prometheus-data :
grafana-data :
networks :
cerbos-network :
driver : bridge
Prometheus configuration (prometheus/prometheus.yml):
global :
scrape_interval : 15s
evaluation_interval : 15s
scrape_configs :
- job_name : 'cerbos'
static_configs :
- targets : [ 'cerbos:3592' ]
metrics_path : '/_cerbos/metrics'
With Database Storage
Using PostgreSQL for policy storage:
services :
cerbos :
image : ghcr.io/cerbos/cerbos:latest
container_name : cerbos
restart : always
ports :
- "3592:3592"
- "3593:3593"
volumes :
- ./config:/conf:ro
command : [ "server" , "--config=/conf/.cerbos.yaml" ]
environment :
- DB_HOST=postgres
- DB_PORT=5432
- DB_USER=cerbos
- DB_PASSWORD=cerbos
- DB_NAME=cerbos
depends_on :
postgres :
condition : service_healthy
networks :
- cerbos-network
postgres :
image : postgres:14-alpine
container_name : postgres
restart : always
environment :
- POSTGRES_USER=cerbos
- POSTGRES_PASSWORD=cerbos
- POSTGRES_DB=cerbos
volumes :
- postgres-data:/var/lib/postgresql/data
- ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
ports :
- "5432:5432"
healthcheck :
test : [ "CMD-SHELL" , "pg_isready -U cerbos" ]
interval : 10s
timeout : 5s
retries : 5
networks :
- cerbos-network
volumes :
postgres-data :
networks :
cerbos-network :
driver : bridge
Configuration file for PostgreSQL (config/.cerbos.yaml):
server :
httpListenAddr : ":3592"
grpcListenAddr : ":3593"
storage :
driver : "postgres"
postgres :
url : "postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}?sslmode=disable"
Configuration
Storage Backends
Disk Storage
Git Storage
Cerbos Hub
PostgreSQL
server :
httpListenAddr : ":3592"
grpcListenAddr : ":3593"
storage :
driver : "disk"
disk :
directory : /policies
watchForChanges : true
TLS Configuration
Enable TLS for secure communication:
server :
httpListenAddr : ":3592"
grpcListenAddr : ":3593"
tls :
cert : /certs/server.crt
key : /certs/server.key
caCert : /certs/ca.crt
Mount certificates:
docker run -d \
--name cerbos \
-p 3592:3592 \
-p 3593:3593 \
-v $( pwd ) /certs:/certs:ro \
-v $( pwd ) /config/.cerbos.yaml:/config/.cerbos.yaml:ro \
ghcr.io/cerbos/cerbos:latest server --config=/config/.cerbos.yaml
Audit Logging
Enable audit logs:
audit :
enabled : true
backend : "file"
file :
path : /audit/audit.log
retentionPeriod : 168h # 7 days
Mount audit directory:
docker run -d \
--name cerbos \
-p 3592:3592 \
-p 3593:3593 \
-v $( pwd ) /audit:/audit \
-v $( pwd ) /config/.cerbos.yaml:/config/.cerbos.yaml:ro \
ghcr.io/cerbos/cerbos:latest server --config=/config/.cerbos.yaml
Health Checks
Built-in Health Check
The Docker image includes a health check:
HEALTHCHECK --interval=10s --timeout=2s --retries=2 \
CMD [ "/cerbos" , "healthcheck" ]
Manual Health Check
# Check container health
docker inspect --format= '{{.State.Health.Status}}' cerbos
# Using curl
docker exec cerbos /cerbos healthcheck
# HTTP endpoint
curl http://localhost:3592/_cerbos/health
Expected response:
Resource Limits
Using Docker Run
docker run -d \
--name cerbos \
--memory= "512m" \
--cpus= "1.0" \
--pids-limit=100 \
-p 3592:3592 \
-p 3593:3593 \
ghcr.io/cerbos/cerbos:latest
Using Docker Compose
services :
cerbos :
image : ghcr.io/cerbos/cerbos:latest
deploy :
resources :
limits :
cpus : '2.0'
memory : 512M
reservations :
cpus : '0.5'
memory : 128M
Networking
Bridge Network (Default)
docker network create cerbos-net
docker run -d \
--name cerbos \
--network cerbos-net \
-p 3592:3592 \
-p 3593:3593 \
ghcr.io/cerbos/cerbos:latest
Host Network
For maximum performance:
docker run -d \
--name cerbos \
--network host \
ghcr.io/cerbos/cerbos:latest
Host networking is only available on Linux and removes network isolation.
Security Best Practices
Run as Non-Root User
The Cerbos image runs as a non-root user by default (scratch-based image).
Read-Only Root Filesystem
docker run -d \
--name cerbos \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
-p 3592:3592 \
-p 3593:3593 \
-v $( pwd ) /policies:/policies:ro \
ghcr.io/cerbos/cerbos:latest
Security Options
docker run -d \
--name cerbos \
--cap-drop=ALL \
--security-opt=no-new-privileges:true \
--read-only \
-p 3592:3592 \
-p 3593:3593 \
ghcr.io/cerbos/cerbos:latest
Docker Compose Security
services :
cerbos :
image : ghcr.io/cerbos/cerbos:latest
read_only : true
security_opt :
- no-new-privileges:true
cap_drop :
- ALL
tmpfs :
- /tmp:rw,noexec,nosuid,size=100m
volumes :
- ./policies:/policies:ro
Monitoring
Container Stats
# Real-time stats
docker stats cerbos
# Logs
docker logs -f cerbos
# Specific time range
docker logs --since 1h cerbos
Prometheus Metrics
Metrics are exposed at http://localhost:3592/_cerbos/metrics:
curl http://localhost:3592/_cerbos/metrics
Key metrics:
cerbos_check_duration_seconds: Authorization check duration
cerbos_check_total: Total authorization checks
cerbos_policy_repo_load_duration_seconds: Policy load time
Troubleshooting
Container Won’t Start
# Check logs
docker logs cerbos
# Inspect container
docker inspect cerbos
# Run interactively
docker run -it --rm \
-v $( pwd ) /config:/config \
ghcr.io/cerbos/cerbos:latest server --config=/config/.cerbos.yaml
Policy Errors
# Validate policies before mounting
docker run --rm \
-v $( pwd ) /policies:/policies \
ghcr.io/cerbos/cerbosctl:latest compile /policies
# Check policy loading
docker logs cerbos | grep -i policy
Permission Issues
# Check volume permissions
ls -la policies/
# Fix permissions
chmod -R 755 policies/
chmod 644 policies/ * .yaml
Port Conflicts
# Check if ports are in use
lsof -i :3592
lsof -i :3593
# Use different ports
docker run -d \
--name cerbos \
-p 13592:3592 \
-p 13593:3593 \
ghcr.io/cerbos/cerbos:latest
Complete Production Example
A complete production setup with all best practices:
services :
cerbos :
image : ghcr.io/cerbos/cerbos:0.52.0
container_name : cerbos-prod
restart : always
hostname : cerbos
# Ports
ports :
- "3592:3592"
- "3593:3593"
# Volumes
volumes :
- ./config/.cerbos.yaml:/config/.cerbos.yaml:ro
- ./policies:/policies:ro
- ./certs:/certs:ro
- ./audit:/audit
- cerbos-cache:/.cache
# Command
command :
- "server"
- "--config=/config/.cerbos.yaml"
- "--log-level=info"
# Environment
environment :
- AUDIT_ENABLED=true
- SCHEMA_ENFORCEMENT=reject
# Security
read_only : true
security_opt :
- no-new-privileges:true
cap_drop :
- ALL
tmpfs :
- /tmp:rw,noexec,nosuid,size=100m
# Resources
deploy :
resources :
limits :
cpus : '2.0'
memory : 512M
reservations :
cpus : '0.5'
memory : 128M
restart_policy :
condition : on-failure
delay : 5s
max_attempts : 3
window : 120s
# Health check
healthcheck :
test : [ "/cerbos" , "healthcheck" ]
interval : 10s
timeout : 2s
retries : 3
start_period : 5s
# Logging
logging :
driver : "json-file"
options :
max-size : "10m"
max-file : "3"
# Network
networks :
- cerbos-network
volumes :
cerbos-cache :
driver : local
networks :
cerbos-network :
driver : bridge
ipam :
config :
- subnet : 172.28.0.0/16
This configuration provides:
Automatic restarts and health checks
Resource limits and security hardening
Persistent cache and audit logs
Proper logging and monitoring
Network isolation