# Issuer Directory Offline Kit Notes ## Purpose Operators bundling Stella Ops for fully disconnected environments must include the Issuer Directory service so VEX Lens, Excititor, and Policy Engine can resolve trusted issuers without reaching external registries. ## 1 · Bundle contents Include the following artefacts in your Offline Update Kit staging tree: | Path (within kit) | Source | Notes | | --- | --- | --- | | `images/issuer-directory-web.tar` | `registry.stella-ops.org/stellaops/issuer-directory-web` (digest from `deploy/releases/.yaml`) | Export with `crane pull --format=tar` or `skopeo copy docker://... oci:...`. | | `config/issuer-directory/issuer-directory.yaml` | `etc/issuer-directory.yaml` (customised) | Replace Authority issuer, tenant header, and log level as required. | | `config/issuer-directory/csaf-publishers.json` | `src/IssuerDirectory/StellaOps.IssuerDirectory/data/csaf-publishers.json` or regional override | Operators can edit before import to add private publishers. | | `secrets/issuer-directory/connection.env` | Secure secret store export (`ISSUER_DIRECTORY_MONGO_CONNECTION_STRING=`) | Encrypt at rest; Offline Kit importer places it in the Compose/Helm secret. | | `docs/issuer-directory/deployment.md` | `docs/modules/issuer-directory/operations/deployment.md` | Ship alongside kit documentation for operators. | > **Image digests:** Update `deploy/releases/2025.10-edge.yaml` (or the relevant manifest) with the exact digest before building the kit so `offline-manifest.json` can assert integrity. ## 2 · Compose (air-gapped) deployment 1. Load images locally on the target: ```bash docker load < images/issuer-directory-web.tar ``` 2. Copy Compose artefacts: ```bash cp deploy/compose/docker-compose.airgap.yaml . cp deploy/compose/env/airgap.env.example airgap.env cp secrets/issuer-directory/connection.env issuer-directory.mongo.env ``` 3. Update `airgap.env` with site-specific values (Authority issuer, tenant, ports) and remove outbound endpoints. 4. Bring up the service: ```bash docker compose \ --env-file airgap.env \ --env-file issuer-directory.mongo.env \ -f docker-compose.airgap.yaml up -d issuer-directory ``` 5. Verify via `curl -k https://issuer-directory.airgap.local:8447/health/live`. ## 3 · Kubernetes (air-gapped) deployment 1. Pre-load the OCI image into your local registry mirror and update `values-airgap.yaml` to reference it. 2. Apply the secret bundled in the kit: ```bash kubectl apply -f secrets/issuer-directory/connection-secret.yaml ``` (Generate this file during packaging with `kubectl create secret generic issuer-directory-secrets ... --dry-run=client -o yaml`.) 3. Install/upgrade the chart: ```bash helm upgrade --install stellaops deploy/helm/stellaops \ -f deploy/helm/stellaops/values-airgap.yaml \ --set services.issuer-directory.env.ISSUERDIRECTORY__AUTHORITY__ISSUER=https://authority.airgap.local/realms/stellaops ``` 4. Confirm `issuer_directory_changes_total` is visible in your offline Prometheus stack. ## 4 · Import workflow summary 1. Run `ops/offline-kit/build_offline_kit.py` with the additional artefacts noted above. 2. Sign the resulting tarball and manifest (Cosign) and record the SHA-256 in the release notes. 3. At the destination: ```bash stellaops-cli offline kit import \ --bundle stella-ops-offline-kit--airgap.tar.gz \ --destination /opt/stellaops/offline-kit ``` 4. Follow the Compose or Helm path depending on your topology. ## 5 · Post-import validation - [ ] `docker images | grep issuer-directory` (Compose) or `kubectl get deploy stellaops-issuer-directory` (Helm) shows the expected version. - [ ] `csaf-publishers.json` in the container matches the offline bundle (hash check). - [ ] `/issuer-directory/issuers` returns global seed issuers (requires token with `issuer-directory:read` scope). - [ ] Audit collection receives entries when you create/update issuers offline. - [ ] Offline kit manifest (`offline-manifest.json`) lists `images/issuer-directory-web.tar` and `config/issuer-directory/issuer-directory.yaml` with SHA-256 values you recorded during packaging.