Ir al contenido
↑↓Navigate↵SelectescClose

Provider Key and Registry Maintenance

Operator procedure for provider key enablement and registry artifact import

Esta página aún no está disponible en tu idioma.

Use this procedure for both the first provider enablement and every later provider-key or catalog update. It is an operator procedure, not a bootstrap script.

Two independent inputs are required before Nexus can route PTB traffic:

  1. A platform provider key lets Nexus authenticate to the upstream provider.
  2. A registry artifact supplies the provider’s models, capabilities, endpoints, and rates.

Loading a key does not make a model routable. Importing an artifact does not create a provider credential.

Run the nexus commands below in a short-lived, operator-owned CLI Job in the target namespace. The Job must have:

  • the same NEXUS_DATABASE_URL, NEXUS_TENANT_ID, and NEXUS_STATE_DIR as the deployed control plane;
  • the existing nexus-state PVC mounted at /var/lib/nexus, so the CLI uses the deployed KMS wrapping key;
  • a read-only mount for the approved artifact and registry verification key; and
  • a secret-manager projection for the provider key, available as a file or environment variable.

Do not run these commands in a long-lived application pod. Do not put provider secrets in Helm values, Git, shell arguments, or Job logs.

The examples assume:

Terminal window
export PROVIDER=openai
export PROVIDER_KEY_FILE=/var/run/secrets/provider/openai
export ARTIFACT=/work/artifacts/openai.json
export VERIFYING_KEY=/work/trust/registry-verifying-key.txt
export EXPECTED_KEY_ID=registry-production

Use a new Job name for each operation so its logs and audit record identify one change. The Kubernetes and OpenShift manifest is the same; OpenShift assigns the runtime UID through its restricted SCC.

For OpenShift, prefer the standalone runner in nexus-iac instead of authoring the Job manifest each time. It creates a hardened one-shot Job, streams its logs, and deletes it after completion. It accepts only references to pre-existing Secrets and ConfigMaps.

Terminal window
export NEXUS_NAMESPACE=nexus-platform
export NEXUS_TENANT_ID=tenant_...
export NEXUS_CLI_IMAGE=registry.example/nexus-cli@sha256:<digest>
# Load a key from a Secret whose data contains OPENAI_PLATFORM_API_KEY.
nexus-iac/scripts/openshift/nexus-cli.sh \
--provider-secret provider-openai -- \
credentials platform-keys set \
--provider openai \
--workspace ws_... \
--secret-env OPENAI_PLATFORM_API_KEY
# Plan an import from an immutable ConfigMap containing the artifact and trusted public key.
nexus-iac/scripts/openshift/nexus-cli.sh \
--registry-inputs-configmap registry-inputs-<artifact-digest> -- \
registry import /work/registry/openai.json --dry-run \
--expected-key-id registry-production \
--verifying-key-path /work/registry/registry-verifying-key.txt

Use --keep-job when retaining the completed Job is required for a change record. The invoking OpenShift identity needs namespace-scoped permission to create, get, watch, read logs from, and delete Jobs, and to read the referenced Secret, ConfigMap, and PVC metadata.

The example assumes the platform team has already delivered:

  • provider-openai, a namespace Secret containing OPENAI_PLATFORM_API_KEY;
  • registry-inputs-<artifact-digest>, an immutable ConfigMap containing openai.json and registry-verifying-key.txt; and
  • a digest-pinned Nexus CLI image and the existing nexus-state PVC.

Replace the image, tenant, workspace, secret names, and artifact ConfigMap name for the target:

apiVersion: batch/v1
kind: Job
metadata:
name: nexus-provider-key-openai-20260802
namespace: nexus-platform
labels:
app.kubernetes.io/name: nexus-cli
app.kubernetes.io/component: provider-maintenance
spec:
backoffLimit: 0
ttlSecondsAfterFinished: 3600
template:
metadata:
labels:
app.kubernetes.io/name: nexus-cli
app.kubernetes.io/component: provider-maintenance
spec:
restartPolicy: Never
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: cli
image: registry.example/nexus-cli@sha256:<digest>
command: ["/usr/local/bin/nexus"]
args:
- credentials
- platform-keys
- set
- --provider
- openai
- --workspace
- ws_...
- --label
- secret-version=<approved-version>
- --secret-env
- OPENAI_PLATFORM_API_KEY
envFrom:
- secretRef:
name: provider-openai
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: platform-postgres-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: platform-postgres-credentials
key: password
- name: NEXUS_DATABASE_URL
value: postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@platform-postgres:5432/nexus_control
- name: AUTH_DATABASE_URL
value: postgres://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@platform-postgres:5432/nexus_auth
- name: NEXUS_TENANT_ID
value: tenant_...
- name: NEXUS_STATE_DIR
value: /var/lib/nexus
volumeMounts:
- name: state
mountPath: /var/lib/nexus
- name: registry-inputs
mountPath: /work/registry
readOnly: true
resources:
requests:
cpu: 10m
memory: 32Mi
limits:
cpu: 500m
memory: 256Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: true
runAsNonRoot: true
volumes:
- name: state
persistentVolumeClaim:
claimName: nexus-state
- name: registry-inputs
configMap:
name: registry-inputs-<artifact-digest>

Create and inspect the key-operation Job:

Terminal window
kubectl apply -f provider-key-job.yaml
kubectl wait --for=condition=complete job/nexus-provider-key-openai-20260802 \
--namespace nexus-platform --timeout=5m
kubectl logs job/nexus-provider-key-openai-20260802 --namespace nexus-platform
# OpenShift uses the same manifest and commands:
oc apply -f provider-key-job.yaml
oc wait --for=condition=complete job/nexus-provider-key-openai-20260802 \
--namespace nexus-platform --timeout=5m
oc logs job/nexus-provider-key-openai-20260802 --namespace nexus-platform

For a registry import, copy the manifest, use a new Job name, remove envFrom, and replace args with the approved import command:

args:
- registry
- import
- /work/registry/openai.json
- --yes
- --expected-key-id
- registry-production
- --verifying-key-path
- /work/registry/registry-verifying-key.txt

Use the same Job shape for platform-keys rotate, platform-keys validate, registry import --dry-run, and registry models list; change only metadata.name and args.

For Docker Compose, the CLI profile starts the equivalent one-shot container on the Compose network:

Terminal window
# From nexus/. The artifact path is relative to the repository mounted at /workspace.
docker compose --env-file .env \
-f deploy/compose/docker-compose.yml -f deploy/compose/docker-compose.dev.yml \
--profile cli run --rm -i \
-e OPENAI_PLATFORM_API_KEY \
cli cargo run -p nexus-cli -- \
credentials platform-keys set \
--provider openai --workspace ws_... \
--secret-env OPENAI_PLATFORM_API_KEY

For the first load, set the intended scope:

Terminal window
nexus credentials platform-keys set \
--provider "$PROVIDER" \
--workspace ws_... \
--label "secret-version=<approved-version>" \
--secret-file "$PROVIDER_KEY_FILE"

For an ongoing secret rotation, update the existing key ID:

Terminal window
nexus credentials platform-keys rotate ppk_... \
--secret-file "$PROVIDER_KEY_FILE"

Verify the stored credential and inspect the active key:

Terminal window
nexus credentials platform-keys validate --provider "$PROVIDER"
nexus credentials platform-keys validate --id ppk_... --live
nexus credentials platform-keys list --provider "$PROVIDER" --workspace ws_...

--live probes OpenAI or Anthropic; other providers are decrypt-only. set revokes an active key at the same provider/scope before replacing it, while rotate keeps the same key ID and replaces its secret. The current CLI has no parallel active keys at one scope, so schedule the provider-side rotation window accordingly.

Use rm only to revoke a key after traffic is intentionally disabled or moved:

Terminal window
nexus credentials platform-keys rm ppk_...

These are PTB credentials. Tenant BYOK credentials use nexus credentials provider-keys.

Generate the artifact outside the cluster in a controlled build environment, not in the Nexus runtime. Keep the artifact, provenance, digest, and signature in the approved artifact store.

Terminal window
just registry-generate \
--generated-at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--artifact-id "provider-catalog-$(date -u +%Y%m%d)" \
--signing-key /secure/path/registry-signing-key.txt \
--key-id "$EXPECTED_KEY_ID" \
--output dist/catalogs
just registry-import "dist/catalogs/$PROVIDER.json" --check \
--expected-key-id "$EXPECTED_KEY_ID" \
--verifying-key-path /secure/path/registry-verifying-key.txt

For a custom or isolated source, build the same artifact from reviewed CSV inputs:

Terminal window
just registry-from-csv "$PROVIDER" catalog.csv rates.csv "dist/catalogs/$PROVIDER.json"

An artifact can give an existing adapter backend a distinct provider name. The name is the registry, credential, policy, billing, and telemetry identity; the typed provider remains the adapter backend. For example, an operator-authored xAI catalog can reuse the OpenAI-compatible adapter without adding a provider implementation:

Terminal window
nexus-registry-generator from-csv \
--provider openai \
--name xai \
--catalog xai-catalog.csv \
--rates xai-rates.csv \
--output dist/catalogs/xai.json
nexus registry import dist/catalogs/xai.json --yes
nexus credentials platform-keys set \
--provider xai \
--secret-env XAI_API_KEY \
--base-url https://api.x.ai/v1

After the import and the gateway’s next registry refresh, clients select the lane with a model string such as xai/grok-4.5. Custom names are one model-route segment: they cannot be empty, contain whitespace, /, or ,, use the reserved nexus name, or reuse a built-in provider name for a different backend. All models and rate cards under one custom name share the artifact’s backend.

Artifacts are complete provider snapshots. Any non-pinned endpoint absent from the next artifact is retired.

Copy or mount the exact approved artifact and verifying key into the CLI Job, then validate it again in the target context and produce the durable import plan:

Terminal window
nexus registry import "$ARTIFACT" --check \
--expected-key-id "$EXPECTED_KEY_ID" \
--verifying-key-path "$VERIFYING_KEY"
nexus registry import "$ARTIFACT" --dry-run --format json \
--expected-key-id "$EXPECTED_KEY_ID" \
--verifying-key-path "$VERIFYING_KEY"

Review the plan before applying it. Record the artifact SHA-256, signature key ID, provider, generation timestamp, and every retire or pricing/capability change. A hard-reject finding cannot be approved; correct the artifact and repeat the procedure.

Apply the same bytes that were planned:

Terminal window
nexus registry import "$ARTIFACT" \
--expected-key-id "$EXPECTED_KEY_ID" \
--verifying-key-path "$VERIFYING_KEY"

The command asks for confirmation. For a non-interactive operator Job, use --yes only after the review record identifies this exact artifact digest and plan:

Terminal window
nexus registry import "$ARTIFACT" --yes \
--expected-key-id "$EXPECTED_KEY_ID" \
--verifying-key-path "$VERIFYING_KEY"

Import is transactional and fails closed on altered artifacts, stale baselines, expired approvals, signature failures, or invalid pricing. Correct an applied registry update by importing a new compensating artifact; do not edit historical rate-card rows.

Terminal window
nexus registry models list
nexus credentials platform-keys list --provider "$PROVIDER"

Confirm the expected endpoint is eligible and that Gateway routing/telemetry shows successful provider traffic. Gateways poll committed registry state; no Gateway restart is required after an artifact import.

One canonical model may be served by several providers at once, each its own registry row with its own price. Two rules decide which one a request reaches:

  • A provider-pinned model string — openai/gpt-5.6-terra, bedrock-gov/gpt-5.1 — resolves that provider’s endpoint or fails with an unknown-provider error. No other provider is tried.
  • An unpinned model string — gpt-5.6-terra — fans out across every provider serving that model and orders the attempts cheapest first, using each endpoint’s own prompt plus completion rate.

Because ordering is by price alone, a row seeded with a placeholder or mistyped rate becomes the first attempt for every request that names its model. Check the seeded prices before enabling a provider, and read them back with nexus registry models list.

To keep an organization’s unpinned traffic off a provider entirely — reserving government capacity is the usual reason — add that provider to the organization’s provider disallow list. Disallowed providers are dropped from the candidate set before any credential is fetched, for pinned and unpinned requests alike.

The manual commands are identical in local Docker Compose; run them through the Compose CLI:

Terminal window
# From nexus/
just load-provider-keys
just cli registry import dist/catalogs/openai.json --dry-run
just cli registry import dist/catalogs/openai.json

The .env-based Docker Desktop and CRC helpers are for local testing only, not shared-cluster maintenance.