diff --git a/content/en/compliance/_index.md b/content/en/compliance/_index.md index eb943e64..4621c6af 100644 --- a/content/en/compliance/_index.md +++ b/content/en/compliance/_index.md @@ -1,7 +1,7 @@ --- -title: "Compliance on Kubernetes: PCI DSS and Security Benchmarks" +title: "Compliance on Kubernetes: PCI DSS, GDPR, DORA, CIS" linkTitle: "Compliance" -description: "How Cozystack supports PCI DSS and other compliance work: which controls the platform provides by default, which are opt-in, and which stay with you." +description: "How Cozystack supports PCI DSS, GDPR, DORA and the CIS Benchmark: which controls the platform provides by default, which are opt-in, and which stay with you." type: "page" weight: 45 --- @@ -22,3 +22,12 @@ command you can run against your own cluster. - **[PCI DSS](/compliance/pci-dss/)** — a requirement-by-requirement mapping of what Cozystack enforces by default, what is opt-in, and what stays with you, with commands to verify each control on your own cluster. +- **[GDPR](/compliance/gdpr/)** — the Article 32 technical measures the platform supplies, + where personal data physically sits, and the awkward parts of erasure nobody should gloss + over. +- **[CIS Benchmark](/compliance/cis-benchmark/)** — a full kube-bench run against Cozystack + on Talos Linux, with every failure sorted into real deviations, controls met another way, + and checks that do not apply. +- **[DORA](/compliance/dora/)** — resilience, backup and restore, incident evidence, and the + ICT third-party risk chapter where an open platform on your own hardware changes the + answer. diff --git a/content/en/compliance/cis-benchmark.md b/content/en/compliance/cis-benchmark.md new file mode 100644 index 00000000..7d75fe87 --- /dev/null +++ b/content/en/compliance/cis-benchmark.md @@ -0,0 +1,324 @@ +--- +title: "CIS Kubernetes Benchmark Results on Cozystack and Talos" +linkTitle: "CIS Benchmark" +description: "Full kube-bench run against Cozystack v1.6 on Talos Linux: 54 pass, 24 fail, and why only four failures are real. Includes the job manifest to reproduce it." +date: 2026-08-18 +type: "page" +weight: 20 +--- + +**Cozystack starts from a hardened position, and the numbers say so: 54 CIS controls pass on +a cluster nobody tuned for the test.** The node operating system is immutable and has no +shell, privileged workloads are refused by admission, every etcd control passes, and tenants +come with network isolation already applied. + +This page publishes the full run rather than the flattering part of it. A raw kube-bench +report also lists two dozen failures, and the useful work is telling them apart: most are the +benchmark looking for files an immutable node does not keep, or testing a flag that newer +Kubernetes releases replaced. Four are worth your attention, and each is covered below with +the reasoning behind it. + +That sorting is the point. Handing an auditor an unannotated kube-bench report is worse than +handing them nothing: they see red lines, and you spend the meeting explaining architecture +instead of security. + +## What the kube-bench run covered + +CIS Kubernetes Benchmark v1.12, executed by [kube-bench](https://github.com/aquasec/kube-bench) +against Cozystack v1.6 on Kubernetes v1.34.3. Control plane checks ran on a control-plane +node, worker checks on a worker. + +Scope: this is the management cluster — the Talos nodes and the Kubernetes +control plane that Cozystack itself runs on. Tenant Kubernetes clusters are not covered by +these numbers. Their control planes are Kamaji Deployments with their own API server flags +and their own etcd, so sections 1, 2 and 3 have to be evaluated separately for them. If +tenant clusters fall inside your assessment, ask for that run as well. + +| Section | Pass | Fail | Warn | +|---|---|---|---| +| 1 — Control plane security configuration | 29 | 22 | 9 | +| 2 — etcd node configuration | 7 | 0 | 0 | +| 3 — Control plane configuration | 1 | 0 | 4 | +| 4 — Worker node security configuration | 17 | 2 | 6 | +| 5 — Kubernetes policies | 0 | 0 | 34 | +| **Total** | **54** | **24** | **53** | + +Section 2 is worth a moment: every etcd flag check passes — client and peer certificates, +`--client-cert-auth`, no `--auto-tls`. The one etcd-related failure sits in section 1 and +concerns the data directory owner; it is discussed below. + +## Why most failures are not findings + +### The benchmark is looking for kubeadm + +Fifteen of the twenty-four failures are file checks — permissions and ownership of the API +server, controller manager, scheduler and etcd pod manifests, and of `admin.conf`, +`scheduler.conf` and `controller-manager.conf`. + +Every one of them reports an empty value. Look at the node and you see why: + +``` +# /etc/kubernetes on a Talos control-plane node +bootstrap-kubeconfig +kubeconfig-kubelet +kubelet.yaml +manifests/ <- empty +pki/ +``` + +The `manifests` directory exists and holds nothing: Talos renders the control plane pods +from its own configuration under `/system`, not from files an administrator edits, and +`/etc/kubernetes/manifests` is left for static pods *you* choose to add. The administrator +kubeconfigs the benchmark looks for — `admin.conf`, `scheduler.conf`, +`controller-manager.conf` — are absent entirely, because credentials are issued through the +Talos API instead of being left on disk. + +Check it on your own node rather than taking this on trust: + +```bash +talosctl -n list -l /etc/kubernetes /etc/kubernetes/manifests +``` + +The honest reading is not "fifteen controls failed" but "fifteen controls are inapplicable, +and the risk they exist to manage — an attacker or a mistake altering control plane +configuration on disk — is handled by immutability instead of by file modes". One check in the same group, 1.1.12, fails for a different reason. The etcd data directory +exists and is readable — check 1.1.11 confirms it is mode 0700 — but etcd runs as root, there +is no system `etcd` account on a Talos node, and the scanning container cannot resolve the +numeric owner to a name. The intent of the control, restricting who can read the etcd data +directory, is met; the literal `etcd:etcd` ownership it asks for cannot exist on a system +with no user accounts. + +### Three checks predate structured authorization + +Checks 1.2.6, 1.2.7 and 1.2.8 require the `--authorization-mode` flag to exclude +`AlwaysAllow` and to include `Node` and `RBAC`. Kubernetes 1.30 introduced a structured +authorization configuration file, and Talos uses it, so the flag is absent and the checks +fail. + +The configuration itself is exactly what the benchmark wants: + +```yaml +apiVersion: apiserver.config.k8s.io/v1beta1 +kind: AuthorizationConfiguration +authorizers: +- name: node + type: Node +- name: rbac + type: RBAC +``` + +Both authorizers are enabled, and `AlwaysAllow` is nowhere. This is not a case of running an +out-of-date benchmark: CIS v1.12 is the current revision and covers Kubernetes 1.32 through +1.34, while structured authorization reached general availability in 1.32. The control simply +still tests for a flag that a conformant modern cluster is entitled not to have. Expect more +false positives like it. Disproving them means reading the configuration, not rerunning the +tool. + +### Both worker failures are architectural + +Check 4.1.1 wants a kubelet service file, which Talos does not use. Check 4.3.1 wants the +kube-proxy metrics endpoint bound to localhost — and there is no kube-proxy to bind: +Cozystack runs Cilium with `kube-proxy-replacement` enabled, so the component the check +targets is not installed. The exposure the control was written about did not vanish, though — +it moved to the Cilium agent's own metrics and health ports on each node, which the benchmark +does not examine at all. Bind those to the node's internal address and firewall them the way +you would have treated kube-proxy. + +## What actually needs attention + +Four failures survive the sort. None of them is exotic, and all four are settings in the +Talos machine configuration rather than platform changes. + +Three of the four are deliberate choices by the platform maintainers rather than oversights, +and knowing the reasoning is more useful than knowing the score. + +| Check | What it means | How to treat it | +|---|---|---| +| 1.2.5 — `--kubelet-certificate-authority` not set | The API server presents a client certificate to the kubelet but does not verify the kubelet's serving certificate against a CA | Deliberate: on bare metal there is no metadata service to issue and distribute kubelet serving certificates. Closing it means building that mechanism | +| 1.3.7 — controller manager `--bind-address=0.0.0.0` | The secure port (10257) listens on every interface rather than loopback, and exposes metrics only. Metrics require authentication and authorization; `/healthz`, `/readyz` and `/livez` do not | Deliberate: this is how metrics are collected today. The cleaner shape is loopback plus an authorizing proxy in front | +| 1.4.2 — scheduler `--bind-address=0.0.0.0` | The same, on port 10259 | As above | +| 1.2.30 — `--service-account-extend-token-expiration` not `false` | Extended service account token lifetime remains on, a compatibility default for older clients | Not a considered decision — the default was simply never changed | + +If your assessor treats any of these as a finding, the answer is a compensating control plus +a plan, not a denial. The first three are each a day or two of engineering to close properly; +the fourth is a flag. What follows is what closing them actually involves. + +One caution before acting on 1.2.5: the flag alone is not the fix, and on its own it breaks +things. By default the kubelet serves a self-signed certificate, so an API server told to +verify it against a CA stops being able to run `kubectl logs`, `exec`, `port-forward` or +metrics-server. Closing this control is a three-part change — enable `serverTLSBootstrap` on +the kubelet, run a signer that approves kubelet serving CSRs, and only then set +`--kubelet-certificate-authority`. Do it on a test cluster and check `kubectl logs` against +every node before calling it done. + +The benchmark's remediation for 1.3.7 and 1.4.2 is `--bind-address=127.0.0.1`, and applying +it literally has a cost: Prometheus scrapes the controller manager and scheduler across +nodes, and loopback-only endpoints stop being scrapable. The proportionate answer is to leave +the bind address alone, close ports 10257 and 10259 to everything but the monitoring path +using the Talos ingress firewall, and record that as a compensating control rather than as a +passed check. + +Before switching off extended token expiration, watch `serviceaccount_stale_tokens_total` on +the API server: while it is above zero, something still depends on the compatibility +behavior. + +### Where these settings live + +All four sit in the Talos machine configuration you apply at install time — Cozystack does +not generate it for you, which is also why the same run on your cluster may differ. Verify +what yours actually runs before changing anything: + +```bash +talosctl -n get authorizationconfig -o yaml +``` + +## Kubernetes audit policy: the check kube-bench leaves to you + +Check 3.2.2 — "ensure that the audit policy covers key security concerns" — is a manual +check, so kube-bench reports a warning and moves on. It is worth doing by hand. + +On the cluster examined here the audit policy is set to `level: Metadata`. That records who +called what and when, but not request or response bodies. For day-to-day operations it is a +reasonable default; for a regime that expects reconstruction of what actually changed — PCI +DSS requirement 10.2.1, for one — it is not enough on its own. + +Resist the obvious fix. Raising everything to `RequestResponse` writes the bodies of every +request into the audit log, and those bodies contain Secret values, tokens and whatever +personal data your users put in annotations. The log stops being a record of access and +becomes a second copy of the data it was meant to protect — now in a file with different +retention, different access control and, quite possibly, a different compliance scope. +Kubernetes' own reference policy keeps Secrets and ConfigMaps at `Metadata` for exactly this +reason. + +The workable shape is per-resource. Log role bindings, webhook configurations and admission +policy at `RequestResponse`, because knowing what changed there is the point; keep Secrets at +`Metadata`, because knowing that a Secret was read is useful and knowing its contents is a +liability. Decide the split deliberately and write down why — an assessor will accept a +reasoned policy far more readily than a maximal one. See the +[PCI DSS page](/compliance/pci-dss/) for how audit logging fits a compliance program more +broadly. + +## Which of the 53 manual checks Cozystack already answers + +Warnings are manual checks: the benchmark cannot decide them, so a human must. Thirty-four +of them are section 5, on RBAC, Pod Security and network policies, and several are already +answered by how Cozystack builds a tenant: + +- Pod Security admission enforces `baseline` and warns at `restricted`. That answers the + section 5.2 checks on privileged containers, host namespaces and hostPath — but not the + ones on running as root, dropped capabilities and seccomp profiles, which need + `restricted`, a namespace label away +- every tenant is created with a set of Cilium network policies that deny traffic from other + tenants, which you can verify with a cross-tenant probe +- the tenant role carries no `get secrets` verb. Read that as least privilege at the API + surface rather than as a confidentiality boundary: anyone who can schedule a workload in a + namespace can mount that namespace's secrets into a pod + +The remaining warnings — client certificates and service account tokens used as user +credentials, in particular — depend on how you run the cluster, not on how it ships. + +## How to run kube-bench on your own cluster + +Two things to get right before you run it. Pass `--benchmark` +explicitly — otherwise kube-bench picks one from the detected Kubernetes version, and a +different pick produces a different set of checks and different totals. And pin the image: +`latest` is not evidence, and an assessor is entitled to ask which version of which tool +produced the report. + +Create a namespace that permits host access, run the job, read the output: + +```bash +kubectl create namespace kube-bench +kubectl label namespace kube-bench pod-security.kubernetes.io/enforce=privileged +``` + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: kube-bench-master + namespace: kube-bench +spec: + backoffLimit: 1 + template: + spec: + hostPID: true + nodeName: + restartPolicy: Never + containers: + - name: kube-bench + image: docker.io/aquasec/kube-bench:v0.12.0 # pin a version, or a digest + command: ["kube-bench"] + args: + - "run" + - "--benchmark" + - "cis-1.12" + - "--targets" + - "master,controlplane,etcd,policies" + - "--json" + volumeMounts: + - { name: var-lib-etcd, mountPath: /var/lib/etcd, readOnly: true } + - { name: var-lib-kubelet, mountPath: /var/lib/kubelet, readOnly: true } + - { name: etc-kubernetes, mountPath: /etc/kubernetes, readOnly: true } + - { name: usr-bin, mountPath: /usr/local/mount-from-host/bin, readOnly: true } + volumes: + - { name: var-lib-etcd, hostPath: { path: /var/lib/etcd } } + - { name: var-lib-kubelet, hostPath: { path: /var/lib/kubelet } } + - { name: etc-kubernetes, hostPath: { path: /etc/kubernetes } } + - { name: usr-bin, hostPath: { path: /usr/bin } } +``` + +For worker checks, run the same job on a worker with `--targets node` and drop the etcd +mount. + +Treat this job as what it is: a privileged, short-lived diagnostic. It runs with `hostPID`, +in a namespace where Pod Security enforcement is switched off, and it mounts +`/var/lib/kubelet` — which holds the node's kubelet client key and the projected service +account tokens of every pod on that node. Anyone who can exec into the pod inherits the +node's identity. So run it in a namespace only cluster administrators can reach, never inside +a tenant, add `automountServiceAccountToken: false` to the pod spec, collect the JSON, and +remove the namespace as soon as you have it: + +```bash +kubectl delete namespace kube-bench +``` + +The exception this job needs from admission is deliberate and temporary — it changes nothing +about enforcement in the namespaces where workloads actually run. + +## Frequently asked questions + +### Is Cozystack CIS Kubernetes Benchmark compliant? + +The benchmark has no pass or fail verdict to award — it is a list of controls, and +compliance is a judgment about a specific cluster. On the run above, 54 controls pass and +four deviations are worth closing. Of the remaining twenty, fifteen test file modes on an +immutable node, three test a flag that structured authorization replaced, one wants a kubelet +unit file Talos has no use for, and one wants a kube-proxy that Cilium replaced. + +### Why do so many CIS checks fail on Talos Linux? + +Because most of section 1.1 checks file permissions and ownership under `/etc/kubernetes`, +and Talos keeps no such files. The controls assume a kubeadm cluster where an administrator +can edit manifests on disk. The risk those controls address is handled differently, not +ignored. + +### Can we run kube-bench ourselves? + +Yes, and you should. The manifest above is the one used for this page. Run it against your +own cluster before an assessment, and keep the output alongside your notes on which failures +are architectural. + +### Does a CIS report satisfy an auditor? + +Not on its own. An unannotated report raises more questions than it answers. What works is +the report plus a mapping: for each failure, whether it is a real deviation, a control met by +other means, or a check that does not apply — which is what this page is. + +## Notes + +This page describes Cozystack v1.6 on Kubernetes v1.34.3 as observed on a single reference +cluster — the management cluster only — measured with CIS Kubernetes Benchmark v1.12 via +kube-bench on August 18, 2026. Your installation may differ, particularly in the Talos +machine configuration, which supplies several of the settings discussed here. This page is +informational, not an assessment or a certification. diff --git a/content/en/compliance/dora.md b/content/en/compliance/dora.md new file mode 100644 index 00000000..0741a4d0 --- /dev/null +++ b/content/en/compliance/dora.md @@ -0,0 +1,194 @@ +--- +title: "DORA on Kubernetes: ICT Third-Party Risk and Resilience" +linkTitle: "DORA" +description: "DORA on Kubernetes: how Cozystack supports digital operational resilience — backup and restore, incident evidence, ICT third-party risk and exit strategy." +date: 2026-08-18 +type: "page" +weight: 25 +--- + +**For the chapter of DORA that decides most platform conversations — dependence on a single +ICT provider — Cozystack is about as good an answer as infrastructure gets.** It is +open-source software under Apache 2.0, it runs on your own hardware, and leaving it means +moving standard Kubernetes objects and virtual machines rather than unwinding a proprietary +format. An exit strategy you can rehearse beats a clause promising cooperation. + +The resilience side is solid too: replicated storage across nodes, live migration between +them, declared state that the platform continuously restores, multi-datacenter topologies as +a normal deployment shape, backups encrypted by default. This page goes through all of it, +and marks the handful of places where you need to configure something rather than inherit it. + +What the platform cannot do is hold the obligation. The Digital Operational Resilience Act — +Regulation (EU) 2022/2554 — has applied since 17 January 2025 and binds the categories of +financial entity listed in Article 2: banks, insurers, investment firms, payment and e-money +institutions, crypto-asset service providers and others. ICT third-party service providers +are not in scope directly; a small number are designated critical by the European Supervisory +Authorities under Article 31 and placed under an EU Oversight Framework with a Lead Overseer, +which is a different regime from the competent-authority supervision financial entities face. + +## ICT third-party risk: the part that depends on the platform + +DORA devotes a whole chapter to ICT third-party risk: register of information, contractual +requirements, concentration risk, exit strategies, and the right to audit. Regulators care +about it because a financial entity that cannot leave a provider has no real control over its +own resilience. + +Three properties matter here. None is a feature you enable; each follows from how the +platform is built and licensed. + +**The source is open, under Apache 2.0.** Contractual continuity does not depend on one +vendor's survival, and the code can be audited by you or by a third party without asking +permission. + +**It runs on your own hardware.** No control plane in someone else's account, no vendor with +standing access required for the platform to function, no dependency on an external service +being up. What you host, you control. + +**Exit is possible in practice, not only on paper.** Workloads are Kubernetes objects and +virtual machines in standard formats; there is no proprietary encapsulation to unwind. An exit +plan you can rehearse is worth more to a regulator than a clause promising cooperation. + +None of this exempts you from maintaining the register of information required by Article +28(3), from holding an exit strategy under Article 28(8), or from contracts carrying the key +provisions of Article 30 of DORA — a different Article 30 from the GDPR one. It makes those +documents easier to write truthfully. + +## Resilience: what the platform provides + +DORA expects ICT systems to withstand and recover from disruption, and to be tested against +that expectation rather than assumed to meet it. + +**Replicated storage, where the StorageClass asks for it.** LINSTOR places volumes with DRBD +replication across nodes, so a replicated volume survives the loss of a node holding one of +its copies. Replication is a property of the StorageClass rather than of the platform — local, +non-replicated classes exist and are the right choice for some workloads — so check which +class each critical or important function actually uses. No separate storage array is required +either way. + +**Live migration.** Virtual machines move between nodes without shutdown, which turns planned +maintenance from an outage into an operation. + +**Declared state, continuously reconciled.** Machines and services are described as +manifests, and the platform works to keep reality matching the description. Kill a workload +directly and it comes back, because the description did not change. + +**Stretched clusters across locations.** Multi-datacenter topologies are a normal deployment +shape rather than an exotic one, which matters when your resilience requirements name +geographic separation. + +Be precise about what is *not* provided. There is no automated virtual machine failover after +unplanned node loss of the kind a dedicated HA product gives you. Node health handling and +restart policies exist and can be combined into a failover procedure, but that is +configuration and rehearsal work, not a switch. + +## Backup, restore and the evidence that they work + +Velero ships with the platform for scheduled backups, volume snapshots, virtual machine +backups and cluster state, and backup data is encrypted in object storage by default through +the kopia uploader. + +Where those backups land needs a decision before an assessment, not after. Platform-managed +backups default to a shared `cozy-backups` bucket in `tenant-root`, separated between tenants +by object path. Article 12(2) expects restoration to run on systems physically and logically +segregated from the source, and Article 12(3) expects backup systems not to be directly +connected to the primary one — a bucket inside the cluster being protected meets neither. +Point the BackupClass at storage outside the cluster, with its own credentials and its own +key, and say so in the backup policy Article 12(1) asks you to write. + +The regulation's emphasis is not on having backups but on being able to restore. Rehearse the +restore against a defined recovery time and recovery point objective, record what you actually +achieved, and keep that record. A restore time you measured is evidence; an estimate is not. + +## Detection, logging and incident evidence + +DORA requires incidents to be detected, classified and — for major ones — reported to the +competent authority on a short clock. That works only if the underlying record exists. + +The platform ships metrics collection, log aggregation, alerting and dashboards, and the +Kubernetes API server writes an audit log under a policy you supply. Set two things +deliberately. Retention first: the default on the cluster examined here is thirty days, shorter than a +financial supervisor will expect for records touching critical or important functions. Then the audit policy, resource by resource — do not raise everything to full request +and response capture, which writes secrets and personal data into the log and buys a GDPR +problem to settle a DORA one. + +Security advisories for the platform are published openly, including assessments of +vulnerabilities that turn out not to affect it. That public record is directly usable in the +threat-intelligence and vulnerability-management parts of an ICT risk framework. + +## Testing resilience without touching production + +DORA expects a program of digital operational resilience testing under Chapter IV, and +threat-led penetration testing under Article 26 for those entities their competent authority +identifies as in scope for it — a designation based on risk profile and systemic importance, +not a category you can read off your own balance sheet. + +Two properties of the platform help the general program. A tenant gives you an isolated place +to run destructive tests against a realistic copy. And because environments are described as +manifests, the environment under test can be recreated exactly, which is what makes a test +result meaningful the second time. + +TLPT is a different exercise, and the distinction matters: Article 26 tests run against live +production systems supporting critical or important functions, so a tenant copy does not +substitute for one. Where the platform is operated for you, or supports a critical or +important function, the ICT third-party service providers involved are drawn into the scope of +that test and have to be arranged with in advance. + +The [CIS Benchmark](/compliance/cis-benchmark/) page shows one such test executed against a +live cluster, together with the reasoning that turns a raw report into something an assessor +can use. + +## What stays with you + +Governance sits with the management body and cannot be delegated to a supplier: the ICT risk +framework, the register of information, incident classification and reporting within the +regulation's deadlines, the digital operational resilience testing program, contractual +arrangements with providers, and the exit strategy itself. + +A platform can make each of those cheaper to satisfy. It cannot hold them. + +## Frequently asked questions + +### Is Cozystack DORA compliant? + +The question does not apply to a platform. Financial entities are subject to DORA; platforms +are part of the ICT estate those entities manage. Cozystack contributes replication, live +migration, backup and restore, observability, audit logging and — most usefully for Chapter V +— an architecture with no vendor dependency to unwind. + +### Does running on our own hardware remove ICT third-party risk? + +Self-hosting removes the platform vendor from the critical path — often the largest single +component of that risk. Hardware suppliers, datacenter operators and any integrator you +contract remain third parties and belong in the register of information. + +### Does Cozystack go into our register of information? + +The register under Article 28(3) records *contractual arrangements* for the use of ICT +services. Downloading and self-hosting Apache 2.0 software creates no contractual arrangement, +so there is no counterparty to name and nothing about the project itself to register. The +moment you buy support, hosting or integration around it, that supplier is an ICT third-party +service provider under Article 3(19) and belongs in the register, with the function it +supports and whether that function is critical or important. Confirm the treatment with your +own competent authority — supervisory practice on open-source components is not uniform. + +### What about the right to audit? + +Article 30(3)(e) is a contractual right of access, inspection and audit for you and for your +competent authority, exercised against a provider. With no provider in the path there is no +contract to carry it, and inspecting the platform means reading public source and running +checks against your own cluster. Where you contract an operator, those access and audit rights +— and the Article 30(3)(f) exit and transition provisions — belong in that contract rather +than in a claim about the software. + +### Can we test failure scenarios safely? + +Yes. Run them in a dedicated tenant, isolated by network policy from everything else, and +recreate the environment from manifests between runs. + +## Notes + +This page describes Cozystack v1.6 as observed on a reference cluster in August 2026 and is +informational. It is not legal advice, not an assessment, and not a statement that any +configuration satisfies a competent authority. Regulation (EU) 2022/2554 applies to defined +categories of financial entity and their critical ICT providers; whether it applies to you, +and in what capacity, is a question for your own counsel. diff --git a/content/en/compliance/gdpr.md b/content/en/compliance/gdpr.md new file mode 100644 index 00000000..5e3020c7 --- /dev/null +++ b/content/en/compliance/gdpr.md @@ -0,0 +1,213 @@ +--- +title: "GDPR Compliance on Kubernetes with Cozystack" +linkTitle: "GDPR" +description: "GDPR on self-hosted Kubernetes: which Article 32 measures Cozystack supplies — data residency, encryption, access control, erasure — and which stay yours." +date: 2026-08-18 +type: "page" +weight: 15 +--- + +**Personal data on Cozystack stays where you put it.** The platform is open-source software +built on Kubernetes, KubeVirt and Talos Linux that runs on your own hardware: no control plane +in someone else's cloud, no vendor account, no service to sign up for. On top of that it +brings the measures Article 32 asks about — encryption in transit and for backups, centralized +identity, tenant isolation enforced by network policy, audit logging, backup and restore. + +That is a strong starting position, and this page walks through it measure by measure. It also +marks the places where a control is available but off until you enable it, and the two or +three questions a data protection officer will raise that no infrastructure can answer for +you. Better to meet those here than in a meeting. + +One framing worth keeping. Compliance belongs to the organization holding the data — why it +holds it, on what legal basis, for how long. A platform supplies measures and makes them +demonstrable; the useful answer to "is Cozystack GDPR compliant" is what follows below, not a +yes that falls apart under the first question. + +## Data residency: where the data physically lives + +Residency is usually the first question, and the easiest one to answer well. + +Cozystack installs on your own hardware, in a facility you choose. There is no control plane +in someone else's cloud, no vendor who needs standing access in order for the platform to +work, and the platform requires no telemetry channel to a vendor in order to run. For Chapter +V — transfers of personal data to third countries — that removes the largest single element +from the analysis. + +It does not close it. Under the EDPB's reading, remote access from a third country is itself a +transfer, so support engineers, an integrator's staff, out-of-hours administrators and +anything you connect for observability all still count. The outbound paths the cluster does +use — container registries, certificate authorities, time sources and update channels — are +worth listing once, because they say where the environment reaches even when the personal data +does not. If you operate in several jurisdictions, tenants and node placement let you keep +processing in one of them rather than spreading it across all of them. + +## Which Article 32 measures Cozystack covers + +### Encryption of personal data + +Three layers, and they behave differently. + +**Kubernetes secrets** are encrypted in etcd where the API server runs with +`--encryption-provider-config`. That setting comes from the Talos machine configuration +supplied at install time, so confirm it on your own cluster. + +**Volumes** — the disks behind databases and virtual machines, which is where personal data +actually sits — are not encrypted unless you ask. LINSTOR supports at-rest encryption with +LUKS, enabled by setting a passphrase and creating a StorageClass that includes the LUKS +layer. See [Creating Encrypted Storage on LINSTOR](/docs/v1.6/storage/disk-encryption/), and +decide it at design time: converting a populated volume later means migrating the data. + +Two consequences belong in the same decision, because they cut against Article 32(1)(b) and +(c) rather than for them. The passphrase is a single shared secret with no rotation procedure, +split knowledge or dual control, so key management is a process you build around it. And it +must be entered by hand after every restart of the LINSTOR controller — encrypted volumes do +not come back on their own, which turns an unattended restart into an availability event. + +**Backups** are encrypted by default. Velero uses the kopia uploader, so backup data is +written to object storage under a repository key held in the cluster. + +For personal data held by the identity layer specifically, Cozystack v1.6 added an optional +encrypting proxy in front of the Keycloak database, giving column-level encryption backed by +a static key or Vault Transit. It is off until you enable it. + +### Confidentiality and access control + +Authentication can be centralized in Keycloak through OIDC, which puts joiners, leavers, +multi-factor authentication and password policy in one place instead of scattering them +across kubeconfig files. It is not the default — a fresh cluster authenticates with a cluster +credential, which is a shared account and unsuitable for anything holding personal data. +Enable OIDC before the environment carries real data. + +Authorization is scoped to the tenant, and more tightly than teams expect: a tenant user can +create databases and virtual machines through the platform API yet cannot read raw Kubernetes +secrets. Check it rather than take it on trust — as the tenant user, against the tenant +namespace: + +```bash +kubectl auth can-i --list -n tenant-a +kubectl auth can-i get secrets -n tenant-a +``` + +The second returns `no`. Read that as least privilege at the API surface rather than as a +confidentiality boundary — a principal who can schedule workloads in a namespace can mount +that namespace's secrets into a pod, so the boundary holds only as far as you also restrict +workload creation. + +### Separation of processing + +Tenants are isolated from each other at the network layer by Cilium policies created together +with the tenant, and that isolation is enforced rather than declared. You can verify it in a +minute — start a pod in one tenant and try to reach it from another, with a same-tenant probe +as the positive control: the cross-tenant probe returns `000`, the same-tenant one `200`. + +Read it for what it is. Network separation is not separation of processing in the sense a data +protection officer means. The control plane, etcd, LINSTOR and the identity layer are shared +services, platform administrators see across every tenant, and platform-managed backups land +in a single `cozy-backups` bucket in `tenant-root` separated between tenants by object path +rather than by credentials or by key. Tenant egress to the internet is not restricted by +default either, so an exfiltration path stays open until you add a `SecurityGroup` or an +egress allow-list. If you process personal data for several controllers, treat the tenant as a +strong first boundary and document the shared components and the administrators who cross +it — that is the part a data protection officer will ask about. + +### Integrity of processing systems + +Article 32(1)(b) names integrity alongside confidentiality, availability and resilience, and +this is the measure with the largest gap. Immutable node images and digest-pinned platform +components make undetected drift harder, and the audit log records who changed what through +the API. But no intrusion detection, no file-integrity monitoring and no change-detection +mechanism ship with the platform. Nothing prevents you running one, and if your risk +assessment calls for it, that is an addition you make rather than a control you inherit. + +### Ability to restore availability after an incident + +Article 32(1)(c) asks for the ability to restore access to personal data in a timely manner. +Velero ships with the platform for scheduled backups, volume snapshots and cluster state, and +restores are worth rehearsing rather than assuming — a backup nobody has restored is a hope, +not a measure. + +### Regular testing of measures + +Article 32(1)(d) asks for a process of testing and evaluating effectiveness. The +[CIS Benchmark](/compliance/cis-benchmark/) page shows one such test run against a live +cluster, with the failures sorted into real deviations and artifacts of the architecture. +Nothing prevents you from running it on your own schedule; the manifest is published there. + +## The right to erasure, and where it gets awkward + +The right to erasure is where infrastructure and law meet uncomfortably, so it is worth being +concrete rather than reassuring. + +Deleting a database row is straightforward. Deleting it from **backups** is not: backups exist +precisely so that deletions can be undone. The commonly used position — one several supervisory +authorities have described as workable, without it being settled across the EEA — is +documented retention: state how long backups live, put the data beyond use in the meantime, +ensure erased data ages out within that window, and do not reintroduce it selectively on +restore. Record the reasoning, tell the data subject when the erasure will complete, and check +the position against your own authority's guidance rather than against this page. +Cozystack does not solve this for you — but it does let you set backup retention deliberately +and point backups at storage you control. + +**Audit logs** create a second version of the same problem. Start from the fact that the audit +log is already a store of personal data: at the default `level: Metadata` it records +usernames, groups and source IP addresses, which are personal data about your administrators +regardless of what the requests contained. It needs an entry in your Article 30 records, a +retention period and an access rule of its own — the default retention on the cluster examined +here is thirty days. + +The trap sits one level up. Raising the policy to `RequestResponse` to satisfy some other +framework writes request bodies — secret values, and whatever personal data your users put in +annotations — into the same file. Split the policy by resource instead: `RequestResponse` +where knowing what changed is the point, `Metadata` for secrets and for anything carrying +personal data. + +## What stays with you + +No infrastructure product supplies any of the following: the lawful basis for processing, +records of processing activities under Article 30, data protection impact assessments where +Article 35 requires them, notification of a personal data breach to the supervisory authority +within 72 hours under Article 33, responses to data subject requests, the appointment of a +data protection officer where Article 37 requires one, and the Article 28 agreement with +anyone who processes personal data on your behalf. + +The platform is a tool. The obligations sit with whoever determines the purposes and means of +the processing. + +## Frequently asked questions + +### Is Cozystack GDPR compliant? + +The question does not apply to infrastructure. An organization is compliant; a platform +supplies measures. Cozystack supplies encryption, access control, tenant separation, audit +logging, backup and restore, and full control over where data physically resides. + +### Does self-hosting Cozystack avoid third-country transfer problems? + +Self-hosting removes the platform itself from the Chapter V analysis: Cozystack runs on your +hardware and needs no vendor access to operate. Whether your own architecture moves data +elsewhere is a separate question, about your applications and integrations. + +### Is personal data encrypted at rest by default? + +For the storage that actually holds personal data — the volumes behind databases and virtual +machines — no. Volume encryption is opt-in per StorageClass and belongs in the design rather +than in a later change. Backups are encrypted by default. Kubernetes secrets are encrypted in +etcd when the API server runs with `--encryption-provider-config`, which comes from the Talos +machine configuration rather than from Cozystack, so verify it on your own cluster — and +secrets hold credentials, not usually the personal data your records of processing describe. + +### Does running Cozystack ourselves introduce a processor? + +No. Running open-source software on your own hardware adds no third party to the processing: +there is no service, no account and no data leaving your infrastructure, so there is nobody to +appoint under Article 28. Your own role is unchanged — you are the controller for personal +data whose purposes and means you determine, and a processor only where you host on behalf of +another controller. If you contract an integrator to operate the platform, that is a processor +or sub-processor relationship and needs an Article 28 agreement. + +## Notes + +This page describes Cozystack v1.6 as observed on a reference cluster in August 2026, and is +informational. It is not legal advice, not an assessment, and not a warranty that any +configuration satisfies a supervisory authority. Your installation may differ, particularly in +the Talos machine configuration that supplies several of the settings above. diff --git a/content/en/compliance/pci-dss.md b/content/en/compliance/pci-dss.md index d03fba96..19052953 100644 --- a/content/en/compliance/pci-dss.md +++ b/content/en/compliance/pci-dss.md @@ -7,15 +7,17 @@ type: "page" weight: 10 --- -**Cozystack is not "PCI DSS certified" — no infrastructure platform can be — but it provides -most of the technical controls a PCI DSS 4.0.1 assessment depends on, and several of them are -active on a fresh install.** Cozystack is an open-source cloud platform built on Kubernetes, -KubeVirt and Talos Linux that runs on your own bare metal. Tenant network isolation, -privilege restrictions on workloads, automatic TLS for published services and encrypted -backups need no configuration. Single sign-on, volume encryption, restricted egress, encrypted -east-west traffic and longer audit retention are shipped but not switched on, because most -clusters do not need them: each is a configuration option, not a development project. This -page says which is which, requirement by requirement. +**Cozystack provides most of the technical controls a PCI DSS 4.0.1 assessment depends on, +and several of them are active on a fresh install.** It is an open-source cloud platform built +on Kubernetes, KubeVirt and Talos Linux that runs on your own bare metal. Tenant network +isolation, privilege restrictions on workloads, automatic TLS for published services and +encrypted backups need no configuration at all. + +Others are shipped but not switched on, because most clusters do not need them: single +sign-on, volume encryption, restricted egress, encrypted east-west traffic, longer audit +retention. Each is a configuration option rather than a development project, and this page +says which is which, requirement by requirement — along with the parts an assessment leaves +to you, so none of them surprise you late. *Will this pass our audit?* The question comes up in the first meeting, every time a cardholder data environment (CDE) moves to a new platform. No platform passes an audit. @@ -243,9 +245,12 @@ the platform for workloads — but shipping the API audit log into them is not w default, and Requirement 10.3.3 expects audit logs to reach a separate, centrally managed server promptly. -Two more things to check rather than assume. The contents of the audit policy: a -`Metadata`-level policy will not produce the per-event detail Requirement 10.2.1 expects, so -sensitive resources need `RequestResponse`. And protection of the trail itself: 10.3.2 +Two more things to check rather than assume. The contents of the audit policy. A `Metadata`-level +policy will not produce the per-event detail Requirement 10.2.1 expects — but raising +everything to `RequestResponse` is the wrong correction, because request bodies carry Secret +values and personal data, and the audit log then becomes another store of the data you are +protecting. Split it by resource: `RequestResponse` for role bindings and admission +configuration, `Metadata` for Secrets. And protection of the trail itself: 10.3.2 through 10.3.4 require the log to be unmodifiable and watched by a change-detection mechanism, neither of which the platform provides. diff --git a/hugo.yaml b/hugo.yaml index bb9d7108..6df56600 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -329,6 +329,18 @@ menus: url: /compliance/pci-dss/ parent: compliance weight: 1 + - name: GDPR + url: /compliance/gdpr/ + parent: compliance + weight: 2 + - name: CIS Benchmark + url: /compliance/cis-benchmark/ + parent: compliance + weight: 3 + - name: DORA + url: /compliance/dora/ + parent: compliance + weight: 4 - name: Community url: /community/ weight: 30