Kubernetes(K8s) 安装 cert-manager 自动续期 Let's Encrypt 的 SSL 证书

2025-04-22 17:46

安装 cert-manager

官方安装文档:https://cert-manager.io/docs/installation/kubectl/

kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.17.1/cert-manager.yaml

安装完成后,会创建名字空间(namespace) cert-manager ,和部署(Deployment) cert-manager cert-manager-cainjector cert-manager-webhook

验证方式

Let's Encrypt 颁发 SSL 证书,需要认证申请人是否为域名的拥有者,可以使用 HTTP01 和 DNS01 两种方式进行域名认证。

HTTP01 认证方式在域名指定的路径 /.well-known/acme-challenge 存放一个文件,Let's Encrypt 访问这个文件进行判断。这种方式较为简单,但有失败的机率,且不支持泛域名证书。

DNS01 认证方式在域名中增加一个 TXT 记录,Let's Encrypt 访问这个 TXT 记录进行判断。这种方式成功率高,功能全,支持泛域名,是推荐的方式。但操作复杂,需要从域名服务商处获取访问密钥。

HTTP01 验证

创建 ClusterIssuer,使用 http01 的方式申请 Let's Encrypt 的证书。只需要一个即可,全局共享。

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-http01
spec:
  acme:
    # 测试时,请使用预生产环境(staging),以免证书限额被耗尽。每 7 天只能申请 5 个证书,每 34 小时恢复 1 个证书额度
    #server: https://acme-staging-v02.api.letsencrypt.org/directory
    server: https://acme-v02.api.letsencrypt.org/directory
    # 使用自己的邮箱
    email: certmaster@example.com
    privateKeySecretRef:
      name: letsencrypt-http01-account-key
    solvers:
    - http01:
        ingress:
          # 查看`集群管理 - 网络 - IngressClass` 的名称
          ingressClassName: nginx

创建 Certificate。如果有多个域名,需要多个证书,可创建多个。

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com-http01-tls
  # 放在网站所在的 namespace 里
  namespace: default
spec:
  # 证书的名称。在 namespace 下的 `配置空间 - 密文` 里
  secretName: example-com-http01-tls
  dnsNames:
  # 需要申请 SSL 的域名
  - "example-com"
  issuerRef:
    name: letsencrypt-http01
    kind: ClusterIssuer

DNS01 验证

安装 webhook,由于不同域名服务商的 api 接口不同,需要安装不同的 webhook。

根据自己的域名服务商选择不同的 webhook:https://cert-manager.io/docs/configuration/acme/dns01/#webhook

创建 alidns-webhook

以 aliyun 为例:https://github.com/pragkent/alidns-webhook

# Install alidns-webhook to cert-manager namespace. 
kubectl apply -f https://raw.githubusercontent.com/pragkent/alidns-webhook/master/deploy/bundle.yaml

如果无法下载文件,可将以下文件内容保存到本地文件执行。其中 docker 镜像地址 pragkent/alidns-webhook:0.1.1 改成了 docker.1ms.run/pragkent/alidns-webhook:0.1.1,以免无法下载镜像。

完整文件内容如下:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: alidns-webhook
  namespace: cert-manager
  labels:
    app: alidns-webhook

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: alidns-webhook
  namespace: cert-manager
  labels:
    app: alidns-webhook
rules:
  - apiGroups:
      - ''
    resources:
      - 'secrets'
    verbs:
      - 'get'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: alidns-webhook:flowcontrol-solver
  labels:
    app: alidns-webhook
rules:
  - apiGroups:
      - "flowcontrol.apiserver.k8s.io"
    resources:
      - 'prioritylevelconfigurations'
      - 'flowschemas'
    verbs:
      - 'list'
      - 'watch'

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: alidns-webhook:flowcontrol-solver
  labels:
    app: alidns-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: alidns-webhook:flowcontrol-solver
subjects:
  - apiGroup: ""
    kind: ServiceAccount
    name: alidns-webhook
    namespace: cert-manager

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: alidns-webhook
  namespace: cert-manager
  labels:
    app: alidns-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: alidns-webhook
subjects:
  - apiGroup: ""
    kind: ServiceAccount
    name: alidns-webhook
    namespace: cert-manager

---
# Grant the webhook permission to read the ConfigMap containing the Kubernetes
# apiserver's requestheader-ca-certificate.
# This ConfigMap is automatically created by the Kubernetes apiserver.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: alidns-webhook:webhook-authentication-reader
  namespace: kube-system
  labels:
    app: alidns-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: extension-apiserver-authentication-reader
subjects:
  - apiGroup: ""
    kind: ServiceAccount
    name: alidns-webhook
    namespace: cert-manager
---
# apiserver gets the auth-delegator role to delegate auth decisions to
# the core apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: alidns-webhook:auth-delegator
  namespace: cert-manager
  labels:
    app: alidns-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
  - apiGroup: ""
    kind: ServiceAccount
    name: alidns-webhook
    namespace: cert-manager
---
# Grant cert-manager permission to validate using our apiserver
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: alidns-webhook:domain-solver
  labels:
    app: alidns-webhook
rules:
  - apiGroups:
      - acme.yourcompany.com
    resources:
      - '*'
    verbs:
      - 'create'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: alidns-webhook:domain-solver
  labels:
    app: alidns-webhook
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: alidns-webhook:domain-solver
subjects:
  - apiGroup: ""
    kind: ServiceAccount
    name: cert-manager
    namespace: cert-manager

---
# Source: alidns-webhook/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: alidns-webhook
  namespace: cert-manager
  labels:
    app: alidns-webhook
spec:
  type: ClusterIP
  ports:
    - port: 443
      targetPort: https
      protocol: TCP
      name: https
  selector:
    app: alidns-webhook

---
# Source: alidns-webhook/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: alidns-webhook
  namespace: cert-manager
  labels:
    app: alidns-webhook
spec:
  replicas:
  selector:
    matchLabels:
      app: alidns-webhook
  template:
    metadata:
      labels:
        app: alidns-webhook
    spec:
      serviceAccountName: alidns-webhook
      containers:
        - name: alidns-webhook
          image: pragkent/alidns-webhook:0.1.1
          imagePullPolicy: IfNotPresent
          args:
            - --tls-cert-file=/tls/tls.crt
            - --tls-private-key-file=/tls/tls.key
          env:
            - name: GROUP_NAME
              value: "acme.yourcompany.com"
          ports:
            - name: https
              containerPort: 443
              protocol: TCP
          livenessProbe:
            httpGet:
              scheme: HTTPS
              path: /healthz
              port: https
          readinessProbe:
            httpGet:
              scheme: HTTPS
              path: /healthz
              port: https
          volumeMounts:
            - name: certs
              mountPath: /tls
              readOnly: true
          resources:
            {}

      volumes:
        - name: certs
          secret:
            secretName: alidns-webhook-webhook-tls

---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: v1alpha1.acme.yourcompany.com
  labels:
    app: alidns-webhook
  annotations:
    cert-manager.io/inject-ca-from: "cert-manager/alidns-webhook-webhook-tls"
spec:
  group: acme.yourcompany.com
  groupPriorityMinimum: 1000
  versionPriority: 15
  service:
    name: alidns-webhook
    namespace: cert-manager
  version: v1alpha1

---
# Create a selfsigned Issuer, in order to create a root CA certificate for
# signing webhook serving certificates
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: alidns-webhook-selfsign
  namespace: cert-manager
  labels:
    app: alidns-webhook
spec:
  selfSigned: {}

---

# Generate a CA Certificate used to sign certificates for the webhook
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: alidns-webhook-ca
  namespace: cert-manager
  labels:
    app: alidns-webhook
spec:
  secretName: alidns-webhook-ca
  duration: 43800h # 5y
  issuerRef:
    name: alidns-webhook-selfsign
  commonName: "ca.alidns-webhook.cert-manager"
  isCA: true

---

# Create an Issuer that uses the above generated CA certificate to issue certs
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: alidns-webhook-ca
  namespace: cert-manager
  labels:
    app: alidns-webhook
spec:
  ca:
    secretName: alidns-webhook-ca

---

# Finally, generate a serving certificate for the webhook to use
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: alidns-webhook-webhook-tls
  namespace: cert-manager
  labels:
    app: alidns-webhook
spec:
  secretName: alidns-webhook-webhook-tls
  duration: 8760h # 1y
  issuerRef:
    name: alidns-webhook-ca
  dnsNames:
  - alidns-webhook
  - alidns-webhook.cert-manager
  - alidns-webhook.cert-manager.svc
  - alidns-webhook.cert-manager.svc.cluster.local

安装成功后会创建负载(Deployment) alidns-webhook

创建阿里云密钥

从阿里云获取到密钥后,需保存在 cert-manager 名称空间的 配置中心 - 密文 中:

apiVersion: v1
kind: Secret
metadata:
  name: alidns-secret
  namespace: cert-manager
data:
  access-key: YOUR_ACCESS_KEY
  secret-key: YOUR_SECRET_KEY

如提示 YOUR_ACCESS_KEY 和 YOUR_SECRET_KEY 不是 base64 格式,可先留空,保存后再到界面中修改。

创建 ClusterIssuer

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    # 使用自己的邮箱
    email: certmaster@example.com
    # 测试时,请使用预生产环境(staging),以免证书限额被耗尽。每 7 天只能申请 5 个证书,每 34 小时恢复 1 个证书额度
    #server: https://acme-staging-v02.api.letsencrypt.org/directory
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-staging-account-key
    solvers:
    - dns01:
        webhook:
          groupName: acme.yourcompany.com
          solverName: alidns
          config:
            region: ""
            accessKeySecretRef:
              name: alidns-secret
              key: access-key
            secretKeySecretRef:
              name: alidns-secret
              key: secret-key

创建 Certificate

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com-tls
  # 放在网站所在的 namespace 里
  namespace: default
spec:
  # 证书的名称。在 namespace 下的 `配置空间 - 密文` 里
  secretName: example-com-tls
  dnsNames:
  # 需要申请 SSL 的域名
  - "example.com"
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer

查看结果与使用

创建成功后,在 namespace 下的 配置空间 - 密文 里可以看到 SSL 证书。名称为 Certificate 中指定的 secretName,如 example-com-tls example-com-http01-tls,类型为 kubernetes.io/tls

如果看到名称为 example-com-tls-xxx,且类型为 Opaque,有可能证书正在生成中,稍作等候。或者到 namespace 下的 消息 中查看生成情况,是否有错误信息。

最后在部署(Deployment)的路由中,选择开启 HTTPS,即可选择相应的 SSL 证书。

0791-85271700
QQ咨询:1779755751
QQ交流群:626599871
微信咨询
微信扫码咨询
微信交流群
微信交流群
Powered by UJCMS © 2010-2025 All Rights Reserved
QQ咨询
电话
微信
微信扫码咨询