csi-driver-spiffe
csi-driver-spiffe 是一个为 Kubernetes 设计的容器存储接口 (CSI) 驱动程序插件,旨在与 cert-manager 一起使用。
它透明地将 SPIFFE SVID(以 X.509 证书密钥对的形式)交付到安装 Kubernetes Pod。
最终结果是,Kubernetes 中运行的任何和所有 Pod 都可以从信任域安全地请求 SPIFFE 身份文档,而配置最少。
这些文档反过来具有以下属性
- 自动续订 ✔️
- 私钥从不离开节点的虚拟内存 ✔️
- 每个 Pod 的文档都是唯一的 ✔️
- 该文档与 Pod 具有相同的生命周期,并在 Pod 终止时销毁 ✔️
- 在信任域中启用 mTLS ✔️
...volumeMounts:- mountPath: "/var/run/secrets/spiffe.io"name: spiffevolumes:- name: spiffecsi:driver: spiffe.csi.cert-manager.ioreadOnly: true
组件
该项目分为两个组件:驱动程序和审批者。
CSI 驱动程序
CSI 驱动程序作为 DaemonSet 在集群上运行,负责生成、请求和挂载证书和私钥到它管理的节点上的 Pod。CSI 驱动程序创建和管理一个 tmpfs 目录。
当使用配置的 CSI 卷创建 Pod 时,驱动程序将在本地生成一个私钥,并在与 Pod 相同的命名空间中创建一个 cert-manager CertificateRequest。
驱动程序使用 CSI 令牌请求。这意味着正在创建的 Pod 的令牌将传递给驱动程序。
该令牌的详细信息用于创建代表 Pod 身份的 SPIFFE ID,并且该令牌用于创建 SVID 的实际 CertificateRequest。
一旦证书由配置的 cert-manager 发行者签名,驱动程序就会将私钥和证书挂载到 Pod 的卷中,并监视证书以根据证书的过期日期续订证书和私钥。
审批者
一个独立的 cert-manager 审批者 部署负责管理 csi-driver-spiffe CertificateRequest 的批准和拒绝。
审批者确保请求具有
- 可接受的密钥用途(密钥加密、数字签名、客户端身份验证、服务器身份验证);
- 与强制执行的持续时间匹配的请求持续时间(默认 1 小时);
- 没有 SAN 或其他可识别属性,除了单个 URI SAN;
- URI SAN 是创建 CertificateRequest 的 ServiceAccount 的 SPIFFE 身份;
- 与启动时配置的 SPIFFE ID 信任域匹配的 SPIFFE ID 信任域。
审批者只考虑具有 spiffe.csi.cert-manager.io/identity
注释的 CertificateRequest,该注释由 csi-driver-spiffe 添加到它创建的所有请求中。
安装
有关如何安装 csi-driver-spiffe 的说明,请参阅 安装指南。
安全注意事项
csi-driver-spiffe 处理高度宝贵的凭据,应将其保密。使用 Kubernetes CSI 卷的设计使其可以轻松地将访问权限限制为仅挂载 CSI 卷的 Pod,但仍应注意不要公开由 csi-driver-spiffe 创建的私钥。
csi-driver-spiffe 始终使用它为其颁发证书的 Pod 的令牌来创建它创建的 SVID 的 CertificateRequest 资源。这意味着
- 在颁发过程中,csi-driver-spiffe 能够执行 Pod 可以执行的任何操作;请记住,一个被破坏的 csi-driver-spiffe Pod 可能滥用这些权限,尽管在正常操作中仅使用 CertificateRequest 权限。
- 重要的是:所有使用 csi-driver-spiffe 的 Pod 必须具有创建 CertificateRequest 资源的权限。
Pod 必须具有创建 CertificateRequest 的权限这一要求具有重要的安全影响。如果具有这些权限的 Pod 被破坏,它可以创建任意 CertificateRequest 资源,这些资源可以引用集群中的任意发行者。
由于 csi-driver-spiffe 要求在集群内使用批准,因此可以通过批准来缓解此风险。
但是,重要的是,集群中的任何其他形式的批准(例如审批者策略)都应仔细配置,以不与 csi-driver-spiffe 审批者重叠,并限制对其他发行者的访问。
例如,允许任何 Pod 使用 ACME(Let's Encrypt)发行者颁发证书的审批者策略 CertificateRequestPolicy
资源可能会允许被破坏的 Pod 颁发一个公开可信的证书,如果该 Pod 使用 csi-driver-spiffe 并且因此具有创建 CertificateRequest 资源的权限。
安全地使用 csi-driver-spiffe 意味着要考虑您的集群中可用的哪些批准方法,并仔细配置这些审批者以确保 Pod 无法针对它们不应该能够使用的发行者。
用法
驱动程序成功安装后,Pod 就可以开始请求和挂载其密钥和 SPIFFE 证书。由于在创建 CertificateRequest 时会模拟 Pod 的 ServiceAccount,因此每个想要使用该卷的 ServiceAccount 都必须获得该权限。
带有虚拟部署的示例清单
kubectl apply -f https://raw.githubusercontent.com/cert-manager/csi-driver-spiffe/ed646ccf28b1ecdf63f628bf16f1d350a9b850c1/deploy/example/example-app.yamlkubectl exec -n sandbox \$(kubectl get pod -n sandbox -l app=my-csi-app -o jsonpath='{.items[0].metadata.name}') \-- \cat /var/run/secrets/spiffe.io/tls.crt | \openssl x509 --noout --text | \grep "Issuer:"# expected output: Issuer: CN = csi-driver-spiffe-cakubectl exec -n sandbox \$(kubectl get pod -n sandbox -l app=my-csi-app -o jsonpath='{.items[0].metadata.name}') \-- \cat /var/run/secrets/spiffe.io/tls.crt | \openssl x509 --noout --text | \grep "URI:"# expected output: URI:spiffe://foo.bar/ns/sandbox/sa/example-app
运行时配置
如果 csi-driver-spiffe 是使用启用运行时配置安装的,它将监视一个名为 ConfigMap 的发行者配置。如果该 ConfigMap 存在并包含一个有效的发行者引用,则该发行者将用于所有创建的 CertificateRequest 资源。
如果 ConfigMap 被删除或不包含有效的发行者引用,它将被忽略。如果在安装时指定了默认发行者,则该默认值将用作后备。如果没有提供有效的运行时配置并且没有指定默认发行者,则颁发(以及 Pod 创建)将失败,直到配置有效的发行者。
运行时配置 ConfigMap 的名称是在安装时使用 app.runtimeIssuanceConfigMap
Helm 值设置的。有效的 ConfigMap 必须包含 issuer-name
、issuer-kind
和 issuer-group
键。
以下是为名为 my-issuer-name
的 ClusterIssuer 创建 ConfigMap 的示例
kubectl create configmap spiffe-issuer -n cert-manager \--from-literal=issuer-name=my-issuer-name \--from-literal=issuer-kind=ClusterIssuer \--from-literal=issuer-group=cert-manager.io
FS 组
在使用指定用户或组运行 Pod 时,由于基于 Unix 的文件系统权限,默认情况下该卷将不可读。可以使用以下卷属性指定挂载卷的文件组
...securityContext:runAsUser: 123runAsGroup: 456volumes:- name: spiffecsi:driver: spiffe.csi.cert-manager.ioreadOnly: truevolumeAttributes:spiffe.csi.cert-manager.io/fs-group: "456"
kubectl apply -f https://raw.githubusercontent.com/cert-manager/csi-driver-spiffe/ed646ccf28b1ecdf63f628bf16f1d350a9b850c1/deploy/example/fs-group-app.yamlkubectl exec -n sandbox $(kubectl get pod -n sandbox -l app=my-csi-app-fs-group -o jsonpath='{.items[0].metadata.name}') -- cat /var/run/secrets/spiffe.io/tls.crt | openssl x509 --noout --text | grep URI:# expected output: URI:spiffe://foo.bar/ns/sandbox/sa/fs-group-app
根 CA 捆绑包
⚠️ 此功能比 trust-manager 弱得多,并且使用和更新起来困难得多。建议使用 trust-manager。
默认情况下,CSI 驱动程序只会挂载 Pod 的私钥和已签名的证书。可以可选地配置 csi-driver-spiffe,以便也从将被写入所有 Pod 卷的卷中挂载静态定义的 CA 捆绑包。
如果 CSI 驱动程序检测到此捆绑包已更改(通过覆盖、续订等),则新的捆绑包将被写入所有现有卷。
以下示例挂载了信任域 ClusterIssuer 使用的 CA 证书。
helm upgrade -i -n cert-manager cert-manager-csi-driver-spiffe jetstack/cert-manager-csi-driver-spiffe --wait \--set "app.logLevel=1" \--set "app.trustDomain=my.trust.domain" \\--set "app.runtimeIssuanceConfigMap=spiffe-issuer"--set "app.issuer.name=csi-driver-spiffe-ca" \--set "app.issuer.kind=ClusterIssuer" \--set "app.issuer.group=cert-manager.io" \\--set "app.driver.volumes[0].name=root-cas" \--set "app.driver.volumes[0].secret.secretName=csi-driver-spiffe-ca" \--set "app.driver.volumeMounts[0].name=root-cas" \--set "app.driver.volumeMounts[0].mountPath=/var/run/secrets/cert-manager-csi-driver-spiffe" \--set "app.driver.sourceCABundle=/var/run/secrets/cert-manager-csi-driver-spiffe/ca.crt"kubectl rollout restart deployment -n sandbox my-csi-appkubectl exec -it -n sandbox $(kubectl get pod -n sandbox -l app=my-csi-app -o jsonpath='{.items[0].metadata.name}') -- ls /var/run/secrets/spiffe.io/# expected output: ca.crt tls.crt tls.key