Skip to main content
Version: Next 🚧

CIS Control Implementation Matrix

This page documents the implementation status of CIS (Center for Internet Security) benchmark controls in Kairos. Control IDs and descriptions are sourced from two permissively-licensed projects:

Important sourcing notes: kube-bench's cfg/cis-1.9/ files carry no CIS profile-level field, so the 130 Kubernetes controls listed below represent the complete v1.9.0 set rather than a derived Level 1 subset; the Level 1 split is not guessed at. Additionally, dev-sec/linux-baseline carries no CIS control-ID tags at all, so the Linux table is keyed on devsec control IDs and maps to CIS numbering in only three cases (os-10, package-09, os-09), which is what "(none in source)" means in the CIS Reference column.

CIS's own benchmark PDF text is not reproduced here. Sourcing details, caveats, and methodology are in the research notes kept alongside this page in the repository.

CIS Kubernetes Benchmark v1.9.0​

Overview​

Kairos is an OS image builder and does not include a Kubernetes control plane. It installs k3s or k0s from those projects' own installers and applies no Kairos-owned CIS-specific flags. The Kubernetes benchmark is therefore operator territory: hardening is configured where the operator configures the distribution, following k3s's or k0s's own CIS hardening guide.

Kairos itself does not set protect-kernel-defaults, tls-cipher-suites, anonymous-auth, audit-log, secrets-encryption, or other CIS-relevant flags. Every flag-shaped control is reachable only through the operator's k3s.args or k0s.args configuration, which Kairos appends verbatim without modification.

Control Summary by Section​

The following table summarizes CIS v1.9.0 coverage by section. Sections 1.x, 2 and 4.x are reachable through the arguments the operator passes to k3s or k0s. Sections 3.x and 5.x are cluster-level policy (RBAC, Pod Security Admission, NetworkPolicy, audit policy) applied after the cluster bootstraps, not flags. The file permission and ownership controls 1.1.9–1.1.12, 1.1.19–1.1.21 and 4.1.3–4.1.10 target paths Kairos persists but never sets a mode or owner on, so those could be addressed in the image and currently are not.

CIS SectionControl IDsControlsImplementedNot ApplicableOpenPath Forward
1.1 Control Plane Node Configuration Files1.1.1–1.1.21210147All 7 open controls are file mode and ownership checks (1.1.9–1.1.12, 1.1.19–1.1.21) on paths Kairos persists; they need a mode or owner set in the image, not a k3s or k0s argument
1.2 API Server1.2.1–1.2.29290029k3s/k0s distro configuration via operator k3s.args or k0s.args
1.3 Controller Manager1.3.1–1.3.77007k3s/k0s distro configuration via operator k3s.args or k0s.args
1.4 Scheduler1.4.1–1.4.22002k3s/k0s distro configuration via operator k3s.args or k0s.args
2 Etcd Node Configuration2.1–2.77007k3s/k0s distro configuration via operator k3s.args or k0s.args
3.1 Authentication and Authorization3.1.1–3.1.33003Cluster-level policy applied post-bootstrap
3.2 Logging3.2.1–3.2.22002Cluster-level policy applied post-bootstrap
4.1 Worker Node Configuration Files4.1.1–4.1.1010028All 8 open controls are file mode and ownership checks (4.1.3–4.1.10) on paths Kairos persists; they need a mode or owner set in the image, not a k3s or k0s argument
4.2 Kubelet4.2.1–4.2.13130013k3s/k0s distro configuration via operator k3s.args or k0s.args
4.3 kube-proxy4.3.11001k3s/k0s distro configuration via operator k3s.args or k0s.args
5.1 RBAC and Service Accounts5.1.1–5.1.13130013Cluster-level policy applied post-bootstrap
5.2 Pod Security Standards5.2.1–5.2.13130013Cluster-level policy applied post-bootstrap
5.3 Network Policies and CNI5.3.1–5.3.22002Cluster-level policy applied post-bootstrap
5.4 Secrets Management5.4.1–5.4.22002Cluster-level policy applied post-bootstrap
5.5 Extensible Admission Control5.5.11001Cluster-level policy applied post-bootstrap
5.7 General Policies5.7.1–5.7.44004Cluster-level policy applied post-bootstrap
Total130016114

Not Applicable Controls​

The following 16 controls are not applicable because their target artifacts do not exist on a Kairos node:

Section 1.1 (Control Plane Node Configuration Files): 1.1.1–1.1.8, 1.1.13–1.1.18

  • Reason: k3s and k0s do not create kubeadm static pod manifests or kubeadm-style *.conf kubeconfigs. These controls reference /etc/kubernetes/manifests files and kubeadm configuration files that do not exist.

Section 4.1 (Worker Node Configuration Files): 4.1.1–4.1.2

  • Reason: k3s and k0s run the kubelet in-process from the server/agent supervisor; there is no standalone kubelet systemd unit or drop-in file to inspect.

Open controls addressing Kubernetes configuration are trackable under kairos-io/kairos#4628.


CIS Distribution Independent Linux L1​

Kairos applies the Linux controls at image build time, in the cisHardening step of kairos-init. The step runs on every base image Kairos supports, so the same controls are present on Ubuntu, Debian, openSUSE, Rocky, Alpine and Hadron based images, and they are part of the image itself, so they survive an A/B upgrade and a kairos-agent reset.

To build an image without them, skip the step:

kairos-init --skip-steps cisHardening ...
Release status

The controls below are on kairos master and ship with the next kairos release after v4.3.0. Images built with v4.3.0 (kairos-init v0.17.3) do not have the cisHardening step at all; they only carry the earlier sshd hardening drop-in.

Controls in place​

Grouped the way kairos-io/kairos#4626 tracks them.

AreaWhat Kairos shipsStatus
Filesystem modules (1.1.1.x)/etc/modprobe.d/cis-blocklist.conf makes cramfs, freevxfs, jffs2, hfs, hfsplus and udf unloadable. squashfs and vfat are required for boot and stay loadable.In place
Mandatory access control (1.6)SELinux enforcing on RHEL-family images.Not yet. Needs its own follow-up.
Warning banner (1.7)/etc/issue.net carries a generic authorized-use banner with no OS or version details. sshd prints it through Banner /etc/issue.net.In place
Network parameters (3.x)/etc/sysctl.d/99-kairos-cis.conf: kernel.randomize_va_space=2, tcp_syncookies=1, source routing and redirects off, IPv6 router advertisements off, and rp_filter=2.In place (see note)
Auditing (4.x)auditd installed and enabled on every base, baseline rules in /etc/audit/rules.d/50-kairos.rules (time changes, identity files, network environment, MAC policy, logins, sessions, permission changes, failed access, mounts, deletions, sudoers, kernel modules; each syscall rule paired for 64-bit and 32-bit), rules locked with -e 2. immucore bind-mounts /var/log/audit from the persistent partition.In place
cron and at (5.1)/etc/crontab 0600; cron.hourly, cron.daily, cron.weekly, cron.monthly, cron.d 0700; cron.allow, cron.deny, at.allow, at.deny 0640. Only paths the base ships are touched.In place
SSH server (5.2)One drop-in, /etc/ssh/sshd_config.d/05-kairos-hardening.conf, owned by kairos-init on every base. See SSH server.In place
Password quality (5.4.1)/etc/security/pwquality.conf: minlen 14, one digit, upper, lower and other character each, difok 4.In place, see PAM wiring for Leap
Account lockout (5.4.2)/etc/security/faillock.conf: deny 5, unlock_time 900, fail_interval 900, even_deny_root.In place except openSUSE, see PAM wiring
Password aging and umask (5.4.1.x, 5.4.5)/etc/login.defs: PASS_MAX_DAYS 365, PASS_MIN_DAYS 1, PASS_WARN_AGE 7, UMASK 027, ENCRYPT_METHOD SHA512. Tighten only: a base that already ships a stricter value keeps it (Hadron keeps PASS_MAX_DAYS 60 and UMASK 077). Applies to accounts created after install.In place
Time synchronizationsystemd-timesyncd on Ubuntu, Debian, openSUSE and Hadron; chronyd on the RHEL family; ntpd on Alpine. Each uses its distribution's default NTP sources.In place
Account database permissions (6.1)Modes tightened on /etc/passwd, /etc/group, /etc/shadow, /etc/gshadow and their - backups. Ownership is left as the base ships it.In place

Reverse path filtering. The benchmark asks for strict mode (rp_filter=1). Kairos ships loose mode (rp_filter=2), because strict mode drops return traffic on multi-homed nodes and on the asymmetric paths CNI plugins create, which breaks Kubernetes networking. Loose mode still drops packets whose source is not reachable through any interface.

PAM wiring per base​

pwquality.conf and faillock.conf only take effect when pam_pwquality.so and pam_faillock.so are in the base image's PAM stack. kairos-init wires them with each distribution's own tool, so a later package update does not overwrite the stack.

Basepam_pwqualitypam_faillock
HadronWired in system-authWired in system-auth
Ubuntu, DebianWired through the stock pwquality pam-auth-update profile (libpam-pwquality is installed)Wired through the kairos-faillock and kairos-faillock-notify pam-auth-update profiles kairos-init ships
Rocky, AlmaLinux, FedoraWired, already part of the authselect profileWired with authselect enable-feature with-faillock, or authselect select local (or minimal) with-faillock when authselect does not manage the stack yet. Without authselect, kairos-init inserts the faillock lines itself.
openSUSE TumbleweedWired through pam-config (replaces pam_cracklib)Not wired. pam-config has no faillock module, and hand-editing the common-* files would be overwritten the next time pam-config runs.
openSUSE Leap 15.6Not changed, keeps the default pam_cracklibNot wired
AlpineNot applicable. Alpine images ship no /etc/pam.d and PAM is not in the login path.Not applicable

The wiring landed in kairos-io/kairos#5096.

Lockout during first boot. On first boot sshd starts before the users: cloud-config stage sets user passwords, and on some bases that window lasts a minute or more. Password logins attempted in it fail, and enough of them would lock the account for unlock_time even after the real password is in place. To avoid that, kairos-init ships /system/oem/34_cis_faillock_reset.yaml, which clears the faillock tally under /run/faillock at the boot.after stage, once users are provisioned. Failed attempts made during that window are therefore not carried past boot.after. Lockout applies normally from then on.

SSH server​

05-kairos-hardening.conf is the single sshd hardening drop-in on every base. Base images no longer ship their own. sshd uses the first value it reads for each directive, in file name order, so an operator can override a setting with a lower-numbered drop-in such as 01-local.conf.

  • Post-quantum first key exchange (mlkem768x25519-sha256, both sntrup761x25519-sha512 names), AEAD and CTR ciphers, ETM-first MACs, ed25519, ECDSA and RSA-SHA2 host key algorithms.
  • PermitRootLogin prohibit-password, PermitEmptyPasswords no, PermitUserEnvironment no, IgnoreRhosts yes, IgnoreUserKnownHosts yes, HostbasedAuthentication no.
  • No X11, TCP, agent or tunnel forwarding, no GatewayPorts, Compression no, StrictModes yes.
  • MaxAuthTries 4, MaxSessions 10, MaxStartups 10:30:60, LoginGraceTime 60, ClientAliveInterval 600, ClientAliveCountMax 1, RekeyLimit 1G 1h.
  • LogLevel VERBOSE, SyslogFacility AUTH, Banner /etc/issue.net.

Password authentication is left on so the default user can log in on first boot. Setting install.ssh_hardening: true in the cloud config makes kairos-agent add a second drop-in at install time that turns off password and keyboard-interactive authentication and requires a public key.

On FIPS images, Hadron adds 02-hadron-fips.conf. It sorts before 05-kairos-hardening.conf, so its FIPS-validated Ciphers, MACs, KexAlgorithms and HostKeyAlgorithms win. Every other directive still comes from the kairos-init drop-in.

DevSec ssh-baseline. Kairos checks the sshd configuration against the DevSec ssh-baseline in CI. Where CIS or the STIG and DevSec disagree, Kairos follows CIS and the STIG and waives the DevSec control: the post-quantum cipher, key exchange and MAC lists (sshd-01 to sshd-03), the post-quantum host key (sshd-14), MaxAuthTries 4 (sshd-19), ClientAliveInterval 600 and ClientAliveCountMax 1 (sshd-36, sshd-37) and the banner (sshd-46). Each waiver and its reason is in tests/assets/ssh-baseline-waivers.yaml.

Status tally against dev-sec/linux-baseline​

The table below keeps the devsec control IDs described at the top of this page.

StatusCount
Implemented14
Not Applicable4
Open41

Not Applicable Controls​

sysctl-01 (IPv4 Forwarding) and sysctl-19 (IPv6 Forwarding)

  • Reason: Kubernetes nodes must forward pod traffic; net.ipv4.ip_forward=0 and net.ipv6.conf.all.forwarding=0 are incompatible with Kairos's intended use as a Kubernetes node OS.

sysctl-29 (Disable loading kernel modules)

  • Reason: Kairos loads kernel modules throughout the boot sequence: storage, virtio, squashfs, tpm, and dm_crypt in the initramfs; CNI modules after cluster bootstrap. Latching module loading off would break boot.

os-12 (Detect vulnerabilities in the cpu-vulnerability-directory)

  • Reason: A property of the host CPU's microcode and the base image's kernel mitigations, not configurable by the image builder.

Permanent Exclusions: squashfs and vfat​

os-10 (Filesystem Modules) is implemented for six of eight filesystems; two are permanently excluded:

  • squashfs: Required. Kairos ships rootfs.squashfs (loop-mounted by initramfs) and recovery.squashfs (mounted by GRUB).
  • FAT/vfat: Required. The EFI system partition uses vfat; blocking it breaks EFI and UKI boot.

Controls​

devsec IDIntentCIS ReferenceStatusEvidence / JustificationIssue
os-01Trusted hosts login(none in source)Open/etc/hosts.equiv is never created or asserted by Kairos; IgnoreRhosts yes is configured in sshd but the file itself is operator-chosen via base image.#4628
os-02Check owner and permissions for /etc/shadow(none in source)ImplementedMode tightened by steps_cis_hardening.go (/etc/shadow and /etc/gshadow to u-x,g-wx,o-rwx; backups owner-only). Partial: mode only; ownership deliberately not forced because unix_chkpwd needs group read on some bases.#4626
os-03Check owner and permissions for /etc/passwd(none in source)ImplementedMode tightened by steps_cis_hardening.go (/etc/passwd and /etc/group to u-x,go-wx; backups guarded on existence). Partial: mode only, not ownership.#4626
os-03bCheck passwords hashes in /etc/passwd(none in source)OpenKairos writes no password hash to /etc/passwd: kairos user has passwd: "!" via yip, root locked with passwd -l. De facto satisfied but not checked.#4628
os-04Dot in PATH variable(none in source)Opensudo path is hardened; interactive login PATH and /etc/profile.d are operator-chosen.#4628
os-05Check login.defs(none in source)Implemented/etc/login.defs pinned for PASS_MAX_DAYS 365, PASS_MIN_DAYS 1, PASS_WARN_AGE 7, UMASK 027, ENCRYPT_METHOD SHA512, tighten-only: a stricter base value is kept. Partial: other keys the devsec check reads are left to the base image.#4626
os-05bCheck login.defs - RedHat specific(none in source)OpenGeneral login.defs keys are pinned (see os-05); the RedHat-specific keys this check reads are left to the base image.#4628
os-06Check for SUID/ SGID blacklist(none in source)OpenNo SUID/SGID pruning in Kairos; inherited from base image.#4628
os-07Unique uid and gid(none in source)OpenKairos adds fixed admin (gid 900) and kairos users; no validation of base image's existing passwd/group for duplicate IDs.#4628
os-09Check for .rhosts and .netrc fileCIS Benchmark 9.2.9-10 (older numbering)OpenPartial: IgnoreRhosts yes and HostbasedAuthentication no set in the sshd drop-in; the files themselves are not pruned.#4628
os-10CIS: Disable unused filesystemsCIS DIL 1.1.1.xImplementedSix of eight filesystems blocklisted in /etc/modprobe.d/cis-blocklist.conf: cramfs, freevxfs, jffs2, hfs, hfsplus, udf. Permanently excluded: squashfs (required for rootfs), vfat (required for EFI boot).#4626
os-11Protect log-directory(none in source)Open/var/log persisted but owner/mode never set.#4628
os-12Detect vulnerabilities in the cpu-vulnerability-directory(none in source)Not applicableCPU microcode and kernel mitigations; not configurable by image builder.
os-13Protect cron directories and files(none in source)Implemented/etc/crontab 0600; cron.hourly, cron.daily, cron.weekly, cron.monthly, cron.d 0700; cron.allow, cron.deny, at.allow, at.deny 0640; all root-owned and guarded on the path existing.#4626
os-14Check mountpoints for noexec mount options(none in source)OpenPartial: Initramfs and early-boot mounts have noexec,nosuid,nodev; immucore's overlay RW paths do not. Several target mountpoints not separate filesystems.#4628
os-15Check mountpoints for nosuid mount options(none in source)OpenPartial: Initramfs and early-boot mounts configured; runtime overlay RW paths not separately mounted.#4628
os-16Check mountpoints for nodev mount options(none in source)OpenPartial: Initramfs and early-boot mounts configured; runtime overlay RW paths not separately mounted.#4628
package-01Do not run deprecated inetd or xinetd(none in source)OpenNever installed; absence not asserted by Kairos.#4628
package-02Do not install Telnet server(none in source)OpenNever installed; absence not asserted by Kairos.#4628
package-03Do not install rsh server(none in source)OpenNever installed; absence not asserted by Kairos.#4628
package-05Do not install ypserv server (NIS)(none in source)OpenNever installed; absence not asserted by Kairos.#4628
package-06Do not install tftp server(none in source)OpenNever installed; absence not asserted by Kairos.#4628
package-08Install auditd(none in source)Implementedauditd (Debian family) or audit (RHEL, SUSE, Alpine) installed on every base and enabled; baseline rules in /etc/audit/rules.d/50-kairos.rules; /var/log/audit bind-mounted from the persistent partition by immucore.#4626
package-09CIS: Additional process hardeningCIS DIL 1.5.4OpenNever installed and never explicitly disabled.#4628
sysctl-01IPv4 Forwarding(none in source)Not applicableKubernetes nodes must forward; incompatible with Kairos's purpose.
sysctl-02Reverse path filtering(none in source)Implementednet.ipv4.conf.all.rp_filter and default.rp_filter set to 2 (loose) in /etc/sysctl.d/99-kairos-cis.conf. Partial: strict mode (1) drops traffic on multi-homed and CNI setups, so loose mode is shipped.#4626
sysctl-03ICMP ignore bogus error responses(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-04ICMP echo ignore broadcasts(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-05ICMP ratelimit(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-06ICMP ratemask(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-07TCP timestamps(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-08ARP ignore(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-09ARP announce(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-10TCP RFC1337 Protect Against TCP Time-Wait(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-11Protection against SYN flood attacks(none in source)Implementednet.ipv4.tcp_syncookies = 1 in 99-kairos-cis.conf.#4626
sysctl-12Shared Media IP Architecture(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-13Disable Source Routing(none in source)Implementednet.ipv4.conf.all.accept_source_route = 0 in 99-kairos-cis.conf. Partial: default and IPv6 keys not set.#4626
sysctl-14Disable acceptance of all IPv4 redirected packets(none in source)Implementednet.ipv4.conf.all.accept_redirects = 0 in 99-kairos-cis.conf. Partial: default key not set.#4626
sysctl-15Disable acceptance of all secure redirected packets(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-16Disable sending of redirects packets(none in source)Implementednet.ipv4.conf.all.send_redirects = 0 in 99-kairos-cis.conf. Partial: default key not set.#4626
sysctl-17Disable log martians(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-19IPv6 Forwarding(none in source)Not applicableKubernetes nodes must forward; incompatible with Kairos's purpose.
sysctl-20Disable acceptance of all IPv6 redirected packets(none in source)Implementednet.ipv6.conf.all.accept_redirects = 0 in 99-kairos-cis.conf. Partial: default key not set.#4626
sysctl-21Disable acceptance of IPv6 router solicitations messages(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-22Disable Accept Router Preference from router advertisement(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-23Disable learning Prefix Information from router advertisement(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-24Disable learning Hop limit from router advertisement(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-25Disable the system's acceptance of router advertisement(none in source)Implementednet.ipv6.conf.all.accept_ra = 0 in 99-kairos-cis.conf. Partial: default key not set.#4626
sysctl-26Disable IPv6 autoconfiguration(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-27Disable neighbor solicitations to send out per address(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-28Assign one global unicast IPv6 addresses to each interface(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-29Disable loading kernel modules(none in source)Not applicableBoot loads modules throughout initramfs and CNI stage; incompatible with Kairos.
sysctl-30Magic SysRq(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-31aSecure Core Dumps - dump settings(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-31bSecure Core Dumps - dump path(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-32kernel.randomize_va_space(none in source)Implementedkernel.randomize_va_space = 2 in 99-kairos-cis.conf.#4626
sysctl-33CPU No execution Flag or Kernel ExecShield(none in source)OpenCPU/kernel capability; not configurable at image build time. Listed as Open (not Not-applicable) because Kairos could in principle assert it and does not.#4628
sysctl-34Ensure links are protected(none in source)OpenNot set by 99-kairos-cis.conf.#4628
sysctl-35Restrict ptrace attach to privileged users(none in source)OpenNot set by 99-kairos-cis.conf.#4628

Next Steps​

  • Kubernetes hardening: Configure k3s or k0s with CIS-compliant settings at cluster deployment time. Refer to the CIS Kubernetes Benchmark v1.9.0 and your Kubernetes distro's CIS profile documentation.
  • Linux baseline hardening: The remaining Linux work (SELinux enforcing on RHEL, pam_faillock on openSUSE, and a CI scan that fails on regression) is tracked in kairos-io/kairos#4626. The control matrix itself is tracked in kairos-io/kairos#4628.