Skip to content

Rotate credentials and certificates

Renew the signing certificate to extend its validity without changing the key. Replace a certificate or key when you need a new identity. Run one change at a time, verify its consumers, then retire the previous value.

In the Console

Settings page What it does
TLS & trust Shows the browser certificate this Console serves and its expiry. Imports existing certificate/key pairs and trusted authorities.
Device packages Compares the certificate the live services present with the public iris-catalog.pem copy that onboarding hands to devices.
Certificates & keys Shows what each certificate protects, its status and expiry. Open the task you need; technical details and advanced changes start closed.

For routine signing expiry, select Renew signing certificate. Replacing the signing key is a separate advanced task. Scheduled key maintenance holds optional schedules and their history. Dates come from public server files; check the live connection separately after a certificate change.

See Renew the instruction signing certificate and Browser and telemetry credentials for those workflows. Installer-owned deployments also have deployment trust maintenance, including root approvals and backup recovery key changes. Use the procedures below without that scoped worker.

Rotate the management credential

The Console reaches server state over the management API on internal HTTPS port 9443. Both sides read the credential from mounted files, and each rereads its file on every request, so rotating the token needs no container restart on Docker. Kubernetes updates mounted Secret files asynchronously; the rollouts below force every pod to pick up the new values. Complete one rotation before starting the next.

Keep the credential in files

Never put it in server/.env, a Compose environment: entry, a URL, or a command argument.

On one Docker host

  1. Rotate it. The old value moves to previous.json, the new one to current.json. The two files must hold distinct values; the server rejects an alias before either rotation or retirement:
docker compose -f server/docker-compose.yml exec iris \
  iris-management-token rotate
  1. Open Inventory in the Console. The page loads.
  2. Retire the old value:
docker compose -f server/docker-compose.yml exec iris \
  iris-management-token retire-previous

On separate Docker hosts

  1. On the server host, run iris_server exec iris iris-management-token rotate. The new value lands in current.json in IRIS_TIER_AUTH_DIR, whose path is set in Install on separate Docker hosts.
  2. Copy that file to the Console host over verified SSH, under a temporary name in its IRIS_TIER_AUTH_DIR. Set owner 10001:10001 and mode 600, then rename it to current.json there.
  3. Open Inventory in the Console. The page loads.
  4. On the server host, run iris_server exec iris iris-management-token retire-previous and remove the temporary copies.

On Kubernetes

  1. Use the protected files from installation. Save the old token, then generate its replacement:
umask 077
cp /secure/path/management-current /secure/path/management-previous
openssl rand -hex 32 > /secure/path/management-current
kubectl -n iris create secret generic iris-tier-auth \
  --from-file=current=/secure/path/management-current \
  --from-file=previous=/secure/path/management-previous \
  --dry-run=client -o yaml | kubectl apply -f -
  1. Restart both Deployments and wait for them to become ready. Each pod's mounted current file holds the new token:
kubectl -n iris rollout restart deployment/iris-seed-server deployment/iris-console
kubectl -n iris rollout status deployment/iris-seed-server
kubectl -n iris rollout status deployment/iris-console
  1. Open Inventory in the Console. The page loads.
  2. Empty previous, apply the Secret again, and restart both Deployments:
: > /secure/path/management-previous
kubectl -n iris create secret generic iris-tier-auth \
  --from-file=current=/secure/path/management-current \
  --from-file=previous=/secure/path/management-previous \
  --dry-run=client -o yaml | kubectl apply -f -
kubectl -n iris rollout restart deployment/iris-seed-server deployment/iris-console

Rotate the certificate that devices trust

Every onboarding path delivers the current public certificate beside the package:

Platform Where the certificate lands
Guest Shell, where the agent runs on Catalyst 9000 series switches and Catalyst 8000 series routers With the other short-lived onboarding artifacts.
IOx, the alternative on Catalyst 9000 series switches with app-hosting storage and the path on Industrial Ethernet switches with app hosting In app-hosting application data, after activation and before the app starts.
IOS-XR appmgr on Cisco 8000 series routers, and on NCS-540 (package transfer, RPM checksum, registration, and app startup validated; image staging, telemetry and undeploy validation pending, and no other NCS model established) In harddisk:/iris-catalog.pem, read through the container's /hostmount bind mount.
  1. Publish the new certificate.
  2. Re-onboard every device: undeploy, then onboard. See Add and onboard devices.
  3. Check the certificate row on Settings → Device packages. No mismatch.

Onboarded agents keep the old certificate

A device you do not re-onboard still trusts the previous certificate.

Rotate the management certificate

The certificate must cover the exact DNS name or IP address the Console calls. Keep each certificate and key pair matched.

On separate Docker hosts

Same authority: replace the server's certificate and key together, then restart the server. New authority or new self-signed certificate:

  1. Add the replacement certificate or authority to the Console's ca.pem beside the current one.
  2. Restart the Console. It still reaches the server.
  3. Replace the server pair and restart the server.
  4. Open Inventory in the Console. The page loads.
  5. Remove the old trust entry and restart the Console again.

On Kubernetes

  1. Add the new issuing authority to iris-management-ca, retaining the old authority. Restart deployment/iris-console and wait for its rollout.
  2. Replace the pair in iris-management-tls. The certificate needs DNS subject names for iris-server-api, iris-server-api.iris, and iris-server-api.iris.svc.
  3. Restart deployment/iris-seed-server and wait for its rollout. The management listener loads its certificate when it starts.
  4. Open Inventory in the Console. Once it loads, remove the old authority from iris-management-ca, then restart the Console and wait for its rollout.

Run these rollouts with kubectl -n iris rollout restart deployment/<name> and wait with kubectl -n iris rollout status deployment/<name>. A replacement signed by the existing authority needs only the server steps.

The management private key goes only to the server

The Console receives the issuing authority alone.

Rotate the Console browser certificate

A certificate installed through Settings → TLS & trust takes precedence over the deployment default, and the card shows the identity the Console is serving. Use deployment default certificate returns to the default one. An encrypted private key asks for its passphrase and is stored encrypted at rest. Drop authority files to trust them, or pick a bundle source to trust a whole public bundle, which appears as one row you can remove again.

For separate Docker hosts, replace the Console host's default tls.crt and tls.key together and restart the Console. On Kubernetes, replace iris-console-tls, restart deployment/iris-console and wait for its rollout. The one-host stack obtains its default browser identity from the server; use the Settings override to replace the browser certificate there. See Find your way around the Console.

Protect browser private keys

Provisioned default keys for separate hosts and Kubernetes belong only on the Console. A Settings override is stored as gui-key.pem.age on the server and delivered to the Console's memory-backed runtime over authenticated HTTPS. Never put plaintext keys in a ConfigMap or an image.

Rotate the seeder announce credential

The seeder announces to the tracker with its own credential in an HTTPS authorization header. Rotation keeps the published torrent URLs and image hashes unchanged.

  1. Freeze maintenance for your layout.
  2. Run rotate-seeder-announce --maintenance-frozen. It exits zero only after the tracker proves the new identity is serving.
  3. Lift the freeze.

Preflight refuses, naming the reason on standard error, when an image has no torrent or its torrent is not uniquely active, when the announce base is not a usable HTTPS IPv4 endpoint, when durable encrypted secrets are missing, or when an earlier recovery manifest is still on disk. For proof, the command polls the tracker's authenticated, pinned-TLS /swarm and requires the current typed service:seeder principal for every torrent, announced after the adds; any other result fails closed. Every run first writes a non-secret recovery manifest of the pre-rotation torrent bytes, and --recover restores it.

A hard no-go can leave an image not being served

If a restore also fails, or a remove fails and live state is therefore unknown, the run becomes a hard no-go. The result lists every disturbed torrent; a false restore result means serving repair is still required for that image before you lift the freeze.

The rotated-out credential stays valid for 30 days, set by IRIS_SEEDER_PREV_TTL. At most two previous credentials can remain valid. Further rotation waits for one to expire; refreshing device torrents does not change this limit.

Rotate the metrics scrape token

Use the Console workflow for encrypted overrides and verified retirement. The following procedure applies only while credentials remain deployment-managed, without a Console override.

  1. Write the new raw value to a new private file. On Docker, give Compose its path; on Kubernetes, put it in current in the iris-observability-auth Secret.
  2. Keep the old value available while you update the scraper: on Docker through IRIS_OBSERVABILITY_PREVIOUS_TOKEN_FILE_HOST, on Kubernetes as previous.
  3. Update the collector or Prometheus credentials file. A scrape succeeds.
  4. Remove the old value. Scrapes keep working.

Keep both files as raw token values so Prometheus reads current as its credentials file. See Set up certificates and tokens.

Rotate the collector headers

Use the Console workflow for destination-bound overrides. Without an override, headers live in their own private file. Write the new value there and restart the server. On Kubernetes, re-apply the iris-otlp-headers Secret and restart the server Deployment. See Export telemetry.

Rotate the age recipients

This changes who can decrypt the stored configuration.

  1. Back up the encrypted configuration and the age identity. See Back up and restore.
  2. Stop configuration writers with the maintenance procedure for your layout.
  3. Set IRIS_AGE_RECIPIENTS to the full public recipient list, including the current service identity's public key, and persist it in the environment.
  4. Run iris-bootstrap --rekey in a server container with the same configuration volume and the current age identity mounted.
  5. Verify decryption with the intended identities, then retire the old recovery material.

Do not add --force

iris-bootstrap --rekey --force can discard state this procedure needs.

Rotate one device's instruction key

For a leaked instruction key on an otherwise honest device, run iris-instr-key rotate --no-overlap <device_id>. The device keeps the last policy it accepted, which the agent re-encrypts locally.

For device retirement or a compromise, run iris-revoke <device_id> instead. See Undeploy, retire and clean up devices.

Never rotate a key to spare a revoked device

A rotation never restores a revoked device. The server refuses its catalog access even when its last report says it runs an accepted policy.

Change the server's public address

The address appears in the certificate devices trust, the tracker announce URL, and the seeder endpoint. Reissue the certificate, publish it, re-onboard devices.

What you see

After you rotate How you know it worked
Management credential An authenticated Console request succeeds with the old value removed.
Device certificate The certificate row on Settings → Device packages stops reporting a mismatch, and re-onboarded devices report in.
Seeder announce credential The command exits zero, which happens only after the tracker proves the new identity is serving.

Edge cases

  • A quarantined image, an image that failed the Cisco hash check and is held back from devices, is skipped during a seeder rotation and its id is listed. Releasing it restarts seeding with the current credential. If every image is quarantined, the command refuses. See Publish and verify images.