Skip to content

Server Configuration

jitsudod is configured via an optional YAML file and JITSUDOD_* environment variables. Environment variables always take precedence over the config file, making them suitable for Kubernetes Secrets and twelve-factor deployments.

Terminal window
# Pass the config file path as a flag
jitsudod --config /etc/jitsudo/config.yaml
# Or via environment variable
JITSUDOD_CONFIG=/etc/jitsudo/config.yaml jitsudod
# Environment-only (no config file required)
JITSUDOD_DATABASE_URL=postgres://... jitsudod

Network listener addresses for the two APIs.

FieldYAML keyEnv varDefaultDescription
HTTP addressserver.http_addrJITSUDOD_HTTP_ADDR:8080REST gateway (grpc-gateway) listen address
gRPC addressserver.grpc_addrJITSUDOD_GRPC_ADDR:8443Native gRPC API listen address
server:
http_addr: ":8080"
grpc_addr: ":8443"

PostgreSQL connection settings. jitsudo requires PostgreSQL — SQLite is not supported.

FieldYAML keyEnv varDefaultDescription
Connection URLdatabase.urlJITSUDOD_DATABASE_URLLocal dev defaultPostgreSQL DSN (postgres://user:pass@host:port/db?sslmode=require)
database:
url: "postgres://jitsudo:password@localhost:5432/jitsudo?sslmode=require"

OIDC token validation settings.

FieldYAML keyEnv varDefaultDescription
OIDC issuerauth.oidc_issuerJITSUDOD_OIDC_ISSUERhttp://localhost:5556/dexMust match the iss claim in tokens issued by your IdP
OIDC discovery URLauth.oidc_discovery_urlJITSUDOD_OIDC_DISCOVERY_URL"" (uses issuer URL)Override the OIDC discovery endpoint. Use when jitsudod reaches the IdP via a different address than the public issuer URL (e.g. Docker service name). Must point to the same provider as oidc_issuer.
Client IDauth.client_idJITSUDOD_OIDC_CLIENT_IDjitsudo-cliMust match the aud claim in tokens presented by the CLI. Use jitsudo-cli for local dev (dex); set to your IdP’s registered client ID in production.
auth:
oidc_issuer: "https://your-idp.example.com"
client_id: "your-oidc-client-id" # must match the aud claim in CLI tokens
# oidc_discovery_url: "http://internal-idp:8080" # only if IdP is behind a private endpoint

Token validation flow: jitsudod fetches JWKS from {oidc_issuer}/.well-known/openid-configuration (or oidc_discovery_url if set), verifies the JWT signature, and validates iss, aud, and exp claims.


TLS configuration for the gRPC listener.

FieldYAML keyEnv varDefaultDescription
Certificate filetls.cert_fileJITSUDOD_TLS_CERT_FILE""Path to PEM-encoded TLS certificate
Key filetls.key_fileJITSUDOD_TLS_KEY_FILE""Path to PEM-encoded TLS private key
CA filetls.ca_fileJITSUDOD_TLS_CA_FILE""Path to CA certificate; non-empty enables mTLS

TLS modes:

cert_filekey_fileca_fileMode
emptyemptyemptyInsecure (local development only)
setsetemptyServer-only TLS
setsetsetMutual TLS (mTLS)
tls:
cert_file: "/etc/jitsudo/tls.crt"
key_file: "/etc/jitsudo/tls.key"
ca_file: "" # set to enable mTLS

Each provider is optional. Omit or comment out sections you don’t use. A nil provider section means the provider is not registered at startup.

FieldYAML keyDefaultDescription
Modeproviders.aws.modests_assume_rolests_assume_role or identity_center
Regionproviders.aws.regionus-east-1Primary AWS region
Role ARN templateproviders.aws.role_arn_templateARN template with {scope} and {role} variables
Max durationproviders.aws.max_durationno capMaximum elevation window (STS hard max: 12h)
Identity Center instance ARNproviders.aws.identity_center_instance_arnRequired for identity_center mode
Identity Center store IDproviders.aws.identity_center_store_idRequired for identity_center mode
Endpoint URLproviders.aws.endpoint_url""Override AWS endpoint (LocalStack testing only)
providers:
aws:
mode: "sts_assume_role"
region: "us-east-1"
role_arn_template: "arn:aws:iam::{scope}:role/jitsudo-{role}"
max_duration: "4h"
FieldYAML keyDefaultDescription
Organization IDproviders.gcp.organization_idGCP organization ID (numeric string)
Credentials sourceproviders.gcp.credentials_sourceapplication_defaultworkload_identity_federation, application_default, or service_account_key
Max durationproviders.gcp.max_durationno capMaximum elevation window
Condition title prefixproviders.gcp.condition_title_prefixjitsudoPrefix for IAM condition titles
providers:
gcp:
organization_id: "123456789012"
credentials_source: "workload_identity_federation"
max_duration: "8h"
condition_title_prefix: "jitsudo"
FieldYAML keyDefaultDescription
Tenant IDproviders.azure.tenant_idEntra ID (Azure AD) tenant ID
Default subscription IDproviders.azure.default_subscription_idFallback subscription for requests without a scope
Client IDproviders.azure.client_idService principal or managed identity client ID
Credentials sourceproviders.azure.credentials_sourceworkload_identityworkload_identity or client_secret
Max durationproviders.azure.max_durationno capMaximum elevation window
providers:
azure:
tenant_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
default_subscription_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
client_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
credentials_source: "workload_identity"
max_duration: "4h"
FieldYAML keyDefaultDescription
Kubeconfig pathproviders.kubernetes.kubeconfig"" (in-cluster)Path to kubeconfig; empty uses in-cluster service account
Default namespaceproviders.kubernetes.default_namespace""Default namespace for RoleBindings
Max durationproviders.kubernetes.max_durationno capMaximum elevation window
Managed labelproviders.kubernetes.managed_labeljitsudo.dev/managedLabel applied to all managed bindings
providers:
kubernetes:
kubeconfig: ""
default_namespace: "default"
max_duration: "1h"
managed_label: "jitsudo.dev/managed"

FieldYAML keyEnv varDefaultDescription
Webhook URLnotifications.slack.webhook_urlJITSUDOD_SLACK_WEBHOOK_URLSlack incoming webhook URL
Channelnotifications.slack.channel""Override the webhook’s default channel
Break-glass mentionnotifications.slack.mention_on_break_glass""Prepended to break-glass alerts (e.g. <!channel>)
notifications:
slack:
webhook_url: "https://hooks.slack.com/services/..."
channel: "#sre-access-requests"
mention_on_break_glass: "<!channel>"
FieldYAML keyEnv varDefaultDescription
Hostnotifications.smtp.hostJITSUDOD_SMTP_HOSTSMTP server hostname
Portnotifications.smtp.port587SMTP port (587=STARTTLS, 465=TLS)
Usernamenotifications.smtp.usernameSMTP auth username
Passwordnotifications.smtp.passwordJITSUDOD_SMTP_PASSWORDSMTP auth password
Fromnotifications.smtp.fromSender email address
Tonotifications.smtp.toList of recipient email addresses
notifications:
smtp:
host: "smtp.example.com"
port: 587
username: "jitsudo@example.com"
password: "" # supply via JITSUDOD_SMTP_PASSWORD
from: "jitsudo@example.com"
to:
- "sre-team@example.com"
- "security@example.com"

A list of generic outbound webhooks. Each entry POSTs a structured JSON payload to the configured URL whenever an event occurs. Multiple entries are supported — each is an independent notifier.

FieldYAML keyEnv varDefaultDescription
URLnotifications.webhooks[].urlJITSUDOD_WEBHOOK_URL*HTTP(S) endpoint to POST to
Headersnotifications.webhooks[].headers{}Custom HTTP headers added to every request (e.g. Authorization)
Secretnotifications.webhooks[].secret""HMAC-SHA256 signing key. When set, a X-Jitsudo-Signature-256: sha256=<hex> header is included so receivers can verify authenticity
Eventsnotifications.webhooks[].events[] (all)Allowlist of event types to forward. Empty means all events are forwarded

* JITSUDOD_WEBHOOK_URL injects a single no-auth, no-filter webhook entry when no webhooks: block is defined in the YAML config. Useful for simple Docker / Kubernetes Secret deployments.

Payload fields

Each POST body is a JSON object:

{
"type": "approved",
"request_id": "01JF4...",
"actor": "approver@example.com",
"provider": "aws",
"role": "ReadOnly",
"scope": "123456789012",
"reason": "incident investigation",
"expires_at": "2025-01-15T18:00:00Z",
"timestamp": "2025-01-15T17:00:00Z"
}

expires_at is omitted when not applicable. timestamp is the UTC time the event was dispatched.

Event types: request_created, approved, auto_approved, ai_approved, ai_denied, ai_escalated, denied, expired, revoked, break_glass.

Signature verification example (Go):

mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))
ok := hmac.Equal([]byte(r.Header.Get("X-Jitsudo-Signature-256")), []byte(expected))
notifications:
webhooks:
- url: "https://hooks.example.com/jitsudo"
secret: "" # supply via a mounted secret; leave empty to skip signing
events: [] # empty = all events
headers:
Authorization: "Bearer <token>"
- url: "https://other.example.com/hook"
events: ["break_glass", "approved"]

Real-time SIEM integration. Events are forwarded as they occur, independent of the audit log. The siem block has two optional sub-sections; configure either or both.

POSTs each event as a self-contained JSON document to an HTTP ingest endpoint (Splunk HEC, Elasticsearch, Datadog Logs, or any compatible receiver). Richer than the generic webhook: includes a source, schema_version, and a per-event UUID (event_id) for deduplication.

FieldYAML keyEnv varDefaultDescription
URLnotifications.siem.json.urlJITSUDOD_SIEM_JSON_URLHTTP(S) ingest endpoint
Headersnotifications.siem.json.headers{}Custom HTTP headers (e.g. Authorization: Bearer <token>)
Eventsnotifications.siem.json.events[] (all)Allowlist of event types to forward. Empty means all events

Payload fields (superset of the generic webhook payload):

{
"source": "jitsudo",
"schema_version": "1",
"event_id": "550e8400-e29b-41d4-a716-446655440000",
"type": "approved",
"request_id": "01JF4...",
"actor": "approver@example.com",
"provider": "aws",
"role": "ReadOnly",
"scope": "123456789012",
"reason": "incident investigation",
"expires_at": "2025-01-15T18:00:00Z",
"timestamp": "2025-01-15T17:00:00Z"
}

event_id is a UUID v4 generated per-event and is unique across all deliveries, making it safe to use as a deduplication key in idempotent SIEM ingest pipelines. expires_at is omitted when not applicable.

Forwards events via the syslog protocol to a remote syslog server or the local Unix socket. Messages use a structured key=value format parseable by any SIEM that consumes syslog (rsyslog, syslog-ng, Splunk Universal Forwarder, etc.).

FieldYAML keyEnv varDefaultDescription
Networknotifications.siem.syslog.network"""tcp", "udp", or "" for the local Unix socket
Addressnotifications.siem.syslog.addressJITSUDOD_SIEM_SYSLOG_ADDRESS"""host:port" for a remote server; empty uses the OS default local socket
Tagnotifications.siem.syslog.tag"jitsudo"Syslog process identifier
Facilitynotifications.siem.syslog.facility"auth"Syslog facility: "auth", "daemon", or "local0""local7"

Severity mapping:

Event typeSyslog severity
break_glassWARNING
denied, ai_deniedNOTICE
All othersINFO

Message format (structured key=value, space-separated):

type=approved request_id=01JF4... actor=alice@example.com provider=aws role=ReadOnly scope=123456789012 reason="incident investigation" expires_at=2025-01-15T18:00:00Z
notifications:
siem:
json:
url: "https://siem.example.com/api/v1/ingest"
events: [] # empty = all events
headers:
Authorization: "Bearer <token>"
syslog:
network: "tcp"
address: "syslog.example.com:514"
tag: "jitsudo"
facility: "auth"

Configuration for the MCP approver endpoint (POST /mcp). The endpoint is disabled when token is empty.

FieldYAML keyEnv varDefaultDescription
Tokenmcp.tokenJITSUDOD_MCP_TOKEN""Bearer token AI agents must present. Empty = endpoint returns 404 (disabled). Generate with openssl rand -hex 32.
Agent identitymcp.agent_identityJITSUDOD_MCP_AGENT_IDENTITY"mcp-agent"Name recorded in the audit log for every AI approval decision. Use a descriptive name per deployment.
mcp:
token: "" # supply via JITSUDOD_MCP_TOKEN — never commit this value
agent_identity: "claude-approver-prod"

FieldYAML keyEnv varDefaultDescription
Levellog.levelJITSUDOD_LOG_LEVELinfoMinimum log level: debug, info, warn, error
Formatlog.formatjsonOutput format: json (structured) or text (human-readable)
log:
level: "info"
format: "json"

A full annotated config file is available in the repository at deploy/config/config.example.yaml.

Additional example configs: