From 832d53739db38e64975334a0ec9a0703364381ce Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Sun, 18 Oct 2026 13:37:03 +0200 Subject: [PATCH] Deploy Sealed Secrets with Argo CD --- README.md | 30 ++++++++++++++++++++++++++- bootstrap/install.sh | 6 ++++++ bootstrap/kustomization.yaml | 2 ++ bootstrap/platform-project.yaml | 32 +++++++++++++++++++++++++++++ bootstrap/sealed-secrets.yaml | 36 +++++++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 bootstrap/platform-project.yaml create mode 100644 bootstrap/sealed-secrets.yaml diff --git a/README.md b/README.md index f752b50..a1a5b30 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ container images and then commits the selected image tag here; it never receives ## Repository layout - `apps/immich-sync/` is the desired Kubernetes state for Immich Share Sync. -- `bootstrap/` contains the Argo CD project and Application that point back to this repository. +- `bootstrap/` contains Argo CD projects and Applications, including the + upstream Sealed Secrets controller. - `scripts/update-immich-sync-image.sh` is the single image-promotion interface used by CI. The only canonical Immich Share Sync image version is `images[0].newTag` in @@ -88,3 +89,30 @@ radius. Argo CD is the normal deployment mechanism. If it is unavailable, `apps/immich-sync/install.sh` renders, performs a server-side dry-run, applies the same Kustomize source, and waits for the Deployment rollout. A later Argo CD refresh will see the same desired resources. + +## Sealed Secrets + +Argo CD installs the official Sealed Secrets chart pinned in +`bootstrap/sealed-secrets.yaml`. Public Git stores only `SealedSecret` +ciphertext. The controller decrypts that ciphertext into namespace-scoped +Kubernetes Secrets; the private sealing key never belongs in this repository. + +Install the matching `kubeseal` client, then seal a Secret for its final name +and namespace. The default strict scope prevents ciphertext from being moved to +another name or namespace: + +```sh +kubectl --namespace default create secret generic example \ + --from-literal=token='replace-me' \ + --dry-run=client --output=yaml \ + | kubeseal \ + --controller-name sealed-secrets-controller \ + --controller-namespace sealed-secrets \ + --format yaml > example-sealed-secret.yaml +``` + +The controller's generated private key is the disaster-recovery key for every +sealed value. Back up the Secrets labelled +`sealedsecrets.bitnami.com/sealed-secrets-key=active` from namespace +`sealed-secrets` to an encrypted offline store. Do not commit that backup. A +cluster rebuilt without one of those keys cannot decrypt existing ciphertext. diff --git a/bootstrap/install.sh b/bootstrap/install.sh index 068f300..6b5638c 100755 --- a/bootstrap/install.sh +++ b/bootstrap/install.sh @@ -17,3 +17,9 @@ kubectl --namespace argocd wait application/immich-sync \ kubectl --namespace argocd wait application/immich-sync \ --for=jsonpath='{.status.health.status}'=Healthy \ --timeout=5m +kubectl --namespace argocd wait application/sealed-secrets \ + --for=jsonpath='{.status.sync.status}'=Synced \ + --timeout=5m +kubectl --namespace argocd wait application/sealed-secrets \ + --for=jsonpath='{.status.health.status}'=Healthy \ + --timeout=5m diff --git a/bootstrap/kustomization.yaml b/bootstrap/kustomization.yaml index e21bed5..8113cb8 100644 --- a/bootstrap/kustomization.yaml +++ b/bootstrap/kustomization.yaml @@ -2,4 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - project.yaml +- platform-project.yaml +- sealed-secrets.yaml - immich-sync.yaml diff --git a/bootstrap/platform-project.yaml b/bootstrap/platform-project.yaml new file mode 100644 index 0000000..ca4d18c --- /dev/null +++ b/bootstrap/platform-project.yaml @@ -0,0 +1,32 @@ +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: platform + namespace: argocd +spec: + description: Cluster services installed from maintained upstream charts + sourceRepos: + - https://bitnami.github.io/sealed-secrets + destinations: + - namespace: sealed-secrets + server: https://kubernetes.default.svc + clusterResourceWhitelist: + - group: apiextensions.k8s.io + kind: CustomResourceDefinition + - group: rbac.authorization.k8s.io + kind: ClusterRole + - group: rbac.authorization.k8s.io + kind: ClusterRoleBinding + namespaceResourceWhitelist: + - group: "" + kind: Service + - group: "" + kind: ServiceAccount + - group: apps + kind: Deployment + - group: monitoring.coreos.com + kind: ServiceMonitor + - group: rbac.authorization.k8s.io + kind: Role + - group: rbac.authorization.k8s.io + kind: RoleBinding diff --git a/bootstrap/sealed-secrets.yaml b/bootstrap/sealed-secrets.yaml new file mode 100644 index 0000000..5c235c0 --- /dev/null +++ b/bootstrap/sealed-secrets.yaml @@ -0,0 +1,36 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: sealed-secrets + namespace: argocd +spec: + project: platform + source: + chart: sealed-secrets + repoURL: https://bitnami.github.io/sealed-secrets + targetRevision: 2.20.0 + helm: + releaseName: sealed-secrets + valuesObject: + fullnameOverride: sealed-secrets-controller + metrics: + serviceMonitor: + enabled: true + labels: + release: prometheus + resources: + limits: + memory: 128Mi + requests: + cpu: 10m + memory: 32Mi + destination: + server: https://kubernetes.default.svc + namespace: sealed-secrets + syncPolicy: + automated: + enabled: true + prune: false + selfHeal: true + syncOptions: + - CreateNamespace=true