From 43d3637bb79bc748885902c140b4ead0a63dab0c Mon Sep 17 00:00:00 2001 From: Nicolas Brieussel Date: Tue, 21 Jul 2026 11:37:56 +0200 Subject: [PATCH] feat: add ExternalDNS for scalepack.fr (scaleway env) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds platform/scaleway/external-dns.yml (provider=scaleway, domainFilters=scalepack.fr) plus apps/external-dns-init/, a small chart whose ExternalSecret materializes Scaleway DNS API credentials from OpenBao (apps/external-dns/scaleway-dns-credentials) into the Secret external-dns mounts. Scaleway-only for now — minikube has nothing public to publish records for. The OpenBao KV entry itself isn't seeded yet; that's a manual, out-of-band step (same as the other OpenBao roles/policies). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01CCgyeSfKWH6m5mmJEg6t43 --- apps/external-dns-init/Chart.yaml | 5 ++ .../templates/externalsecret.yaml | 24 +++++++++ apps/external-dns-init/values.yaml | 21 ++++++++ .../scaleway/templates/external-dns-init.yaml | 27 ++++++++++ platform/scaleway/external-dns.yml | 50 +++++++++++++++++++ 5 files changed, 127 insertions(+) create mode 100644 apps/external-dns-init/Chart.yaml create mode 100644 apps/external-dns-init/templates/externalsecret.yaml create mode 100644 apps/external-dns-init/values.yaml create mode 100644 clusters/scaleway/templates/external-dns-init.yaml create mode 100644 platform/scaleway/external-dns.yml diff --git a/apps/external-dns-init/Chart.yaml b/apps/external-dns-init/Chart.yaml new file mode 100644 index 0000000..c2eea42 --- /dev/null +++ b/apps/external-dns-init/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v2 +name: external-dns-init +description: Materializes Scaleway DNS API credentials from OpenBao into a Secret external-dns can mount +type: application +version: 0.1.0 diff --git a/apps/external-dns-init/templates/externalsecret.yaml b/apps/external-dns-init/templates/externalsecret.yaml new file mode 100644 index 0000000..7c1a182 --- /dev/null +++ b/apps/external-dns-init/templates/externalsecret.yaml @@ -0,0 +1,24 @@ +# Materializes the Scaleway DNS credentials that +# platform/scaleway/external-dns.yml references via secretKeyRef. Lives in +# its own chart (mirrors apps/secrets-sync) rather than inside the +# external-dns Application itself, since platform//*.yml stays plain +# Application manifests pointing at external Helm charts — there's no room +# there for an ExternalSecret alongside. +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: {{ .Values.secret.name }} + namespace: {{ .Values.namespace }} + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + refreshInterval: {{ .Values.refreshInterval | quote }} + secretStoreRef: + name: {{ .Values.clusterSecretStoreName }} + kind: ClusterSecretStore + target: + name: {{ .Values.secret.name }} + creationPolicy: Owner + dataFrom: + - extract: + key: {{ .Values.openbao.path }} diff --git a/apps/external-dns-init/values.yaml b/apps/external-dns-init/values.yaml new file mode 100644 index 0000000..a3e7f24 --- /dev/null +++ b/apps/external-dns-init/values.yaml @@ -0,0 +1,21 @@ +# Pulls the Scaleway Domains & DNS API credentials from OpenBao into a Secret +# that platform/scaleway/external-dns.yml wires into the external-dns pod via +# env[].valueFrom.secretKeyRef. OpenBao stays the source of truth — no +# credential value ever lives in this repo. +# +# The KV entry itself is seeded by hand in OpenBao (same out-of-band workflow +# as the other manually-managed roles/policies), with keys SCW_ACCESS_KEY / +# SCW_SECRET_KEY. Needs an API key scoped to the Scaleway Domains API, +# belonging to the account that owns the domain once one is bought. +namespace: external-dns + +# ClusterSecretStore declared by the openbao-init chart. +clusterSecretStoreName: openbao + +openbao: + path: apps/external-dns/scaleway-dns-credentials + +secret: + name: external-dns-scaleway-credentials + +refreshInterval: 1h diff --git a/clusters/scaleway/templates/external-dns-init.yaml b/clusters/scaleway/templates/external-dns-init.yaml new file mode 100644 index 0000000..5233fe2 --- /dev/null +++ b/clusters/scaleway/templates/external-dns-init.yaml @@ -0,0 +1,27 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: external-dns-init + namespace: argocd + annotations: + # Wave 3: after openbao-init (wave 2), whose chart declares the + # ClusterSecretStore this app's ExternalSecret depends on. + argocd.argoproj.io/sync-wave: "3" +spec: + project: default + + source: + repoURL: {{ .Values.repoURL }} + targetRevision: {{ .Values.revision }} + path: apps/external-dns-init + + destination: + server: https://kubernetes.default.svc + namespace: external-dns + + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/platform/scaleway/external-dns.yml b/platform/scaleway/external-dns.yml new file mode 100644 index 0000000..46273d5 --- /dev/null +++ b/platform/scaleway/external-dns.yml @@ -0,0 +1,50 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: external-dns + namespace: argocd +spec: + project: default + + source: + repoURL: https://kubernetes-sigs.github.io/external-dns + chart: external-dns + targetRevision: 1.21.1 + helm: + values: | + provider: + name: scaleway + + # Credentials materialized by apps/external-dns-init from OpenBao + # (see clusters/scaleway/templates/external-dns-init.yaml). + env: + - name: SCW_ACCESS_KEY + valueFrom: + secretKeyRef: + name: external-dns-scaleway-credentials + key: SCW_ACCESS_KEY + - name: SCW_SECRET_KEY + valueFrom: + secretKeyRef: + name: external-dns-scaleway-credentials + key: SCW_SECRET_KEY + + # scalepack.fr, bought through Scaleway Domains & DNS. Leave + # txtOwnerId as-is going forward — changing it orphans existing TXT + # ownership records. + domainFilters: + - scalepack.fr + policy: upsert-only + registry: txt + txtOwnerId: scaleway + + destination: + server: https://kubernetes.default.svc + namespace: external-dns + + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true