[fluxcd] Add flux-aio module and migration (#1698)

This change is extracted from
- https://github.com/cozystack/cozystack/pull/1641

and reworked to work standalone

requires:

- https://github.com/cozystack/cozystack/pull/1705


## What this PR does

Adds a new `flux-aio` module and migration script to upgrade FluxCD to
version 22. This introduces a new modular approach to FluxCD
installation using the flux-aio OCI module.

Changes:
- Created new `flux-aio` package with Chart.yaml, Makefile, and CUE
configuration
- Added flux-aio module configuration using OCI module from
`ghcr.io/stefanprodan/modules/flux-aio`
- Generated large fluxcd.yaml template (11956+ lines) for FluxCD
resources
- Added migration script (migrations/21) to handle upgrade from version
21 to 22
- Updated installer to include flux-aio module
- Added script `issue-flux-certificates.sh` for managing TLS
certificates for cozystack-assets
- Updated platform templates to support flux-aio module
- Updated cozystack-assets service references

### Release note

```release-note
[fluxcd] Add flux-aio module and migration
```



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added TLS certificate support for Helm package repositories with
automatic certificate provisioning.

* **Chores**
  * Refactored FluxCD integration using Helm chart-based deployment.
  * Updated system to version 22 with automatic migration support.
  * Enhanced security dependencies (OpenSSL).

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Andrei Kvapil 2025-12-10 20:56:13 +01:00 committed by GitHub
commit 10d35742e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 12133 additions and 114 deletions

View file

@ -0,0 +1,3 @@
apiVersion: v2
name: cozy-fluxcd
version: 0.0.0 # Placeholder, the actual version will be automatically set during the build process

View file

@ -0,0 +1,22 @@
NAME=flux-aio
NAMESPACE=cozy-$(NAME)
include ../../../scripts/common-envs.mk
show:
cozypkg show -n $(NAMESPACE) $(NAME) --plain
apply:
cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl apply -f- --server-side --force-conflicts
diff:
cozypkg show -n $(NAMESPACE) $(NAME) --plain | kubectl diff -f-
update:
timoni bundle build -f flux-aio.cue > templates/fluxcd.yaml
yq eval '(select(.kind == "Namespace") | .metadata.labels."pod-security.kubernetes.io/enforce") = "privileged"' -i templates/fluxcd.yaml
sed -i templates/fluxcd.yaml \
-e '/timoni/d' \
-e 's|\.cluster\.local\.,||g' -e 's|\.cluster\.local\,||g' -e 's|\.cluster\.local\.||g' \
-e '/value: .svc/a \ {{- include "cozy.kubernetes_envs" . | nindent 12 }}' \
-e '/hostNetwork: true/i \ dnsPolicy: ClusterFirstWithHostNet'

View file

@ -0,0 +1,16 @@
bundle: {
apiVersion: "v1alpha1"
name: "flux-aio"
instances: {
"flux": {
module: {
url: "oci://ghcr.io/stefanprodan/modules/flux-aio"
version: "latest"
}
namespace: "cozy-fluxcd"
values: {
securityProfile: "privileged"
}
}
}
}

View file

@ -0,0 +1,13 @@
{{- define "cozy.kubernetes_envs" }}
{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack" }}
{{- $cozyContainers := dig "spec" "template" "spec" "containers" dict $cozyDeployment }}
{{- range $cozyContainers }}
{{- if eq .name "cozystack" }}
{{- range .env }}
{{- if has .name (list "KUBERNETES_SERVICE_HOST" "KUBERNETES_SERVICE_PORT") }}
- {{ toJson . }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@ FROM alpine:3.22
RUN wget -O- https://github.com/cozystack/cozypkg/raw/refs/heads/main/hack/install.sh | sh -s -- -v 1.2.0
RUN apk add --no-cache make kubectl helm coreutils git jq
RUN apk add --no-cache make kubectl helm coreutils git jq openssl
COPY --from=builder /src/scripts /cozystack/scripts
COPY --from=builder /src/packages/core /cozystack/packages/core

View file

@ -54,6 +54,8 @@ spec:
env:
- name: KUBERNETES_SERVICE_HOST
value: localhost
- name: INSTALL_FLUX
value: "true"
- name: KUBERNETES_SERVICE_PORT
value: "7445"
- name: K8S_AWAIT_ELECTION_ENABLED

View file

@ -2,24 +2,6 @@
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []
- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator,cilium]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}
- name: cilium
releaseName: cilium
chart: cozy-cilium

View file

@ -2,24 +2,6 @@
{{- $clusterDomain := (index $cozyConfig.data "cluster-domain") | default "cozy.local" }}
releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []
- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}
- name: cert-manager-crds
releaseName: cert-manager-crds
chart: cozy-cert-manager-crds

View file

@ -11,24 +11,6 @@
{{- end }}
releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []
- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator,cilium,kubeovn]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}
- name: cilium
releaseName: cilium
chart: cozy-cilium

View file

@ -11,24 +11,6 @@
{{- end }}
releases:
- name: fluxcd-operator
releaseName: fluxcd-operator
chart: cozy-fluxcd-operator
namespace: cozy-fluxcd
privileged: true
dependsOn: []
- name: fluxcd
releaseName: fluxcd
chart: cozy-fluxcd
namespace: cozy-fluxcd
dependsOn: [fluxcd-operator]
values:
flux-instance:
instance:
cluster:
domain: {{ $clusterDomain }}
- name: cert-manager-crds
releaseName: cert-manager-crds
chart: cozy-cert-manager-crds

View file

@ -17,6 +17,36 @@ Get IP-addresses of master nodes
{{ join "," $ips }}
{{- end -}}
{{/*
Get Kubernetes API Endpoint from cozystack deployment
Returns host:port format
*/}}
{{- define "cozystack.kubernetesAPIEndpoint" -}}
{{- $cozyDeployment := lookup "apps/v1" "Deployment" "cozy-system" "cozystack" }}
{{- $cozyContainers := dig "spec" "template" "spec" "containers" list $cozyDeployment }}
{{- $kubernetesServiceHost := "" }}
{{- $kubernetesServicePort := "" }}
{{- range $cozyContainers }}
{{- if eq .name "cozystack" }}
{{- range .env }}
{{- if eq .name "KUBERNETES_SERVICE_HOST" }}
{{- $kubernetesServiceHost = .value }}
{{- end }}
{{- if eq .name "KUBERNETES_SERVICE_PORT" }}
{{- $kubernetesServicePort = .value }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- if eq $kubernetesServiceHost "" }}
{{- $kubernetesServiceHost = "kubernetes.default.svc" }}
{{- end }}
{{- if eq $kubernetesServicePort "" }}
{{- $kubernetesServicePort = "443" }}
{{- end }}
{{- printf "%s:%s" $kubernetesServiceHost $kubernetesServicePort }}
{{- end -}}
{{- define "cozystack.defaultDashboardValues" -}}
kubeapps:
{{- if .Capabilities.APIVersions.Has "source.toolkit.fluxcd.io/v1" }}

View file

@ -43,8 +43,6 @@ rules:
- cozystack-assets-0
verbs:
- get
- create
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding

View file

@ -8,7 +8,9 @@ metadata:
cozystack.io/repository: system
spec:
interval: 5m0s
url: http://cozystack-assets.cozy-system.svc/repos/system
url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/system
certSecretRef:
name: cozystack-assets-tls
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
@ -20,7 +22,9 @@ metadata:
cozystack.io/repository: apps
spec:
interval: 5m0s
url: http://cozystack-assets.cozy-system.svc/repos/apps
url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/apps
certSecretRef:
name: cozystack-assets-tls
---
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
@ -31,4 +35,6 @@ metadata:
cozystack.io/repository: extra
spec:
interval: 5m0s
url: http://cozystack-assets.cozy-system.svc/repos/extra
url: https://{{ include "cozystack.kubernetesAPIEndpoint" . }}/api/v1/namespaces/cozy-system/pods/cozystack-assets-0/proxy/repos/extra
certSecretRef:
name: cozystack-assets-tls

View file

@ -19,29 +19,11 @@ run_migrations() {
done
}
flux_is_ok() {
kubectl wait --for=condition=available -n cozy-fluxcd deploy/source-controller deploy/helm-controller --timeout=1s
kubectl wait --for=condition=ready -n cozy-fluxcd helmrelease/fluxcd --timeout=1s # to call "apply resume" below
}
ensure_fluxcd() {
if flux_is_ok; then
install_flux() {
if [ "$INSTALL_FLUX" != "true" ]; then
return
fi
# Install fluxcd-operator
if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd-operator; then
make -C packages/system/fluxcd-operator apply resume
else
make -C packages/system/fluxcd-operator apply-locally
fi
wait_for_crds fluxinstances.fluxcd.controlplane.io
# Install fluxcd
if kubectl get helmreleases.helm.toolkit.fluxcd.io -n cozy-fluxcd fluxcd; then
make -C packages/system/fluxcd apply resume
else
make -C packages/system/fluxcd apply-locally
fi
make -C packages/core/flux-aio apply
wait_for_crds helmreleases.helm.toolkit.fluxcd.io helmrepositories.source.toolkit.fluxcd.io
}
@ -49,15 +31,6 @@ wait_for_crds() {
timeout 60 sh -c "until kubectl get crd $*; do sleep 1; done"
}
install_basic_charts() {
if [ "$BUNDLE" = "paas-full" ] || [ "$BUNDLE" = "distro-full" ]; then
make -C packages/system/cilium apply resume
fi
if [ "$BUNDLE" = "paas-full" ]; then
make -C packages/system/kubeovn apply resume
fi
}
cd "$(dirname "$0")/.."
# Run migrations
@ -67,16 +40,14 @@ run_migrations
make -C packages/core/platform namespaces-apply
# Install fluxcd
ensure_fluxcd
install_flux
# Install fluxcd certificates
./scripts/issue-flux-certificates.sh
# Install platform chart
make -C packages/core/platform reconcile
# Install basic charts
if ! flux_is_ok; then
install_basic_charts
fi
# Reconcile Helm repositories
kubectl annotate helmrepositories.source.toolkit.fluxcd.io -A -l cozystack.io/repository reconcile.fluxcd.io/requestedAt=$(date +"%Y-%m-%dT%H:%M:%SZ") --overwrite

View file

@ -0,0 +1,63 @@
#!/bin/sh
set -e
if kubectl get secret -n cozy-system cozystack-assets-tls >/dev/null 2>&1 && kubectl get secret -n cozy-public cozystack-assets-tls >/dev/null 2>&1; then
echo "Secret cozystack-assets-tls already exists in both cozy-system and cozy-public namespaces. Exiting."
exit 0
fi
USER_CN="cozystack-assets-reader"
CSR_NAME="csr-${USER_CN}-$(date +%s)"
# make temp directory and cleanup handler
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
# move into tmpdir
cd "$TMPDIR"
openssl genrsa -out tls.key 2048
openssl req -new -key tls.key -subj "/CN=${USER_CN}" -out tls.csr
CSR_B64=$(base64 < tls.csr | tr -d '\n')
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: ${CSR_NAME}
spec:
signerName: kubernetes.io/kube-apiserver-client
request: ${CSR_B64}
usages:
- client auth
EOF
kubectl certificate approve "${CSR_NAME}"
echo "Waiting for .status.certificate..."
kubectl wait csr "${CSR_NAME}" \
--for=jsonpath='{.status.certificate}' \
--timeout=120s
kubectl get csr "${CSR_NAME}" \
-o jsonpath='{.status.certificate}' | base64 -d > tls.crt
kubectl get -n kube-public configmap kube-root-ca.crt \
-o jsonpath='{.data.ca\.crt}' > ca.crt
kubectl create secret generic "cozystack-assets-tls" \
--namespace='cozy-system' \
--type='kubernetes.io/tls' \
--from-file=tls.crt \
--from-file=tls.key \
--from-file=ca.crt \
--dry-run=client -o yaml | kubectl apply -f -
kubectl create secret generic "cozystack-assets-tls" \
--namespace='cozy-public' \
--type='kubernetes.io/tls' \
--from-file=tls.crt \
--from-file=tls.key \
--from-file=ca.crt \
--dry-run=client -o yaml | kubectl apply -f -

10
scripts/migrations/21 Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
# Migration 21 --> 22
set -euo pipefail
kubectl delete hr -n cozy-fluxcd fluxcd --ignore-not-found
# Stamp version
kubectl create configmap -n cozy-system cozystack-version \
--from-literal=version=22 --dry-run=client -o yaml | kubectl apply -f-