GE Production Deployment Architecture¶
1. Overview¶
GE operates as a fully autonomous AI-managed software development and hosting agency — 66 AI agents develop code, CI validates, and agents deploy. No human developers. This creates unique requirements: every operator is an AI, every action must be verifiable, and client environments must be completely isolated from each other and from GE's internal operations.
Scope boundary — what runs where: - fort-knox-dev (Minisforum): GE internal operations — admin-ui, orchestrator, agent executor, wiki, GitLab, all AI agent workloads. This is the development environment. - UpCloud: Client-facing infrastructure ONLY — commercial website, client-facing API, portals (compliance, monitoring, auth), and client project workloads. NO GE agents, NO admin-ui, NO orchestrator.
Providers (EU-only policy): - UpCloud (Helsinki, Finland) — Compute, Managed Kubernetes, Managed Databases, Object Storage - bunny.net (Ljubljana, Slovenia) — CDN, DNS, WAF/DDoS, Edge Storage, Edge Scripting - TransIP (Leiden, Netherlands) — Domain registration only (registrar for growing-europe.com) - Zitadel (Switzerland, self-hosted) — Multi-tenant auth for client applications (opt-in)
Design principles:
- Immutable infrastructure — replace, never patch
- Zero-trust networking — mTLS between every service, no VPN needed
- GitOps only — agents push to Git, ArgoCD deploys. Zero kubectl access in production
- Defense in depth — every layer assumes the layer above is compromised
- Per-client isolation — every client project in its own namespace with own database, own Redis, own CDN zone
2. Environment Model¶
fort-knox-dev (Dual Role)¶
fort-knox-dev serves two purposes: - Production for GE internal operations (admin-ui, orchestrator, executor, wiki, monitoring) - Staging for client projects (each client project is developed and tested here before promotion)
Only one application is exposed to the internet: office.growing-europe.com (admin-ui).
Everything else remains internal. Data needed by external services routes outward via APIs.
Internet Exposure¶
| Service | Exposed? | URL | Notes |
|---|---|---|---|
| Admin-UI | Yes | office.growing-europe.com | Only internet-facing GE service |
| Wiki (MkDocs) | No | Internal only | LAN access via NodePort 30080 |
| GitLab | No | Internal only | k3s internal |
| Vault | No | Internal only | k3s internal |
| Redis | No | Internal only | k3s internal |
| Client projects (staging) | No | Internal only | fort-knox-dev only |
| Client projects (production) | Yes | *.hosting.growing-europe.com | Via bunny.net CDN on UpCloud |
Promotion Pipeline¶
fort-knox-dev (k3s) ──[45 CI checks]──> UpCloud Acceptance ──[client approval]──> UpCloud Production
Development + Client reviews Live traffic
Client staging DAST + soak tests via bunny.net CDN
| Lane | Infrastructure | Gate to Next | Who Approves |
|---|---|---|---|
| Development | fort-knox-dev k3s | 45 CI checks green (FAST+STANDARD+FULL) | Automated |
| Acceptance | UpCloud Managed K8s (Frankfurt) | DAST scan + soak test + client sign-off | Client (via portal) or Dirk-Jan |
| Production | UpCloud Managed K8s (Frankfurt) | N/A — monitored, auto-rollback | N/A |
Key: The exact same container image built on fort-knox-dev is promoted immutably through each lane. Never rebuild per environment.
3. Client Isolation Architecture¶
Namespace-as-a-Service Model¶
Every client project gets its own isolated environment. This is the Kubernetes multi-tenancy gold standard for managed hosting.
┌─── UpCloud Managed K8s ───────────────────────────────────┐
│ │
│ ┌─── ge-system (GE Platform) ─────────────────────────┐ │
│ │ Vault, ArgoCD, Prometheus, Grafana, Loki │ │
│ │ Zitadel, Compliance Engine, OTel Collector │ │
│ │ PriorityClass: system-critical │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌─── client-acme-corp ────┐ ┌─── client-bakkerij ────┐ │
│ │ App pods │ │ App pods │ │
│ │ Own managed PostgreSQL │ │ Own managed PostgreSQL │ │
│ │ Own managed Redis │ │ Own managed Redis │ │
│ │ OTel sidecar → GE │ │ OTel sidecar → GE │ │
│ │ NetworkPolicy: deny-all │ │ NetworkPolicy: deny-all │ │
│ │ ResourceQuota: enforced │ │ ResourceQuota: enforced │ │
│ │ PriorityClass: client │ │ PriorityClass: client │ │
│ └──────────────────────────┘ └──────────────────────────┘ │
│ │
│ Clients CANNOT see each other. Clients CANNOT see GE. │
│ GE CAN observe and manage all client namespaces. │
└───────────────────────────────────────────────────────────┘
Per-Client Resources¶
| Resource | Per-Client? | Provider | Notes |
|---|---|---|---|
| Kubernetes namespace | Yes | UpCloud MKE | Isolation boundary |
| PostgreSQL database | Yes | UpCloud Managed DB | Separate instance, not shared schema |
| Valkey instance | Yes | UpCloud Managed Valkey | Separate instance (Redis wire-compatible) |
| Object Storage bucket | Yes | UpCloud Object Storage | Client assets, backups |
| CDN pull zone | Yes | bunny.net | EU-only routing, per-client WAF |
| DNS records | Yes | bunny.net DNS (hosting.*) | Auto-provisioned |
| SSL certificate | Yes | Let's Encrypt (auto) | Custom cert upload supported |
| Zitadel organization | Yes (opt-in) | Self-hosted Zitadel | Only if client needs auth |
| NetworkPolicy | Yes | K8s native | Default-deny, explicit allow |
| ResourceQuota | Yes | K8s native | CPU/memory/storage caps |
| ServiceAccount | Yes | K8s RBAC | Namespace-scoped only |
| HPA | Yes | K8s native | Per-client auto-scaling |
Per-Client Cost Estimate¶
| Component | Monthly Cost |
|---|---|
| UpCloud Managed PostgreSQL (starter) | ~€15-20 |
| UpCloud Managed Valkey (starter) | ~€10-15 |
| Namespace compute (shared node pool) | ~€5-15 (based on quotas) |
| bunny.net CDN pull zone | ~€0.06+ (traffic-based) |
| bunny.net Shield Basic | Free |
| Object Storage | ~€1-5 |
| Per-client total | ~€30-60/mo |
Enterprises who want Shield Advanced (+€9.50/zone), larger DB plans, or dedicated nodes pay more.
4. GE Managed Services (Platform Layer)¶
GE offers managed services that sit OUTSIDE client containers. Clients opt in. Data flows one direction: client app → GE platform.
Service Catalog¶
| Service | What It Does | How It Works | Opt-in? |
|---|---|---|---|
| Monitoring | Metrics, logs, alerts, dashboards | OpenTelemetry → Prometheus + Loki + Grafana | Default on |
| Compliance | GDPR evidence, audit trail, data processing records | GE SDK markers → Compliance Engine → Portal | Opt-in |
| Security Scanning | DAST, vulnerability scanning, pen testing | GE agents run ZAP/Nuclei/Trivy against client apps | Default on |
| WAF Management | bunny.net Shield configuration, custom rules | GE agents configure WAF per client project | Default on |
| Auto-scaling | HPA management, scaling decisions | GE agents monitor and adjust HPA targets | Default on |
| Certificate Management | Let's Encrypt auto-renewal, custom cert support | cert-manager + bunny.net auto-SSL | Default on |
| Authentication | OIDC/OAuth2/SAML via Zitadel | Per-client Zitadel organization | Opt-in |
| Backup & Recovery | Automated backups, point-in-time recovery | UpCloud managed DB backups + Object Storage | Default on |
| Incident Response | Auto-detection, agent-managed incident handling | Mira (SRE agent) + alerting pipeline | Default on |
Data Flow: OpenTelemetry Model¶
Client App Pod GE Platform
┌────────────────┐ ┌──────────────────────┐
│ App Container │ │ │
│ ┌────────────┐│ OTLP/gRPC │ OTel Collector │
│ │ GE SDK ├┼──────────────>│ ↓ │
│ │ (telemetry)││ │ Prometheus (metrics) │
│ └────────────┘│ │ Loki (logs) │
│ │ │ Tempo (traces) │
│ OTel Sidecar │ │ ↓ │
│ (auto-inject) ├──────────────>│ Grafana (dashboards) │
└────────────────┘ │ Compliance Engine │
└──────────────────────┘
- Client apps include a lightweight GE SDK (<50KB) that emits compliance-relevant events
- OTel sidecar auto-injected into client pods via admission webhook
- One-way data flow: client → GE. GE never injects data into client containers.
- Compliance portal reads from the same telemetry data sources
5. Authentication Architecture¶
GE Internal: WebAuthn Only¶
| Component | Choice | Notes |
|---|---|---|
| Admin-UI auth | WebAuthn/FIDO2 (YubiKey) | Already implemented, no IdP needed |
| Number of users | 1-3 humans | Passwordless, phishing-resistant |
| Session management | httpOnly cookies | Challenge stored in cookie |
No Keycloak. No external IdP. WebAuthn is the only auth for GE internal systems.
Client Applications: Zitadel (Opt-in Managed Service)¶
For clients who need authentication in their applications, GE offers Zitadel as a managed service.
| Feature | How |
|---|---|
| Multi-tenant isolation | One Zitadel org per client, full data separation |
| Provisioning | GE agents create org → project → app via Management API |
| Protocols | OIDC, OAuth2, SAML 2.0, WebAuthn/Passkeys |
| Custom branding | Per-org logos, colors, fonts, messages |
| Custom domains | Per-org auth domain with DNS verification |
| Self-management | Client admins can manage their own users via delegated access |
| Deployment | Single Zitadel instance on GE platform (ge-system namespace) |
| Cost | €0 additional (runs on existing infrastructure) |
| Terraform | Official zitadel/zitadel provider for IaC provisioning |
Full details: wiki/docs/domains/infrastructure/zitadel-integration.md
Decision record: wiki/docs/development/decisions/DEC-20260414-keycloak-deprecated.md
6. Infrastructure Architecture¶
UpCloud Managed Kubernetes¶
┌─────────────────────────────────────────────────┐
│ UpCloud Managed K8s (de-fra1) │
│ Control plane: free, UpCloud-managed │
│ CNI: Cilium (mTLS-capable, eBPF) │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ App Pool │ │ Infra Pool │ │
│ │ 3 nodes │ │ 2 nodes │ │
│ │ General Purpose │ │ General Purpose │ │
│ │ Client workloads │ │ Vault, monitoring │ │
│ │ €18/mo ea │ │ €18/mo ea │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ Per-Client Managed PostgreSQL ~€15-20/mo │
│ Per-Client Managed Redis ~€10-15/mo │
│ Platform Managed PostgreSQL ~€50/mo │
│ Platform Managed Valkey ~€20/mo │
│ Managed Load Balancer ~€10/mo │
│ Object Storage (state + backups) ~€5/mo │
└─────────────────────────────────────────────────┘
Node pools (2 pools — no agent workloads on UpCloud): - App pool (3 nodes, General Purpose) — Client project workloads, commercial website, API, portals - Infra pool (2 nodes, General Purpose) — Vault, Prometheus, Loki, Grafana, ArgoCD, Zitadel
GE agent execution stays on fort-knox-dev. UpCloud is purely client-facing. Node affinity and taints ensure platform infra doesn't compete with client workloads.
PriorityClass enforcement (fort-knox-dev):
- system-critical — GE platform workloads (never evicted)
- client-staging — Client staging workloads (evictable under pressure)
bunny.net Edge Layer¶
Client → bunny.net DNS (anycast) → bunny.net CDN (119 PoPs, EU filter)
├── Static assets (Edge Storage, €0.005/GB)
├── WAF + DDoS (Shield Basic free, Advanced €9.50/zone)
└── Origin → UpCloud LB → K8s Traefik → Client App Pod
| Service | Configuration |
|---|---|
| DNS | bunny.net DNS for both growing-europe.com (root zone) and hosting.growing-europe.com (client zone) |
| CDN | Pull zone per client project, RoutingFilters: ["eu"], Origin Shield DE |
| WAF | Shield Basic (free) default, Advanced for business tier clients |
| DDoS | Included on all plans, 250+ Tbps absorption |
| Edge Storage | Per-client storage zones for static assets |
| SSL/TLS | Auto Let's Encrypt + custom cert upload + force TLS 1.2+ |
Bunny DNS Architecture¶
growing-europe.com (Bunny DNS nameservers: kiki.bunny.net / coco.bunny.net)
├── office.growing-europe.com → A → fort-knox-dev (admin-ui)
├── api.growing-europe.com → A → UpCloud LB
├── www.growing-europe.com → CNAME → bunny.net CDN
└── hosting.growing-europe.com → separate Bunny DNS zone
├── acme-corp.hosting.growing-europe.com → bunny.net CDN
└── bakkerij.hosting.growing-europe.com → bunny.net CDN
TransIP holds domain registration for growing-europe.com with NS records pointing to Bunny DNS (kiki.bunny.net / coco.bunny.net). All DNS management is in bunny.net.
Full details: wiki/docs/domains/networking/dns-management.md
7. Security Architecture¶
Layer 1: Network Security (Zero-Trust)¶
Service Mesh: Linkerd - Automatic mTLS between all pods - Rust-based proxy, 12MB memory per sidecar - 1-2ms P99 latency overhead
Network Policies: - Default-deny in all namespaces - Client namespaces: allow ingress from Traefik + GE security scanner only - Client → Client: BLOCKED - Client → GE: BLOCKED (except OTel telemetry) - GE → Client: scanning, deployment, scaling (RBAC-controlled)
Layer 2: Image Supply Chain¶
| Control | Tool | Effect |
|---|---|---|
| Image signing | Cosign (keyless via Sigstore) | Every image cryptographically signed in CI |
| SBOM generation | Syft (CycloneDX) | Bill of materials attached to every image |
| Admission control | Sigstore Policy Controller | K8s rejects unsigned images |
| Vulnerability scanning | Trivy | Blocks CRITICAL CVEs in CI |
| SLSA provenance | Cosign attestation | Build provenance attached to image |
Layer 3: Secrets Management¶
Vault (single instance on fort-knox-dev, HA on UpCloud):
- secret/ge/* — GE internal secrets
- secret/clients/{client}/* — Per-client secrets
- Dynamic database credentials per client (Vault creates/destroys DB users)
- Kubernetes auth — pods authenticate with ServiceAccount token
- Per-environment path isolation: staging pods CANNOT read production secrets
LLM API keys: Stored in Vault, injected via Vault Secrets Operator. Agents never see raw keys.
Layer 4: Agentic Security¶
| Threat | Mitigation |
|---|---|
| Credential theft | Vault dynamic secrets, 1-hour TTL |
| Supply chain attack | Cosign signing, SLSA provenance, Trivy scanning |
| Unauthorized deployment | GitOps only — agents push to Git, ArgoCD deploys |
| Prompt injection | Constitution v2, narrow tool scoping per agent_class |
| Lateral movement | Per-client namespaces, default-deny NetworkPolicy |
| Noisy neighbor | ResourceQuotas per namespace, PriorityClass enforcement |
Layer 5: Edge Security (bunny.net)¶
- WAF with OWASP rule set (managed rules on all zones)
- Custom WAF rules for business/enterprise clients (up to 10/zone on Advanced)
- DDoS absorption at 250+ Tbps
- TLS 1.2+ enforced, HSTS headers via edge rules
- EU-only routing filter on all zones
- Rate limiting per IP/path/ASN
8. Deployment Strategy¶
Phase 1: Blue-Green (immediate)¶
Replace Deployment with Argo Rollouts Rollout CRD:
- Two ReplicaSets: blue (current) and green (new)
- Traffic switches atomically via Service selector
- Instant rollback (< 1 second)
- 2x resources during deployment window only
Phase 2: Canary (after metrics pipeline mature)¶
- Progressive: 5% → 25% → 50% → 100% over 15 minutes
- Argo Rollouts AnalysisTemplate with Prometheus queries
- Auto-rollback if error rate > 1% or P99 latency > 500ms
Rollback Triggers (automated)¶
| Metric | Threshold | Action |
|---|---|---|
| HTTP 5xx rate | > 1% for 2 min | Auto-rollback |
| P99 latency | > 500ms for 5 min | Auto-rollback |
| Pod restart count | > 3 in 5 min | Auto-rollback |
| Agent task failure rate | > 10% above baseline | Auto-rollback + alert |
9. Terraform Module Structure¶
ge-ops/infrastructure/terraform/
├── modules/
│ ├── upcloud-k8s-cluster/ # Managed K8s + node pools (app + infra, no agent pool)
│ ├── upcloud-managed-db/ # PostgreSQL + Redis (per-client)
│ ├── upcloud-load-balancer/ # Managed LB
│ ├── upcloud-object-storage/ # S3-compat (state backend, backups, client assets)
│ ├── bunny-cdn-zone/ # Pull zone + WAF + SSL per client
│ ├── bunny-dns-zone/ # DNS zone + records
│ ├── bunny-edge-storage/ # Static asset storage per client
│ ├── linkerd/ # Service mesh install
│ ├── vault-ha/ # 3-node Vault with Raft
│ ├── zitadel/ # Zitadel deployment + per-org provisioning
│ └── client-project/ # Composite module: namespace + DB + Redis + CDN + WAF
├── environments/
│ ├── acceptance/ # UpCloud acceptance cluster
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── production/ # UpCloud production cluster
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ └── client-projects/ # Per-client Terraform workspaces
│ ├── growing-europe/ # Dogfood: www.growing-europe.com
│ └── {client-slug}/ # Auto-generated per client onboarding
└── state/
└── backend.tf # UpCloud Object Storage backend
Key module: client-project/ — Composite module that provisions everything a client needs:
1. K8s namespace with NetworkPolicy + ResourceQuota + ServiceAccount
2. UpCloud Managed PostgreSQL (per-client)
3. UpCloud Managed Redis (per-client)
4. UpCloud Object Storage bucket (per-client)
5. bunny.net pull zone with EU routing + Shield + auto-SSL
6. bunny.net DNS record ({client}.hosting.growing-europe.com)
7. Vault secret path (secret/clients/{client}/)
8. Zitadel organization (optional, if auth requested)
9. OTel collector sidecar configuration
10. Implementation Phases¶
Phase 0: Knowledge Foundation (This Session — 2026-04-14)¶
- [x] Deep research: UpCloud API, Managed K8s, Managed DBs, Terraform provider
- [x] Deep research: bunny.net CDN, DNS, WAF/Shield, SSL, Edge Storage, Terraform
- [x] Deep research: TransIP API, domain registration
- [x] Deep research: Zitadel architecture, K8s deployment, API, Terraform
- [x] Write wiki brain pages for all 4 services
- [x] Deprecate Keycloak (decision document)
- [ ] Update deployment plan (this document)
Phase 1: UpCloud Foundation — PARTIALLY COMPLETE (2026-04-14)¶
- [x] Install Terraform + providers (UpCloud, bunny.net, Zitadel)
- [x] Configure Terraform state backend (UpCloud Object Storage)
- [x] Provision UpCloud Managed K8s cluster (Frankfurt, de-fra1) —
ge-acceptance, 4 nodes, K8s 1.32 - [x] Configure node pools
- [x] Provision platform Managed PostgreSQL 17 + Valkey
- [x] Provision Load Balancer, NAT Gateway, SDN Network
- [x] Provision bunny.net DNS zone (hosting.growing-europe.com)
- [ ] Deploy Linkerd service mesh (needs kubeconfig)
- [ ] Deploy Vault HA (needs kubeconfig)
- [ ] Deploy ArgoCD to UpCloud cluster
- [ ] Configure ArgoCD to sync from GitLab
Phase 2: Acceptance Environment¶
- [ ] Deploy core GE platform services to UpCloud (monitoring stack only — admin-ui stays on fort-knox-dev)
- [ ] Verify bunny.net DNS zones for
growing-europe.comandhosting.growing-europe.com - [ ] Wire CI/CD pipeline to deploy to UpCloud acceptance
- [ ] Smoke tests + DAST against acceptance environment
- [ ] Deploy Vault to UpCloud (HA with Raft)
- [ ] Configure Vault Secrets Operator
Phase 3: Dogfood — www.growing-europe.com (DOD)¶
- [ ] Brief Faye: "Create landing page for growing-europe.com — Hello, agentic world!"
- [ ] Monitor: Does Faye decompose into 1 work package for Urszula?
- [ ] Monitor: Does Urszula build it correctly?
- [ ] Monitor: Does testing team use CI/CD pipeline?
- [ ] Monitor: Does infra team set up environment?
- [ ] Provision client namespace
client-growing-europevia Terraformclient-projectmodule - [ ] Provision per-project UpCloud Managed PostgreSQL (if app needs it — static page may not)
- [ ] Provision bunny.net pull zone for
www.growing-europe.com - [ ] Configure Bunny DNS:
www.growing-europe.com→ bunny.net CDN - [ ] Deploy container to acceptance
- [ ] Verify site works on acceptance URL
- [ ] Promote to production
- [ ] Verify https://www.growing-europe.com is live
- [ ] 🍾
Phase 4: Production Hardening¶
- [ ] Argo Rollouts for blue-green deployments
- [ ] Cosign image signing + admission controller
- [ ] Default-deny NetworkPolicies in all production namespaces
- [ ] bunny.net Shield Advanced for GE's own zone
- [ ] Canary analysis with Prometheus metrics
- [ ] Runbook for incident response
- [ ] Backup + disaster recovery tested
Phase 5: Client Onboarding Automation¶
- [ ]
client-projectTerraform module tested and production-ready - [ ] Per-client bunny.net pull zone auto-provisioning
- [ ] Per-client database auto-provisioning
- [ ] Per-client Vault secret path auto-creation
- [ ] Custom domain support (client brings own domain)
- [ ] Custom SSL certificate upload flow
- [ ] Per-client cost attribution
- [ ] Zitadel per-client organization auto-provisioning (opt-in)
Phase 6: Deep Integration (Follow-on)¶
- [ ] bunny.net WAF rule automation (per-client custom rules)
- [ ] UpCloud auto-scaling integration (HPA + UpCloud node scaling)
- [ ] GE SDK for compliance markers
- [ ] OpenTelemetry pipeline (OTel Collector → Prometheus/Loki/Tempo)
- [ ] Compliance portal data ingestion
- [ ] Pen testing automation (agent-run ZAP/Nuclei)
- [ ] Certificate lifecycle management dashboard
11. Cost Estimate (Monthly)¶
GE Platform (fixed)¶
| Component | Cost |
|---|---|
| UpCloud K8s (5 nodes, 2 pools) | ~€130 |
| Platform Managed PostgreSQL (Business) | ~€50 |
| Platform Managed Valkey (Business) | ~€20 |
| Managed Load Balancer | ~€10 |
| Object Storage (state + backups) | ~€5 |
| bunny.net CDN (GE zones) | ~€1 |
| bunny.net DNS | Free (< 20M queries) |
| bunny.net Shield Advanced (GE zone) | ~€9.50 |
| Zitadel | €0 (runs on existing infra) |
| Platform total | ~€225/mo |
Per-Client (variable)¶
| Component | Starter | Business | Enterprise |
|---|---|---|---|
| Managed PostgreSQL | ~€15 | ~€50 | ~€100+ |
| Managed Redis | ~€10 | ~€20 | ~€50+ |
| Compute (namespace quota) | ~€5-15 | ~€20-50 | ~€100+ |
| bunny.net CDN | ~€1 | ~€5 | ~€20+ |
| bunny.net Shield | Free (Basic) | €9.50 (Advanced) | Custom (Enterprise) |
| Object Storage | ~€1-5 | ~€5-20 | ~€20-100 |
| Zitadel org | €0 | €0 | €0 |
| Per-client total | ~€30-50/mo | ~€100-150/mo | €300+/mo |
12. Key Decisions¶
| Decision | Choice | Why |
|---|---|---|
| Client auth | Zitadel (not Keycloak) | EU, API-first, native multi-tenancy, Go (lightweight), official Terraform |
| GE internal auth | WebAuthn/YubiKey only | 1-3 users, no IdP needed, phishing-resistant |
| Client isolation | Namespace-per-project | Industry standard for managed K8s hosting, strong isolation |
| Client databases | Per-client managed DB | True data isolation, independent backup/scaling, compliance-friendly |
| Service mesh | Linkerd (not Istio) | 3x less memory, 2x less latency, auto mTLS, simpler ops |
| Deployment strategy | Blue-green → canary | Start simple, graduate when metrics mature |
| Secret injection | Vault Secrets Operator | Cloud-native, auto-rotation, no sidecar overhead |
| Container registry | GitLab Container Registry (or Harbor on UpCloud) | UpCloud has NO native registry. GitLab already running. Harbor as EU-only alternative. |
| Managed "Redis" | UpCloud Managed Valkey | Valkey is Redis fork, wire-compatible. Use type: valkey in API. |
| K8s autoscaling | Custom via UpCloud API | UpCloud has no built-in K8s cluster autoscaler. Must automate node group scaling. |
| State backend | UpCloud Object Storage | Same provider, S3-compatible, EU-only |
| Primary DC | Frankfurt (de-fra1) | Central EU, lowest latency to NL/DE clients |
| CDN | bunny.net with EU-only routing | EU provider, 119 PoPs, Shield WAF included |
| DNS (all zones) | bunny.net DNS | EU-native, CDN-integrated, smart routing, manages both root and hosting zones |
| Domain registrar | TransIP | NL-based, holds growing-europe.com registration, NS delegated to Bunny DNS |
| Monitoring | OpenTelemetry → Prometheus/Loki/Tempo | Standard protocol, one-way data flow from client |
| GE internet exposure | office.growing-europe.com ONLY | Minimal attack surface |
| fort-knox-dev protection | PriorityClass (system-critical vs client-staging) | Client staging can't starve GE operations |
| Dogfood project | www.growing-europe.com | Real domain, "Hello, agentic world!", validates full pipeline |
| Certificates | Let's Encrypt default + custom cert upload | bunny.net handles both via API |
13. Integration Reference¶
| Service | Wiki Brain Page | Terraform Provider | Vault Path |
|---|---|---|---|
| UpCloud | infrastructure/upcloud-integration.md |
UpCloudLtd/upcloud |
secret/ge/upcloud |
| bunny.net | infrastructure/bunnynet-integration.md |
BunnyWay/bunnynet |
secret/ge/bunny |
| TransIP | infrastructure/transip-integration.md |
None (registrar only, no Terraform provider) | secret/ge/transip |
| Zitadel | infrastructure/zitadel-integration.md |
zitadel/zitadel |
secret/ge/zitadel |
Architecture redesigned 2026-04-14 based on Dirk-Jan's direction. Previous version (2026-04-03) superseded. Maintained by Arjan (Infrastructure), Thijmen (K8s), Stef (Network), Leon (Deployment), Karel (CDN).