# Configuration examples

Adapt the excerpts below into the `gateway.yaml` supplied in the release archive, then validate it before use:

```
/opt/particle_horizon/keystone-gateway config validate --config /opt/particle_horizon/local_config/keystone-gateway/gateway.yaml
```

## Standalone

Use the complete configuration in [standalone installation](https://portal.cjcit.io/knowledge-base/keystone_gateway/0.2/deployment/standalone/). For production TLS, enable `api.https`, set its TLS files, use `api.auth.mode: mtls`, and disable `api.http`.

## Multiple caller principals

The fixed fields under `api.auth` support only the one shared principal used by `mode: none`. For multiple installations or both product types, select a mapping-based mode. This mTLS excerpt points the Gateway at a separate principal mapping file:

```
api:
  auth:
    mode: mtls
  https:
    enabled: true
    listen: "0.0.0.0:8443"
    advertise_url: "https://gateway-a.internal:8443"
    server_cert_file: /opt/particle_horizon/local_config/keystone-gateway/server.crt
    server_key_file: /opt/particle_horizon/local_config/keystone-gateway/server.key
    client_ca_file: /opt/particle_horizon/local_config/keystone-gateway/client-ca.crt
    principal_mappings_file: /opt/particle_horizon/local_config/keystone-gateway/principals.yaml
  http:
    enabled: false
```

```
# /opt/particle_horizon/local_config/keystone-gateway/principals.yaml
principals:
  - common_name: product-phocol-01
    principal_id: product-phocol-01
    allowed_license_type: phocol
    operator: false
  - common_name: product-lmc-exporter-01
    principal_id: product-lmc-exporter-01
    allowed_license_type: lmc_exporter
    operator: false
```

Each entry permits exactly one product license type. Add entries for additional installations; the mapping document has a 1 MiB total size limit rather than a fixed entry-count limit. See [client authentication](https://portal.cjcit.io/knowledge-base/keystone_gateway/0.2/security/deployment-security/#configure-client-authentication) for bearer mappings, validation constraints, and endpoint visibility.

## HA A-side

A complete Active/Standby configuration for replica A. Both replicas share `gateway_id`, the state-encryption key, and a signed license listing both replica IDs; everything else is per-replica. `storage.peer.replica_id` names the _other_ replica, and the peer channels are private to the pair — publish only the client listener.

```
gateway_id: gw-acme-production
api:
  http:
    enabled: true
    listen: "10.20.0.10:8080"
    advertise_url: "http://gateway-a.internal:8080"
    allow_insecure_http: true
  auth:
    mode: none
    principal_id: local-operator
    allowed_license_type: phocol
    operator: true
storage:
  directory: /opt/particle_horizon/local_data/keystone-gateway/state
  encryption_key_file: /opt/particle_horizon/local_config/keystone-gateway/state.key
  peer:
    replica_id: gateway-b
    listen: "10.20.0.10:9443"
    target: "10.20.0.11:9443"
    reconcile_listen: "10.20.0.10:9543"
    reconcile_target: "10.20.0.11:9543"
    tls:
      cert_file: /opt/particle_horizon/local_config/keystone-gateway/peer.crt
      key_file: /opt/particle_horizon/local_config/keystone-gateway/peer.key
      ca_file: /opt/particle_horizon/local_config/keystone-gateway/peer-ca.crt
license: { file: /opt/particle_horizon/local_config/keystone-gateway/gateway-license.json }
ha: { enabled: true, replica_id: gateway-a, bootstrap_expect: 2, peer_loss_timeout_seconds: 5 }
leases: { default_ttl_seconds: 120, min_ttl_seconds: 30, max_ttl_seconds: 300, max_clock_skew_seconds: 5, expiry_sweep_seconds: 15 }
reports: { directory: /opt/particle_horizon/local_data/keystone-gateway/reports, retention_days: 90 }
logging: { level: info, format: json }
```

Peer traffic always uses mutual TLS: each certificate must chain to `ca_file`, carry a CN matching the peer identity configured on the other node, and carry a SAN matching the address that node targets. This example uses a private HTTP client listener for brevity; for production TLS, enable `api.https`, set its TLS files, use `api.auth.mode: mtls`, and disable `api.http`.

## HA B-side delta

Copy the A-side configuration above, then swap all local and target peer values, update the client address, and set unique replica IDs:

```
api:
  http: { enabled: true, listen: "10.20.0.11:8080", advertise_url: "http://gateway-b.internal:8080", allow_insecure_http: true }
storage:
  peer:
    replica_id: gateway-a
    listen: "10.20.0.11:9443"
    target: "10.20.0.10:9443"
    reconcile_listen: "10.20.0.11:9543"
    reconcile_target: "10.20.0.10:9543"
ha: { enabled: true, replica_id: gateway-b, bootstrap_expect: 2, peer_loss_timeout_seconds: 5 }
```

## Telemetry and air gap

```
telemetry:
  enabled: true
  protocol: grpc
  otlp_endpoint: "https://otel-collector.internal:4317"
  ca_file: /opt/particle_horizon/local_config/keystone-gateway/otel-ca.crt
  export_timeout_seconds: 10
```

For air-gapped use, omit `telemetry` or set `enabled: false`; no external connectivity is needed for license verification or leasing.
