TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

k3s·RKE2·k0s 安全与运维:CIS·FIPS 默认值、升级、气隙、备份

状态:草稿 (2026-10-13),基于官方文档 + 部分实测。 安全默认值与运维流程于 2026-10-13 打开官方文档进行了核实。“实测”是 TT Lab 课程实验虚拟机中的实际操作结果,并一同记录了版本。我们并未做使用相同检查工具(如 kube-bench 等)在三个发行版上运行并对比通过数量的实验(未实测)。编写规则:以实测数据为准,无法测量的标记为“未实测”,在文档中未找到的标记为“未确认”。

目录

1. 安全默认值一览

第 1 篇中看到的架构差异在安全方面表现得更为明显。首先通过表格来查看。

项目 k3s RKE2 k0s
CIS 基准 默认通过多数项,其余项按加固指南手动设置 profile: cis 通过 自动大规模应用,主机准备工作由运维人员负责 文档中说明通过了 kube-bench 的 k0s-1.0 基准测试(除少数例外)
FIPS 140 官方文档未找到(未确认) FIPS 140-2,Go BoringCrypto 构建 开源版超出范围,仅限商业合同
SELinux k3s-selinux 策略,通过 --selinux 开启 rke2-selinux 策略,RPM 安装则自动开启 有关于在 Worker 的 containerd 中开启的说明
Pod 安全标准 (PSA) 默认 不单独设置则为 Kubernetes 默认 (privileged) 默认 privileged,cis profile 下为 restricted k0s 自身默认值在文档中未记录(未确认)
控制平面运行用户 单个进程 默认 root,cis profile 下将 etcd 设为 etcd 用户 etcd、apiserver、scheduler、konnectivity 分别使用独立用户
其他 审计日志与 Secret 加密需手动开启 在构建流水线中使用 Trivy 进行 CVE 扫描 默认开启遥测(实测,v1.36.4)

仅看表格可能会觉得 RKE2 领先,但实际上这只是三个发行版的目标不同。核心在于各自自动完成了什么,以及将什么留给了运维人员。

2. k3s:大部分已就绪,其余按指南配置

k3s 加固指南的出发点是:仅凭默认设置可以通许多 CIS 控制项,但并非全部。由于 k3s 不会修改宿主机 OS,因此宿主机的配置需要由运维人员来做。指南的要求大致如下:

文档特别指出,即使完全遵循指南,仍有一些项目需要人工判断。在文档中未找到 FIPS 相关内容。 docs.k3s.io/security/fips 返回 404,且安全部分列表中也没有(2026-10-13)。如果需要 FIPS,最好理解为应该选择 RKE2 而非 k3s。

支持 SELinux。安装脚本会在兼容系统上安装 k3s-selinux RPM,并通过 --selinux 标志或配置文件开启。不过,在 SELinux 下不支持用于更改数据目录的 --data-dir 。

3. RKE2:单行开启,但前提是主机已就绪

RKE2 的安全默认值集中在 profile: cis 这一行中。它遵循匹配 Kubernetes 版本的 CIS 基准(按指南,v1.35 及以上为 CIS v2.0),开启后会发生以下变化:

留给运维人员的工作有两项:将安装包中包含的针对 CIS 的 sysctl 文件放置到 /etc/sysctl.d/ 中,以及创建 etcd 系统用户。之所以选择不自动修改而是直接停止,是因为如果发行版擅自修改主机设置,可能会破坏同一主机上的其他软件。

实测:在运行中的集群上开启 cis 会发生什么

在 TT Lab 的 RKE2 实验(v1.36.4+rke2r1,2026-09-15)中,我们在一个以默认 profile 运行的服务器上添加了 profile: cis 并重启。按顺序发生了以下情况(实测)。

  1. missing required: user: unknown user etcd 拒绝启动。正如预期那样。
  2. systemctl stop 停止并准备好 etcd 用户和 sysctl 后再次启动,但这次 etcd 因无法打开数据库文件而 panic。
  3. 原因是第 1 篇中看到的静态 Pod。 systemctl stop 之后仍然残留着以 root 运行的旧 etcd 容器,新启动的 RKE2 发送的碎片整理请求被该旧 etcd 接收,并重新将 db 文件写成了 root 所有权。随后以 etcd 用户启动的新 etcd 无法打开该文件。
  4. rke2-killall.sh 将残留的容器也停止并启动后,仅用 9 秒 API 就绪了,RKE2 自行调整了数据目录的所有权。

PSA 方面也有陷阱。在默认 profile 下,PSA 配置文件是 enforce privileged,特权 Pod 得以照常启动。在改成 cis 后,相同的清单在新命名空间中被拒绝,但 已经启动的特权 Pod 继续保持 Running 状态(实测)。因为 PSA 仅检查创建请求。开启 profile 的当天风平浪静,但在重新部署该 Pod 的那一天就会被拦截。

教训有两个。cis profile 应当在 最初搭建时 开启。如果必须稍后开启,切记不仅要停止服务,还要连同静态 Pod 一起关闭后再开启。

FIPS 与 SELinux

RKE2 对 FIPS 140-2 的支持来自使用 Go 编译器 BoringCrypto 模块(NIST 认证编号 4407)构建的二进制文件。文档中仅有 140-2,未提及 140-3(未确认)。文档称 CNI 中为 FIPS 重新构建的是 canal,但同一页的组件列表中也包含 Calico,文档内部存在不一致之处。如果即将面临 FIPS 审计,最好直接向 SUSE 确认应选择哪个 CNI。

SELinux 需要 rke2-selinux 策略和 selinux: true ,如果通过 RPM 安装则这两者会自动处理。若为 tarball 安装则需手动处理。

4. k0s:划分用户,其余保持均衡

k0s 从另一个方向切入安全性。正如第 1 篇中所见,它让控制平面的每个组件都在不同的系统用户下运行,并且由于 Controller 节点上没有 kubelet 和容器运行时,因此工作负载无法紧挨着控制平面运行。

CIS 文档指出,如果使用 kube-bench 的 k0s-1.0 基准进行检查,默认状态下除少数例外均可通过。列出的例外包括 EventRateLimit、AlwaysPullImages(与气隙环境冲突)、审计日志与审计策略、加密提供程序、protect-kernel-defaults、kubelet 服务文件项等。文档中未给出通过/失败的数量。

FIPS 超出了开源项目的范围。2025-12 合并的更改(PR #6777)删除了 README 中的 FIPS 提及并给出了此理由,其官网写着在有“请求与商业合同”时提供。

PSA 提供了通过 spec.api.extraArgs 传递 AdmissionConfiguration 的方法。示例中的默认值为 privileged,但未找到明确记录 k0s 自身默认级别的句子(未确认)。

另外, 默认开启了遥测。 在 TT Lab 实验虚拟机(v1.36.4+k0s.0)中, k0s config create 的默认输出显示 telemetry 为启用状态(实测)。如果是不允许向外部发送指标的环境,请在配置中将其关闭后再启动。

5. 安装

k3s RKE2 k0s
默认安装 get.k3s.io 脚本 get.rke2.io 脚本(tarball 或 RPM) get.k0s.sh 通过 k0s install controller
批量管理多节点 每个节点执行脚本 + token 每个节点执行脚本 + token k0sctl:通过单个配置文件跳过 SSH 进行安装与加入
kubeconfig /etc/rancher/k3s/k3s.yaml /etc/rancher/rke2/rke2.yaml k0s kubeconfig admin 导出获取
kubectl 随附安装 /var/lib/rancher/rke2/bin(不在默认 PATH 中) k0s kubectl(不单独安装)

k3s 和 RKE2 遵循相同的模型,即“在每个节点上运行脚本”。在实验中,k3s 的安装时间为 8 秒,节点 Ready 为 11 秒(实测,v1.35.8+k3s1,自虚拟机启动完成后开始计时)。

k0s 的亮点在于 k0sctl。只要有一个写明了主机列表和角色的 k0sctl.yaml ,敲下 k0sctl apply 就会通过 SSH 进入各个主机进行安装和加入。文档中记载,添加节点可行,但移除节点 k0sctl 并不负责。

RKE2 安装脚本有一个与环境相关的痛点。 /usr/local 如果是只读的或挂载在独立的分区上,则会解压到 /opt/rke2 中。实验虚拟机的根磁盘较小,安装包(128M,实测)差点占满根目录,必须通过 INSTALL_RKE2_TAR_PREFIX 指定位置。

6. 升级

① k3s · RKE2 — system-upgrade-controller 의 Plan 둘 Plan: server channel 또는 version Plan: agent prepare 로 server 를 기다림 서버를 하나씩(concurrency 1) (cordon) → 바이너리 교체 → 재시작 서버가 다 끝난 뒤 시작 동시에 몇 대씩 할지 정한다 수동이면 설치 스크립트를 판을 지정해 다시 돌린다. 실측(k3s 1.34→1.35): 교체 11초, 노드 Ready 12초, 파드 그대로 ② k0s — autopilot 의 Plan 하나 Plan: autopilot (이름이 반드시 autopilot) k0supdate: 바이너리 교체 · airgapupdate: 이미지 번들 교체 컨트롤러를 하나씩 매번 전부 /ready 인지 확인 그다음 워커 기본 동시성 1 k0sctl 로 SSH 를 건너 바깥에서 올리는 길도 있다. 공통: 컨트롤 플레인 먼저. k3s·RKE2 문서는 마이너 판 건너뛰기를 금한다.
图:k3s·RKE2 的 system-upgrade-controller 与 k0s autopilot 的升级顺序

k3s 与 RKE2 使用相同的工具。如果是手动升级,则指定版本(INSTALL_K3S_VERSION 等)或通道重新运行安装脚本。此时,如果未再次传入初次安装时给出的参数,参数将会丢失,因此将配置写入配置文件比依赖参数更加安全。如果是自动升级,则 system-upgrade-controller 中配置 Plan。服务器端 Plan 逐个升级服务器,而代理端 Plan 会在 prepare 阶段等待服务器端 Plan 完成后再开始。如果在 Plan 中指定 channel ,则会跟随新版本;如果指定 version ,则会固定在该版本。这两份文档都建议不要跳过小版本。

在实测中,通过脚本将 k3s 从 v1.34.11 升级到 v1.35.8 耗时 11 秒,节点变为 Ready 状态耗时 12 秒,运行中的 Pod 的 UID、容器 ID 以及重启次数都保持不变(实际测量)。不过,我们也注意到了在同一实测中容易忽略的一点。 stable 通道在当时(2026-09-15)已经指向 v1.36,因此如果从 1.34 跟随通道升级,就会 一次性跳过两个小版本 。安装脚本和 Plan CRD 都没有阻止这一点(实际测量)。对于自动升级,建议固定版本而不是使用通道。

k0s 的默认方式是更换二进制文件并重启,自动化则由 autopilot 负责。在名为 autopilot 的单个 Plan 中指定要更改的内容(用k0supdate 指定二进制文件,用 airgapupdate 指定离线镜像包)。autopilot 会逐个升级控制器,每次都确认所有控制器就绪,然后默认逐个升级工作节点。还可以对二进制文件进行 sha256 校验。如果想从外部通过 SSH 进行升级,可以使用 k0sctl。

7. 离线安装

在无网环境中搭建的方法三者大同小异。提前传输二进制文件和 镜像包,将其放在指定目录中或使用私有镜像仓库。

镜像存放位置 其他方法
k3s /var/lib/rancher/k3s/agent/images/ 私有镜像仓库 + registries.yaml,内置分布式镜像加速(Spegel)
RKE2 /var/lib/rancher/rke2/agent/images/ 私有镜像仓库 + registries.yaml,Hauler,内置镜像加速
k0s 使用工作节点的 /var/lib/k0s/images/ k0s airgap list-images 获取列表并手动打包

需要传输的数据量可以通过第 3 篇资源表格中的 GitHub 发布文件大小进行对比。先说结论,RKE2 是最重的。因为除了二进制文件外,还需要同时传输包含 kubelet、containerd 的运行时镜像以及 CNI 镜像。

8. 备份与恢复

k3s RKE2 k0s
默认存储的备份 SQLite: server/db/ 复制文件夹 自动 etcd 快照 k0s backup(etcd 或 kine/SQLite)
自动快照 etcd 时每 12 小时一次,保留 5 个 每 12 小时一次,每个服务器保留 5 个 文档中未找到(未确认)
发送至 S3 --etcd-s3* --etcd-s3* - 通过标准输出直接流式传输
恢复 --cluster-reset --cluster-reset-restore-path 相同方式 k0s restore <파일>
需一并妥善保管的内容 服务器令牌 服务器令牌 压缩包中包含 PKI

k3s 和 RKE2 必须 令牌与备份一同保管。由于快照中的引导数据(如 CA 等机密信息)是用令牌加密的,因此在恢复到其他主机时,如果没有令牌,快照将无法使用。

k0s 的备份压缩包中包含 PKI、etcd 快照(或 kine/SQLite 快照)、 k0s.yaml、清单、镜像和 Helm 配置。遗漏的数据包括 PV 数据以及在 kine 背后使用了 外部 MySQL·PostgreSQL 时的数据库数据。该数据库需通过数据库侧进行单独备份。

实测:恢复命令成功执行,但没有任何内容恢复

这是 TT Lab 的 k0s 实验中最危险的一幕。如果在 k0s stop 之后立即执行 k0s restore <파일> 并重新启动,命令会在没有错误或警告的情况下结束,集群也会启动,但 备份之后创建的 ConfigMap 仍然保留着(实际测量)。这是因为如果 etcd 的数据目录已经存在,它就会直接使用该目录并忽略解压的快照。正确的顺序应该是 k0s stop → 清空现有的 etcd 数据 → k0s restore → k0s start 。误以为已经恢复成功才是最危险的。备份只有在验证过恢复之后才能称之为真正的备份。

k3s 的恢复结果要明确得多。通过 --cluster-reset 恢复后,6 秒内完成重置,启动后 11 秒 API 即恢复响应,快照之后的更改已消失,之前的数据库则留在了 etcd-old-<시각> 文件夹中(实际测量,v1.35.8+k3s1)。

小 T 寄语。 开启安全开关只需一行命令,但让这行命令得以运行的基础(主机准备工作)需要人工来完成。此外,请务必亲自尝试恢复一次备份。因为我曾遇到过显示“成功”但实际上什么也没有恢复的情况。

参考

所有文档均于 2026-10-13 查阅。

登录后即可点赞

评论

还没有评论。

登录后即可发表评论