058.Kubernetes cert-manager 申请证书及ingress注解介绍

文章目录

Requesting Certificates介绍

证书申请介绍

当配置好 Issuer 后,即可开始正式申请证书,当前通过 cert-manager 申请证书有以下几种常见场景和方法:

  • ingress 集成:为集群中的 Ingress 资源提供安全通信;
  • OpenFaaS 函数:使用 cert-manager 为 OpenFaaS 服务提安全通信;
  • 与 Garden 集成:Garden 是用于开发 Kubernetes 应用程序的开发者工具,提供对 cert-manager 集成支持。
  • Knative 集成:使用可信 HTTPS 证书为 Knative 服务提供安全通信;
  • Istio 网关集成:在 Kubernetes 中使用 cert-manager 保护 Istio 网关,提供安全通信。

提示 :本文主要关注和 ingress 的集成,其他更多方案参考Requesting Certificates

在 cert-manager 里,Certificate 资源不是最终的证书文件本身,而是一个"人类可读的证书申请声明"。

通俗的理解:

  • 告知 cert-manager,需要哪个域名的证书
  • 用哪个 Issuer/ClusterIssuer 去签发
  • 证书放到哪个 Secret
  • 证书要什么用途、什么主题、什么有效期
  • 私钥如何生成、是否轮换

cert-manager 再根据这个声明进行下一步操作:

  1. 生成私钥
  2. 生成 CertificateRequest
  3. 调用指定的 Issuer 去签发,通过 certificate.spec.issuerRef
  4. 把签发结果写回 Secret
  5. 后续自动续期

即Issuer 决定"谁给签发",Certificate 决定"需什么证书"。

  • Issuer / ClusterIssuer:签发能力提供者
  • Certificate:证书申请模板
  • Secret:最终落地结果

也就是说Certificate 资源的核心职责主要是如下4件:

  • 定义证书申请参数
  • 指定签发器
  • 管理证书和私钥输出到 Secret
  • 自动续期和按条件重新签发

证书申请配置

最简示例:

shell 复制代码
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
  namespace: web
spec:
  secretName: example-com-tls

  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

  dnsNames:
    - example.com
    - www.example.com

  privateKey:
    algorithm: RSA
    size: 2048
    rotationPolicy: Always

  duration: 2160h
  renewBefore: 360h

  usages:
    - digital signature
    - key encipherment
    - server auth

证书申请配置至少需要如下字段:

  • spec.secretName
  • spec.issuerRef
  • 至少一个身份字段:
    • dnsNames
    • 或 commonName
    • 或 uris
    • 或 emailAddresses
    • 或 ipAddresses
    • 或 otherNames

总结:最简配置至少需要谁发证书、谁来签、签好后放哪儿的一个声明。

以下是一个官方 Certificate 资源示例,适用于 example.comwww.example.com DNS 名称,包含 spiffe://cluster.local/ns/sandbox/sa/example URI 主题备用名称,有效期为 90 天并在到期前 15 天续期。

该示例列出了 Certificate 资源所有可能的配置选项,但仅标注了必需字段的子集。

shell 复制代码
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
  namespace: sandbox
spec:
  # Secret 名称必填
  secretName: example-com-tls

  # secretTemplate 是可选的。如果设置了它,这些注解(annotations)和标签(labels)
  # 将会被复制到名为 example-com-tls 的 Secret 上。
  # 如果 Certificate 的 secretTemplate 发生变化,这些标签和注解会被重新协调(re-reconciled)。
  # secretTemplate 也会被强制生效,因此如果第三方对该 Secret 上相关标签或注解进行了修改,
  # cert-manager 会将其覆盖为与 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:
    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

  # 应避免在终端实体(leaf)证书中将 commonName 用作 DNS 名称。
  # 除非环境中确实对此有特定需求,否则应仅使用 dnsNames,以避免 commonName 带来的问题。
  # 通常,commonName 用于为 CA 证书提供便于人类识别的名称,
  # 对于其他证书,一般可以避免使用。
  commonName: example.com

  # literalSubject 字段与 subject / commonName 互斥。
  # 它允许将 subject 直接指定为字符串。
  # 这在以下场景中很有用:当 subject 字段的顺序很重要时,或者当 subject 包含可通过其 OID 指定的特殊类型时。
  # literalSubject: "O=jetstack, CN=example.com, 2.5.4.42=John, 2.5.4.4=Doe"
  # commonName(或 literalSubject)、dnsNames、uris、emailAddresses、ipAddresses 或 otherNames 中,至少需要提供一个。

  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
  # cert-manager 1.14+ 且启用 OtherNames feature flag
  otherNames:
    # 仅支持ut8的 oid 类型值
    - oid: 1.3.6.1.4.1.311.20.2.3 # User Principal Name "OID"
      utf8Value: upn@example.local

  # Issuer 引用始终是必需的
  issuerRef:
    name: ca-issuer
    # 可以通过修改此处的 kind 来引用 ClusterIssuer。
    # 默认值是 Issuer(即命名空间内的本地 Issuer)。
    kind: Issuer
    # group是可选的,因为 cert-manager 会默认使用该值;
    # 但如果使用的是外部 issuer,请将其改为对应 issuer 所属的 group。
    group: cert-manager.io

主要配置释义:

secretName:输出目标,必填项,它表示:证书签发成功后,要把结果写到哪个 Secret,生成的 Secret 一般在同命名空间下,通常包含:

  • tls.key:私钥
  • tls.crt:证书链
  • ca.crt:上级 CA 证书(如果签发器能提供)
    后续的Ingress或者Gateway,Pod 挂载等可能都要引用这个 Secret。

issuerRef:签发来源,表示这个 Certificate 要使用哪个签发器,name:Issuer / ClusterIssuerkind:Issuer 或 ClusterIssuergroup:API Group,默认通常是 cert-manager.io。如果希望跨命名空间复用统一签发器,通常会用ClusterIssuer。

dnsNames:证书身份信息,这是 Certificate 中最核心的一块,最常见,用于 TLS 网站证书。对于 Web 服务,这通常是最主要字段。现代 TLS 实际校验主要基于 SAN(Subject Alternative Name),而不是 commonName。

提示

  1. 对终端实体(leaf)DNS 证书,尽量不要依赖 commonName 表示 DNS 名称,除非环境确实需要。
  2. 以下之一必须存在:
  • commonName(或通过 literalSubject 表达)
  • dnsNames
  • uris
  • emailAddresses
  • ipAddresses
  • otherNames

privateKey:私钥配置,证书配套私钥应该怎样生成。algorithm常见的有RSA、ECDSA、Ed25519,不同的算法可能影响性能、兼容性、密钥长度要求、签名效率,一般兼容优先使用RSA 2048/3072,性能优先使用ECDSA。

rotationPolicy:私钥轮换,cert-manager >= v1.18.0:默认是 Always。两种区别是:

项目 描述
Never 只要 Secret 里已有 tls.key,后续重新签发时就复用旧私钥
Always 每次重签发都生成新私钥cert-manager 会等新证书成功签发后,再覆盖 Secret 中的 tls.key

duration / renewBefore / renewBeforePercentage:控制证书有效期与续期。

duration:表示期望的证书有效期,默认值是 90 天,某些 Issuer 可能不接受指定的时长,最终实际签出来的有效期,可能由 Issuer 决定。

renewBefore:表示在证书到期前多久开始续期。

renewBeforePercentage:这是相对新的机制,它不是写固定时长,而是按证书实际有效期的百分比计算续期提前量。

isCA:是 CA 证书还是叶子证书(业务证书),配置为True通常适合自建 PKI,或者签发中间 CA。

secretTemplate:把标签和注解复制到目标 Secret 上,不是只创建时复制一次,如果之后修改 secretTemplate,cert-manager 会重新同步到 Secret,如果第三方改了这些受控 labels/annotations,cert-manager 会直接覆盖掉。适用于给 Secret 打统一标签场景。

证书交付物

最终生成的 Secret 是证书申请的交付物。通常生成的 Secret 至少会包含 tls.crttls.key,有时还会有:ca.crt

tls.crt:当证书由中间 CA 签发且 Issuer 能提供签发证书的链时, tls.crt 的内容将是请求的证书后接证书链,即:tls.crt = 叶子证书/业务证书 + 中间证书链,也就是说它通常不只是单张叶子证书。

tls.key:对应私钥。

ca.crt:如果 cert-manager 知晓 issuing CA,则可能写入 ca.crt。如ACME:通常不知道稳定可用的 ca.crt,所以可能没有。某些 CA / SelfSigned / 内部 CA:通常会有。

证书重签发

cert-manager 不只是"签一次证书",它持续负责两类事情:

  • 证书到期前自动续期
  • 当配置变化时重新签发

对于证书续期和重签发,需要注意:

  1. duration 最小值:1 小时,renewBefore 最小值:5 分钟,且必须满足:duration > renewBefore
  2. 对于默认续期时间,如果你不显式设置:cert-manager 默认会在证书生命周期的 2/3 处安排续期。
  3. 90d(90天)是错误的写法,字段底层是基于Go time.Duration 格式,可用的后缀是 s、m、h
  4. 虽然issuer里配置了多个字段,但签发机构不一定完全照办,cert-manager 会尝试按照配置提出请求,但某些 Issuer 可能被忽略,或者强制加默认值,甚至删除某些用法。

同时除了自然到期,下面情况也会触发重新签发,当修改了 Certificate.spec 中这些字段之一:

  • commonName
  • dnsNames
  • ipAddresses
  • uris
  • emailAddresses
  • subject
  • isCA
  • usages
  • duration
  • issuerRef
    这些字段一旦变更,cert-manager 会认为:这是"不同的证书需求",需要重新申请。

注意 :不建议删除目标 Secret 试图让 cert-manager 重建证书,而应该使用 cmctl renew <certificate-name> 方式重新签发。

提示:基于保护业务,删除 Certificate 时,Secret 不会自动删除,Secret 是基于 Certificate 生成的产物,但是证书不再自动续期。

ingress 注解

ingress注解方案

方案介绍

cert-manager 的常见应用场景是为 Ingress 资源申请 TLS 签名证书以实现安全加密。只需在 Ingress 资源中添加注解,cert-manager 即可代为创建 Certificate 资源。该功能由 cert-manager 的子组件 ingress-shim 负责实现。

本方案主要是描述如何通过给 Ingress 打注解,让 cert-manager 自动创建 Certificate 并管理 TLS Secret。

即Annotated Ingress resource(带 cert-manager 注解的 Ingress)。

核心思路:

  1. 不手工写 Certificate
  2. 只需要在 Ingress 上加 cert-manager 相关注解
  3. cert-manager 的 ingress-shim 组件获知后,自动创建对应的 Certificate
  4. 最终证书写入 spec.tls[].secretName 指定的 Secret

所以它本质上是:Ingress → 自动派生 Certificate → 自动签发证书 → 自动填充 TLS Secret ,从而实现自动化全链路流程。

组件关系梳理:

  1. Ingress 不负责签发证书;
  2. Ingress 也不是证书对象,真正证书管理对象仍然是 Certificate ;
方案优点

使用 Ingress 注解方式,而不是手工创建 Certificate,有几个明显优点:

  1. 更符合"应用入口即 TLS 配置"的思维,开发/平台侧只改 Ingress 就行,不用关心额外 Certificate YAML。
  2. 简化使用,尤其对普通 Web 应用部署非常方便。
  3. 适合标准化平台,平台可以规定Ingress 写法统一,注解统一,所有业务自动获得证书管理能力。

ingress-shim工作机制

ingress-shim 是 cert-manager 的一个子组件,它做的是:监听 Ingress,并根据注解自动生成/维护对应的 Certificate 对象。即 ingress-shim 理解成一个"Ingress 到 Certificate 的转换控制器"。

其工作的核心流程是:

  1. ingress-shim 监听整个集群的 Ingress
  2. 如果发现某个 Ingress 上有 cert-manager 支持的注解,它就检查这个 Ingress 的:
    • spec.tls[].hosts
    • spec.tls[].secretName
    • issuer 相关注解
  3. 然后在同 namespace 中创建或维护一个 Certificate
  4. Certificate 再触发后续 cert-manager 签发流程
  5. 最终证书写入 secretName 对应的 Secret
  6. Ingress 通过这个 Secret 提供 HTTPS

Ingress 本身不直接申请证书,是 ingress-shim 看到注解后,自动创建 Certificate。

ingress配置讲解

典型的配置示例如下:

shell 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    # 添加一个标注,以指示要使用的发布者。
    cert-manager.io/cluster-issuer: nameOfClusterIssuer
  name: myIngress
  namespace: myIngress
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: myservice
            port:
              number: 80
  - host: www.example.com
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: myservice
            port:
              number: 80
  tls: # 在 TLS 配置中放置主机将决定最终出现在证书的 subjectAltNames 中的内容
  - hosts:
    - example.com
    - www.example.com
    secretName: myingress-cert # cert-manager 将创建的证书存储在这个密钥中

配置释义:

annotations.[]:指定用哪个 ClusterIssuer 来签发证书。

tls.hosts:决定"证书包含哪些域名",这里的 host 会成为 Certificate 中的 SAN / DNS 名称来源。即 Ingress 的 tls.hosts 会映射成生成的 Certificate 的主机名集合。

tls.secretName:ingress-shim 会让自动生成的 Certificate 使用这个 Secret 名称。最终 Ingress 就通过这个 Secret 提供 HTTPS。

请求issuer注解

  • cert-manager.io/issuer
    cert-manager.io/issuer: <issuer-name> 的主要作用是用来指定要使用的 Issuer。

注意:这个注解并不一定只表示 namespaced Issuer。

它默认会指向 cert-manager.io group 下的 Issuer,但对于外部 issuer,它既可以表示 namespaced,也可以表示 cluster-scoped 类型,只是需要配合 kind/group 说明。

如果用的是 namespaced issuer,那么该 issuer 必须和 Ingress 在同一个 namespace。

  • cert-manager.io/cluster-issuer

cert-manager.io/cluster-issuer: <clusterissuer-name> 的主要作用是用来指定 cert-manager 内置的 ClusterIssuer。

注意:这个注解Ingress 在哪个 namespace 都可以引用,因为 ClusterIssuer 本身是 cluster-scoped。

它默认会指向 cert-manager.io group 下的 ClusterIssuer,但对于外部 ClusterIssuer(也就是集群的Issuer 没有写在默认的 cert-manager 命名空间),不要使用该方式,而要使用 cert-manager.io/issuer,再配 issuer-kindissuer-group

  • cert-manager.io/issuer-kind: AWSPCAIssuer

    指定外部 issuer 的 kind,只对 out-of-tree issuer 有用。

  • cert-manager.io/issuer-group: awspca.cert-manager.io

    指定外部 issuer 的 API Group,同样只在外部 issuer 场景下需要。

如上四个注解选择方式如下:

内置 namespaced Issuer,使用 cert-manager.io/issuer: my-issuer

内置 ClusterIssuer,使用 cert-manager.io/cluster-issuer: letsencrypt-prod

外部 issuer,使用:

shell 复制代码
cert-manager.io/issuer: my-external-issuer
cert-manager.io/issuer-kind: AWSPCAIssuer
cert-manager.io/issuer-group: awspca.cert-manager.io

ACME HTTP01注解

如果你的 issuer 是 ACME,并且使用 HTTP01,需要了解如下几个注解。

  • acme.cert-manager.io/http01-ingress-class: nginx

acme.cert-manager.io/http01-ingress-class: nginx 用于指定用于 ACME HTTP01 challenge 的 ingress class 。

如果业务 Ingress 的 class,和用来做 ACME challenge质询的 ingress 需要区分开,例如:业务 Ingress 是内部 Ingress,但 HTTP01 challenge 需要经由公网入口验证,这时 challenge 可能要走另一个 ingress class。

  • acme.cert-manager.io/http01-edit-in-place: "true"

作用是控制 HTTP01 challenge 时,是直接修改现有 Ingress,还是新建一个专门用于 challenge 的 Ingress

值为 "true" 时,cert-manager 直接修改现有 Ingress,在当前 Ingress 中添加 challenge 路由。默认为 false,即cert-manager 会单独创建一个 challenge Ingress。

提示:如果同时存在默认 issuer 配置以及 Ingress 上显式 cert-manager.io/issuer / cluster-issuer,那么显式注解优先于默认 issuer。

Certificate 通用字段映射类注解

此部分注解非常实用,它允许在 Ingress 上直接控制自动生成的 Certificate.spec 某些字段。

即可直接在ingress添加注解来控制 Certificate 证书申请的行为。

  • cert-manager.io/common-name

    该注解映射到 Certificate 的 spec.commonName

  • cert-manager.io/email-sans

    该注解映射到 Certificate 的 spec.emailAddresses ,支持逗号分隔:cert-manager.io/email-sans: "me@example.com,you@example.com"

  • 其他字段

    支持如下丰富的字段注解来映射到 Certificate.spec.subject.*:

总结:Ingress 注解不仅能让你"自动建证书",还允许你把一些证书主体信息直接从 Ingress 层下发到 Certificate。

不过实际公网 Web TLS 场景里,如上字段一般不是最常用,通常主要还是:

  • hosts
  • secretName
  • issuer
  • cert-manager.io/duration

    该注解映射到 Certificate 的 spec.duration

  • cert-manager.io/renew-before

    该注解映射到 Certificate 的 spec.renewBefore,从而能在 Ingress 侧控制证书期望有效期,续期提前量。

Certificate 私钥字段映射类注解

此部分注解相当于把 Certificate.spec.privateKey.* 相关能力融合到 Ingress 注解层。它允许在 Ingress 上直接控制自动生成的 Certificate.spec.privateKey 某些字段。

即可直接在ingress添加注解来控制 Certificate 证书申请的私钥有关配置。

  • cert-manager.io/private-key-algorithm

    私钥的加密算法类型,支持 RSAECDSAEd25519,默认为 RSA

  • cert-manager.io/private-key-encoding

    支持``PKCS1PKCS8,默认PKCS1` 。

  • cert-manager.io/private-key-size

    私钥的加密算法长度,如果算法是:

    RSA:支持 2048 / 4096 / 8192

    ECDSA:支持 256 / 384 / 521

    Ed25519:忽略 size

默认:

RSA 默认 2048

ECDSA 默认 256

  • cert-manager.io/private-key-rotation-policy
    证书是否自动续期,默认是cert-manager.io/private-key-rotation-policy: Always

注解使用建议

使用ingress注解实现自动化证书申请,需要关注以下几个点:

  1. 当多个 Ingress 生成多个证书时,即要从多个 Ingress 生成多个 Certificate,则每个 Ingress 都必须有 issuer 相关注解,且每个 Ingress 都必须有唯一的 tls.secretName。

总结:一个自动生成的 Ingress TLS 证书,最好对应一个唯一 Secret。

  1. 安装 cert-manager 时,ingress-shim 通常就已经随 cert-manager 一起部署好了,不需要额外管理。
  2. 通过ingress注解方式自动申请证书只是"自动化捷径",即把整个链条自动化,但不是唯一方式,完全可以手工创建 Certificate来使用。
  3. ingress-shim 是桥梁,不是签发器,后面的签发逻辑仍然由 Certificate / CertificateRequest / Issuer 完成。
相关推荐
kabu_Charlie2 小时前
使用Docker运行python程序
运维·docker·容器
骥龙3 小时前
第五篇:运行时安全——Docker沙箱与命令审批机制
安全·docker·容器
会算数的⑨3 小时前
演进——从查日志到 AI 自治,企业监控体系的变迁
人工智能·分布式·后端·微服务·云原生
南山十一少4 小时前
docker的安装及使用
运维·docker·容器
道清茗5 小时前
【Kubernetes知识点问答题】PriorityClass、HPA、Argo CD 与 CI/CD 流水线
ci/cd·容器·kubernetes
yuezhilangniao5 小时前
大白话AI运维K8S整体思路和相关名词-结合腾讯云
运维·人工智能·kubernetes
DJ斯特拉5 小时前
Docker基本使用
运维·docker·容器
苦涩花开54865 小时前
Kubernetes学习,记一些笔记
笔记·学习·kubernetes
遇见火星5 小时前
生产级 DevOps 自动化交付模板(基于 Kubernetes 与 GitOps)
kubernetes·自动化·devops·gitops