安全 (security)
security 类不是一套独立的 kustomize 应用,而是给两个安全相关组件 —— cert-manager 和 kyverno —— 补充的监控与网络策略片段。这两个组件的主体 manifest 实际都放在 infrastructure 类的同名目录下,由各自的 ArgoCD Application 同步。
applications/security/cert-manager/ 和 applications/security/kyverno/ 这两个目录里只有 ServiceMonitor(以及 kyverno 的一个 NetworkPolicy),没有 kustomization.yaml,也没有 Deployment。真正的控制器、CRD、ClusterIssuer、RBAC 都在 applications/infrastructure/cert-manager/ 和 applications/infrastructure/kyverno/。下面的事实区分这两处来源。这个类里有什么
applications/security/ 下只有两份目录,各自只装监控相关的零散 manifest:
- Name
- cert-manager/servicemonitor.yaml
- Description
- 一个 ServiceMonitor,namespace 为
cert-manager,按app.kubernetes.io/instance: cert-manager选中 Service,从tcp-prometheus-servicemonitor端口的/metrics每 30s 抓一次指标。
- Name
- kyverno/servicemonitor.yaml
- Description
- 一个 ServiceMonitor,namespace 为
kyverno,覆盖 admission-controller / background-controller / cleanup-controller / reports-controller 四个组件的metrics-port,每 30s 抓一次/metrics。
- Name
- kyverno/networkpolicy-allow-prometheus.yaml
- Description
- NetworkPolicy
allow-prometheus-scraping,放行来自prometheusnamespace 的 ingress 到 kyverno pod 的 TCP8000端口,让 Prometheus 能抓到上面的指标。
组件
两个组件的完整定义都在 infrastructure 目录,下面是从 manifest 直接核对的事实。
- Name
- cert-manager
- Description
- 集群的 TLS 证书签发器,路径
applications/infrastructure/cert-manager/,由 ArgoCD Applicationcert-manager(projectinfrastructure,标签category: security,sync-wave 1)同步到cert-managernamespace。控制器镜像quay.io/jetstack/cert-manager-controller:v1.20.2,含 controller / cainjector / webhook 三个 Deployment,各带 VPA;webhook 有 PodDisruptionBudget。ClusterIssuerletsencrypt-prod走 ACME(acme-v02.api.letsencrypt.org,邮箱admin@yldm.tech),同时配置 HTTP-01(IngressClasstraefik)和 Cloudflare DNS-01 两种 solver;DNS-01 覆盖yldm.tech/yldm.ai/dunaifen.games/relaya.pro,其中*.relaya.pro通配证书只能靠 DNS-01 签发。Cloudflare API token、letsencrypt 私钥等都走 ExternalSecret 从 Vault 取。
- Name
- kyverno
- Description
- 策略引擎 / 准入控制器,路径
applications/infrastructure/kyverno/,由 ArgoCD Applicationkyverno(projectplatform,标签category: policy,sync-wave 5)同步到kyvernonamespace。镜像reg.kyverno.io/kyverno/kyverno:v1.18.1(initContainerkyvernopre同版本),拆成 admission-controller / background-controller / cleanup-controller / reports-controller 四个 Deployment,各自独立 ServiceAccount + Role/RoleBinding。webhook 用到的 TLS 证书对(kyverno-tls-pair/kyverno-tls-ca)通过 ExternalSecret 提供。该 Application 开了ServerSideApply,并对两份体积巨大的 CRD 单独用compare-options: ServerSideDiff=false注解避免 perma-OutOfSync(见仓库 #808)。
category: security,而 kyverno 打的是 category: policy —— 但本页按习惯把这两个安全组件归在 security 类一起讲。它们的 manifest 物理位置都在 applications/infrastructure/ 下。cert-manager 与 metallb 自签 issuer
除了对外签发 Let's Encrypt 证书,cert-manager 还给集群内部的 webhook 签自签证书。最典型的就是 metallb 的 validating webhook:它的证书不走 ACME,而是用一个 namespace 级的自签 Issuer。
相关对象都在 applications/networking/metallb/,不在 cert-manager 目录里:
# applications/networking/metallb/issuers-selfsigned.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: metallb-system
spec:
selfSigned: {}
配套的 certificates-webhook.yaml 用这个 Issuer 给 webhook-server-cert 签一张有效期 1 年、提前 30 天续订的证书,dnsNames 为 webhook-service.metallb-system.svc 及其 .cluster.local 形式。这就是为什么 metallb 的 manifest 相比上游做了定制(--webhook-mode=enabled),它依赖 cert-manager 在场才能起 webhook。
kyverno 的保护策略
kyverno 目前装了两条 ClusterPolicy(applications/infrastructure/kyverno/policies/),都是 validationFailureAction: Enforce、background: false,作用是阻止误删核心基础设施:
| ClusterPolicy | 保护对象 | 拒绝的操作 |
|---|---|---|
protect-core-infrastructure | kube-system / kube-public / kube-node-lease / default 这几个系统 namespace;kube-system 里的 kube-dns / metrics-server Service 与 coredns / metrics-server Deployment;kube-system 和 default 里的 default ServiceAccount | DELETE |
protect-kubernetes-service | default namespace 里的 kubernetes Service | DELETE |
也就是说,这两条策略只在删除这些关键对象时拦截并报错,对其它资源不做校验。
工作负载隔离:沙箱运行时决策
是否给集群引入 VM/沙箱级容器运行时(gVisor / Kata Containers)做过一次评估。结论:暂不引入,沿用默认 runc。
判断依据:不可信/多租户用户代码的现状是「可能跑,但很少(约 5%)」。为偶发负载维护一个常驻的沙箱运行时,固定运维成本(额外节点要求、guest 内核/镜像维护、两层排障、可观测性失配)摊不薄,ROI 不划算。这是私有 K3s homelab,不是公网多租户平台 —— 沙箱的核心价值(hypervisor 级、每 Pod 独立内核的隔离)在当前威胁模型下基本兑现不了。
RuntimeClass 分流:默认 runc 承载受信任负载,只把少数不可信负载路由到沙箱(再配 taint/nodeSelector 钉到独立节点池收敛爆炸半径)。当前决定是连这一步也先不做。将来真要做隔离时的选型结论(已调研,避免重复评估):
| 运行时 | 适用场景 | 理由 |
|---|---|---|
| runc(默认) | 受信任负载(95%+) | 共享内核 + Pod 硬化即可,零额外运维 |
| gVisor | 不可信但短生命周期 / CI | 冷启动比 Kata 快约 2 倍、不依赖 /dev/kvm、固定运维成本低 —— 偶发隔离首选 |
| Kata | 不可信 + 长生命周期 + 能控节点 | 真 hypervisor 隔离;本集群是裸金属/PVE,/dev/kvm 可得,但仅当三条件同时成立 ROI 才为正 |
| 临时 VM | 极低频、延迟不敏感的一次性任务 | 零常驻平台复杂度,跑完即销毁 |
yldm-backend-runners)是潜在的不可信代码入口。若将来稳定接外部贡献者/客户代码在 runner 上跑,因其短生命周期特性,优先评估 gVisor 而非 Kata。重新评估的触发线(出现任一条就重启此决策):不可信任务从偶发变成常规(如开始稳定接外部 PR / 客户代码);开始多租户、租户间共享内核;出现合规层面的强隔离要求。
Pod 安全硬化:现状与缺口
一次实地核对(2026-06):集群目前有「运维 guardrail + 网络隔离」层,但没有「Pod 安全硬化」基线。这与上面的隔离决策是配套的 —— 同样基于「为约 5% 的偶发风险折腾,对私有 homelab 不划算」而有意暂缓。
已有:
- Name
- 网络隔离
- Description
- app / platform / game 各一套 NetworkPolicy(
bootstrap/applications/*-network-policies.yaml),加各组件自带的 allow 规则。
- Name
- 删除保护 guardrail
- Description
- ValidatingAdmissionPolicy
protect-system-resources(cluster/policies/)+ 两条 kyverno ClusterPolicy(见上节表),拦截误删核心对象。
- Name
- 项目级 RBAC
- Description
- AppProject
app/game设clusterResourceWhitelist: [],禁止其下服务创建任何 cluster-scoped 资源。
缺口(即「Pod 硬化」层缺失):
- Name
- 无全局 seccomp 默认
- Description
- kubelet 未开
seccompDefault;仅 prometheus / registry / argocd-image-updater / reloader / deadman-switch 等个别 Deployment 在自己的 pod spec 里写了seccompProfile,不是集群默认。
- Name
- 业务 namespace 无 PSA enforce
- Description
- app / platform / game / data 等 namespace 没有打 Pod Security Admission 的
enforce标签,默认即privileged档(只有metallb-system/velero显式打了privileged例外,那是它们确实需要特权)。
- Name
- kyverno 无 Pod 硬化策略
- Description
- 现有两条 ClusterPolicy 都是「防删除」guardrail,没有 require-non-root / drop-capabilities / disallow-privileged 这类校验。
若改主意要补,按本仓库既有模式、运行时无关的硬化路径(任选):
- 沿用 PSA 标签(
metallb-system/velero已在用):给业务 namespace 加pod-security.kubernetes.io/enforce: baseline+warn/audit: restricted,观察无破坏后再把enforce升到restricted。 - kubelet
seccompDefault: true:节点级改动,需重启 kubelet(节点在自己手里,可灰度)。 - 加一条 kyverno ClusterPolicy:kyverno 已安装,用
validationFailureAction: Audit先观察、再升Enforce。 - 自己的服务在 pod spec 里补
securityContext:runAsNonRoot/capabilities.drop: [ALL]/allowPrivilegeEscalation: false/seccompProfile.type: RuntimeDefault。
看 infrastructure 类全貌