<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cloud Native Architecture – gitops</title><link>https://deploy-preview-35--cncfarchitecture.netlify.app/tags/gitops/</link><description>Recent content in gitops on Cloud Native Architecture</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Thu, 11 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://deploy-preview-35--cncfarchitecture.netlify.app/tags/gitops/index.xml" rel="self" type="application/rss+xml"/><item><title>Architectures: GitOps-Native Multi-Cluster Kubernetes Platform for EU Data Sovereignty</title><link>https://deploy-preview-35--cncfarchitecture.netlify.app/architectures/obmondo/</link><pubDate>Thu, 11 Jun 2026 00:00:00 +0000</pubDate><guid>https://deploy-preview-35--cncfarchitecture.netlify.app/architectures/obmondo/</guid><description>
&lt;h2 id="relevant-projects">Relevant Projects&lt;/h2>
&lt;div class="row row-cols-1 row-cols-md-3 mb-4">
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Kubernetes
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/kubernetes/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/kubernetes/icon/color/kubernetes-icon-color.svg" alt="kubernetes logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2019&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> 1.33.x&lt;/li>
&lt;/ul>
&lt;p>The runtime substrate for all workloads. Cluster API manages the lifecycle of every cluster across Hetzner bare metal, AWS, and Azure declaratively from Git. No cloud console required.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Argo CD
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/argo/">&lt;img src="https://github.com/cncf/artwork/raw/main/projects/argo/horizontal/color/argo-horizontal-color.svg" alt="argo logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2021&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v3.x&lt;/li>
&lt;/ul>
&lt;p>The reconciliation engine for the entire fleet. A fix committed once to the shared KubeAid chart library propagates to every cluster on the next ArgoCD sync no manual per-cluster patching.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Prometheus
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/prometheus/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/prometheus/icon/color/prometheus-icon-color.svg" alt="prometheus logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2020&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v3.x&lt;/li>
&lt;/ul>
&lt;p>Generated per-cluster from a single Jsonnet vars file using kube-prometheus. Custom alerting rules for TLS expiry forecasting, backup SLIs, database replication lag, and Kubernetes ListWatch failures compose with upstream rule libraries without YAML merge conflicts.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Cilium
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/cilium/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/cilium/icon/color/cilium_icon-color.svg" alt="cilium logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2022&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v1.17.x&lt;/li>
&lt;/ul>
&lt;p>Network policies are embedded alongside every workload manifest in KubeAid. FQDN egress rules for every external API dependency ship with the chart. Operators do not write network policies — KubeAid writes them once and applies them to every cluster.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
cert-manager
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/cert-manager/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/cert-manager/icon/color/cert-manager-icon-color.svg" alt="cert-manager logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2021&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v1.17.x&lt;/li>
&lt;/ul>
&lt;p>Defaults to DNS-01 ACME challenge validation with cloud-specific IAM scoping: IRSA on AWS, Workload Identity on Azure, API tokens on Hetzner. A CertificateNotReady alerting rule and external TLS expiry probe ship as KubeAid defaults added after a silent TLS expiry failure in production.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Velero
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/velero/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/velero/icon/color/velero-icon-color.svg" alt="velero logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2021&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v1.15.x&lt;/li>
&lt;/ul>
&lt;p>Backup schedules, IAM policies, and object storage (S3, GCS, Azure Blob) are provisioned at cluster bootstrap. Velero also exports the Sealed Secrets private key to external object storage at bootstrap — making DR proven at provision time, not during a drill.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Cluster API
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://cluster-api.sigs.k8s.io/">&lt;img src="https://raw.githubusercontent.com/kubernetes-sigs/cluster-api/main/logos/icons/cluster.svg" alt="cluster api logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2022&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v1.10.x&lt;/li>
&lt;/ul>
&lt;p>Manages cluster lifecycle declaratively across Hetzner bare metal, AWS, and Azure. MachineHealthChecks detect and replace unhealthy nodes automatically. Cluster topology is version-controlled in Git.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Helm
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/helm/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/helm/icon/color/helm-icon-color.svg" alt="helm logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Using since:&lt;/strong> 2019&lt;/li>
&lt;li>&lt;strong>Current version:&lt;/strong> v3.x&lt;/li>
&lt;/ul>
&lt;p>Over 100 curated Helm charts form the KubeAid chart library. Each chart ships with pre-wired Cilium network policies, Prometheus alerting rules, and ArgoCD ignoreDifferences configurations. Customers override only genuine differences.&lt;/p>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;h2 id="tldr-synopsis">TLDR; Synopsis&lt;/h2>
&lt;p>This reference architecture describes how Obmondo operates production Kubernetes for dozens of customer clusters across four cloud providers and bare metal with a team of under 10 engineers using a two-repo GitOps pattern built entirely on CNCF projects.&lt;/p>
&lt;p>The core insight: every production failure fixed once in the shared platform repo (KubeAid) propagates to every cluster on the next ArgoCD sync. No cluster is ever patched manually. No cluster becomes a snowflake.&lt;/p>
&lt;p>This architecture targets:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Zero snowflake clusters&lt;/strong> — a fix committed once applies everywhere within hours via ArgoCD&lt;/li>
&lt;li>&lt;strong>Full EU data sovereignty&lt;/strong> — identical stack on Hetzner bare metal in Germany, on-premises datacentres, and EU-region cloud VMs, with no vendor control plane, no proprietary APIs, and full auditability&lt;/li>
&lt;li>&lt;strong>Disaster recovery by default&lt;/strong> — backup schedules, IAM, and Sealed Secrets key export are automated at cluster bootstrap; if a cluster can be created, it can be recovered&lt;/li>
&lt;li>&lt;strong>Sub-10-engineer fleet operations&lt;/strong> — platform-level abstractions that scale cluster count without scaling headcount&lt;/li>
&lt;/ul>
&lt;h2 id="organization">Organization&lt;/h2>
&lt;p>Obmondo (EnableIT ApS) is a Danish Managed Kubernetes provider. It builds and operates production Kubernetes platforms for customers in financial services, healthcare, and public sector organizations across Denmark and the EU. All infrastructure must satisfy GDPR, NIS2, and in many cases ISO 27001 — by architecture, not by policy.&lt;/p>
&lt;p>KubeAid, the open-source platform that powers Obmondo&amp;rsquo;s managed service, is available at &lt;a href="https://github.com/Obmondo/KubeAid">https://github.com/Obmondo/KubeAid&lt;/a> under the Apache 2.0 license.&lt;/p>
&lt;h2 id="teams">Teams&lt;/h2>
&lt;p>&lt;strong>Platform Engineering&lt;/strong> maintains KubeAid the shared chart library, Jsonnet monitoring templates, and ArgoCD application definitions that apply uniformly to every cluster. A fix here reaches every customer automatically.&lt;/p>
&lt;p>&lt;strong>SRE / Customer Operations&lt;/strong> handles day-2 operations: incident response, capacity planning, and customer-specific overrides in per-customer config repos. With KubeAid abstracting the platform layer, this team focuses exclusively on the ~10% that is genuinely different per customer.&lt;/p>
&lt;h2 id="architecture">Architecture&lt;/h2>
&lt;h3 id="goals">Goals&lt;/h3>
&lt;p>&lt;strong>Eliminate snowflake clusters.&lt;/strong> Every production failure becomes a KubeAid default. The silent TLS expiry became DNS-01 + external probe + alert. The duplicate Prometheus timestamp alert became a scrape-level relabeling rule. The RBAC gap became a ClusterRole fix. Each fix landed once; every cluster received it automatically.&lt;/p>
&lt;p>&lt;strong>EU data sovereignty without vendor lock-in.&lt;/strong> No proprietary control plane. No per-node SaaS fees. No APIs that cannot be audited. The entire stack runs on CNCF projects identically on Hetzner bare metal in Germany, on-premises in Danish datacentres, and in EU-region cloud VMs. Customers can move it, fork it, and audit every component.&lt;/p>
&lt;p>&lt;strong>Disaster recovery proven at provision time.&lt;/strong> Backup schedules, IAM policies, object storage, and Sealed Secrets private key export are automated at bootstrap. The DR gap was discovered simultaneously on every cluster during a planned drill and made impossible to miss on any future cluster.&lt;/p>
&lt;p>&lt;strong>Observability without per-cluster overhead.&lt;/strong> Monitoring configuration is generated from a single Jsonnet vars file. One engineer maintains alerting for the entire fleet. Custom rules compose with upstream libraries without merge conflicts.&lt;/p>
&lt;h3 id="architecture-overview">Architecture Overview&lt;/h3>
&lt;p>&lt;img src="images/obmondo-architecture.png" alt="Obmondo Platform Architecture">&lt;/p>
&lt;p>The architecture follows a strict two-repo pattern:
&lt;strong>Repo 1 — KubeAid (shared platform defaults)&lt;/strong>
Over 100 curated Helm charts with pre-wired integrations. ArgoCD ApplicationSets deploy these charts to every cluster. Monitoring is generated per-cluster from a single Jsonnet vars file using kube-prometheus. Cilium network policies ship alongside workload manifests. DR configuration is provisioned at bootstrap. Every production failure becomes a default here.&lt;/p>
&lt;p>&lt;strong>Repo 2 — Customer config (genuine differences only)&lt;/strong>
Each customer config repo holds only what is genuinely different: cloud provider, node sizes, alerting thresholds, compliance scope. If a value matches the KubeAid default, it does not exist in the config repo. ArgoCD reconciles both repos continuously across every cluster.&lt;/p>
&lt;p>&lt;strong>Per-cluster stack (all CNCF projects):&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Layer&lt;/th>
&lt;th>Project&lt;/th>
&lt;th>Role&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Lifecycle&lt;/td>
&lt;td>Cluster API&lt;/td>
&lt;td>Declarative cluster provisioning across all providers&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Networking&lt;/td>
&lt;td>Cilium&lt;/td>
&lt;td>CNI + FQDN egress policies + Hubble metrics&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>TLS&lt;/td>
&lt;td>cert-manager&lt;/td>
&lt;td>DNS-01 ACME with cloud IAM scoping&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>GitOps&lt;/td>
&lt;td>ArgoCD&lt;/td>
&lt;td>Continuous reconciliation from both repos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Observability&lt;/td>
&lt;td>Prometheus + Alertmanager&lt;/td>
&lt;td>Generated from Jsonnet per cluster&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Ingress&lt;/td>
&lt;td>Traefik&lt;/td>
&lt;td>Wildcard TLS, HTTP→HTTPS redirect&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Backup / DR&lt;/td>
&lt;td>Velero&lt;/td>
&lt;td>Scheduled backups + Sealed Secrets key export&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Secrets&lt;/td>
&lt;td>Sealed Secrets (Bitnami)&lt;/td>
&lt;td>Encrypted secrets in Git, key exported at bootstrap&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="infrastructure-layer">Infrastructure Layer&lt;/h3>
&lt;p>Cluster API manages cluster lifecycle across all providers. The same declarative topology definition works on Hetzner bare metal (HCloud provider), AWS, and Azure. MachineHealthChecks detect unhealthy nodes and trigger automatic replacement. Node removal by CAPI is tracked and DaemonSet ghost pods are handled via alerting.&lt;/p>
&lt;p>On Hetzner bare metal, clusters run on dedicated physical servers with ZFS and Ceph storage. Network isolation is enforced by Cilium at the pod level. No hypervisor, no shared infrastructure with other tenants.&lt;/p>
&lt;h3 id="networking-layer">Networking Layer&lt;/h3>
&lt;p>Cilium is the CNI for every cluster. Every KubeAid Helm chart ships with a &lt;code>CiliumNetworkPolicy&lt;/code> alongside the workload manifest. FQDN egress rules for every external API dependency are pre-written and applied by ArgoCD. Operators do not write network policies they are a platform default.&lt;/p>
&lt;p>FQDN policy enforcement is critical for compliance: customers need to attest that workloads only communicate with approved external endpoints. Cilium&amp;rsquo;s Hubble metrics feed into Prometheus for network observability.&lt;/p>
&lt;h3 id="tls-and-certificate-management">TLS and Certificate Management&lt;/h3>
&lt;p>cert-manager defaults to DNS-01 ACME challenge validation. The switch from HTTP-01 was forced by a production failure: Traefik&amp;rsquo;s global HTTP→HTTPS redirect for HSTS compliance made HTTP-01 ACME validation permanently impossible every challenge request was redirected before reaching the solver pod. Certificates failed to renew silently for up to 90 days.&lt;/p>
&lt;p>DNS-01 with cloud-specific IAM scoping (IRSA on AWS, Workload Identity on Azure, API tokens on Hetzner) is now the only supported challenge type. An external TLS expiry probe and a &lt;code>CertificateNotReady&lt;/code> Alertmanager rule ship as KubeAid defaults.&lt;/p>
&lt;h3 id="observability-layer">Observability Layer&lt;/h3>
&lt;p>Prometheus and Alertmanager are generated per-cluster from a single Jsonnet vars file using kube-prometheus. Custom alerting rules compose with upstream rule libraries using Jsonnet merging semantics no YAML merge conflicts.&lt;/p>
&lt;p>Custom rules added after production failures:&lt;/p>
&lt;ul>
&lt;li>&lt;code>CertificateNotReady&lt;/code> — 30-day TLS expiry warning&lt;/li>
&lt;li>&lt;code>VeleroBackupMissed&lt;/code> — backup age SLI&lt;/li>
&lt;li>&lt;code>PrometheusKubernetesListWatchFailures&lt;/code> — RBAC-induced scrape gaps&lt;/li>
&lt;li>&lt;code>KubeDaemonSetMisScheduled&lt;/code> — CAPI node removal detection&lt;/li>
&lt;li>Database replication lag alerts per database type&lt;/li>
&lt;/ul>
&lt;p>One engineer maintains monitoring configuration for the entire fleet.&lt;/p>
&lt;h3 id="disaster-recovery">Disaster Recovery&lt;/h3>
&lt;p>Velero backup schedules, IAM policies, and object storage configuration are provisioned at cluster bootstrap. DR is not a follow-up task it is a bootstrap invariant.&lt;/p>
&lt;p>The Sealed Secrets private key gap was discovered during a planned DR drill: a key that exists only inside the cluster cannot survive cluster loss, and every sealed secret in Git becomes permanently unrecoverable ciphertext. The private key is now automatically exported to external object storage via Velero at bootstrap. This protection is mandatory it is impossible to create a new KubeAid cluster without it.&lt;/p>
&lt;p>Velero backup completion metrics are scraped by Prometheus. An alert fires if a backup has not succeeded within its scheduled window.&lt;/p>
&lt;h2 id="can-you-expand-on-why-you-are-using-those-projectsservices">Can you expand on why you are using those projects/services?&lt;/h2>
&lt;p>&lt;strong>ArgoCD over Flux:&lt;/strong> ApplicationSets allow a single ArgoCD instance to manage an arbitrary number of clusters from a centralized config. ArgoCD&amp;rsquo;s multi-source application support maps cleanly to the two-repo pattern — one source for KubeAid defaults, one for customer overrides. The ArgoCD UI provides fleet-wide visibility into sync status and drift.&lt;/p>
&lt;p>&lt;strong>Cilium over Calico/Flannel:&lt;/strong> FQDN-based egress policies are a hard compliance requirement. Cilium&amp;rsquo;s &lt;code>CiliumNetworkPolicy&lt;/code> with FQDN selectors is the only CNI that supports this at the policy layer without a proxy. Hubble metrics integrate directly with Prometheus. eBPF-based enforcement has lower overhead than iptables at scale.&lt;/p>
&lt;p>&lt;strong>cert-manager with DNS-01 exclusively:&lt;/strong> HTTP-01 is broken by Traefik&amp;rsquo;s global HTTP→HTTPS redirect, which cannot be disabled without breaking HSTS compliance. DNS-01 with cloud IAM scoping works identically on bare metal and cloud, and does not require inbound HTTP access.&lt;/p>
&lt;p>&lt;strong>Cluster API over cloud-specific tooling:&lt;/strong> Provider-agnostic cluster lifecycle in Git. The same declarative model covers Hetzner bare metal, AWS, and Azure. Rolling control plane replacements, MachineHealthChecks, and autoscaling are provider-agnostic concerns handled by CAPI — not bespoke automation per cloud.&lt;/p>
&lt;p>&lt;strong>Helm for chart packaging:&lt;/strong> The KubeAid chart library wraps upstream charts and embeds the platform layer (network policies, monitoring rules, ArgoCD ignoreDifferences) alongside the workload. Customers use standard Helm values overrides. No custom CRDs or operators required for the integration layer.&lt;/p>
&lt;h2 id="what-works-particularly-well">What works particularly well&lt;/h2>
&lt;p>&lt;strong>The two-repo pattern scales linearly.&lt;/strong> A platform fix committed to KubeAid propagates to every cluster within hours. A team of under 10 engineers operates dozens of production clusters across four cloud providers with no per-cluster patching.&lt;/p>
&lt;p>&lt;strong>Production failures become permanent fixes.&lt;/strong> Every incident is an opportunity to close the gap for every cluster simultaneously. The fleet never re-experiences the same failure in the same way.&lt;/p>
&lt;p>&lt;strong>Jsonnet for monitoring composition.&lt;/strong> kube-prometheus Jsonnet templates allow custom alerting rules to compose with upstream libraries without merge conflicts. One engineer maintains alerting for the entire fleet.&lt;/p>
&lt;p>&lt;strong>Cilium FQDN policies as a compliance primitive.&lt;/strong> Embedding FQDN egress rules alongside every workload manifest means network policy is not a separate compliance exercise it ships with the workload definition and is applied everywhere.&lt;/p>
&lt;p>&lt;strong>Velero key export as a bootstrap invariant.&lt;/strong> Making Sealed Secrets private key export mandatory at cluster creation means DR is never an afterthought. The constraint was added after finding the same gap on every cluster simultaneously during a drill.&lt;/p>
&lt;p>&lt;strong>Zero vendor control plane.&lt;/strong> The same CNCF stack runs on Hetzner bare metal in Germany, on-premises in Danish datacentres, and in EU-region cloud VMs. Customers can move it, fork it, and audit every component. GDPR, NIS2, and ISO 27001 requirements are satisfied by architecture.&lt;/p>
&lt;h2 id="what-needs-improvement">What needs improvement&lt;/h2>
&lt;p>&lt;strong>ArgoCD ignoreDifferences maintenance.&lt;/strong> Runtime drift Azure webhook injections, controller-managed fields, CRD caBundle rotation requires ongoing ignoreDifferences tuning in every affected chart. Each cloud provider introduces its own drift patterns. This operational overhead ideally belongs upstream in the charts themselves.&lt;/p>
&lt;p>&lt;strong>kube-prometheus regeneration across clusters.&lt;/strong> When a fix lands in a shared Jsonnet library, manifests must be regenerated for every affected cluster. This is currently a per-cluster manual step. A CI pipeline that detects library changes, regenerates all affected clusters, and opens PRs automatically would eliminate the gap.&lt;/p>
&lt;p>&lt;strong>Cluster API bare metal host pool management.&lt;/strong> Rolling control plane replacements require a spare host in the pool. When all bare metal hosts are occupied, a new control plane node cannot be provisioned and the rollout stalls. Better capacity planning automation is needed.&lt;/p>
&lt;p>&lt;strong>Sealed Secrets rotation.&lt;/strong> Sealed Secrets use asymmetric encryption keyed to a specific cluster key. Key rotation requires re-sealing every secret in the config repo. Tooling to automate re-sealing across the fleet is not yet in place.&lt;/p>
&lt;h2 id="what-sort-of-glue-had-to-be-developed">What sort of &amp;ldquo;glue&amp;rdquo; had to be developed?&lt;/h2>
&lt;p>&lt;strong>KubeAid chart library.&lt;/strong> The 100+ Helm chart wrappers that embed Cilium policies, Prometheus rules, and ArgoCD ignoreDifferences alongside upstream charts. These are the integration layer pre-built wiring that no operator writes from scratch for each cluster.&lt;/p>
&lt;p>&lt;strong>kube-prometheus Jsonnet library extensions.&lt;/strong> Custom libsonnet files that extend the upstream kube-prometheus library with Obmondo-specific alerting rules. These compose cleanly with upstream rules via Jsonnet merging semantics.&lt;/p>
&lt;p>&lt;strong>ArgoCD ApplicationSet templates.&lt;/strong> Parameterized ApplicationSet definitions that deploy the full KubeAid chart suite to any cluster whose config repo follows the two-repo pattern. Adding a new cluster is a config-repo operation, not a platform operation.&lt;/p>
&lt;p>&lt;strong>Sealed Secrets key export automation.&lt;/strong> A bootstrap step that exports the Sealed Secrets private key to external object storage via Velero immediately after cluster creation. This step is mandatory it cannot be skipped.&lt;/p>
&lt;p>&lt;strong>Prometheus alert composition templates.&lt;/strong> A set of reusable Jsonnet patterns for constructing SLI-based alerts (backup age, certificate validity window, database replication lag) that are consistent across the fleet without per-cluster duplication.&lt;/p>
&lt;h2 id="how-did-the-architecture-evolve">How did the Architecture Evolve&lt;/h2>
&lt;p>The architecture began as manually-managed clusters with per-cluster Helm deployments. The first pain point was drift: a fix applied to cluster A was not applied to clusters B–Z. The second was silent failures that were only discovered at impact.&lt;/p>
&lt;p>Each failure drove a platform default:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Failure&lt;/th>
&lt;th>Root Cause&lt;/th>
&lt;th>KubeAid Default Added&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Silent TLS expiry (90 days)&lt;/td>
&lt;td>HTTP-01 blocked by Traefik redirect&lt;/td>
&lt;td>DNS-01 + CertificateNotReady alert + external probe&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Duplicate Prometheus timestamps&lt;/td>
&lt;td>Two kubelet endpoints emitting same metric&lt;/td>
&lt;td>Scrape-level relabeling rule in kube-prometheus&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Service discovery silent failure&lt;/td>
&lt;td>Missing RBAC on prometheus-k8s ServiceAccount&lt;/td>
&lt;td>ClusterRole fix in prometheus-k8s chart&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>DR gap across all clusters&lt;/td>
&lt;td>Sealed Secrets key not exported&lt;/td>
&lt;td>Mandatory Velero key export at bootstrap&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>snowflake clusters&lt;/td>
&lt;td>Per-cluster manual patching&lt;/td>
&lt;td>Two-repo GitOps with KubeAid defaults&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Each fix landed in KubeAid once. Every cluster received it. No future cluster will hit any of these failures in the same way.&lt;/p>
&lt;h2 id="whats-next-for-your-architecture">What&amp;rsquo;s next for your architecture?&lt;/h2>
&lt;p>&lt;strong>Automated kube-prometheus regeneration.&lt;/strong> A CI pipeline that detects when a shared Jsonnet library changes, regenerates manifests for all affected clusters, and opens PRs automatically eliminating the manual per-cluster regeneration step.&lt;/p>
&lt;p>&lt;strong>Deeper OpenTelemetry integration.&lt;/strong> Distributed tracing across customer workloads, integrated with the existing Prometheus metrics pipeline for a unified observability experience.&lt;/p>
&lt;p>&lt;strong>Automated compliance evidence generation.&lt;/strong> Generating GDPR, NIS2, and ISO 27001 evidence artifacts directly from Prometheus metrics and Kubernetes audit logs compliance as a cluster output, not a manual exercise.&lt;/p>
&lt;p>&lt;strong>Broader FQDN egress coverage.&lt;/strong> Extending Cilium FQDN policy defaults to every KubeAid chart in the library, closing the remaining gap between workloads that have pre-wired policies and those that do not.&lt;/p>
&lt;p>&lt;strong>Sealed Secrets rotation tooling.&lt;/strong> Automation to re-seal every secret in a config repo after a cluster key rotation making key rotation a safe, routine operation rather than a risky manual process.&lt;/p>
&lt;h2 id="key-takeaways--lessons">Key Takeaways / Lessons&lt;/h2>
&lt;p>&lt;strong>Every manual fix is a fix that has not been applied everywhere.&lt;/strong> The two-repo GitOps pattern is not primarily about automation it is about making the gap visible. If a fix requires touching a per-cluster config repo, it is a signal that the fix belongs in KubeAid instead.&lt;/p>
&lt;p>&lt;strong>Silent failures are the expensive ones.&lt;/strong> TLS expiry, backup failures, and RBAC gaps were all silent no component logged an error until impact. The alerting investment (CertificateNotReady, VeleroBackupMissed, PrometheusKubernetesListWatchFailures) pays back in avoided incidents, not reduced noise.&lt;/p>
&lt;p>&lt;strong>Compliance by architecture, not by policy.&lt;/strong> GDPR, NIS2, and ISO 27001 requirements are satisfied by the architecture itself: no vendor control plane, full auditability, data residency by infrastructure choice, DR proven at bootstrap. Policy documents that reference the architecture are a consequence, not the mechanism.&lt;/p>
&lt;p>&lt;strong>The CNCF ecosystem composability is the product.&lt;/strong> ArgoCD reconciles Helm charts. Helm packages Cilium, Prometheus, cert-manager, Velero. Prometheus scrapes Cilium Hubble metrics, cert-manager certificate status, and Velero backup completion metrics. Each CNCF project does one thing well. KubeAid is the integration layer and it is open source because the problems it solves are not unique to Obmondo.&lt;/p>
&lt;p>&lt;strong>DR gaps are always discovered on every cluster simultaneously.&lt;/strong> If a DR gap exists, it exists everywhere because every cluster was provisioned from the same template. The corollary is equally powerful: close the gap once, and it closes everywhere.&lt;/p>
&lt;h2 id="discussion">Discussion&lt;/h2>
&lt;p>End user members may participate in the &lt;a href="https://github.com/cncf/tab/issues/139">discussion thread&lt;/a> for this architecture.&lt;/p></description></item><item><title>Architectures: End-to-End Cloud Native Telco Platform Automation at Swisscom</title><link>https://deploy-preview-35--cncfarchitecture.netlify.app/architectures/swisscom-cloud-native-telco/</link><pubDate>Mon, 16 Mar 2026 00:00:00 +0000</pubDate><guid>https://deploy-preview-35--cncfarchitecture.netlify.app/architectures/swisscom-cloud-native-telco/</guid><description>
&lt;h2 id="relevant-projects">Relevant Projects&lt;/h2>
&lt;h3 id="cncf-projects">CNCF Projects&lt;/h3>
&lt;div class="row row-cols-1 row-cols-md-3 mb-4">
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Kubernetes
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/kubernetes/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/kubernetes/icon/color/kubernetes-icon-color.svg" alt="kubernetes logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2021&lt;/p>
&lt;p>The Kubernetes API is the database backend and control plane of the entire automation platform. It acts as the runtime for all CNFs, operators, and platform services. Custom Resource Definitions extend the API to cover telco-specific concerns like IPAM, DNS, and network function configuration.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Flux
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/flux/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/flux/icon/color/flux-icon-color.svg" alt="flux logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2022&lt;/p>
&lt;p>Flux is the GitOps engine for continuous reconciliation. It monitors Git repositories and synchronizes all desired state — CNF deployment manifests, Custom Resources, DNS endpoints, certificate requests, IP claims, and test definitions — into Kubernetes clusters.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
cert-manager
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/cert-manager/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/cert-manager/icon/color/cert-manager-icon-color.svg" alt="cert-manager logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2023&lt;/p>
&lt;p>Automated certificate lifecycle management integrated with Swisscom&amp;rsquo;s internal PKI. Certificate requests are expressed as Kubernetes CRs, reconciled by Flux, and managed by cert-manager. Private keys never leave the cluster.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Headlamp
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/headlamp/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/headlamp/icon/color/headlamp-icon-color.svg" alt="headlamp logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2025&lt;/p>
&lt;p>Kubernetes dashboard for the management cluster, providing cluster visibility, RBAC-based access control, a CRD documentation browser, and extensible plugin system. Swisscom is listed as an official Headlamp adopter.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
SDC (Schema Driven Configuration)
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://docs.sdcio.dev/">&lt;img src="https://landscape.cncf.io/logos/c5f5fbc1c0b595d28bcfc1f443d46b7c0e4aa4c0dc9f239b0e0fa90ca3a4fda4.svg" alt="sdc logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2024&lt;/p>
&lt;p>Used as the Config Sync Operator to push assembled configurations to CNFs. SDC enables vendor-agnostic, declarative configuration management using YANG schemas and NETCONF/gNMI protocols. Swisscom adopted SDC as its strategic configuration management solution and actively contributes features including config blame, drift detection, validation, testing compatibility with CNFs, and NETCONF Actions support. Swisscom is listed as an official SDC adopter.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
CoreDNS
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/coredns/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/coredns/icon/color/coredns-icon-color.svg" alt="coredns logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2021&lt;/p>
&lt;p>In-cluster DNS service discovery for Kubernetes services. Also used with conditional forwarding to route queries for private 5G zones (e.g., 3gppnetwork.org) to the authoritative PowerDNS servers.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
ExternalDNS
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://kubernetes-sigs.github.io/external-dns/latest/">&lt;img src="https://kubernetes-sigs.github.io/external-dns/latest/docs/img/external-dns.png" alt="externaldns logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2023&lt;/p>
&lt;p>Kubernetes-native automation of DNS records in PowerDNS using Custom Resources and annotations.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
MetalLB
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.cncf.io/projects/metallb/">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/metallb/icon/color/metallb-icon-color.svg" alt="metallb logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2022&lt;/p>
&lt;p>Load balancer for bare-metal Kubernetes clusters. MetalLB IP address pools are managed via KRM, with IP addresses dynamically allocated from NetBox via the NetBox Operator.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
Kubebuilder / controller-runtime
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://github.com/kubernetes-sigs/kubebuilder">&lt;img src="https://raw.githubusercontent.com/cncf/artwork/main/projects/kubernetes/icon/color/kubernetes-icon-color.svg" alt="kubernetes logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2022&lt;/p>
&lt;p>Scaffolding framework and libraries for building custom Kubernetes operators. Used to build all domain-specific operators for CNF configuration abstraction, IPAM integration, config synchronization, and DNS automation.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;h3 id="other-projects">Other Projects&lt;/h3>
&lt;div class="row row-cols-1 row-cols-md-3 mb-4">
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
PowerDNS
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://www.powerdns.com">&lt;img src="https://upload.wikimedia.org/wikipedia/commons/9/9e/Logo_of_PowerDNS.svg" alt="powerdns logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2023&lt;/p>
&lt;p>Authoritative DNS server supporting automation of advanced resource records (NAPTR, SRV) required for 5G/SIP via ExternalDNS.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
NetBox Operator
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://github.com/netbox-community/netbox-operator">&lt;img src="https://raw.githubusercontent.com/netbox-community/netbox/main/docs/netbox_logo_light.svg" alt="netbox logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2024&lt;/p>
&lt;p>Kubernetes operator for IPAM integration, open-sourced by Swisscom. Brings IPAM into the Kubernetes API with a claim model inspired by PersistentVolumeClaims — dynamically allocating IP prefixes and addresses from NetBox, managing their lifecycle through Kubernetes garbage collection, and supporting sticky IPs for disaster recovery.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;div class="col mb-4">
&lt;div class="card h-100">
&lt;div class="card-header">
NetBox
&lt;/div>
&lt;div class="card-body">
&lt;p class="card-text">
&lt;p>&lt;a href="https://github.com/netbox-community/netbox">&lt;img src="https://raw.githubusercontent.com/netbox-community/netbox/main/docs/netbox_logo_light.svg" alt="netbox logo">&lt;/a>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Using since:&lt;/strong> 2023&lt;/p>
&lt;p>IP Address Management (IPAM) and network infrastructure modeling. Used as the IPAM backend for dynamic IP allocation across all CNFs and platform services.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/p>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;/div>
&lt;h2 id="tldr-or-synopsis">TL;DR or Synopsis&lt;/h2>
&lt;p>Swisscom has built a cloud native telco platform for the end-to-end automation of its 5G standalone core network and cross-domain resource orchestration. The architecture replaces traditional imperative network management (Jenkins pipelines, Ansible playbooks) with a fully declarative, Kubernetes-native automation model driven by GitOps and the Kubernetes Resource Model (KRM).&lt;/p>
&lt;p>A mobile core development environment contains approximately 2,000 pods with over 5,000 interdependent configuration parameters across Cloud-Native Network Functions (CNFs) such as UPF, SMF, AMF, UDM, UDR, BSF, NRF, NSSF, and AUSF. Engineers express high-level intents as Kubernetes Custom Resources; custom operators dynamically assemble full configurations at runtime — fetching IP addresses from IPAM, secrets from Vault, certificates from PKI, and infrastructure details from the cluster.&lt;/p>
&lt;p>While the 5G core is the primary domain, the orchestration framework extends across multiple network domains and infrastructure services, applying the same intent-based automation patterns consistently.&lt;/p>
&lt;h2 id="organisation">Organisation&lt;/h2>
&lt;p>Swisscom is the leading Telecommunications/ISP and ICT company and offers mobile, Internet and TV products, as well as comprehensive IT and digital services to private and business customers.
Swisscom&amp;rsquo;s expertise in cloud native technologies is well-established, as evidenced by its status as a former Gold member and Management Board member of the Cloud Foundry Foundation, along with its certification for Cloud Foundry.
Additionally, Swisscom demonstrates a strong commitment to the Open-Source community, having been a CNCF Silver Member for several years and serving as a Kubernetes Certified Service Provider (KCSP) partner.
Our skilled employees have delivered numerous talks and presentations at prestigious events such as KubeCon, Cloud Native Zürich, Swiss Cloud Native Day, KCD Suisse Romande, ContainerDays.&lt;/p>
&lt;p>The company has embarked on a strategic transformation from a traditional telecom operator (&amp;ldquo;Telco&amp;rdquo;) to a technology company (&amp;ldquo;TechCo&amp;rdquo;) with 5G as a central driver.
Swisscom operates an extensive 5G Non-Standalone (NSA) network covering 99% of the Swiss population. The cloud native platform described here powers the 5G Standalone (SA) core.&lt;/p>
&lt;h2 id="teams">Teams&lt;/h2>
&lt;p>Multiple teams collaborate on this platform:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Cloud Native Resource Orchestration&lt;/strong> — creates a robust framework for orchestrating cloud-native resources such as CNFs, IPAM, Networks, DNS, Kubernetes Clusters, and more. Designs and operates GitOps pipelines, builds Kubernetes operators, and develops the management cluster UI/UX.&lt;/li>
&lt;li>&lt;strong>Mobile Cloud Native Engineering&lt;/strong> — designs, implements, and operates the cloud native 5G core platform, including GitOps pipelines, Kubernetes operators, and network function lifecycle management.&lt;/li>
&lt;li>&lt;strong>DNS Engineering&lt;/strong> — builds and operates the highly reliable cloud native DNS service underpinning the 5G core and other infrastructures.&lt;/li>
&lt;li>&lt;strong>Network Engineering&lt;/strong> — provides IPAM and Network-as-a-Service.&lt;/li>
&lt;li>&lt;strong>Platform &amp;amp; Developer Experience&lt;/strong> — manages Kubernetes clusters and builds developer tooling.&lt;/li>
&lt;/ul>
&lt;h2 id="architecture-overview--goals">Architecture overview &amp;amp; Goals&lt;/h2>
&lt;h3 id="goals">Goals&lt;/h3>
&lt;ol>
&lt;li>&lt;strong>Full GitOps for the 5G Core&lt;/strong> — Extend GitOps beyond CNF deployment to include network function configuration, certificate management, DNS record provisioning, IP address management, and testing — achieving continuous reconciliation across all layers.&lt;/li>
&lt;li>&lt;strong>Declarative, Intent-Based Configuration&lt;/strong> — Replace static, low-level configuration manifests with abstract, intent-driven Custom Resources. Engineers specify &lt;em>what&lt;/em> they want using a high level intent (e.g., &amp;ldquo;this CNF needs an IP address from a subnet in network zone A&amp;rdquo;) rather than &lt;em>how&lt;/em> to achieve it, with Kubernetes operators dynamically assembling configurations at runtime.&lt;/li>
&lt;li>&lt;strong>Automated CD&lt;/strong> — High level of automation for telco deployment rollouts. This includes rethinking Change Processes as well as building solid CI/CD/CT pipelines to ensure a highly reliable network.&lt;/li>
&lt;li>&lt;strong>In-Band with Kubernetes&lt;/strong> — Bring all automation in-band with the Kubernetes API, eliminating out-of-band tools like Jenkins pipelines and Ansible playbooks. This ensures that the Kubernetes orchestrator has full visibility and control over all resources, enabling self-healing and reconciliation.&lt;/li>
&lt;li>&lt;strong>Cloud Native DNS Service&lt;/strong> — Operate a highly reliable, geo-redundant, on-premises DNS service for the 5G core using open-source technologies (CoreDNS, PowerDNS, ExternalDNS), fully automated via GitOps and Kubernetes Custom Resources.&lt;/li>
&lt;li>&lt;strong>Contribute to the Ecosystem and Shape the Industry Discussion&lt;/strong> — Open-source key components built or contributed to during this journey (NetBox Operator, SDC, demo code) to enable other organizations to adopt similar patterns. Contribute to Meetups and Conferences in order to achieve broader success of Cloud Native adoption in the Telco Community.&lt;/li>
&lt;/ol>
&lt;h3 id="architecture-overview">Architecture overview&lt;/h3>
&lt;p>The platform is organized in three layers:&lt;/p>
&lt;p>&lt;img src="./images/swisscom-cloud-native-telco-automation-layers.svg" alt="Cloud Native Telco Automation Layers">&lt;/p>
&lt;p>The &lt;strong>Intent Layer&lt;/strong> stores high-level desired state in Git — engineers define &lt;em>what&lt;/em> they want using concise Custom Resources (e.g., a DNN configuration with hostname, region, and SNSSAI).&lt;/p>
&lt;p>The &lt;strong>Automation Layer&lt;/strong> runs on Kubernetes and continuously reconciles. Flux pulls intents from Git. Custom operators dynamically assemble full configurations by fetching IP addresses from NetBox (via the NetBox Operator) and creating connectivity in a Network-as-a-Service platform. It then pushes the KRM formatted Runtime Configuration to a Git repository for the Runtime layer to consume.&lt;/p>
&lt;p>The &lt;strong>Runtime Layer&lt;/strong> hosts the 5G core CNFs and supporting services. Flux pulls intents from Git. SDC pushes the assembled configuration to CNFs via NETCONF/gNMI. MetalLB, cert-manager, External Secrets Operator, ExternalDNS are used to configure the Workload cluster.&lt;/p>
&lt;p>&lt;img src="./images/swisscom-cloud-native-telco-automation-architecture-overview.svg" alt="Cloud Native Telco Automation Architecture Overview">&lt;/p>
&lt;h3 id="key-design-principles">Key Design Principles&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>GitOps + KRM&lt;/strong>: Git stores high-level intents; Kubernetes manages dynamic, low-level configuration assembly. This is a shared source of truth across Git and Kubernetes.&lt;/li>
&lt;li>&lt;strong>Continuous Reconciliation&lt;/strong>: Every aspect of the system is continuously reconciled against the desired state — following the four OpenGitOps principles.&lt;/li>
&lt;li>&lt;strong>Abstraction over Complexity&lt;/strong>: Engineers work with simple, high-level intents; operators handle the complex assembly.&lt;/li>
&lt;/ul>
&lt;h2 id="can-you-expand-on-why-you-are-using-those-projectsservices">Can you expand on why you are using those projects/services?&lt;/h2>
&lt;h3 id="from-gitops-to-krm">From GitOps to KRM&lt;/h3>
&lt;p>Standard GitOps tools (Flux, Argo CD) combined with Helm/Kustomize have limitations for complex telco use cases: they cannot use live Kubernetes resources as inputs during rendering, cannot invoke custom business logic during template processing, and cannot dynamically assemble configurations from multiple sources. By extending GitOps with the Kubernetes Resource Model (KRM) — Custom Resource Definitions, Custom Resources, and custom Operators — the platform achieves dynamic configuration assembly at runtime.&lt;/p>
&lt;h3 id="configuration-abstraction--dynamic-assembly">Configuration Abstraction &amp;amp; Dynamic Assembly&lt;/h3>
&lt;p>A typical 5G core configuration includes IP addresses, VLAN IDs, DNS records, NF variables, secret references, and certificate references. Previously, engineers had to know all values upfront and embed them statically. The new intent-based model inverts this. The following is an example of a DNN configuration in pseudo-yaml-code.&lt;/p>
&lt;p>On the intent layer, only a very stripped-down KRM manifest exists:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">telco.swisscom.com/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Dnn&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">hostname&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;gprs.swisscom.com&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ipv4&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">region&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ch-east&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">type&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">MobileInternet&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">snssai&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">10&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This KRM manifest is stored in git and synced to the Management cluster using Flux. From this, the Operators in the automation layer create intermediate resources, in this case an IP Address via NetBox:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">netbox.dev/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">IpAddressClaim&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">parentPrefixSelector&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">region&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;ch-east&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.region&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">family&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;IPv4&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.ipv4&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">status&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ipAddress&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1.2.3.4&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The Automation Layer creates the following low level resources for the Runtime Layer:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">config.sdcio.dev/v1alpha1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Config&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">labels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">config.sdcio.dev/targetName&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ch-east &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.region&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">config.sdcio.dev/targetNamespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">default&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">priority&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">10&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">config&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">path&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">/&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">value&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">dnn&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;gprs.swisscom.com&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.hostname&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ip&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1.2.3.4&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from IpAddressClaim.status.ipAddress&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">snssai&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#000;font-weight:bold">,&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">10&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.snssai&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">type&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">MobileInternet &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.type&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#000">---&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">externaldns.k8s.io/v1alpha1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">DNSEndpoint&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">endpoints&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">dnsName&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;gprs.swisscom.com&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from Dnn.spec.hostname&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">recordType&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">A&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">targets&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#0000cf;font-weight:bold">1.2.3.4&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># from IpAddressClaim.status.ipAddress&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SDC will now sync the configuration to the 5G CNF and ExternalDNS will create the DNS records in the authoritative PowerDNS backend.&lt;/p>
&lt;h2 id="what-has-worked-well">What has worked well?&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Intent-based configuration&lt;/strong> dramatically reduced the complexity engineers face. Instead of managing thousands of interdependent parameters, they work with concise Custom Resources.&lt;/li>
&lt;li>&lt;strong>Full GitOps reconciliation&lt;/strong> across all layers (deployment, configuration, DNS, certificates, IPAM), configuration drift is detected and reverted to ensure consistency.&lt;/li>
&lt;li>&lt;strong>Custom Kubernetes Operators&lt;/strong> (built with Kubebuilder/controller-runtime) proved to be the right pattern for telco domain-specific concerns, providing full reconciliation support and native KRM integration.&lt;/li>
&lt;li>&lt;strong>The claim model for IPAM&lt;/strong> (NetBox Operator) elegantly solved dynamic IP allocation by following established Kubernetes patterns (PVC analogy).&lt;/li>
&lt;li>&lt;strong>Bringing all automation in-band with Kubernetes&lt;/strong> gave the orchestrator full visibility and control, enabling self-healing and eliminating the brittleness of out-of-band tools.&lt;/li>
&lt;li>&lt;strong>DNS resilience engineering&lt;/strong> — dedicated hackathons, chaos testing, and disaster recovery playbooks significantly improved DNS service reliability.&lt;/li>
&lt;li>&lt;strong>Cross-team collaboration&lt;/strong> on a shared platform and KRM patterns accelerated adoption across multiple network domains.&lt;/li>
&lt;/ul>
&lt;h2 id="what-has-not-worked-well">What has not worked well?&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>NETCONF as a configuration protocol&lt;/strong> introduces complexity — it requires SDC as an intermediary and prevents fully Kubernetes-native configuration. Ideally, CNF vendors would support native K8s APIs using CRs/CRDs or Secrets/ConfigMaps.&lt;/li>
&lt;li>&lt;strong>Tooling gap for KRM-based configuration assembly&lt;/strong> — no mature, community-standard Kubernetes-native tool exists for dynamic configuration hydration. Swisscom had to build custom operators to fill this gap.&lt;/li>
&lt;li>&lt;strong>GitOps+KRM auditability trade-off&lt;/strong> — with dynamically assembled configurations, not all state is visible in Git history. The team continues to explore automated intermediary Git layers.&lt;/li>
&lt;li>&lt;strong>Cumbersome vendor configuration manifests&lt;/strong> — large, monolithic configuration files from CNF vendors (with ~5,000 interdependent parameters) required significant effort to decompose into intent-based abstractions.&lt;/li>
&lt;li>&lt;strong>Telco’s imperative model and Kubernetes’ declarative approach do not align well&lt;/strong> - SDC follows the declarative paradigm, where users define the desired state and SDC determines the actions to achieve it. In contrast, NETCONF/gNMI use an imperative model that requires explicit ordered steps (“do A, then B, then C”). Translating declarative goals into imperative sequences is complex when user‑defined ordering matters, such as for firewall rules where evaluation order affects behaviour. Example: &lt;a href="https://github.com/sdcio/data-server/issues/394">Issue &amp;ldquo;Support user sorted lists&amp;rdquo;&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="what-sort-of-glue-have-you-had-to-develop">What sort of &amp;ldquo;glue&amp;rdquo; have you had to develop?&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Custom Kubernetes Operators&lt;/strong> — domain-specific operators for CNF configuration abstraction, config synchronization, IPAM integration, and DNS automation, all scaffolded with Kubebuilder and controller-runtime.&lt;/li>
&lt;li>&lt;strong>Configuration hydration logic&lt;/strong> — the CNF Config Operator dynamically assembles full configurations from multiple sources (NetBox, Vault, cluster environment) based on high-level intents.&lt;/li>
&lt;li>&lt;strong>SDC contributions&lt;/strong> — &lt;a href="https://github.com/search?q=org%3Asdcio+author%3Aalexandernorth&amp;amp;type=pullrequests">significant development work on SDC&lt;/a> including early testing of CNF compatibility, configuration validation, monitoring, config blame, drift detection, and NETCONF Actions support.&lt;/li>
&lt;li>&lt;strong>ExternalDNS NAPTR support&lt;/strong> — contributed &lt;a href="https://github.com/kubernetes-sigs/external-dns/pull/4212">PR #4212&lt;/a> to enable NAPTR record support for SIP phone calls.&lt;/li>
&lt;li>&lt;strong>Resilient DNS architecture&lt;/strong> — created a reference architecture and open sourced on &lt;a href="https://github.com/swisscom/cloud-native-telco/tree/main/prototypes/dns">GitHub&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Headlamp plugins&lt;/strong> — &lt;a href="https://github.com/kubernetes-sigs/headlamp/pulls?q=is%3Apr+author%3Afaebr+">Custom Resource plugin&lt;/a>.&lt;/li>
&lt;/ul>
&lt;h2 id="how-did-the-architecture-evolve">How did the Architecture Evolve&lt;/h2>
&lt;h3 id="journey">Journey&lt;/h3>
&lt;p>The architecture evolved significantly from traditional imperative automation to the current declarative, KRM-based model:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Phase 1 — Ansible + Jenkins&lt;/strong>: Initial automation used Ansible playbooks triggered by Jenkins pipelines. Configuration was fire-and-forget with no continuous reconciliation.&lt;/li>
&lt;li>&lt;strong>Phase 2 — GitOps for deployment&lt;/strong>: Introduced Flux for CNF deployment, but configuration remained out-of-band via Ansible/NETCONF.&lt;/li>
&lt;li>&lt;strong>Phase 3 — Full GitOps + KRM&lt;/strong>: Extended GitOps to cover configuration, DNS, IPAM, certificates, and testing. Built custom operators and adopted SDC for config synchronization. Achieved continuous reconciliation across all layers.&lt;/li>
&lt;/ol>
&lt;h3 id="key-lessons">Key lessons&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>De facto GitOps for operators is not true GitOps&lt;/strong> — creating Helm releases in Git while configuring NFs via NETCONF out-of-band breaks the GitOps model. Bringing configuration into the Kubernetes API was essential.&lt;/li>
&lt;li>&lt;strong>Bringing everything in-band with Kubernetes&lt;/strong> enables self-healing, reconciliation, and eliminates the brittleness of out-of-band tools.&lt;/li>
&lt;li>&lt;strong>Git as the &lt;em>only&lt;/em> source of truth is insufficient&lt;/strong> — the shared source of truth model (Git for intents, Kubernetes for dynamic state) was a deliberate and necessary evolution.&lt;/li>
&lt;li>&lt;strong>Abstraction is critical&lt;/strong> — engineers cannot effectively manage 5,000+ parameters directly. Intent-based CRs with dynamic assembly significantly reduced cognitive load and errors.&lt;/li>
&lt;li>&lt;strong>Custom Kubernetes Operators&lt;/strong> are the right pattern for domain-specific concerns that existing tools cannot address.&lt;/li>
&lt;li>&lt;strong>Contribute upstream&lt;/strong> — local patches create long-term maintenance burden. Swisscom prioritizes upstream contributions (ExternalDNS, SDC, NetBox Operator) for sustainability.&lt;/li>
&lt;/ul>
&lt;h3 id="whats-next-for-your-architecture">What&amp;rsquo;s next for your architecture?&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Mature SDC Integration&lt;/strong> — Continue expanding SDC for full lifecycle management with continuous reconciliation via gNMI and NETCONF, including completion of NETCONF Actions support.&lt;/li>
&lt;li>&lt;strong>Eliminate NETCONF Dependency&lt;/strong> — Work with CNF vendors to move toward fully Kubernetes-native configuration APIs, reducing reliance on legacy telco protocols.&lt;/li>
&lt;li>&lt;strong>Advanced Dynamic Configuration Assembly&lt;/strong> — Develop more sophisticated Kubernetes operators for multi-source configuration hydration, enabling even more complex intent-based workflows across multiple network domains.&lt;/li>
&lt;li>&lt;strong>Multi-Cluster &amp;amp; Edge Expansion&lt;/strong> — Scale the architecture to additional edge locations and Kubernetes clusters while maintaining consistent GitOps-driven automation.&lt;/li>
&lt;li>&lt;strong>Community Tooling for KRM&lt;/strong> — Contribute toward a mature, Kubernetes-native tool for dynamic configuration assembly that the wider cloud native community can adopt, addressing the current gap in tooling identified during the project.&lt;/li>
&lt;li>&lt;strong>Resilience &amp;amp; Reliability&lt;/strong> — Ongoing improvements to cross-cluster redundancy, disaster recovery playbooks, chaos testing framework, and enhanced monitoring/alerting.&lt;/li>
&lt;li>&lt;strong>Observability &amp;amp; AIOps&lt;/strong> — Integrate AI-driven operations capabilities leveraging the rich telemetry data from the platform&amp;rsquo;s monitoring stack.&lt;/li>
&lt;li>&lt;strong>Cross-Domain Expansion&lt;/strong> — Extend the orchestration framework to additional network domains and infrastructure services beyond the 5G core, applying the same intent-based automation patterns consistently.&lt;/li>
&lt;/ul>
&lt;h2 id="community-contributions">Community Contributions&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Contribution&lt;/th>
&lt;th>Details&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>NetBox Operator&lt;/strong>&lt;/td>
&lt;td>Open-sourced under &lt;a href="https://github.com/netbox-community/netbox-operator">https://github.com/netbox-community/netbox-operator&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>SDC Contributions&lt;/strong>&lt;/td>
&lt;td>Active contributor to the &lt;a href="https://docs.sdcio.dev/">SDC project&lt;/a> (on its path to CNCF incubation)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>KRM Demo Code&lt;/strong>&lt;/td>
&lt;td>&lt;a href="https://github.com/swisscom/containerdays-2024-krm">https://github.com/swisscom/containerdays-2024-krm&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Conference Talks&lt;/strong>&lt;/td>
&lt;td>&lt;a href="https://github.com/swisscom/cloud-native-telco/">KubeCon EU, ContainerDays, Open Source Summit EU&lt;/a>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>CNCF/LFN Whitepaper&lt;/strong>&lt;/td>
&lt;td>Co-authored &lt;a href="https://github.com/lfn-cnti/bestpractices/blob/main/doc/whitepaper/Accelerating_Cloud_Native_in_Telco.md">Accelerating Cloud Native in Telco&lt;/a>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="discussion">Discussion&lt;/h2>
&lt;p>End user members may participate in the &lt;a href="https://github.com/cncf/tab/discussions/136">discussion thread&lt;/a> for this architecture.&lt;/p></description></item></channel></rss>