证书资源
apiVersion: cert-manager.io/v1
kind: Certificate
在 cert-manager 中,Certificate
资源表示证书请求的人类可读定义。cert-manager 使用此输入来生成私钥和 CertificateRequest
资源,以便从 Issuer
或 ClusterIssuer
获取已签名的证书。然后,已签名的证书和私钥将存储在指定的 Secret
资源中。cert-manager 将确保证书在到期之前 自动续期 并在 需要时重新签发。
要签发任何证书,您需要首先配置 Issuer
或 ClusterIssuer
资源。
创建证书资源
Certificate
资源指定用于生成证书签名请求的字段,这些请求随后将由您所引用的颁发者类型来满足。Certificates
通过指定 certificate.spec.issuerRef
字段来指定它们希望从哪个颁发者获取证书。
以下是一个针对 example.com
和 www.example.com
DNS 名称,spiffe://cluster.local/ns/sandbox/sa/example
URI 主题备用名称,有效期为 90 天,并在到期前 15 天续期的 Certificate
资源示例。它包含 Certificate
资源可能具有的所有选项的完整列表,但仅需部分字段,如标记所示。
apiVersion: cert-manager.io/v1kind: Certificatemetadata:name: example-comnamespace: sandboxspec:# Secret names are always required.secretName: example-com-tls# secretTemplate is optional. If set, these annotations and labels will be# copied to the Secret named example-com-tls. These labels and annotations will# be re-reconciled if the Certificate's secretTemplate changes. secretTemplate# is also enforced, so relevant label and annotation changes on the Secret by a# third party will be overwriten by cert-manager to match the secretTemplate.secretTemplate:annotations:my-secret-annotation-1: "foo"my-secret-annotation-2: "bar"labels:my-secret-label: fooprivateKey:algorithm: RSAencoding: PKCS1size: 2048# keystores allows adding additional output formats. This is an example for reference only.keystores:pkcs12:create: truepasswordSecretRef:name: example-com-tls-keystorekey: passwordprofile: Modern2023duration: 2160h # 90drenewBefore: 360h # 15disCA: falseusages:- server auth- client authsubject:organizations:- cert-manager# Avoid using commonName for DNS names in end-entity (leaf) certificates. Unless you have a specific# need for it in your environment, use dnsNames exclusively to avoid issues with commonName.# Usually, commonName is used to give human-readable names to CA certificates and can be avoided for# other certificates.commonName: example.com# The literalSubject field is exclusive with subject and commonName. It allows# specifying the subject directly as a string. This is useful for when the order# of the subject fields is important or when the subject contains special types# which can be specified by their OID.## literalSubject: "O=jetstack, CN=example.com, 2.5.4.42=John, 2.5.4.4=Doe"# At least one of commonName (possibly through literalSubject), dnsNames, uris, emailAddresses, ipAddresses or otherNames is required.dnsNames:- example.com- www.example.comuris:- spiffe://cluster.local/ns/sandbox/sa/exampleemailAddresses:- john.doe@cert-manager.ioipAddresses:- 192.168.0.5# Needs cert-manager 1.14+ and "OtherNames" feature flagotherNames:# Should only supply oid of ut8 valued types- oid: 1.3.6.1.4.1.311.20.2.3 # User Principal Name "OID"# Issuer references are always required.issuerRef:name: ca-issuer# We can reference ClusterIssuers by changing the kind here.# The default value is Issuer (i.e. a locally namespaced Issuer)kind: Issuer# This is optional since cert-manager will default to this value however# if you are using an external issuer, change this to that issuer group.group: cert-manager.io
已签名的证书将存储在名为 example-com-tls
的 Secret
资源中,该资源与 Certificate
位于同一个命名空间,前提是颁发者已成功签发了请求的证书。
如果存在 secretTemplate
,则此属性中设置的批注和标签将复制到 example-com-tls
秘密。这两个属性都是可选的。
该 Certificate
将使用名为 ca-issuer
的颁发者签发,该颁发者位于 sandbox
命名空间中(与 Certificate
资源相同的命名空间)。
注意:如果您要创建可以在 所有 命名空间中的
Certificate
资源中引用的Issuer
,则应创建一个ClusterIssuer
资源并将certificate.spec.issuerRef.kind
字段设置为ClusterIssuer
。
注意:
renewBefore
和duration
字段必须使用 Gotime.Duration
字符串格式进行指定,该格式不允许d
(天)后缀。您必须使用s
、m
和h
后缀来指定这些值。如果不安装webhook 组件
则无法这样做,这可能会导致 cert-manager 无法正常运行#1269
。
注意:设置
renewBefore
字段的值非常接近于duration
时要格外小心,因为这会导致续期循环,即Certificate
始终处于续期期间。有些Issuers
在签发时间之前将他们签发的 X.509 证书上的notBefore
字段设置为固定时钟偏移问题,这会导致证书的实际 工作持续时间 小于证书的完整持续时间。例如,Let's Encrypt 将其设置为签发时间之前的一个小时,因此证书的实际 工作持续时间 为 89 天 23 小时(完整持续时间 仍然为 90 天)。
可以在 API 参考文档 中找到证书资源上支持的字段的完整列表。
目标秘密
当证书由中间 CA 签发并且 Issuer
可以提供签发证书的链时,tls.crt
的内容将是请求的证书,后面跟着证书链。
此外,如果已知证书颁发机构,则相应的 CA 证书将存储在带有键 ca.crt
的秘密中。例如,使用 ACME 颁发者时,CA 是未知的,ca.crt
将不存在于秘密中。签发时的 ca.crt
值可以复制到使用证书的应用程序的信任存储中。但是,不要将 ca.crt
值直接安装到应用程序的信任存储中,因为当证书续期时它将被更新(有关更多详细信息,请参阅 信任证书)。
cert-manager 故意避免将根证书添加到 tls.crt
中,因为在安全执行 TLS 的情况下它们毫无用处。有关更多信息,请参阅 RFC 5246 第 7.4.2 节,其中包含以下说明
由于证书验证需要独立分发根密钥,因此可以省略指定根证书颁发机构的自签名证书,假设远程端必须已经拥有它才能在任何情况下验证它。
X.509 密钥用法和扩展密钥用法
cert-manager 支持请求具有多个 自定义密钥用法 和 扩展密钥用法 的证书。虽然 cert-manager 会尝试满足此请求,但有些颁发者会删除、添加默认值或完全忽略此请求。该 CA
和 SelfSigned
Issuer
将始终返回与您所请求的用法相匹配的证书。
除非设置了任何数量的用法,否则 cert-manager 将设置 数字签名
、密钥加密
和 服务器身份验证
的默认请求用法。如果当前证书与当前密钥用法设置不匹配,则 cert-manager 将不会尝试请求新的证书。
可以在 API 参考文档 中找到支持的密钥用法的完整列表。
其他证书输出格式
additionalOutputFormats
是证书 spec
上的一个字段,它允许指定已签发证书及其私钥的额外补充格式。目前支持两种额外输出格式:CombinedPEM
和 DER
。这两种输出格式都可以指定在同一个证书上。
apiVersion: cert-manager.io/v1kind: Certificatespec:...secretName: my-cert-tlsadditionalOutputFormats:- type: CombinedPEM- type: DER# Results in:apiVersion: v1kind: Secretmetadata:name: my-cert-tlstype: kubernetes.io/tlsdata:ca.crt: <PEM CA certificate>tls.key: <PEM private key>tls.crt: <PEM signed certificate chain>tls-combined.pem: <PEM private key + "\n" + PEM signed certificate chain>key.der: <DER binary format of private key>
CombinedPEM
类型为 CombinedPEM
的证书将在生成的证书的 Secret 中创建一个新的密钥条目 tls-combined.pem
。该条目将包含 PEM 编码的私钥,后面紧跟着至少一个换行符,然后是 PEM 编码的已签名证书链。
<private key> + "\n" + <signed certificate chain>
apiVersion: v1kind: Secretmetadata:name: my-cert-tlstype: kubernetes.io/tlsdata:tls-combined.pem: <PEM private key + "\n" + PEM signed certificate chain>...
DER
类型为 DER
的证书将在生成的证书的 Secret 中创建一个新的密钥条目 key.der
。该条目将包含私钥的 DER 二进制格式。
apiVersion: v1kind: Secretmetadata:name: my-cert-tlstype: kubernetes.io/tlsdata:key.der: <DER binary format of private key>...
使用名称约束创建证书
根证书或中间 CA 证书可以具有名称约束。名称约束指示一个名称空间,在该名称空间中,证书路径中所有后续证书的主题名称必须位于该名称空间内。查看 https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 获取更多详细信息。
⛔️ 此功能仅通过将其添加到 cert-manager 控制器和 webhook 组件的 --feature-gates
标志中启用
--feature-gates=NameConstraints=true
要使用名称约束创建 CA 证书,请使用以下配置
apiVersion: cert-manager.io/v1kind: Certificatemetadata:name: ca-cert-examplespec:secretName: example-ca-key-pairisCA: trueissuerRef:name: selfsignedkind: ClusterIssuercommonName: "example1.com"dnsNames:- example1.comnameConstraints:critical: truepermitted:dnsDomains: ["example1.com", "example2.com"]ipRanges: ["10.10.0.0/16"]excluded:ipRanges: ["10.10.0.0/24"]
请注意,当与 cert-manager 的内置 CA 和 SelfSigned Issuer 一起使用时,SAN(DNS 名称、IP 地址、URI 和电子邮件地址)不会与证书本身的名称约束进行检查,也不会与证书所属证书链中的任何名称约束进行检查。
证书可能成功签发,但在 TLS 握手期间被客户端拒绝。
签发触发器
到期(续订)触发的重新签发
cert-manager 将自动续订 Certificate
。它将根据已签发的 X.509 证书的持续时间和一个“renewBefore”值来计算何时续订 Certificate
,该值指定在证书到期之前多长时间应该续订证书。
spec.duration
和 spec.renewBefore
/spec.renewBeforePercentage
字段可以在 Certificate
上使用,以指定 X.509 证书的持续时间和“renewBefore”值。 spec.duration
的默认值为 90 天。一些签发者可能配置为仅签发具有设定持续时间的证书,因此实际持续时间可能会有所不同。 spec.renewBefore
指定一个绝对持续时间,而 spec.renewBeforePercentage
使用已签发证书的实际持续时间来计算有效的“renewBefore”。建议使用 spec.renewBeforePercentage
来防止在实际持续时间少于预期时出现续订循环。 spec.duration
的最小值为 1 小时,有效 spec.renewBefore
的最小值为 5 分钟。还需要 spec.duration
> spec.renewBefore
。
签发 X.509 证书后,cert-manager 将计算 Certificate
的续订时间。默认情况下,这将是 X.509 证书持续时间的 2/3。如果已设置 spec.renewBefore
或 spec.renewBeforePercentage
,它将是到期之前有效的 spec.renewBefore
时间。cert-manager 将 Certificate
的 status.RenewalTime
设置为尝试续订的时间。
用户操作触发的重新签发
证书对象在以下情况下重新签发
- 当对证书的规范中的以下字段之一进行更改时:
commonName
、dnsNames
、ipAddresses
、uris
、emailAddresses
、subject
、isCA
、usages
、duration
或issuerRef
;可以在 FAQ 页面 上找到更详细的解释。 - 当使用以下方法手动触发重新签发时
请注意,上述命令需要 cmctl。cmctl renew cert-1
❌ 删除与证书资源关联的 Secret 资源不是手动旋转私钥的推荐解决方案。手动旋转私钥的推荐方法是使用以下命令触发证书资源的重新签发(需要 cmctl
)
cmctl renew cert-1
签发行为:签发期间的临时证书
在请求证书时使用 ingress-shim,组件 ingress-gce
(如果使用)需要在等待签发已签署证书时提供临时证书。为了便于此操作,如果以下批注
cert-manager.io/issue-temporary-certificate: "true"
存在于证书上,在签署的证书签发并覆盖它之前,自签名的临时证书将存在于 Secret
上。
在 Ingress 上添加以下批注将自动在证书上设置“issue-temporary-certificate”
acme.cert-manager.io/http01-edit-in-place: "true"
签发行为:私钥的旋转
默认情况下,私钥不会自动旋转。使用设置 rotationPolicy: Always
,可以将与证书对象关联的私钥 Secret 配置为在证书重新签发后立即旋转(参见 签发触发器)。
使用 rotationPolicy: Always
,cert-manager 会等到证书对象正确签署后才会覆盖 Secret 中的 tls.key
文件。
使用此设置,如果您 的应用程序可以检测到挂载的 tls.crt
和 tls.key
的更改,并优雅地重新加载或自动重启,那么您可以预期不会出现停机。
如果您的应用程序仅在启动时加载一次私钥和已签署证书,那么新的证书不会立即由您的应用程序提供服务,您需要使用 kubectl rollout restart
手动重启您的 Pod,或者通过运行 wave 来实现自动化操作。Wave 是一个 Secret 控制器,它可以确保每次挂载的 Secret 发生更改时,部署都会重新启动。
私钥的重复使用
某些签发者(例如内置的 Venafi 签发者)可能不允许重复使用私钥。如果是这种情况,您必须为每个证书对象显式配置 rotationPolicy: Always
设置。
在以下示例中,证书已使用 rotationPolicy: Always
设置。
apiVersion: cert-manager.io/v1kind: Certificatespec:secretName: my-cert-tlsprivateKey:rotationPolicy: Always # 🔰 Here.
rotationPolicy
设置
rotationPolicy
的可能值是
值 | 描述 |
---|---|
Never (默认) | cert-manager 在每次签发时重用现有的私钥 |
Always (推荐) | cert-manager 在每次签发时生成新的私钥 |
使用 rotationPolicy: Never
时,仅当目标 Secret 资源中不存在私钥时才会生成私钥(使用 tls.key
密钥)。所有后续签发将重新使用此私钥。这是默认设置,以保持与先前版本的兼容性。
使用 rotationPolicy: Always
时,每次操作触发证书对象的重新签发时都会生成新的私钥(参见上面的 触发私钥轮换的操作)。请注意,如果私钥 Secret 在创建证书对象时已经存在,则不会使用现有的私钥,因为轮换机制还包括初始签发。
👉 我们建议您在证书资源上配置 rotationPolicy: Always
。同时轮换证书和私钥可以防止出现使用泄露的私钥签发证书的风险。定期更新私钥的另一个好处是,您可以确信在紧急情况下可以进行私钥轮换。一般来说,尽可能频繁地轮换密钥是一种良好的做法,可以降低与密钥泄露相关的风险。
证书被删除时清理 Secret
默认情况下,cert-manager 不会删除包含签署证书的 Secret
资源,即使相应的 Certificate
资源被删除。这意味着删除 Certificate
不会使当前依赖该证书的任何服务停止运行,但证书将不再被续订。如果不再需要 Secret
,则需要手动删除它。
如果您希望在 Certificate
被删除时自动删除 Secret
,则需要将 --enable-certificate-owner-ref
标志传递给控制器。
针对开发人员的内部工作原理图
[1] http://cert-manager.k8s.ac.cn/docs/usage/certificaterequest