Technical — OPA Config
The image that runs RAGA's OPA (Open Policy Agent) server along with its Rego policy. Unlike opa-auth/opa-data, this is not a custom HTTP service — the image simply wraps the official opa binary, the Infisical CLI, and the policy files, then runs opa run --server as orchestrated by the rest of the OPA subsystem.
Repository
| Key | Value |
|---|---|
| Git Remote | https://git.tlab.co.id/tarantula/tarantula-v2/opa-bun/opa-config.git |
| Active Branch | main |
git clone https://git.tlab.co.id/tarantula/tarantula-v2/opa-bun/opa-config.git
cd opa-configTech Stack
| Layer | Technology |
|---|---|
| Base Image | Alpine 3.20 |
| Policy Engine | OPA binary v1.5.1 (downloaded directly from the GitHub release during image build) |
| Policy Language | Rego |
| Secret Management | Infisical CLI (not the SDK) — run via infisical run --watch |
Environment Variables
There is no runtime .env file — running.sh reads bootstrap variables from the container environment, and the Infisical CLI injects the rest as environment variables into the opa run process.
| Variable | Description |
|---|---|
INFISICAL_CLIENT_ID | Universal Auth Client ID (required, checked at the start of running.sh) |
INFISICAL_CLIENT_SECRET | Universal Auth Client Secret (required) |
INFISICAL_PATH | Secrets path in Infisical |
INFISICAL_PROJECT_ID | Infisical project ID |
INFISICAL_ENVIRONMENT | Target environment (dev / staging / prod) |
JWT_SECRET | Declared in .env.example ("keep in sync with user-service") for the Rego policy to verify JWT signatures via opa.runtime()["env"]["JWT_SECRET"] |
File Structure
opa-config/
├── Dockerfile # Alpine + opa binary + Infisical CLI
├── running.sh # Entrypoint: Infisical login -> run `opa run --server`
├── config.yml # OPA server config (decision log, etc — currently disabled)
├── policy.rego # Active Rego policy (loaded by running.sh)
├── policy.old.rego # Previous policy variant (not loaded)
├── policy.new.v0.rego # Draft of the next policy variant (not loaded)
└── .env.exampleOnly
policy.regois loaded byrunning.sh(see the command below).policy.old.regoandpolicy.new.v0.regoexist in the repo as history/drafts and are not active at runtime.
Startup (running.sh)
# 1. Log in to Infisical using Universal Auth
export INFISICAL_TOKEN=$(infisical login \
--method=universal-auth \
--client-id="$INFISICAL_CLIENT_ID" \
--client-secret="$INFISICAL_CLIENT_SECRET" \
--silent --plain)
# 2. Run the OPA server with secrets injected as env vars,
# loading config, data, and policy from the /share volume
exec infisical run --watch --path="$INFISICAL_PATH" --projectId="$INFISICAL_PROJECT_ID" --env="$INFISICAL_ENVIRONMENT" -- \
opa run --log-level=debug --server --addr 0.0.0.0:8181 -c /share/config.yml /share/data.json /share/policy.rego--watch makes the Infisical CLI monitor secret changes and restart the opa run process on updates — so rotating a secret in Infisical doesn't require a manual redeploy, except for secrets hardcoded directly in a policy file (see the note below).
OPA Server Configuration (config.yml)
Currently the entire contents of config.yml are commented out — the OPA server runs with default settings (no decision log to an external service). If enabled, this configuration would send every authorization decision to a logger service (opa-logger-v2) for an audit trail:
# services:
# logger:
# url: http://opa-logger-v2:3000
# decision_logs:
# console: true
# service: logger
# reporting:
# min_delay_seconds: 0
# max_delay_seconds: 1Policy Decision Flow (policy.rego)
The verify_access policy receives input: { method, token, path } from opa-auth and evaluates it through the following rules:
| Rule | Function |
|---|---|
token | Verifies the JWT signature (HS256) then decodes its payload. Verification failure → is_token_valid: false. |
is_token_not_exp | True if token.payload.exp has not yet passed the current time. |
user_roles | Pulled from data.user_roles[token.payload.username] — data supplied by OPA Data. |
user_is_granted | Merges every grant from data.role_grants[role] for all of the user's roles. |
path_matches | Matches grant.path against input.path segment by segment, supporting a * wildcard on a single segment. |
user_cases | Grants whose method matches, status == true, and whose path matches. |
allow | true if: method is OPTIONS, or the path is /auth/login / /auth/refresh-token (whitelisted without a token), or (the token is not expired and at least one user_cases entry matches). |
Technical note: the currently active
policy.regoverifies the JWT signature with a secret that is hardcoded directly in the policy file, rather than read from theJWT_SECRETenvironment variable aspolicy.old.rego/policy.new.v0.regodo. As a result, rotatingJWT_SECRETin Infisical/user-service will not automatically be picked up by the currently active policy — this needs to be reconciled so the mechanism is consistent with the other two file variants.
Build & Run
docker build -t opa-config .
docker run -p 8181:8181 \
-v /host/share:/share \
-e INFISICAL_CLIENT_ID=... \
-e INFISICAL_CLIENT_SECRET=... \
-e INFISICAL_PATH=... \
-e INFISICAL_PROJECT_ID=... \
-e INFISICAL_ENVIRONMENT=dev \
opa-configThe
-v /host/share:/sharevolume is required and must match the volume used by OPA Data —config.yml,data.json, andpolicy.regoare all read from the/sharepath.