NEW: 在TwitterMastodon 获取项目更新。

证书资源

apiVersion: cert-manager.io/v1
kind: Certificate

在 cert-manager 中,Certificate 资源表示证书请求的人类可读定义。cert-manager 使用此输入来生成私钥和 CertificateRequest 资源,以便从 IssuerClusterIssuer 获取已签名的证书。然后,已签名的证书和私钥将存储在指定的 Secret 资源中。cert-manager 将确保证书在到期之前 自动续期 并在 需要时重新签发

要签发任何证书,您需要首先配置 IssuerClusterIssuer 资源。

创建证书资源

Certificate 资源指定用于生成证书签名请求的字段,这些请求随后将由您所引用的颁发者类型来满足。Certificates 通过指定 certificate.spec.issuerRef 字段来指定它们希望从哪个颁发者获取证书。

以下是一个针对 example.comwww.example.com DNS 名称,spiffe://cluster.local/ns/sandbox/sa/example URI 主题备用名称,有效期为 90 天,并在到期前 15 天续期的 Certificate 资源示例。它包含 Certificate 资源可能具有的所有选项的完整列表,但仅需部分字段,如标记所示。

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: example-com
namespace: sandbox
spec:
# 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: foo
privateKey:
algorithm: RSA
encoding: PKCS1
size: 2048
# keystores allows adding additional output formats. This is an example for reference only.
keystores:
pkcs12:
create: true
passwordSecretRef:
name: example-com-tls-keystore
key: password
profile: Modern2023
duration: 2160h # 90d
renewBefore: 360h # 15d
isCA: false
usages:
- server auth
- client auth
subject:
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.com
uris:
- spiffe://cluster.local/ns/sandbox/sa/example
emailAddresses:
- john.doe@cert-manager.io
ipAddresses:
- 192.168.0.5
# Needs cert-manager 1.14+ and "OtherNames" feature flag
otherNames:
# Should only supply oid of ut8 valued types
- oid: 1.3.6.1.4.1.311.20.2.3 # User Principal Name "OID"
utf8Value: [email protected]
# 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-tlsSecret 资源中,该资源与 Certificate 位于同一个命名空间,前提是颁发者已成功签发了请求的证书。

如果存在 secretTemplate,则此属性中设置的批注和标签将复制到 example-com-tls 秘密。这两个属性都是可选的。

Certificate 将使用名为 ca-issuer 的颁发者签发,该颁发者位于 sandbox 命名空间中(与 Certificate 资源相同的命名空间)。

注意:如果您要创建可以在 所有 命名空间中的 Certificate 资源中引用的 Issuer,则应创建一个 ClusterIssuer 资源并将 certificate.spec.issuerRef.kind 字段设置为 ClusterIssuer

注意:renewBeforeduration 字段必须使用 Go time.Duration 字符串格式进行指定,该格式不允许 d(天)后缀。您必须使用 smh 后缀来指定这些值。如果不安装 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 会尝试满足此请求,但有些颁发者会删除、添加默认值或完全忽略此请求。该 CASelfSigned Issuer 将始终返回与您所请求的用法相匹配的证书。

除非设置了任何数量的用法,否则 cert-manager 将设置 数字签名密钥加密服务器身份验证 的默认请求用法。如果当前证书与当前密钥用法设置不匹配,则 cert-manager 将不会尝试请求新的证书。

可以在 API 参考文档 中找到支持的密钥用法的完整列表。

其他证书输出格式

additionalOutputFormats 是证书 spec 上的一个字段,它允许指定已签发证书及其私钥的额外补充格式。目前支持两种额外输出格式:CombinedPEMDER。这两种输出格式都可以指定在同一个证书上。

apiVersion: cert-manager.io/v1
kind: Certificate
spec:
...
secretName: my-cert-tls
additionalOutputFormats:
- type: CombinedPEM
- type: DER
# Results in:
apiVersion: v1
kind: Secret
metadata:
name: my-cert-tls
type: kubernetes.io/tls
data:
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: v1
kind: Secret
metadata:
name: my-cert-tls
type: kubernetes.io/tls
data:
tls-combined.pem: <PEM private key + "\n" + PEM signed certificate chain>
...

DER

类型为 DER 的证书将在生成的证书的 Secret 中创建一个新的密钥条目 key.der。该条目将包含私钥的 DER 二进制格式。

apiVersion: v1
kind: Secret
metadata:
name: my-cert-tls
type: kubernetes.io/tls
data:
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/v1
kind: Certificate
metadata:
name: ca-cert-example
spec:
secretName: example-ca-key-pair
isCA: true
issuerRef:
name: selfsigned
kind: ClusterIssuer
commonName: "example1.com"
dnsNames:
- example1.com
nameConstraints:
critical: true
permitted:
dnsDomains: ["example1.com", "example2.com"]
ipRanges: ["10.10.0.0/16"]
emailAddress: ["[email protected]"]
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.durationspec.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.renewBeforespec.renewBeforePercentage,它将是到期之前有效的 spec.renewBefore 时间。cert-manager 将 Certificatestatus.RenewalTime 设置为尝试续订的时间。

用户操作触发的重新签发

证书对象在以下情况下重新签发

  • 当对证书的规范中的以下字段之一进行更改时:commonNamednsNamesipAddressesurisemailAddressessubjectisCAusagesdurationissuerRef;可以在 FAQ 页面 上找到更详细的解释。
  • 当使用以下方法手动触发重新签发时
    cmctl renew cert-1
    请注意,上述命令需要 cmctl

删除与证书资源关联的 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.crttls.key 的更改,并优雅地重新加载或自动重启,那么您可以预期不会出现停机

如果您的应用程序仅在启动时加载一次私钥和已签署证书,那么新的证书不会立即由您的应用程序提供服务,您需要使用 kubectl rollout restart 手动重启您的 Pod,或者通过运行 wave 来实现自动化操作。Wave 是一个 Secret 控制器,它可以确保每次挂载的 Secret 发生更改时,部署都会重新启动。

私钥的重复使用

某些签发者(例如内置的 Venafi 签发者)可能不允许重复使用私钥。如果是这种情况,您必须为每个证书对象显式配置 rotationPolicy: Always 设置。

在以下示例中,证书已使用 rotationPolicy: Always 设置。

apiVersion: cert-manager.io/v1
kind: Certificate
spec:
secretName: my-cert-tls
privateKey:
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