Skip to content

Onboarding a workload

Excalibur identifies callers by principal kind. Pick the path that matches the workload; you do not have to install anything on the workload itself in any of them.

Path When Section
Service credential Long-lived servers, batch jobs, build runners, on-prem services §1 Service credential
SSH session identity Operators on jump hosts, interactive dev shells through your bastion §2 SSH session
Kubernetes attestation Pods that already have a projected service-account token §3 Kubernetes attestation
Developer-device Roaming engineers on managed laptops, identified by the NetBird overlay §4 Developer-device

All four end up the same way at runtime: every outbound HTTP request the workload makes carries a verifiable identity, and every audit event quotes a principal ID.


1. Service credential — long-lived servers

A service credential is an operator-minted token bound to a source network. The workload presents it as proxy authentication (Proxy-Authorization: Bearer …); the proxy refuses to let the same token authenticate from a different source IP.

Operator: mint the credential

excalibur-ctl service-credential create \
  --name   "ci-runner" \
  --user   ci \
  --source 10.0.0.0/8

Or via API:

curl -X POST http://localhost:8443/api/service-credentials \
  -H "Content-Type: application/json" \
  -d '{
        "name":            "ci-runner",
        "user":            "ci",
        "source_network":  "10.0.0.0/8",
        "allowed_domains": ["api.github.com","registry.npmjs.org"]
      }'

Or do it in the UI on the Sessions & Services page, in the Create service credential card at the bottom:

Sessions & Services page

The response includes a token value (shown once). Store that as a secret in the workload's deployment system the same way you store any other secret — but note that this token is a proxy bearer, not a provider bearer. The worst an attacker can do with it is authenticate to Excalibur from the configured source CIDR; they still need an applicable translation rule to redeem any placeholder.

Workload: present the credential

export HTTP_PROXY=http://excalibur:3128
export HTTPS_PROXY=http://excalibur:3128
export PROXY_AUTH="Bearer ${EXCALIBUR_SVC_TOKEN}"

curl -x "$HTTP_PROXY" \
     --proxy-header "Proxy-Authorization: $PROXY_AUTH" \
     -H "Authorization: Bearer XCALIBUR_GITHUB_TOKEN" \
     https://api.github.com/user

Verify

The credential appears in the Sessions & Services page under Service credentials, with columns ID, Name, User, Source, Allowed domains, Prefix, Created. Every flow it produces shows up on the Flows page with the principal column populated.

What gets recorded

Event When
service_credential_created Admin minted the credential
proxy_auth_ok / proxy_auth_denied On every CONNECT — denied if the source IP is outside the CIDR
flow_recorded Per outbound request, with the principal ID

If the same token authenticates from a different source IP, the proxy returns 407 Proxy Authentication Required, writes a proxy_auth_denied event with reason="source_network_mismatch", and revokes the credential automatically. See Responding to an incident for the full token-jack scenario.


2. SSH session identity

If your operators reach systems through Excalibur's SSH gateway, their session is their identity. Every HTTP request a shell in that session makes inherits the SSH principal automatically — no extra configuration on the workload.

Operator: SSH through Excalibur

ssh -p 2222 alice@excalibur.corp.example

You land on the configured target host. The SSH gateway records the session, optionally injects HTTP_PROXY / HTTPS_PROXY into the shell, and starts attributing every outbound HTTP request to user_session:alice@….

Verify

The session appears on the Sessions page with columns Session, User, Source, Started, State, plus a Revoke button (admin-only).

Active sessions

Switch to Audit and search for type=ssh_session_started to see the full session record. SFTP transfers are also logged.

Multi-target routing

A single Excalibur instance can route SSH to many backend hosts based on user identity and source network. See the SSH route table in the operator UI for the live rules.


3. Kubernetes attestation

Pods on Kubernetes already have a strong, platform-issued identity: the projected service-account token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token. Excalibur verifies it against the cluster's own JWKS, derives a principal from namespace/serviceaccount, and mints a short-lived proxy bearer.

Operator: configure once

Tell Excalibur which Kubernetes issuer to trust:

EXCALIBUR_K8S_ISSUER=https://kubernetes.default.svc
EXCALIBUR_K8S_CLUSTER=prod-eu-west
EXCALIBUR_K8S_JWKS_URL=https://kubernetes.default.svc/openid/v1/jwks

(Or use a static JWKS file via EXCALIBUR_K8S_JWKS_FILE.)

Optionally create a namespace for the workloads on the Fleet & Namespaces page, with an explicit allowed-domain list:

Fleet & namespaces

Workload: exchange the SA token

The workload performs one stock HTTP POST at startup (no Excalibur-specific code, no SDK, no sidecar). This is RFC 8693 token exchange:

SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

PROXY_TOKEN=$(curl -sf -X POST https://excalibur:8443/api/oauth/token \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
  --data-urlencode "subject_token=${SA_TOKEN}" \
  --data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:jwt' \
  --data-urlencode 'audience=https://excalibur.corp.example' \
  --data-urlencode 'scope=provider:github provider:stripe' \
  | jq -r .access_token)

export HTTPS_PROXY=https://excalibur:8443
curl --proxy-header "Proxy-Authorization: Bearer ${PROXY_TOKEN}" \
     -H "Authorization: Bearer XCALIBUR_GITHUB_TOKEN" \
     https://api.github.com/user

The minted PROXY_TOKEN is short-lived (its TTL never exceeds the service-account token's remaining lifetime, capped by your configured max_workload_token_ttl).

Verify

The pod appears on the Fleet & Namespaces page in the Workloads table with columns ID, Namespace, Principal, Attestation, Source, Token prefix, Created. The attestation column shows kubernetes.

What gets recorded

Event Details
workload_attested attestor=kubernetes, subject=ns/sa, cluster=…
workload_token_issued Token prefix, TTL, allowed scopes
workload_token_replay_denied If the same jti is presented twice within the token lifetime

4. Developer-device — NetBird overlay

For roaming engineers, real NetBird peer / group / route / policy state is ingested. A synced peer becomes a developer_device principal automatically; nothing else is required on the laptop.

Operator: connect Excalibur to your NetBird control plane

EXCALIBUR_NETBIRD_SYNC_URL=https://netbird.your.tld/api
EXCALIBUR_NETBIRD_SYNC_TOKEN=

The NetBird dashboard page shows sync status and the live peer list:

NetBird peers

What you get

  • Imported route ACLs derive per-peer allowed domains.
  • Imported network routes derive effective peer networks and default-route state.
  • DNS source policy is automatically populated.
  • Every flow from the peer is attributed to its developer_device:<peer-id> principal.

Combining with the rest of the model

Once a developer-device principal exists, it works exactly like any other principal: write a translation rule for it (Translation rules) and an egress policy for its namespace (Namespace egress). The dashboard does not treat overlay peers as a special case.


What's next