- Add RateLimitConfig for configuration management with YAML binding support. - Introduce RateLimitDecision to encapsulate the result of rate limit checks. - Implement RateLimitMetrics for OpenTelemetry metrics tracking. - Create RateLimitMiddleware for enforcing rate limits on incoming requests. - Develop RateLimitService to orchestrate instance and environment rate limit checks. - Add RateLimitServiceCollectionExtensions for dependency injection registration.
5.8 KiB
5.8 KiB
Issuer Directory Backup & Restore
Scope
- Applies to: Issuer Directory when deployed via Docker Compose (
deploy/compose/docker-compose.*.yaml) or the Helm chart (deploy/helm/stellaops). - Artifacts covered: PostgreSQL database
issuer_directory, service configuration (etc/issuer-directory.yaml), CSAF seed file (data/csaf-publishers.json), and secret material for the PostgreSQL connection string. - Frequency: Take a hot backup before every upgrade and at least daily in production. Keep encrypted copies off-site/air-gapped according to your compliance program.
Inventory checklist
| Component | Location (Compose default) | Notes |
|---|---|---|
| PostgreSQL data | postgres-data volume (/var/lib/docker/volumes/.../postgres-data) |
Contains issuers, issuer_keys, issuer_trust_overrides, and issuer_audit tables in the issuer_directory schema. |
| Configuration | etc/issuer-directory.yaml |
Mounted read-only at /etc/issuer-directory.yaml inside the container. |
| CSAF seed file | src/IssuerDirectory/StellaOps.IssuerDirectory/data/csaf-publishers.json |
Ensure customised seeds are part of the backup; regenerate if you ship regional overrides. |
| PostgreSQL secret | .env entry ISSUER_DIRECTORY_POSTGRES_CONNECTION_STRING or secret store export |
Required to restore connectivity; treat as sensitive. |
Tip: Export the secret via
kubectl get secret issuer-directory-secrets -o yaml(sanitize before storage) or copy the Compose.envfile into an encrypted vault. For PostgreSQL credentials, consider usingpg_dumpwith connection info from environment variables.
Hot backup (no downtime)
- Create output directory
BACKUP_DIR=backup/issuer-directory/$(date +%Y-%m-%dT%H%M%S) mkdir -p "$BACKUP_DIR" - Dump PostgreSQL tables
For Kubernetes, run the same
docker compose -f deploy/compose/docker-compose.prod.yaml exec postgres \ pg_dump --format=custom --compress=9 \ --file=/dump/issuer-directory-$(date +%Y%m%dT%H%M%SZ).dump \ --schema=issuer_directory issuer_directory docker compose -f deploy/compose/docker-compose.prod.yaml cp \ postgres:/dump/issuer-directory-$(date +%Y%m%dT%H%M%SZ).dump "$BACKUP_DIR/"pg_dumpcommand inside thestellaops-postgrespod and copy the archive viakubectl cp. - Capture configuration and seeds
cp etc/issuer-directory.yaml "$BACKUP_DIR/" cp src/IssuerDirectory/StellaOps.IssuerDirectory/data/csaf-publishers.json "$BACKUP_DIR/" - Capture secrets
grep '^ISSUER_DIRECTORY_POSTGRES_CONNECTION_STRING=' dev.env > "$BACKUP_DIR/issuer-directory.postgres.secret" chmod 600 "$BACKUP_DIR/issuer-directory.postgres.secret" - Generate checksums and encrypt
(cd "$BACKUP_DIR" && sha256sum * > SHA256SUMS) tar czf "$BACKUP_DIR.tar.gz" -C "$BACKUP_DIR" . age -r you@example.org "$BACKUP_DIR.tar.gz" > "$BACKUP_DIR.tar.gz.age"
Cold backup (planned downtime)
- Notify stakeholders and pause automation calling the API.
- Stop services:
(For Helm:
docker compose -f deploy/compose/docker-compose.prod.yaml down issuer-directorykubectl scale deploy stellaops-issuer-directory --replicas=0.) - Snapshot volumes:
docker run --rm -v postgres-data:/data \ -v "$(pwd)":/backup busybox tar czf /backup/postgres-data-$(date +%Y%m%d).tar.gz -C /data . - Copy configuration, seeds, and secrets as in the hot backup.
- Restart services and confirm
/health/livereturns200 OK.
Restore procedure
- Provision clean volumes
- Compose:
docker volume rm postgres-data(optional) thendocker compose up -d postgres. - Helm: delete the PostgreSQL PVC or attach a fresh volume snapshot.
- Compose:
- Restore PostgreSQL
docker compose exec -T postgres \ pg_restore --format=custom --clean --if-exists \ --dbname=issuer_directory < issuer-directory-YYYYMMDDTHHMMSSZ.dump - Restore configuration/secrets
- Copy
issuer-directory.yamlintoetc/. - Reapply the secret:
kubectl apply -f issuer-directory-secret.yamlor repopulate.env.
- Copy
- Restore CSAF seeds (optional)
- If you maintain a customised seed file, copy it back before starting the container. Otherwise the bundled file will be used.
- Start services
docker compose up -d issuer-directory # or kubectl scale deploy stellaops-issuer-directory --replicas=1 - Validate
curl -fsSL https://localhost:8447/health/live- Issue an access token and list issuers to confirm results.
- Check PostgreSQL counts match expectations (
SELECT COUNT(*) FROM issuer_directory.issuers;, etc.). - Confirm Prometheus scrapes
issuer_directory_changes_totalandissuer_directory_key_operations_totalfor the tenants you restored.
Disaster recovery notes
- Retention: Maintain 30 daily + 12 monthly archives. Store copies in geographically separate, access-controlled vaults.
- Audit reconciliation: Ensure
issuer_auditentries cover the restore window; export them for compliance. - Seed replay: If the CSAF seed file was lost, set
ISSUER_DIRECTORY_SEED_CSAF=truefor the first restart to rehydrate the global tenant. - Testing: Run quarterly restore drills in a staging environment to validate procedure drift.
Verification checklist
/health/livereturns200 OK.- PostgreSQL tables (
issuers,issuer_keys,issuer_trust_overrides) have expected counts. issuer_directory_changes_total,issuer_directory_key_operations_total, andissuer_directory_key_validation_failures_totalmetrics resume within 1 minute.- Audit entries exist for post-restore CRUD activity.
- Client integrations (VEX Lens, Excititor) resolve issuers successfully.