Skip to content

Authentication & Authorization

varTrack's CLI API (/v1/cli/*) is secured by a three-layer auth stack: OIDC for identity, RBAC for coarse-grained roles, and OPA for fine-grained policy. All three are optional — when absent, CLI routes are disabled.


Enabling auth

Auth is configured in the bundle under auth:

bundle: {
  auth: {
    oidc: {
      issuer_url: "https://accounts.google.com"
      client_id:  "my-client-id"
    }
    rbac: {
      policy: """
        p, role:admin,    *, *,         allow
        p, role:operator, datasource, sync,     allow
        p, role:operator, datasource, validate, allow
        p, role:operator, task,       get,      allow
        p, role:viewer,   datasource, validate, allow
        p, role:viewer,   task,       get,      allow

        g, alice@myorg.com, role:admin
        g, bob@myorg.com,   role:operator
      """
      default_role: "role:viewer"
    }
  }
}

OIDC — identity layer

varTrack validates the Authorization: Bearer <token> header against your OIDC provider. Any compliant provider works.

auth: {
  oidc: {
    issuer_url:   "https://accounts.google.com"  // required
    client_id:    "my-client-id"                 // required
    audience:     ""          // optional — defaults to client_id
    extra_scopes: []          // optional additional OAuth2 scopes
    groups_claim: "groups"    // JWT claim for group memberships
  }
}

Supported providers: Google, Azure AD / Entra ID, Okta, Auth0, Keycloak, GitLab, any OIDC-compliant provider.

The CLI logs in via vt login and stores the token locally. The token is sent as a Bearer header on every request.


RBAC — role layer (Casbin)

Casbin RBAC maps users and groups to roles, and roles to allowed actions.

auth: {
  rbac: {
    policy: """
      // Format: p, <role>, <resource>, <action>, allow
      p, role:admin,    *,          *,        allow
      p, role:operator, datasource, sync,     allow
      p, role:operator, datasource, validate, allow
      p, role:operator, task,       get,      allow
      p, role:viewer,   datasource, validate, allow
      p, role:viewer,   task,       get,      allow

      // Format: g, <email-or-group>, <role>
      g, alice@myorg.com,   role:admin
      g, bob@myorg.com,     role:operator
      g, platform-team,     role:operator    // group from groups_claim
    """
    default_role: "role:viewer"              // for users with no explicit assignment
  }
}

Resources: datasource, task, bundle, watcher

Actions: sync, validate, get, list, heal

The default_role applies to any authenticated user who has no explicit role assignment.


OPA — policy layer (Open Policy Agent)

OPA runs after RBAC for fine-grained decisions that RBAC can't express — e.g., "only allow syncing to production if the user's group is platform-team".

auth: {
  opa: {
    policy: """
      package vartrack.authz

      default allow = false

      allow {
        input.action == "sync"
        input.env    != "production"   // anyone can sync non-prod
      }

      allow {
        input.action == "sync"
        input.env    == "production"
        "platform-team" in input.user.groups   // only platform-team can sync prod
      }

      allow {
        input.action == "validate"     // everyone can validate
      }
    """
  }
}

OPA input document

Every request evaluation receives:

Field Example
input.user.sub "alice@myorg.com"
input.user.email "alice@myorg.com"
input.user.groups ["platform-team", "sre"]
input.action "sync"
input.resource "datasource"
input.datasource "mongo"
input.env "production"
input.file_path "configs/app.yaml"
input.tenant_id "acme"
input.dry_run false

OPA runs embedded (in-process, ~50µs) — no external OPA server required. To reload a policy without restarting, call POST /admin/opa/reload.

A full example policy is at examples/policies/vartrack_authz.rego.


Layer evaluation order

Request
OIDC validation       ← 401 if token invalid or expired
RBAC check            ← 403 if role doesn't allow action
OPA evaluation        ← 403 if policy returns false
Handler

All three must pass. OPA is skipped if no opa block is configured.