From d9ae0a6c4442397f1839de6e2ce432fd473128af Mon Sep 17 00:00:00 2001 From: Story Crater Bot <19826264+Riotpiaole@users.noreply.github.com> Date: Tue, 18 Aug 2026 15:08:02 -0700 Subject: [PATCH] feat(substrate): deploy cert-manager/ingress-nginx/reloader + privileged PodSecurity for ingress-nginx --- k8s/argocd/apps/00-substrate.yaml | 162 ++++++++++++++++++ k8s/argocd/projects/homelab-project.yaml | 4 + .../cert-manager/cert-manager-values.yaml | 26 +++ .../cert-manager/cloudflare-secrets.enc.yaml | 23 +++ 4 files changed, 215 insertions(+) create mode 100644 k8s/argocd/apps/00-substrate.yaml create mode 100644 k8s/bootstrap/cert-manager/cloudflare-secrets.enc.yaml diff --git a/k8s/argocd/apps/00-substrate.yaml b/k8s/argocd/apps/00-substrate.yaml new file mode 100644 index 0000000..1bedc2e --- /dev/null +++ b/k8s/argocd/apps/00-substrate.yaml @@ -0,0 +1,162 @@ +# Wave 0/1 — cluster substrate: cert-manager, ingress-nginx, reloader, and the +# Let's Encrypt issuers + wildcard cert. Previously installed by Terraform; now +# owned by app-of-apps (Pure GitOps). Controllers at wave 0; the ClusterIssuers +# and wildcard Certificate at wave 1 so cert-manager CRDs exist first. +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cert-manager + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + revisionHistoryLimit: 3 + sources: + - repoURL: https://charts.jetstack.io + chart: cert-manager + targetRevision: "v1.21.0" + helm: + valueFiles: + - $values/k8s/bootstrap/cert-manager/cert-manager-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: cert-manager + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + - ServerSideApply=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: ingress-nginx + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + revisionHistoryLimit: 3 + sources: + - repoURL: https://kubernetes.github.io/ingress-nginx + chart: ingress-nginx + targetRevision: "4.15.1" + helm: + valueFiles: + - $values/k8s/bootstrap/ingress/nginx-values.yaml + - repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + ref: values + destination: + server: https://kubernetes.default.svc + namespace: ingress-nginx + syncPolicy: + managedNamespaceMetadata: + # hostPort 80/443 requires the privileged PodSecurity level; the default + # baseline/restricted enforce blocks the controller DaemonSet. + labels: + pod-security.kubernetes.io/enforce: privileged + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: reloader + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: homelab + revisionHistoryLimit: 3 + source: + repoURL: https://stakater.github.io/stakater-charts + chart: reloader + targetRevision: "2.2.14" + helm: + values: | + reloader: + deployment: + tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + destination: + server: https://kubernetes.default.svc + namespace: reloader + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +--- +# Wave 1 — LE ClusterIssuers + wildcard cert (needs cert-manager CRDs from wave 0). +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cert-manager-issuers + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + revisionHistoryLimit: 3 + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/bootstrap/cert-manager + directory: + include: "letsencrypt-issuer.yaml" + destination: + server: https://kubernetes.default.svc + namespace: cert-manager + syncPolicy: + automated: + prune: true + selfHeal: true +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: wildcard-cert + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io + annotations: + argocd.argoproj.io/sync-wave: "1" +spec: + project: homelab + revisionHistoryLimit: 3 + source: + repoURL: http://forgejo.riotpiao.com:3000/riotpiao.com/homelab.git + targetRevision: main + path: k8s/bootstrap/ingress + directory: + include: "riotpiao-com-cert.yaml" + destination: + server: https://kubernetes.default.svc + namespace: ingress-nginx + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/k8s/argocd/projects/homelab-project.yaml b/k8s/argocd/projects/homelab-project.yaml index 77c4097..0fcacf0 100644 --- a/k8s/argocd/projects/homelab-project.yaml +++ b/k8s/argocd/projects/homelab-project.yaml @@ -25,6 +25,10 @@ spec: - https://charts.bitnami.com/bitnami - https://go.temporal.io/helm-charts - https://portainer.github.io/k8s/ + # Substrate charts (cert-manager, ingress-nginx, reloader) — app-of-apps owned + - https://charts.jetstack.io + - https://kubernetes.github.io/ingress-nginx + - https://stakater.github.io/stakater-charts destinations: - server: https://kubernetes.default.svc namespace: "*" diff --git a/k8s/bootstrap/cert-manager/cert-manager-values.yaml b/k8s/bootstrap/cert-manager/cert-manager-values.yaml index 2ff1e97..71b34f2 100644 --- a/k8s/bootstrap/cert-manager/cert-manager-values.yaml +++ b/k8s/bootstrap/cert-manager/cert-manager-values.yaml @@ -3,6 +3,32 @@ # wildcard cert nginx serves — certmanager_certificate_expiration_timestamp_seconds # is the early-warning signal before any service's TLS breaks. +# CRDs must be installed by the chart — ArgoCD helm-template does not apply a +# chart's crds/ folder, and the ClusterIssuer/Certificate resources (wave 1) +# depend on them existing first. +installCRDs: true + +# Tolerate the control-plane taint (talos-cp-1 is the only schedulable node). +tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule +webhook: + tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule +cainjector: + tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule +startupapicheck: + tolerations: + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + prometheus: enabled: true servicemonitor: diff --git a/k8s/bootstrap/cert-manager/cloudflare-secrets.enc.yaml b/k8s/bootstrap/cert-manager/cloudflare-secrets.enc.yaml new file mode 100644 index 0000000..3a7157c --- /dev/null +++ b/k8s/bootstrap/cert-manager/cloudflare-secrets.enc.yaml @@ -0,0 +1,23 @@ +apiVersion: ENC[AES256_GCM,data:AYk=,iv:/1G8RSCBaiQ6msQEPPOO4LzlbYOzEbNvT9OwnY0E1JQ=,tag:Gq2I92mI3c1FFsbv2ZE+BQ==,type:str] +kind: ENC[AES256_GCM,data:PbHIh8xS,iv:KMW7WL9ZjTmUz3NOQRhjsuAH2EZFXGk1P4hhl7cp8c0=,tag:9vJiqOtV3EhVfXWjJr4ZhA==,type:str] +metadata: + name: ENC[AES256_GCM,data:mF7O9mz8+KGfU6DJ8ifP974at95QOPH7yIaC,iv:1qXckUq4RTBZ06YNLXsuMW1UWRK9cgymDdVnmwLZles=,tag:v2dzEB+J23h4MxxkcJThIg==,type:str] + namespace: ENC[AES256_GCM,data:7omPsuwSfF1IwvCN,iv:YCv7jIXpkzTx9iu9ScwHme8Nc8iqJr1xn8yXK/OsHk8=,tag:5zslu/jpTpMHi2XvCP92Ig==,type:str] +type: ENC[AES256_GCM,data:nF1pv2+3,iv:iseIGnyGeVE76BORrjX/TnvrfzaRMOFrQ7oWT0jIS9M=,tag:qTpF2hYVmnCwL8EQA9Ot8w==,type:str] +stringData: + api-token: ENC[AES256_GCM,data:Evzvkz7ywKLsTXA0/ZF09Y+uKWDQ16SbAsogo4t9aAd+zsvFAnsyVifQc0SUNxzjSv8FXws=,iv:uFvlesWdZUbiuh8WTq1uLBRtuptV2tXxGJ6PVgu7vCI=,tag:thpyhOHtKWNn0bi1Xi1q6w==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwM0ovVUZmZVFmbjlwOXgx + U2h6aDNVVmV6NC8xckZtN3lwVytneHZvQ0VFCld3YjlhTFU5aVd0T3NpOUU3NW16 + ak10VVFiMnNsNG9GS0tIN1ViZjRrcG8KLS0tIFNScE5ibkYvQWszeDl2UkF2VHpG + Rzd2NlNSYlRYY0pkaDY1YklGS1NaWFUKTmYqAOF+iPbgl8Qv1qEyGLSDn3Yqw3Sd + iYpwVUPMrrLG9FiaSTUavmkv96DCEnof3GStaYsd62MXFWHW9eFAtA== + -----END AGE ENCRYPTED FILE----- + recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh + lastmodified: "2026-07-20T19:49:33Z" + mac: ENC[AES256_GCM,data:6d8l+mal0zlwSyK1zkvpE8Y2cknXM+deaiIdzc2nySEm2pkC2ryY6exmPOsiyjDFrH9vnvwpvWxUqOZc1GPJ7/Pe6lDsdgT7ZPKrzJwfG07lXCZTNMTKruQ745mPgMzoJ82OjC8dXrXRXAqbFMw7SJeCajlfwL2Odmqr0reTnYs=,iv:FEcmRP5KYbI6QBZDLvcgF4ko4g5j2I8+eFrzPay80fw=,tag:cdUfwl+8Zwjyvu/p8htS1w==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.2