feat(substrate): deploy cert-manager, ingress-nginx, reloader + LE staging issuers via app-of-apps — restores substrate ownership after Terraform removal

Substrate had no owner since Terraform was deleted (Pure GitOps). Adds 5 wave-0/1
Applications: cert-manager v1.21.0 (installCRDs, CP tolerations), ingress-nginx
4.15.1 (LB 192.168.1.160), reloader 2.2.14 at wave 0; LE ClusterIssuers +
*.riotpiao.com wildcard cert at wave 1 (DNS-01 via Cloudflare). Adds 3 chart
repos to AppProject sourceRepos and SOPS-encrypted cloudflare-api-token secret.
Cert starts on letsencrypt-staging; flip to prod after clean issue.
This commit is contained in:
Story Crater Bot
2026-07-20 12:50:02 -07:00
parent d9d2e34558
commit d841bbdb95
4 changed files with 210 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
# 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:
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
+4
View File
@@ -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: "*"
@@ -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:
@@ -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