Skip to main content

OPAL Configuration Guide

Getting Started with OPAL Configuration​

OPAL supports multiple ways to configure your deployment:

  • Environment Variables (recommended) - export OPAL_SERVER_URL=http://localhost:7002
  • Command Line Arguments - opal-server run --server-url http://localhost:7002
  • Configuration Files - .env or .ini files in your project

Essential Configuration​

Let's get OPAL running! You'll need to set a few environment variables that tell OPAL where to find your policies and how to connect everything together.

OPAL Server​

# Where your policies are stored (Git repo)
export OPAL_POLICY_REPO_URL=https://github.com/your-org/policy-repo.git

# Where clients get initial data
export OPAL_DATA_CONFIG_SOURCES='{
"config": {
"entries": [{
"url": "http://localhost:7002/policy-data",
"topics": ["policy_data"],
"dst_path": "/static"
}]
}
}'

# Broadcast channel for scaling (use Redis or PostgreSQL)
export OPAL_BROADCAST_URI=postgres://postgres:postgres@localhost:5432/postgres

OPAL Client​

# Connect to your OPAL server
export OPAL_SERVER_URL=http://localhost:7002

# Authentication token (change in production!)
export OPAL_CLIENT_TOKEN=your-secret-token

# Policy engine type (OPA is default, Cedar also available)
export OPAL_POLICY_STORE_TYPE=opa

Production Configuration​

When you're ready to deploy to production, you'll need to configure a few more things to ensure security and reliability.

  • Use HTTPS for all OPAL server communication
  • Generate strong cryptographic keys for JWT authentication
  • Store secrets securely (never commit to repositories)
  • Use webhooks instead of polling for policy updates

Common Configuration​

Below are some common configuration options that you may want to consider:

🔐 Security Configuration
# Enable secure mode with proper authentication
export OPAL_AUTH_PRIVATE_KEY="your-rsa-private-key"
export OPAL_AUTH_PUBLIC_KEY="your-rsa-public-key"
export OPAL_AUTH_MASTER_TOKEN="secure-random-token"

# Use HTTPS
export OPAL_SERVER_URL=https://opal.your-domain.com
⚡ Performance & Scaling
# Scale with multiple server workers
export UVICORN_NUM_WORKERS=4

# Use webhooks instead of polling for better performance
export OPAL_POLICY_REPO_POLLING_INTERVAL=0
export OPAL_POLICY_REPO_WEBHOOK_SECRET=your-webhook-secret
📊 Monitoring & Logging
# Enhanced logging and statistics
export OPAL_LOG_FORMAT_INCLUDE_PID=true
export OPAL_LOG_LEVEL=INFO
export OPAL_STATISTICS_ENABLED=true

Read more about secure mode setup.

Configuration Reference

Common OPAL Configs​

These configuration variables are shared between OPAL Client and OPAL Server.

General Configuration​

OPAL_ALLOWED_ORIGINS​

Default: *

Comma-separated list of allowed origins for CORS. Use * to allow all origins.

OPAL_PROCESS_NAME​

Default: opal

The process name to be shown in logs.

OPAL_CLIENT_SELF_SIGNED_CERTIFICATES_ALLOWED​

Default: False

Whether OPAL Client will trust HTTPS connections protected by self-signed certificates. Not recommended for production use.

Read more about using self-signed certificates.

OPAL_CLIENT_SSL_CONTEXT_TRUSTED_CA_FILE​

Default: None

Path to your own CA public certificate file (usually a .crt or .pem file). Certificates signed by this issuer will be trusted by OPAL Client.

Read more about using self-signed certificates.

OPAL_POLICY_REPO_POLICY_EXTENSIONS​

Default: [".rego"]

List of file extensions to serve as policy modules.

OPAL_ENABLE_METRICS​

Default: False

Enable metrics collection.

For more information, see monitoring OPAL.

OPAL_ENABLE_DATADOG_APM​

Default: False

Enable tracing with DataDog APM. Note: OPAL uses ddtrace v3.0.0+ which requires Python 3.8+.

For more information, see monitoring OPAL.

OPAL_HTTP_FETCHER_PROVIDER_CLIENT​

Default: aiohttp

The client to use for fetching data. Options: aiohttp, httpx.

Added in OPAL v0.7.7

OPAL_GIT_SSH_KEY_FILE​

Default: ~/.ssh/opal_repo_ssh_key

Path to the SSH key file for Git operations.

For more information, see tracking a Git repository.

OPAL_STATISTICS_ENABLED​

Default: False

Collect statistics about OPAL clients.

For more information, see monitoring OPAL.

OPAL_STATISTICS_ADD_CLIENT_CHANNEL​

Default: __opal_stats_add

The topic to update about new OPAL client connections.

For more information, see monitoring OPAL.

OPAL_STATISTICS_REMOVE_CLIENT_CHANNEL​

Default: __opal_stats_rm

The topic to update about OPAL client disconnections.

For more information, see monitoring OPAL.

Logging Configuration​

OPAL_LOG_FORMAT_INCLUDE_PID​

Default: False

Whether to include the process ID in log messages.

OPAL_LOG_FORMAT​

Default: {time} | {process} | {name} | {level} | {message}

The format string for log messages.

OPAL_LOG_TRACEBACK​

Default: True

Whether to include traceback information in log messages.

OPAL_LOG_DIAGNOSE​

Default: False

Include diagnosis (local variable values) in tracebacks. Also gates verbose git SSH protocol tracing (GIT_TRACE/GIT_CURL_VERBOSE).

Added in OPAL v0.6.0

Default changed

The default is now False (previously True). Operators upgrading lose diagnostic tracebacks and verbose git tracing unless they opt back in with OPAL_LOG_DIAGNOSE=true.

danger

When OPAL_LOG_DIAGNOSE is enabled, logs may contain sensitive information such as secrets.

OPAL_LOG_COLORIZE​

Default: True

Whether to colorize log messages.

OPAL_LOG_SERIALIZE​

Default: False

Serialize log messages into JSON format (useful for log aggregation platforms).

Added in OPAL v0.6.0

OPAL_LOG_SHOW_CODE_LINE​

Default: True

Whether to include the source code line number in log messages.

OPAL_LOG_LEVEL​

Default: INFO

The minimum log level to display. Options: DEBUG, INFO, WARNING, ERROR, CRITICAL.

OPAL_LOG_MODULE_EXCLUDE_LIST​

Default: ["uvicorn"]

List of module names to exclude from logging.

OPAL_LOG_MODULE_INCLUDE_LIST​

Default: ["uvicorn.protocols.http"]

List of module names to include in logging (if empty, all modules are included).

OPAL_LOG_PATCH_UVICORN_LOGS​

Default: True

Take over Uvicorn's logs so they appear in the main logger.

OPAL_LOG_PIPE_TO_STDERR​

Default: True

Whether to send logs to stderr instead of stdout.

Added in OPAL v0.8.2

OPAL_LOG_TO_FILE​

Default: False

Whether to write logs to a file in addition to console output.

OPAL_LOG_FILE_PATH​

Default: opal_{process_name}{time}.log

Path to define where to save the log file.

OPAL_LOG_FILE_ROTATION​

Default: 250 MB

Log file rotation size (e.g., "10 MB", "1 GB").

OPAL_LOG_FILE_RETENTION​

Default: 10 days

How long to keep rotated log files (e.g., "30 days", "1 week").

OPAL_LOG_FILE_COMPRESSION​

Default: None

Compression format for rotated log files.

OPAL_LOG_FILE_SERIALIZE​

Default: True

Serialize log messages in file into JSON format (useful for log aggregation platforms).

OPAL_LOG_FILE_LEVEL​

Default: INFO

The minimum log level for file logging.

Authentication Configuration​

OPAL_AUTH_PUBLIC_KEY_FORMAT​

Default: SSH

Format of the public key. Options: PEM, JWK, SSH.

Read more about secure mode setup.

OPAL_AUTH_PUBLIC_KEY​

Default: None

The public key for JWT verification.

Read more about secure mode setup.

OPAL_AUTH_JWT_ALGORITHM​

Default: RS256

JWT algorithm for token verification. See possible values here.

Read more about secure mode setup.

OPAL_AUTH_JWT_AUDIENCE​

Default: https://api.opal.ac/v1/

The expected audience in JWT tokens.

Read more about secure mode setup.

OPAL_AUTH_JWT_ISSUER​

Default: https://opal.ac/

The expected issuer in JWT tokens.

Read more about secure mode setup.

Fetching Configuration​

OPAL_FETCH_PROVIDER_MODULES​

Default: ["opal_common.fetcher.providers"]

List of custom fetch provider modules to load.

For more information, see writing your own fetch provider and available fetch providers.

OPAL_FETCHING_WORKER_COUNT​

Default: 6

The number of workers to use for fetching data concurrently.

OPAL_FETCHING_CALLBACK_TIMEOUT​

Default: 10

The timeout for fetching callbacks, in seconds.

OPAL_FETCHING_ENQUEUE_TIMEOUT​

Default: 10

The timeout for enqueueing a fetch operation, in seconds.

OPAL Server Configs​

These configuration variables are specific to the OPAL Server.

Server Configuration​

OPAL_SERVER_WORKER_COUNT​

Default: auto (calculated based on CPU cores)

Worker count for the server (when run using CLI).

OPAL_SERVER_HOST​

Default: 127.0.0.1

Address for the server to bind to (when run using CLI).

OPAL_SERVER_PORT​

Default: None

note

DEPRECATED - Use OPAL_SERVER_BIND_PORT instead.

OPAL_SERVER_BIND_PORT​

Default: 7002

Port for the server to bind to (when run using CLI).

Added in OPAL v0.6.0

OPAL_BASE_DIR​

Default: ~/.local/state/opal

Base directory for OPAL server.

OPAL_NO_RPC_LOGS​

Default: True

Disable RPC logging.

OPAL_WS_LOCAL_URL​

Default: ws://localhost:7002/ws

The local WebSocket URL for OPAL.

OPAL_WS_TOKEN​

Default: THIS_IS_A_DEV_SECRET

The WebSocket token for OPAL.

OPAL_CLIENT_LOAD_LIMIT_NOTATION​

Default: None

If supplied, rate limiting will be enforced on the server's WebSocket endpoint. Format is limits-style notation (e.g., "10 per second"). Learn more.

OPAL_SCOPES​

Default: False

Enable scopes for multi-tenancy.

Added in OPAL v0.2.0

OPAL_SCOPES_REPO_CLONES_SHARDS​

Default: 1

The max number of local clones to use for the same repo (reused across scopes).

OPAL_SCOPES_GIT_FETCH_TIMEOUT​

Default: 120.0

Soft timeout in seconds for a single scope git clone/fetch: the awaiting operation is abandoned (the event loop and the sync pass move on) and the op is logged and skipped, retried next cycle. It is a SOFT timeout: the underlying git call keeps running on its own thread, and the pinned libgit2 sets no socket/server read timeout, so a black-holed remote can keep that thread — and the source's in-flight marker — alive for the life of the process (that source is then skipped until it recovers or the process restarts); SCOPES_GIT_MAX_ZOMBIES bounds how many such threads accumulate. Either way one unreachable repo never blocks boot or other scopes (0 = no timeout).

OPAL_SCOPES_GIT_MAX_WORKERS​

Default: 10

Maximum number of concurrent scope git operations. It bounds phase 1 (the network clone/fetch of each distinct repo) AND phase 2 (the local change-check of scopes that reuse an already-cloned repo), so it sets how many scopes are synced at once in either phase. A timed-out operation stops counting against this limit, so one hung remote does not hold a concurrency slot — its lingering daemon thread persists on its own (a black-holed remote's can persist for the life of the process). That tail is bounded by SCOPES_GIT_MAX_ZOMBIES, which is a GLOBAL ceiling: read its description, because at that ceiling new git ops are refused for every scope, healthy ones included.

OPAL_SCOPES_PURGE_CHANNEL​

Default: __opal_scope_purge__

Pub/sub channel (worker-to-worker, over the broadcaster) used to purge GitPolicyFetcher caches fleet-wide when a scope is deleted or repointed to a new source. Every worker subscribes and drops its own cache entries; the leader is the only actor that may authorize that, because only it can check whether a surviving scope still shares the source. It does not remove the clone dir.

OPAL_SCOPES_GIT_PRELOAD_DRAIN_TIMEOUT​

Default: 10.0

Max seconds the pre-fork scope preload waits for in-flight git ops to finish before tearing down and forking workers. Ops still lingering past this bound are left running on their daemon threads and their cached handles are left unfreed by the pre-fork cache reset, avoiding a use-after-free (0 = don't wait).

OPAL_SCOPES_GIT_MAX_ZOMBIES​

Default: 40

Maximum number of in-flight scope git operations (live plus lingering timed-out) allowed to hold a daemon thread at once, counted GLOBALLY across all sources. It is a last-resort ceiling on thread growth when remotes hang, not a per-source guard — that is handled separately, by skipping a source that already has an operation in flight. Once the ceiling is reached, new git ops are refused (logged, and retried next cycle) for EVERY scope, healthy ones included, until enough threads drain; with remotes that never return, that state can persist. Set it well above SCOPES_GIT_MAX_WORKERS and alert on the refusal log (0 = no cap; a negative value is clamped to 0 and also means no cap, at the cost of unbounded thread growth during an outage).

OPAL_SCOPES_GIT_BACKOFF_BASE_SECONDS​

Default: 10.0

First delay before the periodic sync pass re-attempts a SOURCE whose git clone or fetch just failed (unreachable host, revoked credentials, deleted repo); every further consecutive failure doubles it — 10s, 20s, 40s, ... minutes, hours, days — with no upper bound unless SCOPES_GIT_BACKOFF_MAX_SECONDS is set. A delay shorter than the gap to the next pass simply does not skip that pass, so the first few doublings cost one attempt per pass exactly as before and the schedule bites from roughly the fourth consecutive failure. It exists because nothing else records a failure: without it every pass re-attempts every dead repo, and so does every duplicate scope sharing that repo — a handful of dead repositories can account for thousands of clone attempts per hour. Only the periodic pass and the boot preload honour it (in both phases, and re-checked under the source lock, so duplicates of a source that fails in a pass cost one attempt, not one per scope): an explicit POST /scopes/:scope_id/refresh, POST /scopes/refresh or PUT /scopes attempts the source immediately, so an operator who has just repaired credentials recovers at once, and any successful clone or fetch clears both the delay and the consecutive-failure count. The state is in-memory and per process — it resets on restart. When a periodic pass runs (POLICY_REFRESH_INTERVAL > 0) a forked worker inherits whatever the pre-fork preload recorded, so the leader does not re-hammer repos that already failed at boot; without one, the boot sync is the only pass-originated sync, so it drops the inherited entries and attempts every source once. Watch opal_server.scopes.sources_in_backoff (gauge of sources currently being skipped, tagged by pid) and opal_server.scopes.git_op_skipped with reason:backoff (counter); the WARNING logged when a source enters backoff, and again when its delay first exceeds a day, names the repository. 0 or negative disables the backoff entirely — nothing is recorded and nothing is skipped; nan and inf are treated as disabled too, because they parse cleanly rather than failing the process at startup and neither is a duration.

OPAL_SCOPES_GIT_BACKOFF_MAX_SECONDS​

Default: 0.0

Optional cap on the per-source doubling backoff of SCOPES_GIT_BACKOFF_BASE_SECONDS. 0 (the default), negative, nan or inf means NO cap: a repository that has been unreachable for a day is checked again in two, then four, and before long only at the next restart or explicit refresh — a repository that keeps failing is, in all likelihood, dead. Set a positive value to bound instead how stale a repository that comes back on its own (without anyone touching its scope) can get: the periodic pass then re-attempts it at most that long after the previous attempt. A value below the base is floored at the base (one pass at a time), never inert. Lowering the cap at runtime is not retroactive for delays already armed.

OPAL_SCOPES_STORE_READ_TIMEOUT​

Default: 10.0

Timeout for a scope-store read taken while holding a source's lock — the sibling check a delete/repoint purge runs before authorizing the fleet-wide cache purge. The Redis client is built without a socket timeout, so without this an unreachable store would pin that lock for the life of the process and block every later sync, purge and delete for the source. On expiry the sibling check fails open, and what that decides is the fleet-wide MEMORY purge only — the leader no longer touches the clone tree: a DELETE confirms it defensively (its record is already gone, so withholding would strand the fleet's cache entries, while over-purging self-heals on the surviving sibling's next sync), a REPOINT withholds it (the old source's record is still live, just moved). The clone dir is unaffected either way: on a store fault the delete floor KEEPS this worker's clone rather than risk deleting one a live sibling shares, leaving an orphan tracked by PER-15612 (0 or negative means no timeout).

OPAL_SCOPES_POLICY_CLONE_WAIT_SECONDS​

Default: 20.0

How long GET /scopes/:scope_id/policy holds a request while that scope's clone is still being populated, before falling through to the 503 + Retry-After it answers today. The route re-checks once a second and returns the bundle the moment the clone is usable. It exists because the opal-client PDP ignores Retry-After: it makes five attempts with random-exponential backoff capped at 10s (~20-40s of coverage) and then stays quiet until the next pub/sub policy message or a reconnect, so a clone that outlives those attempts strands that PDP with no policy — and the update-all published when a clone completes names only the scope that was syncing, so siblings sharing the same clone are not woken. Holding the request converts that gap into latency the client already tolerates: five client attempts against a 20s hold cover about two minutes of clone time, so short and medium re-clones — meaning the download phase; the rmtree-and-init window before it answers 503 + Retry-After 5 and is not waited on — produce no client-visible gap. What this bounds is the WAIT plus at most one more bundle attempt: time queued behind other bundle builds on the shared executor is outside the deadline, which is what SCOPES_POLICY_CLONE_WAIT_MAX_INFLIGHT bounds instead. The budget matters in both directions — 20s is well under the 60s ALB idle timeout (a longer hold surfaces as a 504, which the client cannot tell apart from a dead server) and far under the client's 300s aiohttp total timeout. Readiness is derived from DISK (the clone still has no remote-tracking refs), never from an in-process marker, so every worker answers alike: the clone runs in the leader while this route is served by any worker. The hold is an awaited sleep loop, so it occupies no thread between polls and leaves the event loop and the gunicorn worker heartbeat unaffected; it is abandoned early if the client disconnects. 0 or negative disables the wait (answer 503 immediately). nan, inf and -inf are treated as disabled too: unlike a non-numeric value, which fails this process at startup when the environment is parsed, they parse cleanly — inf would otherwise mean the clamped maximum hold on every clone-in-progress request, and nan is not a budget at all. Values above 55s are clamped to 55s so the hold can never outlive the load balancer's idle timeout.

OPAL_SCOPES_POLICY_CLONE_WAIT_MAX_INFLIGHT​

Default: 64

Maximum number of requests one worker process may hold at once inside the SCOPES_POLICY_CLONE_WAIT_SECONDS wait. Requests beyond the cap get the immediate 503 + Retry-After 30 they would have got before the wait existed, so the cap can never make things worse than not waiting. It exists because polling is cheap but RELEASING is not: when the clone lands, every held request builds a full bundle on the loop's DEFAULT executor: about min(32, cpu+4) threads shared by every off-loop call this process makes, in front of an unbounded queue. Measured throughput there falls from ~52 bundles/s at 32 concurrent builds to ~18/s at 1000. Scope git clone/fetch does NOT share that pool — each op runs on its own single-use daemon-thread executor, bounded by SCOPES_GIT_MAX_WORKERS through a semaphore — so this key is the only bound on how many bundle builds can pile up at once. Size it so the cap divided by the bundles-per-second that pod can really build fits inside the 60s ALB idle timeout MINUS the hold: above that, released requests queue past the timeout and 504 — the very failure the hold exists to prevent — and a rolling restart drains worse, because uvicorn waits for in-flight requests while gunicorn SIGKILLs the worker at 30s, dropping every websocket that worker still holds. The count is per process, not per pod: a pod running N workers holds up to N times this number. 0 or negative means no cap.

OPAL_LEADER_LOCK_FILE_PATH​

Default: /tmp/opal_server_leader.lock

Path to the leader lock file for distributed deployments.

OPAL_MAX_CHANNELS_PER_CLIENT​

Default: 15

Maximum number of records per client. After this number, it will not be added to statistics (relevant only if OPAL_STATISTICS_ENABLED is true).

OPAL_STATISTICS_WAKEUP_CHANNEL​

Default: __opal_stats_wakeup

The topic a waking-up OPAL server uses to notify others it needs their statistics data.

OPAL_STATISTICS_STATE_SYNC_CHANNEL​

Default: __opal_stats_state_sync

The topic other servers with statistics provide their state to a waking-up server.

OPAL_STATISTICS_SERVER_KEEPALIVE_CHANNEL​

Default: __opal_stats_server_keepalive

The topic workers use to signal they exist and are alive.

OPAL_STATISTICS_SERVER_KEEPALIVE_TIMEOUT​

Default: 20

Timeout for forgetting a server from which a keep-alive haven't been seen (keep-alive frequency would be half of this value).

Broadcasting Configuration​

OPAL_BROADCAST_URI​

Default: None

URI for the broadcast backend (Redis, PostgreSQL, etc.).

Postgres TCP keepalive (opal-server ≥ 0.9.9-rc.3 / permit-broadcaster ≥ 0.2.7): the Postgres backend enables TCP keepalive on every backbone connection by default (idle 30 s, interval 10 s, 3 lost probes → a silently vanished server — e.g. an RDS Multi-AZ failover — is detected within ~60 s instead of never). It can be tuned or disabled with libpq-style parameters in the URI: postgres://…/db?keepalives=1&keepalives_idle=30&keepalives_interval=10&keepalives_count=3 (keepalives=0 disables).

version constraint

Only set keepalives* parameters when every opal-server that shares this URI runs ≥ 0.9.9-rc.3. Earlier versions (permit-broadcaster ≤ 0.2.6) forward these parameters to Postgres as session settings, and Postgres rejects the connection with FATAL: unrecognized configuration parameter — a pod rolled back (or a canary slice still on the old image) would have zero backbone connectivity while its health checks stay green. The defaults require no URI change at all; only add the parameters once the fleet is uniformly upgraded.

Connection budget (Postgres backend): each worker process that holds a backbone reader opens a connection pool: 10 connections at boot (asyncpg's default min_size, not configurable downward via BROADCASTER_PG_MAX_POOL_SIZE, which only raises the ceiling), decaying to ~1 idle connection after ~300 s. Size the broadcast database's max_connections for 10 × workers × pods during a rolling restart, not for the steady state.

For more information, see running OPAL with Kafka and running OPAL with Apache Pulsar.

OPAL_BROADCAST_CHANNEL_NAME​

Default: EventNotifier

The channel name for broadcasting messages.

For more information, see running OPAL with Kafka and running OPAL with Apache Pulsar.

OPAL_BROADCAST_RECONNECT_ENABLED​

Default: True

Reconnect the broadcaster reader on a backbone disconnect instead of dropping all client connections. Set to False to revert to the legacy (non-reconnecting) broadcaster.

OPAL_BROADCAST_RECONNECT_MAX_RETRIES​

Default: 0

Maximum consecutive broadcaster reconnect attempts before giving up and letting the worker restart (0 = retry forever).

OPAL_BROADCAST_RECONNECT_BACKOFF_MIN_SECONDS​

Default: 0.5

Minimum backoff in seconds between broadcaster reconnect attempts.

OPAL_BROADCAST_RECONNECT_BACKOFF_MAX_SECONDS​

Default: 30.0

Maximum backoff in seconds between broadcaster reconnect attempts.

OPAL_BROADCAST_REPLAY_BUFFER_SIZE​

Default: 10000

Maximum number of outbound broadcasts buffered while the backbone is down and replayed on reconnect (0 disables buffering).

OPAL_BROADCAST_RESYNC_ON_RECONNECT​

Default: True

After a backbone gap that may have lost updates, force this worker's connected clients to reconnect so they re-fetch full policy + data state (guarantees cross-instance consistency).

OPAL_BROADCAST_RESYNC_SETTLE_SECONDS​

Default: 2.0

Grace period after a broadcaster reconnect before replaying buffered broadcasts and resyncing clients, to let peer servers re-subscribe.

OPAL_BROADCAST_HEALTHCHECK_ENABLED​

Default: True

Make /healthcheck reflect the broadcaster reader's health, so a Kubernetes readiness/liveness probe can route away from or restart a worker whose reader is wedged while clients depend on it.

OPAL_BROADCAST_KEEPALIVE_INTERVAL​

Default: 3600

The time to wait between sending two consecutive broadcaster keepalive messages, in seconds.

OPAL_BROADCAST_KEEPALIVE_TOPIC​

Default: __broadcast_session_keepalive__

The topic on which to send broadcaster keepalive messages.

OPAL_PUBLISHER_ENABLED​

Default: True

Enable the publisher for broadcasting updates.

OPAL_REDIS_URL​

Default: redis://localhost

Redis connection URL.

Authentication Configuration​

OPAL_AUTH_PRIVATE_KEY_FORMAT​

Default: PEM

Format of the private key. Options: PEM, JWK.

Read more about secure mode setup.

OPAL_AUTH_PRIVATE_KEY_PASSPHRASE​

Default: None

Passphrase for the private key (if encrypted).

Read more about secure mode setup.

OPAL_AUTH_PRIVATE_KEY​

Default: None

The private key for JWT signing.

Read more about secure mode setup.

OPAL_AUTH_JWKS_URL​

Default: /.well-known/jwks.json

URL to fetch JSON Web Key Set (JWKS).

Read more about secure mode setup.

OPAL_AUTH_JWKS_STATIC_DIR​

Default: ./jwks_dir

Directory containing static JWKS files.

Read more about secure mode setup.

OPAL_AUTH_MASTER_TOKEN​

Default: None

Master token for authentication (bypasses JWT verification).

Read more about secure mode setup.

Policy Configuration​

OPAL_POLICY_SOURCE_TYPE​

Default: GIT

Set your policy source type. Options: GIT, API.

For more information, see tracking a Git repository and tracking an API bundle server.

OPAL_POLICY_REPO_URL​

Default: None

Set your remote repository URL - relevant only for GIT source type. Example: https://github.com/permitio/opal-example-policy-repo.git.

For more information, see tracking a Git repository.

OPAL_POLICY_REPO_CLONE_PATH​

Default: ./regoclone

Base path to create local git folder for managing policy changes.

For more information, see tracking a Git repository.

OPAL_POLICY_REPO_CLONE_FOLDER_PREFIX​

Default: opal_repo_clone

Prefix for the local git folder.

OPAL_POLICY_REPO_REUSE_CLONE_PATH​

Default: False

Set if OPAL server should use a fixed clone path (and reuse if it already exists) instead of randomizing its suffix on each run.

OPAL_POLICY_REPO_MAIN_BRANCH​

Default: master

The main branch to track for policy files.

For more information, see tracking a Git repository.

OPAL_POLICY_REPO_SSH_KEY​

Default: None

SSH private key content for Git repository access.

For more information, see tracking a Git repository.

OPAL_POLICY_REPO_MANIFEST_PATH​

Default: ""

Path of the directory holding the '.manifest' file (updated way), or of the manifest file itself (old way). Repository root is used by default.

For more information, see tracking a Git repository.

OPAL_POLICY_REPO_CLONE_TIMEOUT​

Default: 0

Timeout for Git clone operations in seconds. If set to 0, waits indefinitely until successful clone.

OPAL_REPO_WATCHER_ENABLED​

Default: True

Enable repository watching for policy changes.

In scopes mode (OPAL_SCOPES=true) this same flag enables the scopes sync task on the leader worker: the boot-time sync of all scopes, the periodic sync_scopes pass when OPAL_POLICY_REFRESH_INTERVAL is greater than 0 (it defaults to 0, which skips the periodic pass), and the fleet-wide purge handler for deleted or repointed scopes. With it set to false in scopes mode, scopes are registered, preloaded and served but never re-synced or purged afterwards — the server logs a warning at startup when it detects this combination. Note that this flag does not gate the gunicorn master's pre-fork preload: every registered scope is still cloned/fetched once at every boot, so boot-time git traffic and clone-tree disk usage are expected even with the flag off.

OPAL_POLICY_REFRESH_INTERVAL​

Default: 0

Interval in seconds for refreshing policies. If set to 0, automatic refresh is disabled.

OPAL_POLICY_REPO_POLLING_INTERVAL​

Default: 0

Interval in seconds for polling the policy repository for changes. If set to 0, polling is disabled.

For more information, see tracking a Git repository.

OPAL_FILTER_FILE_EXTENSIONS​

Default: [".rego", ".json"]

List of file extensions to filter when processing policy files.

OPAL_BUNDLE_IGNORE​

Default: []

List of patterns to ignore in the bundle.

For more information, see tracking a Git repository.

OPAL_POLICY_BUNDLE_GIT_ADD_PATTERN​

Default: *

File pattern to add files to all git default files.

OPAL_POLICY_BUNDLE_URL​

Default: None

Set your API bundle URL - relevant only for API source type.

For more information, see tracking an API bundle server.

OPAL_POLICY_BUNDLE_SERVER_TYPE​

Default: HTTP

Type of policy bundle server. Options: HTTP (authenticated with bearer token), AWS-S3 (authenticated with AWS REST Auth).

For more information, see tracking an API bundle server.

OPAL_POLICY_BUNDLE_SERVER_TOKEN_ID​

Default: None

The Secret Token ID (AKA user ID, AKA access-key) sent to the API bundle server.

For more information, see tracking an API bundle server.

OPAL_POLICY_BUNDLE_SERVER_TOKEN​

Default: None

The Secret Token (AKA password, AKA secret-key) sent to the API bundle server.

For more information, see tracking an API bundle server.

OPAL_POLICY_BUNDLE_SERVER_AWS_REGION​

Default: us-east-1

The AWS region of the S3 bucket.

For more information, see tracking an API bundle server.

OPAL_POLICY_BUNDLE_TMP_PATH​

Default: /tmp/bundle.tar.gz

Path for temporary policy files. Must be writable.

OPAL_POLICY_REPO_WEBHOOK_SECRET​

Default: None

Secret for validating webhook requests from the policy repository.

For more information, see tracking a Git repository.

OPAL_POLICY_REPO_WEBHOOK_TOPIC​

Default: webhook

Topic for policy repository webhook events.

OPAL_POLICY_REPO_WEBHOOK_ENFORCE_BRANCH​

Default: False

Enforce webhook events only from a specific branch.

OPAL_POLICY_REPO_WEBHOOK_PARAMS​

Default:

{
"secret_header_name": "x-hub-signature-256",
"secret_type": "signature",
"secret_parsing_regex": "sha256=(.*)",
"event_header_name": "X-GitHub-Event",
"event_request_key": null,
"push_event_value": "push"
}

Additional parameters for webhook processing.

For more information, see tracking a Git repository.

OPAL_OPAL_POLICY_REPO_URL​

Default: None

note

DEPRECATED - Use OPAL_POLICY_REPO_URL instead.

The repository URL where the policy repository is located. Must be available from the machine running OPAL (prefer public internet addresses). Supported URI schemes: https:// and ssh (i.e., git@).

OPAL_OPAL_POLICY_REPO_SSH_KEY​

Default: None

note

DEPRECATED - Use OPAL_POLICY_REPO_SSH_KEY instead.

The content of the SSH private key. You will need to register the matching public key with your repository. The passed value must be the contents of the SSH key in one line (replace newlines with underscores, i.e., \n with _).

OPAL_OPAL_POLICY_REPO_CLONE_PATH​

Default: /tmp/opal_policy_repo

note

DEPRECATED - Use OPAL_POLICY_REPO_CLONE_PATH instead.

Where to clone the repository in your Docker filesystem (not important unless you mount a Docker volume).

OPAL_OPAL_POLICY_REPO_MAIN_BRANCH​

Default: main

note

DEPRECATED - Use OPAL_POLICY_REPO_MAIN_BRANCH instead.

Name of the git branch to track for policy files.

OPAL_OPAL_BUNDLE_IGNORE​

Default: []

note

DEPRECATED - Use OPAL_BUNDLE_IGNORE instead.

Paths to omit from policy bundle. List of glob-style paths, or paths without wildcards but ending with "/**" indicating a parent path (ignoring all under it).

Added in OPAL v0.5.0

Data Configuration​

OPAL_ALL_DATA_TOPIC​

Default: data

Top-level topic for data updates.

OPAL_ALL_DATA_ROUTE​

Default: /policy-data

Route for all data configuration.

OPAL_ALL_DATA_URL​

Default: http://localhost:7002/policy-data

URL for all data configuration (if you choose to have it all in one place).

OPAL_DATA_CONFIG_ROUTE​

Default: /data/config

URL to fetch the full basic configuration of data.

OPAL_DATA_CALLBACK_DEFAULT_ROUTE​

Default: /data/callback_report

Default route for data callbacks (exists as a sane default in case the user did not set OPAL_DEFAULT_UPDATE_CALLBACKS).

OPAL_DATA_CONFIG_SOURCES​

Default:

{
"config": {
"entries": [{
"url": "http://localhost:7002/policy-data",
"topics": ["data"]
}]
}
}

Configuration of data sources by topics.

For more information, see configuring external data sources and data source configuration.

OPAL_DATA_UPDATE_TRIGGER_ROUTE​

Default: /data/update

URL to trigger data update events.

For more information, see triggering data updates.

OPAL Client Configs​

These configuration variables are specific to the OPAL Client.

Client Configuration​

OPAL_SERVER_URL​

Default: http://localhost:7002

The URL of the OPAL server.

OPAL_SERVER_WS_URL​

Default: ws://localhost:7002/ws

The WebSocket URL of the OPAL server.

OPAL_SERVER_PUBSUB_URL​

Default: ws://localhost:7002/ws

The Pub/Sub URL of the OPAL server.

OPAL_CLIENT_TOKEN​

Default: THIS_IS_A_DEV_SECRET

The OPAL Server Auth Token.

For more information, see obtaining a JWT token.

OPAL_WAIT_ON_SERVER_LOAD​

Default: False

If set, client will wait for 200 response from server's loadlimit endpoint before starting background tasks.

OPAL_CLIENT_API_SERVER_WORKER_COUNT​

Default: 1

Worker count for the opal-client's internal server (when run using CLI).

OPAL_CLIENT_API_SERVER_HOST​

Default: 127.0.0.1

Address for the opal-client's internal server to bind to (when run using CLI).

OPAL_CLIENT_API_SERVER_PORT​

Default: 7000

Port for the opal-client's internal server to bind to (when run using CLI).

OPAL_KEEP_ALIVE_INTERVAL​

Default: 0

Interval in seconds for keep-alive messages.

OPAL_SCOPE_ID​

Default: default

Scope identifier for multi-tenancy.

For more information, see OPAL scopes.

OPAL_OPAL_CLIENT_STAT_ID​

Default: auto-generated

Unique client statistics identifier.

For more information, see monitoring OPAL.

OPAL_OFFLINE_MODE_ENABLED​

Default: False

If set, OPAL client will try to load policy store from backup file and operate even if server is unreachable. Ignored if OPAL_INLINE_OPA_ENABLED=False.

Added in OPAL v0.6.0

OPAL_STORE_BACKUP_PATH​

Default: /opal/backup/opa.json

Path to backup policy store's data to.

Added in OPAL v0.6.0

OPAL_STORE_BACKUP_INTERVAL​

Default: 60

Interval in seconds to backup policy store's data.

Added in OPAL v0.6.0

Policy Store Configuration​

OPAL_POLICY_STORE_TYPE​

Default: opa

Type of policy store to use. Options: opa, cedar.

For more information, see Cedar and OPAL.

OPAL_POLICY_STORE_URL​

Default: http://localhost:8181

The URL of the policy store (e.g., OPA agent).

OPAL_POLICY_STORE_AUTH_TYPE​

Default: none

The authentication method for connecting to the policy store. Options: none, oauth, token.

OPAL_POLICY_STORE_AUTH_TOKEN​

Default: None

The authentication (bearer) token OPAL client will use to authenticate against the policy store (i.e., OPA agent).

OPAL_POLICY_STORE_AUTH_OAUTH_SERVER​

Default: None

The authentication server OPAL client will use to authenticate against for retrieving the access token.

OPAL_POLICY_STORE_AUTH_OAUTH_CLIENT_ID​

Default: None

The client ID OPAL will use to authenticate against the OAuth server.

OPAL_POLICY_STORE_AUTH_OAUTH_CLIENT_SECRET​

Default: None

The client secret OPAL will use to authenticate against the OAuth server.

OPAL_POLICY_STORE_TLS_CLIENT_CERT​

Default: None

Path to the client certificate used for TLS authentication with the policy store.

Added in OPAL v0.7.2

OPAL_POLICY_STORE_TLS_CLIENT_KEY​

Default: None

Path to the client key used for TLS authentication with the policy store.

Added in OPAL v0.7.2

OPAL_POLICY_STORE_TLS_CA​

Default: None

Path to the file containing the CA certificate(s) used for TLS authentication with the policy store.

Added in OPAL v0.7.2

OPAL_EXCLUDE_POLICY_STORE_SECRETS​

Default: False

If set, policy store secrets will be excluded from the /policy-store/config route.

Added in OPAL v0.7.8

OPAL_POLICY_STORE_CONN_RETRY​

Default: {"retries": 3, "backoff_factor": 0.3}

Retry options when connecting to the policy store (i.e., the agent that handles the policy, e.g., OPA).

OPAL_POLICY_STORE_LIVENESS_PROBE_ENABLED​

Default: True

If enabled, OPAL Client periodically probes the policy store's health endpoint in a background task and factors the result into the /healthy HTTP response.

Without this probe, /healthy reflects only the success of the last server -> policy-store transaction, which can stay True even if OPA hangs, deadlocks, or stops accepting HTTP connections in steady state. With it enabled, supervisors that probe /healthy will see the client report unhealthy within one probe interval if the policy store becomes unresponsive, and recover automatically once it returns.

The /healthy endpoint itself remains O(1): the probe runs once per interval in the background and updates a cached flag — high-frequency /healthy polling does not translate into proportional load on the policy store.

OPAL_POLICY_STORE_LIVENESS_PROBE_INTERVAL_SECONDS​

Default: 10

Interval (in seconds) between background liveness probes against the policy store.

OPAL_POLICY_STORE_LIVENESS_PROBE_TIMEOUT_SECONDS​

Default: 2

Per-request HTTP timeout (in seconds) for liveness probes against the policy store. A probe that exceeds this timeout is treated as an unreachable sample.

OPAL_POLICY_STORE_POLICY_PATHS_TO_IGNORE​

Default: []

Which policy paths pushed to the client should be ignored. List of glob-style paths, or paths without wildcards but ending with "/**" indicating a parent path (ignoring all under it). Supports paths starting with '!' to force not ignoring them: a negated path always takes precedence.

OPAL_OPA_HEALTH_CHECK_POLICY_ENABLED​

Default: False

Should we load a special healthcheck policy into OPA that checks that OPA was synced correctly and is ready to answer authorization queries.

For more information, see monitoring OPAL.

OPAL_OPA_HEALTH_CHECK_TRANSACTION_LOG_PATH​

Default: system/opal/transactions

Path to OPA document that stores the OPA write transactions.

For more information, see monitoring OPAL.

OPAL_OPA_HEALTH_CHECK_POLICY_PATH​

Default: engine/healthcheck/opal.rego

Path to the custom healthcheck policy file.

For more information, see monitoring OPAL.

Inline Engines Configuration​

OPAL_INLINE_OPA_ENABLED​

Default: True

Whether OPAL should run OPA by itself in the same container.

OPAL_INLINE_OPA_EXEC_PATH​

Default: None

The path to the OPA executable. Defaults to searching for 'opa' binary in PATH if not specified.

OPAL_INLINE_OPA_CONFIG​

Default: {}

If inline OPA is enabled, the user can set the server configuration options that affect how OPA will start when running opa run --server inline. Watch escaping quotes.

OPAL_OPA_V0_COMPAT​

Default: True (for OPAL v0.9.x, will be changed to unconfigured in v0.10.0)

Set to true to enable OPA v0 compatibility mode (--v0-compatible flag). This setting merges with OPAL_INLINE_OPA_CONFIG.v0_compatible - if either is enabled, the flag will be added to OPA. This allows for easier migration from OPA v0 to OPA v1 by enabling the compatibility mode by default until everyone migrates.

OPAL_INLINE_OPA_LOG_FORMAT​

Default: none

The log format for inline OPA. Options: none, minimal, http, full.

OPAL_INLINE_CEDAR_ENABLED​

Default: True

Whether OPAL should run Cedar agent by itself in the same container.

Added in OPAL v0.7.0

For more information, see Cedar and OPAL.

OPAL_INLINE_CEDAR_EXEC_PATH​

Default: None

The path to the Cedar agent executable. Defaults to searching for 'cedar-agent' binary in PATH if not specified.

Added in OPAL v0.7.0

For more information, see Cedar and OPAL.

OPAL_INLINE_CEDAR_CONFIG​

Default: {}

If inline Cedar is enabled, provide options for running the Cedar agent.

Added in OPAL v0.7.0

For more information, see Cedar and OPAL.

OPAL_INLINE_CEDAR_LOG_FORMAT​

Default: none

The log format for inline Cedar. Options: none, minimal, http, full.

Added in OPAL v0.7.0

For more information, see Cedar and OPAL.

Policy Updates Configuration​

OPAL_POLICY_UPDATER_ENABLED​

Default: True

If set to FALSE, OPAL Client will not fetch policies or listen to policy updates.

OPAL_SPLIT_ROOT_DATA​

Default: False

Split writing data updates to root path.

OPAL_POLICY_SUBSCRIPTION_DIRS​

Default: ["."]

The directories in a policy repository to subscribe to for policy code (rego) modules.

For more information, see tracking a Git repository.

OPAL_POLICY_UPDATER_CONN_RETRY​

Default:

{
"wait_strategy": "random_exponential",
"max_wait": 10,
"attempts": 5,
"wait_time": 1
}

Retry options when connecting to the policy source (e.g., the policy bundle server).

Data Updates Configuration​

OPAL_DATA_UPDATER_ENABLED​

Default: True

If set to FALSE, OPAL Client will not listen to dynamic data updates.

OPAL_DATA_TOPICS​

Default: ["data"]

Data topics to subscribe to.

For more information, see subscribing to data topics.

OPAL_DEFAULT_DATA_SOURCES_CONFIG_URL​

Default: {SERVER_URL}/data/config

Default URL to fetch data configuration from.

For more information, see configuring external data sources.

OPAL_DEFAULT_DATA_URL​

Default: http://localhost:8000/policy-config

Default URL to fetch data from.

OPAL_SHOULD_REPORT_ON_DATA_UPDATES​

Default: False

Should the client report on updates to callbacks defined in OPAL_DEFAULT_UPDATE_CALLBACKS or within the given updates.

For more information, see monitoring OPAL.

OPAL_DEFAULT_UPDATE_CALLBACK_CONFIG​

Default:

{
"method": "POST",
"headers": {
"content-type": "application/json"
},
"process_data": false
}

Default configuration for update callbacks.

For more information, see monitoring OPAL.

OPAL_DEFAULT_UPDATE_CALLBACKS​

Default: {"callbacks": ["{SERVER_URL}/data/callback_report"]}

Where/how the client should report on the completion of data updates.

For more information, see monitoring OPAL.

OPAL_DATA_UPDATER_CONN_RETRY​

Default:

{
"wait_strategy": "random_exponential",
"max_wait": 10,
"attempts": 5,
"wait_time": 1
}

Retry options when connecting to the base data source (e.g., an external API server which returns data snapshot).

OPAL_DATA_STORE_CONN_RETRY​

Default: None

note

DEPRECATED - The old confusing name for OPAL_DATA_UPDATER_CONN_RETRY, kept for backwards compatibility.

Added in OPAL v0.7.5

Advanced Configuration Options​

CLI Help​

# View all options
opal-server --help
opal-client --help

# View specific command options
opal-server run --help
opal-client run --help

Kubernetes Deployment​

For Kubernetes deployments, see OPAL Helm Chart for Kubernetes.

Proxy Configuration​

For proxy configurations, see Setup OPAL Behind a Proxy.

Source Code​

Configuration Architecture​

OPAL's configuration is based on our very own Confi module, which in turn is based on Decouple, and adds complex value parsing with Pydantic, and command line arguments via Typer/Click.