Quantum-Safe Cloud -- Part 7
The Quantum-Safe Reference Architecture
The Problem
Seven articles. Three products. Field-level encryption, quantum-safe secrets, ML-DSA authentication, signed CI/CD pipelines, mTLS between services.
If you’ve followed the series, you’ve applied each piece to a specific problem. What you don’t have yet is the full picture — how all the pieces work together, where each one sits in the architecture, and what the gaps are when you take this to a real multi-service system.
Most developers apply security piece by piece, problem by problem. They add a vault when a secret leaks. They add mTLS when there’s an incident. They think about post-quantum when a compliance audit asks about it. The result is a patchwork — secure in some places, fragile in others, and with gaps where the pieces don’t connect.
A reference architecture solves this. Not a diagram you put in a slide deck and forget — a concrete description of every layer, every component, and every decision, with the ATLAS structure behind it so you can adapt it to your system.
The Solution
The quantum-safe reference architecture has five layers:
- Perimeter: what the outside world touches. HTTPS, QuantumID OIDC, TLS 1.3.
- Identity: every actor (user, service, pipeline) proves who they are. QuantumID for users and services.
- Secrets: no secret lives in configuration or code. QuantumVault for all secret material.
- Data: sensitive data encrypted before storage. QuantumAPI EaaS at the repository layer.
- Transport: service-to-service communication encrypted and authenticated. mTLS with ML-DSA certificates.
Each layer is independent. A failure or compromise in one layer doesn’t automatically break the others. This is defence in depth — not just as a phrase, but as a design principle.
Execute
The ATLAS document
=== QUANTUM-SAFE REFERENCE ARCHITECTURE ===
[A] ARCHITECT
System: multi-service .NET platform on AKS (Azure Kubernetes Service).
Services used as example: users-api, notifications service, API gateway.
Security requirements:
- Secrets: zero secrets in code, config, or pipeline YAML
- Data at rest: PII fields encrypted before database storage
- Data in transit: TLS 1.3 externally, mTLS internally
- Authentication: quantum-safe token signing (ML-DSA)
- Pipeline: signed images, SBOM, secrets from vault at runtime
Post-quantum requirements:
- All key material: QRNG-generated, ML-KEM wrapped at rest
- All token signatures: ML-DSA-65
- All service certificates: ML-DSA-65, 24-hour validity
- All data encryption: ML-KEM-768 + AES-256-GCM hybrid
Out of scope:
- Key ceremony / root of trust (handled by QuantumAPI platform)
- Hardware security modules (QuantumAPI manages QRNG hardware)
- Compliance reporting automation (next series)
[T] TRACE
External user → API request:
1. DNS resolves to Azure Front Door (TLS termination, DDoS protection)
2. Front Door forwards to AKS ingress (nginx)
3. Ingress routes to API gateway pod
4. API gateway validates QuantumID token (JWKS from QuantumID)
5. Gateway routes to users-api pod
6. users-api fetches DB connection string from QuantumVault (if not cached)
7. users-api decrypts requested PII fields via QuantumAPI EaaS
8. Response back to user
Service-to-service (users-api → notifications):
1. users-api calls notifications.users-api.svc.cluster.local:8080
2. TCP allowed by NetworkPolicy (users-api → notifications)
3. TLS handshake: both sides present ML-DSA certificate
4. Both sides verify cert against QuantumAPI CA
5. Request forwarded; notifications service processes it
Pipeline (push to main):
1. Azure DevOps: qapi CLI fetches secrets from QuantumVault
2. Build → test → Trivy scan → docker push to ACR
3. Cosign: fetch ML-DSA signing key from QuantumVault → sign image
4. CycloneDX: generate SBOM → attach to image in ACR
5. Cosign: verify signature before kubectl deploy
6. kubectl rolling update → readiness probe gated
[L] LINK
| Component | Connects to | Protocol | Auth |
| ------------------ | ---------------- | ---------------- | ------------------------ |
| Browser | API Gateway | HTTPS / TLS 1.3 | QuantumID OIDC token |
| API Gateway | users-api | mTLS | ML-DSA cert from QA CA |
| users-api | PostgreSQL | Npgsql / TLS | Conn string from Vault |
| users-api | QuantumAPI EaaS | HTTPS | X-Api-Key (env var) |
| users-api | QuantumVault | HTTPS | X-Api-Key (env var) |
| users-api | QuantumID (JWKS) | HTTPS (read-only)| None (public endpoint) |
| users-api | notifications | mTLS | ML-DSA cert from QA CA |
| ADO pipeline | QuantumVault | HTTPS | Service account API key |
| ADO pipeline | ACR | HTTPS | Service connection |
| Cosign | ACR | OCI / HTTPS | ACR credentials |
| K8s pods | QuantumAPI CA | HTTPS | X-Api-Key (K8s Secret) |
Failure modes:
- QuantumAPI unreachable: secrets cached in memory for one request lifetime.
If unavailable at startup, pod fails readiness check → old pods stay up.
- QuantumID JWKS unreachable: .NET caches signing keys. Short outage handled.
- Certificate expired: CertificateRotationService renews at -4h before expiry.
- mTLS handshake failure: request rejected → 503 logged → alert triggers.
[A] ASSEMBLE
Phase 1: Foundation (applies once per environment)
- QuantumAPI account + tenant setup
- QuantumVault: create secrets for each service
- QuantumID: register each service as an application
- ACR: create signing key in QuantumVault, distribute CA cert to cluster
Phase 2: Service hardening (per service)
- Add QuantumAPI.Client NuGet
- IEncryptionService → QuantumApiEncryptionService
- ISecretProvider → QuantumVaultSecretProvider
- IServiceCertificateProvider → fetches ML-DSA cert from QuantumAPI CA
- Kestrel: ClientCertificateMode.RequireCertificate for internal endpoints
- HttpClient "internal": attach service cert, verify peer against CA
Phase 3: Pipeline (per repository)
- Install qapi CLI in pipeline
- Replace variable group secrets with QuantumVault IDs
- Add Cosign signing + verification stages
- Add CycloneDX SBOM generation
Phase 4: Cluster configuration
- NetworkPolicy per namespace
- Distribute QuantumAPI CA public cert to cluster ConfigMap
- RBAC: service accounts with minimum permissions
[S] STRESS-TEST
Scenario 1: Compromised pod
- Pod A is compromised. Attacker has pod A's ML-DSA certificate.
- Can they call services that pod A isn't allowed to call?
- NetworkPolicy blocks TCP. Even if they forge a cert, TCP is rejected first.
- Can they read data from PostgreSQL directly?
- NetworkPolicy: only users-api pods can reach the DB namespace.
- Attacker would need to compromise a users-api pod and use its cert.
Scenario 2: Leaked API key
- A QuantumAPI API key is leaked (committed to a public repo).
- Attacker calls QuantumVault: can read secrets that key has access to.
- Mitigation: scope API keys per service (minimum permissions).
- Recovery: revoke the key in QuantumVault dashboard. Issue new key.
- Damage: limited to what that key could read (not all tenants, not all secrets).
Scenario 3: Malicious image pushed to ACR
- Attacker with ACR write access pushes a malicious image with the same tag.
- Pipeline: Cosign verify step fails → deploy stage never runs.
- Manual deploy: engineer runs kubectl with the malicious image tag.
- Mitigation: Kubernetes admission webhook (Ratify) rejects unsigned images.
- This webhook is the missing piece — covered in the next series.
Scenario 4: Database backup leaked
- An unencrypted database backup ends up in a public storage container.
- Users table: EmailCiphertext, PhoneNumberCiphertext → ML-KEM ciphertext.
- Attacker needs the QuantumAPI private key to decrypt. That never leaves QA.
- Password hashes: Argon2id. Not decryptable.
- Non-PII fields (FirstName, LastName): plaintext. These should be assessed
for encryption too in regulated environments.
The reference diagram
graph TB
subgraph External["External"]
User["Browser / Client"]
Pipeline["Azure DevOps Pipeline"]
end
subgraph Azure["Azure"]
AFD["Azure Front Door\nTLS 1.3"]
ACR["Azure Container\nRegistry"]
end
subgraph QuantumAPI["quantumapi.eu"]
QV["QuantumVault\nML-KEM secrets"]
QE["EaaS\nML-KEM + AES-GCM"]
QI["QuantumID\nML-DSA OIDC"]
QCA["Certificate Authority\nML-DSA-65"]
end
subgraph AKS["AKS Cluster"]
subgraph NS_GW["namespace: gateway"]
GW["API Gateway\nmTLS client"]
end
subgraph NS_USERS["namespace: users-api"]
UA["users-api\nML-DSA cert"]
PG["PostgreSQL\nencrypted PII"]
end
subgraph NS_NOTIF["namespace: notifications"]
NOTIF["notifications\nML-DSA cert"]
end
subgraph NS_SYSTEM["namespace: system"]
NP["NetworkPolicy\nper namespace"]
end
end
User -->|"HTTPS + QuantumID token"| AFD
AFD -->|"route"| GW
GW -->|"mTLS\nML-DSA cert"| UA
UA -->|"mTLS\nML-DSA cert"| NOTIF
UA -->|"Npgsql TLS"| PG
UA -->|"X-Api-Key\nencrypt/decrypt PII"| QE
UA -->|"X-Api-Key\nget secrets"| QV
UA -->|"JWKS\nvalidate tokens"| QI
UA -->|"X-Api-Key\nget cert"| QCA
GW -->|"X-Api-Key\nget cert"| QCA
NOTIF -->|"X-Api-Key\nget cert"| QCA
Pipeline -->|"qapi CLI\nfetch secrets"| QV
Pipeline -->|"push image"| ACR
Pipeline -->|"Cosign sign\nML-DSA key from Vault"| ACR
GW -->|"pull image\nCosign verify"| ACR
NP -.->|"controls TCP"| NS_USERS
NP -.->|"controls TCP"| NS_NOTIF
style QuantumAPI fill:#1e3a5f,color:#fff
style QV fill:#2563eb,color:#fff
style QE fill:#2563eb,color:#fff
style QI fill:#2563eb,color:#fff
style QCA fill:#2563eb,color:#fff
style AKS fill:#0f172a,color:#fff
style External fill:#1f2937,color:#fff
style Azure fill:#1c3a5e,color:#fff
The GOTCHA prompt for the complete system
=== GOALS ===
Harden an existing .NET 10 microservices platform on AKS with:
- Post-quantum secrets management (QuantumVault)
- Field-level PII encryption (QuantumAPI EaaS, ML-KEM-768)
- Quantum-safe authentication (QuantumID, ML-DSA tokens)
- mTLS between services (QuantumAPI CA, ML-DSA-65 certs)
- Quantum-safe CI/CD (QuantumVault secrets, Cosign image signing)
=== ORCHESTRATION ===
Phase 1: Foundation
1. QuantumAPI tenant setup + service account API keys
2. QuantumVault: migrate all secrets from variable groups + appsettings
3. QuantumID: register all services as OIDC applications
Phase 2: Per service
4. Add QuantumAPI.Client NuGet
5. IEncryptionService → encrypt PII fields (Email, Phone, DOB)
6. ISecretProvider → connection strings + API keys from Vault
7. IServiceCertificateProvider → ML-DSA cert from QuantumAPI CA
8. Kestrel: require client cert on internal endpoints
9. HttpClient "internal": attach cert, verify peer
Phase 3: Pipeline
10. Install qapi CLI in ADO pipeline
11. Replace variable group secrets with qapi vault get calls
12. Add Cosign signing stage after docker push
13. Add CycloneDX SBOM stage after build
Phase 4: Cluster
14. NetworkPolicy per namespace (restrict ingress/egress)
15. Distribute QuantumAPI CA cert to cluster ConfigMap
=== TOOLS ===
- QuantumAPI.Client (NuGet)
- QuantumApiClient: Encryption, Vault, Certificates namespaces
- .NET 10: Kestrel, HttpClientFactory, BackgroundService
- Entity Framework Core + Npgsql (existing)
- qapi CLI (quantumapi.eu/cli)
- Cosign (image signing)
- CycloneDX (SBOM generation)
- kubectl + Azure DevOps YAML pipelines
=== CONTEXT ===
- Platform: AKS (Azure Kubernetes Service)
- Services: users-api, notifications, API gateway
- Database: PostgreSQL 16 per service
- CI/CD: Azure DevOps multi-stage YAML
- Existing: Trivy scanning, rolling deploys, variable groups (to be replaced)
- QuantumAPI tenant: quantumapi.eu (EU data residency)
=== HEURISTICS ===
DO:
- Resolve secrets at startup, cache for process lifetime (connection strings)
- Resolve certificates at startup, cache with IsExpiringSoon check
- Encrypt fields in parallel (Task.WhenAll)
- Use SHA3-256 for searchable hashes (email lookup)
- Mark all fetched secrets as issecret=true in Azure DevOps
- Verify image signature before kubectl apply
DON'T:
- Don't write private keys or decrypted secrets to disk
- Don't log decrypted field values
- Don't put QuantumAPI key in appsettings.json (environment variable only)
- Don't use the "internal" HttpClient for external API calls
- Don't skip NetworkPolicy — mTLS alone is not enough
=== ARGS ===
ML-KEM algorithm: ML-KEM-768 (default tenant key)
ML-DSA algorithm: ML-DSA-65 (service certificates)
Certificate validity: 24 hours
Certificate renewal threshold: 4 hours before expiry
Rotation check interval: 1 hour (BackgroundService)
SearchableEmail hash: SHA3-256, lowercase+trim input
qapi CLI version: pinned in pipeline (QAPI_VERSION variable)
Cosign: --exit-code 1 on verify failure
The checklist for production readiness
=== QUANTUM-SAFE PRODUCTION CHECKLIST ===
SECRETS
[ ] Zero connection strings in appsettings.json or variable groups
[ ] Zero secrets in pipeline YAML (only QUANTUMAPI_KEY remains in ADO)
[ ] git grep -r "password\|secret\|connectionstring" --include="*.json" → 0
[ ] QuantumVault audit log: verify app reads are appearing
DATA ENCRYPTION
[ ] PII fields in all services: EmailCiphertext, PhoneNumberCiphertext, etc.
[ ] SearchableEmail: SHA3-256 hash, indexed
[ ] Existing rows: encrypted via migration script
[ ] EaaS latency: p99 < 100ms (measure in staging)
AUTHENTICATION
[ ] QuantumID: all services registered as OIDC applications
[ ] .NET AddJwtBearer: authority = QuantumID, algorithm = ML-DSA
[ ] No custom JWT issuance anywhere in codebase
[ ] Token introspection: enabled for high-sensitivity operations
PIPELINE
[ ] Cosign: every image pushed to ACR is signed
[ ] Cosign verify: passes before every deploy
[ ] SBOM: attached as OCI attestation
[ ] No ADO secrets except QUANTUMAPI_KEY
CLUSTER
[ ] NetworkPolicy: ingress/egress restricted per namespace
[ ] mTLS: all internal services require client certs
[ ] CA cert: distributed to cluster as ConfigMap
[ ] Certificate rotation: BackgroundService running, logs expiry time
MONITORING
[ ] mTLS handshake failures: alert configured
[ ] Certificate expiry: alert if < 2 hours left (below rotation threshold)
[ ] QuantumVault: alert on read failures (secret unavailable)
[ ] QuantumID: JWKS fetch failures logged
What Comes Next
This series covered the security foundations. Post-quantum cryptography as the base. Three products — QuantumVault, EaaS, QuantumID — applied to real problems in real systems. Zero trust at the service layer. A pipeline that produces signed, attested, SBOM-annotated images.
There are two things we left open that belong in a next series:
Kubernetes admission control. Scenario 3 in the stress test exposed a gap: if an engineer manually deploys an unsigned image, nothing stops them. The fix is a Kubernetes admission webhook — Ratify with Cosign integration — that rejects pods with unsigned images at the cluster level. This belongs in a dedicated series on Kubernetes security hardening.
Compliance and audit. GDPR, NIS2, eIDAS 2.0 have specific requirements: data subject access requests, right to erasure, audit trails for key operations, breach notification timelines. QuantumVault has audit logs. QuantumID has session history. But turning those logs into compliance evidence requires a framework — automated DSAR responses, key operation reports, encryption coverage reports. That’s the next series.
If you want to be notified when either series starts, subscribe below.
Final Words
Security is often treated as a feature — something you add after the system works. “We’ll add encryption later.” “We’ll fix the secrets when we have time.”
This series is about the opposite approach: security as a design decision made before the first line of code. The ATLAS checklist forces you to think about secrets, authentication, and encryption in the design phase — not after a breach. GOTCHA structures those decisions into AI prompts that produce code matching your security requirements.
quantumAPI makes the post-quantum part practical. You don’t need to implement ML-KEM yourself. You don’t need to manage a hardware security module. You call an API. You get back quantum-safe cryptography backed by real QRNG hardware and NIST-standardised algorithms.
The harvest-now-decrypt-later threat is real. The NIST deadline is not theoretical. But the tools exist, the standards are published, and the migration is manageable if you start now.
The time to build a quantum-safe system is before the attackers have a quantum computer. That time is now.
See you in the next series.
Victor
If this series helps you, consider buying me a coffee.
Loading comments...