> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getbifrost.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Governance

> Seed virtual keys, budgets, rate limits, routing rules, and admin auth in config.json

The `governance` block lets you seed all governance resources directly in `config.json`. On startup, Bifrost loads these into the configuration store. This is the recommended approach for GitOps workflows where governance state is managed as code.

<Note>
  **Governance enforcement is always active** in OSS - you do not need a plugin entry to enable it. To require a virtual key on every inference request, set `client.enforce_auth_on_inference: true`. This is the global default, but a more specific inference-auth flag such as `governance.auth_config.disable_auth_on_inference` overrides it; if no specific override is set, `client.enforce_auth_on_inference` applies.
</Note>

***

## Admin Authentication

Protect the Bifrost dashboard and management API with username/password auth:

```json theme={null}
{
  "governance": {
    "auth_config": {
      "is_enabled": true,
      "admin_username": "env.BIFROST_ADMIN_USERNAME",
      "admin_password": "env.BIFROST_ADMIN_PASSWORD",
      "disable_auth_on_inference": false
    }
  }
}
```

| Field                       | Default | Description                                 |
| --------------------------- | ------- | ------------------------------------------- |
| `is_enabled`                | `false` | Enable admin username/password auth         |
| `admin_username`            | -       | Admin username (supports `env.` prefix)     |
| `admin_password`            | -       | Admin password (supports `env.` prefix)     |
| `disable_auth_on_inference` | `false` | Skip auth check on `/v1/*` inference routes |

***

## Virtual Keys

Virtual keys are issued to clients and act as scoped API tokens. Each key specifies which providers, models, and API keys the bearer is allowed to use.

```json theme={null}
{
  "governance": {
    "virtual_keys": [
      {
        "id": "vk-team-platform",
        "name": "platform-team",
        "value": "env.VK_PLATFORM_TEAM",
        "is_active": true,
        "provider_configs": [
          {
            "provider": "openai",
            "allowed_models": ["gpt-4o", "gpt-4o-mini"],
            "key_ids": ["*"],
            "weight": 1
          },
          {
            "provider": "anthropic",
            "allowed_models": ["*"],
            "key_ids": ["*"],
            "weight": 1
          }
        ]
      }
    ]
  }
}
```

### Virtual Key Fields

| Field              | Required | Description                                                                  |
| ------------------ | -------- | ---------------------------------------------------------------------------- |
| `id`               | Yes      | Unique virtual key ID (referenced by budgets / rate limits)                  |
| `name`             | Yes      | Human-readable name                                                          |
| `value`            | No       | The key token sent by clients (use `env.` prefix). Auto-generated if omitted |
| `is_active`        | No       | Default `true`. Set `false` to disable without deleting                      |
| `team_id`          | No       | Associate with a team (mutually exclusive with `customer_id`)                |
| `customer_id`      | No       | Associate with a customer                                                    |
| `rate_limit_id`    | No       | Attach a rate limit                                                          |
| `calendar_aligned` | No       | Snap budget resets to day/week/month/year boundaries                         |
| `provider_configs` | No       | Allowed provider/model/key combinations (empty = deny all)                   |

### Provider Config Fields

| Field            | Required | Description                                                                                                                     |
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `provider`       | Yes      | Provider name (e.g. `"openai"`)                                                                                                 |
| `allowed_models` | No       | Model allow-list. `["*"]` = all models; `[]` = deny all                                                                         |
| `key_ids`        | No       | Provider key names allowed for this VK. `["*"]` = all keys; `[]` = deny all. Use key `name` values (not UUIDs) in `config.json` |
| `weight`         | No       | Load-balancing weight when multiple provider configs are present                                                                |
| `rate_limit_id`  | No       | Attach a per-provider-config rate limit                                                                                         |

***

## Budgets

Budgets cap cumulative spend (in USD) for a virtual key or provider config over a rolling window:

```json theme={null}
{
  "governance": {
    "budgets": [
      {
        "id": "budget-platform-monthly",
        "max_limit": 500.00,
        "reset_duration": "1M",
        "virtual_key_id": "vk-team-platform"
      }
    ]
  }
}
```

| Field                | Required | Description                                                            |
| -------------------- | -------- | ---------------------------------------------------------------------- |
| `id`                 | Yes      | Unique budget ID                                                       |
| `max_limit`          | Yes      | Maximum spend in USD                                                   |
| `reset_duration`     | Yes      | Window length: `"30s"`, `"5m"`, `"1h"`, `"1d"`, `"1w"`, `"1M"`, `"1Y"` |
| `virtual_key_id`     | No       | Attach to a virtual key (mutually exclusive with `provider_config_id`) |
| `provider_config_id` | No       | Attach to a provider config ID                                         |

***

## Rate Limits

Rate limits cap requests or tokens over a rolling window:

```json theme={null}
{
  "governance": {
    "rate_limits": [
      {
        "id": "rl-platform-hourly",
        "request_max_limit": 1000,
        "request_reset_duration": "1h",
        "token_max_limit": 1000000,
        "token_reset_duration": "1h"
      }
    ]
  }
}
```

| Field                    | Required | Description                               |
| ------------------------ | -------- | ----------------------------------------- |
| `id`                     | Yes      | Unique rate limit ID                      |
| `request_max_limit`      | No       | Maximum requests in window                |
| `request_reset_duration` | No       | Window for request counter                |
| `token_max_limit`        | No       | Maximum tokens (input + output) in window |
| `token_reset_duration`   | No       | Window for token counter                  |

Attach a rate limit to a virtual key via `virtual_keys[].rate_limit_id`, or to a provider config via `virtual_keys[].provider_configs[].rate_limit_id`.

***

## Routing Rules

Routing rules dynamically select the provider and model for each request based on a [CEL](https://cel.dev) expression. They are evaluated in priority order before the request is dispatched.

```json theme={null}
{
  "governance": {
    "routing_rules": [
      {
        "id": "route-gpt4-to-azure",
        "name": "Redirect GPT-4o to Azure",
        "cel_expression": "request.model == 'gpt-4o'",
        "targets": [
          { "provider": "azure", "model": "gpt-4o", "weight": 1.0 }
        ]
      },
      {
        "id": "route-cost-split",
        "name": "Split traffic 70/30 between providers",
        "cel_expression": "true",
        "targets": [
          { "provider": "openai",    "weight": 0.7 },
          { "provider": "anthropic", "weight": 0.3 }
        ]
      }
    ]
  }
}
```

### Rule Fields

| Field            | Required    | Description                                                   |
| ---------------- | ----------- | ------------------------------------------------------------- |
| `id`             | Yes         | Unique rule ID                                                |
| `name`           | Yes         | Human-readable name                                           |
| `cel_expression` | No          | CEL expression. `"true"` matches every request                |
| `targets`        | Yes         | Weighted target list (weights must sum to `1.0`)              |
| `enabled`        | No          | Default `true`                                                |
| `priority`       | No          | Evaluation order within scope - lower numbers run first       |
| `scope`          | No          | `"global"` (default), `"team"`, `"customer"`, `"virtual_key"` |
| `scope_id`       | Conditional | Required when `scope` is not `"global"`                       |
| `chain_rule`     | No          | If `true`, re-evaluates the chain after this rule matches     |
| `fallbacks`      | No          | Ordered fallback provider list if primary target fails        |

### Target Fields

| Field      | Required | Description                                                   |
| ---------- | -------- | ------------------------------------------------------------- |
| `weight`   | Yes      | Fraction of traffic (all weights in a rule must sum to `1.0`) |
| `provider` | No       | Target provider. Omit to keep the incoming request's provider |
| `model`    | No       | Target model. Omit to keep the incoming request's model       |
| `key_id`   | No       | Pin a specific API key by name                                |

***

## Customers & Teams

Define organizational entities and attach budgets or rate limits to them:

```json theme={null}
{
  "governance": {
    "customers": [
      {
        "id": "customer-acme",
        "name": "Acme Corp",
        "budget_id": "budget-acme-monthly",
        "rate_limit_id": "rl-acme-hourly"
      }
    ],
    "teams": [
      {
        "id": "team-ml",
        "name": "ML Team",
        "customer_id": "customer-acme",
        "budget_id": "budget-team-ml"
      }
    ]
  }
}
```

***

## Full Governance Example

```json theme={null}
{
  "$schema": "https://www.getbifrost.ai/schema",
  "encryption_key": "env.BIFROST_ENCRYPTION_KEY",

  "client": {
    "enforce_auth_on_inference": true
  },

  "governance": {
    "auth_config": {
      "is_enabled": true,
      "admin_username": "env.BIFROST_ADMIN_USERNAME",
      "admin_password": "env.BIFROST_ADMIN_PASSWORD"
    },

    "budgets": [
      {
        "id": "budget-platform",
        "max_limit": 1000.00,
        "reset_duration": "1M",
        "virtual_key_id": "vk-platform"
      }
    ],

    "rate_limits": [
      {
        "id": "rl-platform",
        "request_max_limit": 5000,
        "request_reset_duration": "1h",
        "token_max_limit": 5000000,
        "token_reset_duration": "1h"
      }
    ],

    "virtual_keys": [
      {
        "id": "vk-platform",
        "name": "platform-key",
        "value": "env.VK_PLATFORM",
        "is_active": true,
        "rate_limit_id": "rl-platform",
        "provider_configs": [
          {
            "provider": "openai",
            "allowed_models": ["*"],
            "key_ids": ["*"],
            "weight": 1
          }
        ]
      }
    ],

    "routing_rules": [
      {
        "id": "fallback-to-anthropic",
        "name": "Fallback on error",
        "cel_expression": "true",
        "targets": [{ "provider": "openai", "weight": 1.0 }],
        "fallbacks": ["anthropic"]
      }
    ]
  },

  "providers": {
    "openai": {
      "keys": [{ "name": "openai-primary", "value": "env.OPENAI_API_KEY", "models": ["*"], "weight": 1.0 }]
    },
    "anthropic": {
      "keys": [{ "name": "anthropic-primary", "value": "env.ANTHROPIC_API_KEY", "models": ["*"], "weight": 1.0 }]
    }
  },

  "config_store": {
    "enabled": true,
    "type": "postgres",
    "config": {
      "host": "env.PG_HOST",
      "port": "5432",
      "user": "env.PG_USER",
      "password": "env.PG_PASSWORD",
      "db_name": "bifrost"
    }
  }
}
```
