sourceRef: kind: OCIRepository name: cozystack-platform namespace: cozy-system path: / migrations: enabled: false image: ghcr.io/cozystack/cozystack/platform-migrations:v1.3.0@sha256:555e4b76421361805a84bc9088b01b23a9c4a9430bd8ebd2db82ef9677d7008c targetVersion: 40 # Bundle deployment configuration bundles: system: enabled: false variant: "isp-full" # Options: "isp-full", "isp-full-generic", "isp-hosted", "distro-full" iaas: enabled: false paas: enabled: false naas: enabled: false disabledPackages: [] enabledPackages: [] # Network configuration networking: clusterDomain: "cozy.local" podCIDR: "10.244.0.0/16" podGateway: "10.244.0.1" serviceCIDR: "10.96.0.0/16" joinCIDR: "100.64.0.0/16" # KubeOVN master nodes override (optional) # By default, KubeOVN helm chart uses `lookup` to find control-plane nodes # by label `node-role.kubernetes.io/control-plane`. On fresh clusters or # during initial deployment, lookup may return empty results. # Set this to comma-separated list of master node IPs to override. kubeovn: MASTER_NODES: "" # Service publishing and ingress configuration publishing: host: "example.org" ingressName: tenant-root exposedServices: - api - dashboard - vm-exportproxy - cdi-uploadproxy apiServerEndpoint: "" # example: "https://api.example.org" externalIPs: [] # Exposure mode for the ingress-nginx Service. When "externalIPs" (current # default) is selected, the Service is created as ClusterIP with # Service.spec.externalIPs set from publishing.externalIPs. When # "loadBalancer" is selected, the Service is type: LoadBalancer and a # CiliumLoadBalancerIPPool makes those same addresses allocatable via LB IPAM. # # Service.spec.externalIPs is deprecated upstream in Kubernetes v1.36 # (KEP-5707). The AllowServiceExternalIPs feature gate is expected to default # to false around v1.40 and the implementation removed around v1.43 — switch # to "loadBalancer" before upgrading past v1.40. # # Caveats for the "loadBalancer" mode: # - publishing.externalIPs must contain at least one non-empty address, # otherwise the chart render fails with an explicit error (a LoadBalancer # Service without a pool would sit in forever). # - The ingress-nginx Service is created with externalTrafficPolicy: Local # to preserve the client source IP. Traffic arriving on a node that does # not host an ingress-nginx pod is dropped, so the external IP must be # routed to a node that runs the ingress pod (floating IP / keepalived / # upstream router / podAntiAffinity). # - Cilium does NOT announce the IP on its own unless L2 announcements or # BGP are enabled in the Cilium values (disabled by default in Cozystack). # This mode assumes the operator already routes the externalIPs to a # cluster node; enabling announcements is out of scope for this setting. # - Switching this value on a running cluster causes the ingress-nginx # Service to be recreated (the HelmRelease has upgrade.force: true and # the Service kind changes between ClusterIP and LoadBalancer). Expect a # brief interruption of ingress traffic during the flip. # # Scope: this setting only controls the ingress-nginx Service. Other # cozystack components that currently write Service.spec.externalIPs directly # (e.g. the vpn app at packages/apps/vpn/templates/service.yaml) are NOT # migrated by flipping this value and must be addressed separately before # the AllowServiceExternalIPs feature gate flips to off in ~v1.40. exposure: externalIPs # "externalIPs" or "loadBalancer" # Enable PROXY-protocol on the host ingress-nginx and auto-deploy # ouroboros (system/ouroboros) to fix the resulting hairpin-NAT # problem (intra-cluster traffic to the cluster's own public hostnames # arrives at ingress-nginx without the PROXY header it now requires). # Single cozystack-side switch: flipping this to true configures both # pieces in one go — ingress-nginx use-proxy-protocol and the # cozystack.ouroboros Package CR. # # TALOS RE-RENDER NOTE (host scope only): the host CoreDNS is a # Talos-managed Deployment; ouroboros mutates its live Corefile in # place between BEGIN/END markers. A Talos machine-config push or # upgrade re-renders the Corefile and overwrites the markers — there # is a flap window of up to one ouroboros reconcile loop (bounded # by `controller.resync`, default 10 minutes) until the controller # re-applies the block. The reconcile loop is ALSO event-driven on # Ingress/Gateway watches, so on a busy cluster the window often # closes much sooner — but on a stable production cluster with no # incidental Ingress/Gateway churn, the upper bound is the resync # interval. In-cluster DNS for hairpinned hostnames briefly returns # the upstream LB IP instead of the proxy ClusterIP during that # window, which fails the same way pre-PR behaviour fails. # Acceptable, but worth knowing during a Talos roll. # # PRECONDITION: the upstream L4 load balancer / WAN edge in front of # ingress-nginx MUST already be injecting PROXY-protocol v1 headers # before flipping this flag. Without that, every external request # arrives at ingress-nginx without the PROXY header, ingress-nginx # closes the connection, and ALL ingress traffic breaks. cozystack # cannot configure that upstream LB for you — it lives outside the # cluster (cloud LB, F5, MetalLB+haproxy, hcloud-cloud-controller, # etc.). PROXY-protocol frames travel from the upstream LB to # ingress-nginx (the LB opens a fresh TCP connection to the backend # and prepends the frame on that connection), not back to the # client — `nc` from a laptop will never see one. Pick one of: # # * tcpdump --interface any 'port 80 or port 443' -A on the node # hosting ingress-nginx and watch for a leading "PROXY TCP4 ..." # frame on inbound TCP from the LB BEFORE flipping this flag. # * make any external HTTP request after the LB-side change but # before flipping this flag, and watch # `kubectl --namespace cozy-ingress-nginx logs deploy/ingress-nginx-controller` # for "client sent invalid proxy protocol header" — that error # means the LB started injecting PROXY frames but ingress-nginx # is not yet configured to accept them, which is the transition # state this flag is meant to resolve. # # If neither check shows PROXY frames, fix the upstream LB before # touching this flag. Leave it false on clusters where PROXY-protocol # is not yet wired at the upstream LB; ouroboros wastes resources # when the bug it fixes does not exist. # # FAN-OUT NOTE: this flag affects ONLY the host control plane. To # turn the same hairpin fix on inside a tenant cluster, also set # `addons.ouroboros.enabled: true` in the per-tenant Kubernetes CR # (and `addons.ingressNginx.enabled: true` is a hard precondition # there). The flag does not cascade into tenants on its own. # # DISABLE PATH: flipping this back from true to false has TWO # asymmetric effects. ingress-nginx side: the next reconcile re-emits # cozystack.ingress-application without the use-proxy-protocol / # real-ip-header / enable-real-ip overrides (cozystack deliberately # never set use-forwarded-headers or compute-full-forwarded-for here # — those would allow any upstream proxy to spoof X-Forwarded-For # without a paired proxy-real-ip-cidr — see bundles/system.yaml), # so ingress-nginx # stops accepting PROXY-protocol headers. If the upstream L4 LB is # still prepending PROXY frames at that moment, every external # request to ingress-nginx breaks until the LB is also reconfigured # — flip the LB OFF FIRST, then flip this flag. ouroboros side: # stops emitting the cozystack.ouroboros Package CR, but every Package # CR carries `helm.sh/resource-policy: keep`, so Helm leaves the # existing Package on the cluster, ouroboros stays installed, and # the live Corefile rewrite block keeps pointing at the still-running # ouroboros-proxy Service. Flag-flip alone leaves ouroboros idempotent. # # To actually uninstall ouroboros, the operator removes the Package # CR explicitly: # # kubectl delete package.cozystack.io cozystack.ouroboros # # or adds the package name to bundles.disabledPackages. THAT is the # path that triggers the chart's pre-delete Helm hook # (charts/ouroboros/templates/coredns-cleanup-hook.yaml, vendored at # 0.7.0) — the hook quiesces the controller, sed-strips the # BEGIN/END block from the live kube-system/coredns Corefile, and # restores the cleaned ConfigMap via kubectl replace. The hook is # automatic; operators do NOT need to run a manual sed recipe in # the normal disable path. Documentation of the hook's exact # behaviour lives in the upstream chart's README. # # Manual cleanup recipe (only if the chart's pre-delete hook fails # to land — controller pod stuck in CrashLoop blocking the quiesce # step, ConfigMap RBAC drift on the namespace, helm uninstall # interrupted before the hook ran). Uses a JSON merge-patch so # labels, annotations, and other data keys on the ConfigMap — # including any Talos-managed metadata — are preserved: # # # === BEGIN cleanup-recipe === # existing=$(kubectl --namespace kube-system get configmap coredns \ # --output jsonpath='{.data.Corefile}') # cleaned=$(printf '%s\n' "$existing" \ # | sed '/# === BEGIN ouroboros/,/# === END ouroboros ===/d') # kubectl --namespace kube-system patch configmap coredns \ # --type merge \ # --patch "$(jq --null-input --arg c "$cleaned" \ # '{data: {Corefile: $c}}')" # kubectl --namespace kube-system rollout restart deployment/coredns # # === END cleanup-recipe === proxyProtocol: false # Acknowledgement gate for the helm.sh/resource-policy: keep # asymmetry (NOT a substitute for the chart's pre-delete cleanup # hook — the hook handles the Corefile patch automatically when # the chart actually uninstalls). The hazard this gate catches: # flipping publishing.proxyProtocol from true to false stops # emitting the cozystack.ouroboros Package CR, but resource-policy: # keep means Helm leaves the existing Package on the cluster. # ouroboros keeps running, the cleanup hook never fires, the # rewrite block stays live. The platform render fails until the # operator either restores proxyProtocol: true OR runs `kubectl # delete package.cozystack.io cozystack.ouroboros` (which lets # the chart actually uninstall and the hook run) and sets this # flag to true to confirm. Once the cluster has been clean for # one reconcile cycle, flip back to false. # # KNOWN HOLE: the guard keys off a `lookup` for the cozystack.ouroboros # Package CR on the cluster. An operator who manually # `kubectl delete package cozystack.ouroboros` before flipping the # flag back bypasses the check entirely (the lookup returns nil, the # render proceeds). In the chart 0.7.0 that path is mostly safe — # `kubectl delete package` triggers helm uninstall and the chart's # pre-delete hook patches the Corefile automatically. The hole is # the rare case where the hook itself fails (controller pod stuck, # ConfigMap RBAC drift, hook timeout) and the operator never # noticed. The values comment + the acknowledge gate are # defence-in-depth, not an airtight lock; an operator deliberately # working around them gets to keep the broken pieces. proxyProtocolAcknowledgeUnclean: false certificates: solver: http01 # "http01" or "dns01" issuerName: letsencrypt-prod # Authentication configuration authentication: oidc: enabled: false insecureSkipVerify: false keycloakExtraRedirectUri: "" # Internal URL to access KeyCloak realm for backend-to-backend requests (bypasses external DNS). # When set, oauth2-proxy uses --skip-oidc-discovery and routes all backend calls (token, jwks, # userinfo, logout) through this URL while keeping browser redirects on the external URL. # Example: http://keycloak-http.cozy-keycloak.svc:8080/realms/cozy keycloakInternalUrl: "" # Pod scheduling configuration scheduling: globalAppTopologySpreadConstraints: "" # UI branding configuration branding: {} # Container registry mirrors configuration # # Example: # registries: # mirrors: # docker.io: # endpoints: # - http://10.0.0.1:8082 # ghcr.io: # endpoints: # - http://10.0.0.1:8083 # gcr.io: # endpoints: # - http://10.0.0.1:8084 # registry.k8s.io: # endpoints: # - http://10.0.0.1:8085 # quay.io: # endpoints: # - http://10.0.0.1:8086 # cr.fluentbit.io: # endpoints: # - http://10.0.0.1:8087 # docker-registry3.mariadb.com: # endpoints: # - http://10.0.0.1:8088 # config: # "10.0.0.1:8082": # tls: # insecureSkipVerify: true registries: {} # Resource allocation ratios resources: cpuAllocationRatio: 10 memoryAllocationRatio: 1 ephemeralStorageAllocationRatio: 40