Initial sealed-secrets gitops app
Validate manifests / validate (push) Successful in 6s

This commit is contained in:
2026-04-20 01:19:54 +01:00
commit 6590db133c
6 changed files with 242 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
name: Validate manifests
on:
push:
pull_request:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tools
run: |
curl -sL https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz \
| tar xz -C /usr/local/bin
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
curl -fsSL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 \
-o /usr/local/bin/yq
chmod +x /usr/local/bin/yq
mkdir -p .ci-schemas/argoproj.io
curl -fsSL https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/argoproj.io/applicationset_v1alpha1.json \
-o .ci-schemas/argoproj.io/applicationset_v1alpha1.json
cp .ci-schemas/argoproj.io/applicationset_v1alpha1.json .ci-schemas/argoproj.io/ApplicationSet_v1alpha1.json
cp .ci-schemas/argoproj.io/applicationset_v1alpha1.json .ci-schemas/argoproj.io/ApplicationSet.json
cp .ci-schemas/argoproj.io/applicationset_v1alpha1.json .ci-schemas/argoproj.io/applicationset.json
- name: kubeconform - raw YAML
run: |
bootstrap_enabled=false
if [ -f bootstrap/config.yaml ] && grep -Eq '^[[:space:]]*enabled:[[:space:]]*true[[:space:]]*$' bootstrap/config.yaml; then
bootstrap_enabled=true
fi
mapfile -t manifests < <(
find . -type f -name '*.yaml' \
! -path './.gitea/*' \
! -path './manifest/overlays/*/helm-values/*' \
! -path './bootstrap/config.yaml' \
| sort
)
if [ "$bootstrap_enabled" != "true" ]; then
filtered=()
for manifest in "${manifests[@]}"; do
[ "$manifest" = "./bootstrap/applicationset.yaml" ] && continue
filtered+=("$manifest")
done
manifests=("${filtered[@]}")
fi
if [ "${#manifests[@]}" -eq 0 ]; then
echo "No manifests found"
exit 0
fi
printf '%s\n' "${manifests[@]}" \
| xargs kubeconform \
-strict \
-kubernetes-version 1.35.0 \
-schema-location default \
-schema-location '.ci-schemas/{{.Group}}/{{.ResourceKind}}{{.KindSuffix}}.json' \
-schema-location '.ci-schemas/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
-summary
- name: Helm template
run: |
chart_version=$(yq '.spec.generators[0].list.elements[0].chartVersion' bootstrap/applicationset.yaml)
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm repo update sealed-secrets
helm template sealed-secrets-controller sealed-secrets/sealed-secrets \
--namespace kube-system \
--version "$chart_version" \
-f manifest/overlays/production/helm-values/values.yaml \
>/tmp/rendered.yaml
kubeconform \
-strict \
-kubernetes-version 1.35.0 \
/tmp/rendered.yaml
- name: Apply bootstrap ApplicationSet
env:
KUBECONFIG_B64: ${{ secrets.KUBECONFIG_B64 }}
run: |
if [ "${GITHUB_EVENT_NAME:-}" != "push" ] || [ "${GITHUB_REF:-}" != "refs/heads/main" ]; then
echo "Skipping bootstrap apply: only push events on main may apply"
exit 0
fi
if [ ! -f bootstrap/config.yaml ] || ! grep -Eq '^[[:space:]]*enabled:[[:space:]]*true[[:space:]]*$' bootstrap/config.yaml; then
echo "Skipping bootstrap apply: bootstrap/config.yaml is not enabled"
exit 0
fi
if [ -z "${KUBECONFIG_B64:-}" ]; then
echo "KUBECONFIG_B64 secret is required to apply bootstrap/applicationset.yaml"
exit 1
fi
curl -fsSL https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl \
-o /usr/local/bin/kubectl
chmod +x /usr/local/bin/kubectl
mkdir -p "${HOME}/.kube"
printf '%s' "$KUBECONFIG_B64" | base64 -d > "${HOME}/.kube/config"
kubectl apply -f bootstrap/applicationset.yaml
+5
View File
@@ -0,0 +1,5 @@
.DS_Store
.idea/
.vscode/
*.swp
*.swo
+59
View File
@@ -0,0 +1,59 @@
# sealed-secrets
GitOps source-of-truth repository for the cluster Sealed Secrets controller.
This repo follows the same dormant-bootstrap pattern as the other application
repositories, but the runtime payload is a pinned upstream Helm chart instead of
raw kustomize manifests. The controller is installed in `kube-system` with the
name `sealed-secrets-controller` so `kubeseal` works with its default controller
name assumptions.
## Layout
```text
.
├── .gitea/
│ └── workflows/validate.yaml
├── .gitignore
├── bootstrap/
│ ├── applicationset.yaml
│ └── config.yaml
├── manifest/
│ └── overlays/
│ └── production/
│ └── helm-values/
│ └── values.yaml
└── README.md
```
## Bootstrap activation model
1. Prepare the repo on `init`.
2. Keep `bootstrap/config.yaml` set to `enabled: false` while validating.
3. Promote the repo to `main`.
4. Change `bootstrap/config.yaml` to `enabled: true` on `main`.
5. Let the bootstrap workflow apply `bootstrap/applicationset.yaml`.
## Controller decisions
- Namespace: `kube-system`
- Helm chart: `bitnami-labs/sealed-secrets`
- Chart version pin: `2.18.5`
- Controller name override: `sealed-secrets-controller`
The name override matters because the chart defaults to `sealed-secrets`, while
`kubeseal` expects `sealed-secrets-controller` unless you pass explicit flags.
## Secret migration workflow
1. Install `kubeseal` locally.
2. Fetch the controller cert:
`kubeseal --fetch-cert --controller-namespace kube-system > sealed-secrets.pem`
3. Convert an existing Secret manifest:
`kubeseal --format yaml --cert sealed-secrets.pem < secret.yaml > sealed-secret.yaml`
4. Commit the resulting `SealedSecret` manifest in the owning app repo.
5. Remove the old SOPS-backed secret generator entry only after the app is
syncing from the new `SealedSecret` path.
Use the default `strict` scope unless a secret must survive renames inside the
same namespace. Avoid `cluster-wide` scope unless there is a concrete need.
+46
View File
@@ -0,0 +1,46 @@
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: sealed-secrets
namespace: argocd
spec:
goTemplate: true
goTemplateOptions:
- missingkey=error
generators:
- list:
elements:
- environment: production
namespace: kube-system
path: manifest/overlays/production
chartVersion: 2.18.5
template:
metadata:
name: 'sealed-secrets-{{ .environment }}'
labels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/name: sealed-secrets
spec:
project: default
sources:
- repoURL: https://bitnami-labs.github.io/sealed-secrets
chart: sealed-secrets
targetRevision: '{{ .chartVersion }}'
helm:
releaseName: sealed-secrets-controller
valueFiles:
- $values/{{ .path }}/helm-values/values.yaml
- repoURL: http://gitea-ha-http.apps:3000/olb42/sealed-secrets.git
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: '{{ .namespace }}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=false
- ApplyOutOfSyncOnly=true
- ServerSideApply=true
+3
View File
@@ -0,0 +1,3 @@
enabled: false
target_namespace: argocd
apply_from_branch: main
@@ -0,0 +1,21 @@
# Production values for the official sealed-secrets Helm chart.
# Chart version is pinned in bootstrap/applicationset.yaml.
fullnameOverride: sealed-secrets-controller
namespace: kube-system
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
podLabels:
app.kubernetes.io/part-of: sealed-secrets
app.kubernetes.io/environment: production
metrics:
serviceMonitor:
enabled: false