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
- Rotate it. The old value moves to
previous.json, the new one tocurrent.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
- Open Inventory in the Console. The page loads.
- Retire the old value:
docker compose -f server/docker-compose.yml exec iris \
iris-management-token retire-previous
On separate Docker hosts
- On the server host, run
iris_server exec iris iris-management-token rotate. The new value lands incurrent.jsoninIRIS_TIER_AUTH_DIR, whose path is set in Install on separate Docker hosts. - Copy that file to the Console host over verified SSH, under a temporary name
in its
IRIS_TIER_AUTH_DIR. Set owner10001:10001and mode 600, then rename it tocurrent.jsonthere. - Open Inventory in the Console. The page loads.
- On the server host, run
iris_server exec iris iris-management-token retire-previousand remove the temporary copies.
On Kubernetes
- 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 -
- Restart both Deployments and wait for them to become ready. Each pod's
mounted
currentfile 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
- Open Inventory in the Console. The page loads.
- 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. |
- Publish the new certificate.
- Re-onboard every device: undeploy, then onboard. See Add and onboard devices.
- 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:
- Add the replacement certificate or authority to the Console's
ca.pembeside the current one. - Restart the Console. It still reaches the server.
- Replace the server pair and restart the server.
- Open Inventory in the Console. The page loads.
- Remove the old trust entry and restart the Console again.
On Kubernetes
- Add the new issuing authority to
iris-management-ca, retaining the old authority. Restartdeployment/iris-consoleand wait for its rollout. - Replace the pair in
iris-management-tls. The certificate needs DNS subject names foriris-server-api,iris-server-api.iris, andiris-server-api.iris.svc. - Restart
deployment/iris-seed-serverand wait for its rollout. The management listener loads its certificate when it starts. - 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.
- Freeze maintenance for your layout.
- Run
rotate-seeder-announce --maintenance-frozen. It exits zero only after the tracker proves the new identity is serving. - 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.
- Write the new raw value to a new private file. On Docker, give Compose its
path; on Kubernetes, put it in
currentin theiris-observability-authSecret. - Keep the old value available while you update the scraper: on Docker through
IRIS_OBSERVABILITY_PREVIOUS_TOKEN_FILE_HOST, on Kubernetes asprevious. - Update the collector or Prometheus credentials file. A scrape succeeds.
- 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.
- Back up the encrypted configuration and the age identity. See Back up and restore.
- Stop configuration writers with the maintenance procedure for your layout.
- Set
IRIS_AGE_RECIPIENTSto the full public recipient list, including the current service identity's public key, and persist it in the environment. - Run
iris-bootstrap --rekeyin a server container with the same configuration volume and the current age identity mounted. - 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.