简介

cert-manager 是一个云原生证书管理开源项目,用于在 Kubernetes 集群中自动管理和颁发来自各种颁发源的 TLS 证书,它可以从各种受支持的来源颁发证书,包括 Let’s Encrypt、HashiCorp Vault和Venafi以及私有 PKI,它将确保证书定期有效和更新,并在到期前的适当时间尝试更新证书。

架构

jenkins_plugin_download Issuers/ClusterIssuers:定义使用 什么证书颁发机构 (CA) 来去颁发证书,Issuers和ClusterIssuers区别是issuers是一个名称空间级别的资源, 只能用来签发自己所在 namespace 下的证书,ClusterIssuer是个集群级别的资源 可以签发任意 namespace 下的证书

Certificate:定义所需的 X.509 证书,该证书将更新并保持最新。Certificate是一个命名空间资源,当Certificate被创建时,它会去创建相应的CertificateRequest资源来去申请证书。

安装

安装cert-manager相对比较简单,这里安装的cert-manager版本为v1.5.6,注意该版本要求kubectl版本>= v1.19.0-rc.1

所有资源(CustomResourceDefinitions和 cert-manager、cainjector 和 webhook 组件)都包含在一个 YAML 清单文件中:

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

默认情况下,cert-manager 将安装到cert-manager 命名空间中,我们可以使用如下命令验证安装

配置Issuer/ClusterIssuer

cert-manager支持以下几种证书颁发者

  • SelfSigned
  • CA
  • Vault
  • Venafi
  • External
  • ACME 这里只介绍使用ACME作为证书颁发者的方式。

HTTP-01 校验原理

HTTP-01 的校验原理是给你域名指向的 HTTP 服务增加一个临时 location ,Let’s Encrypt 会发送 http 请求到 http:///.well-known/acme-challenge/,YOUR_DOMAIN 就是被校验的域名,TOKEN 是 ACME 协议的客户端负责放置的文件,在这里 ACME 客户端就是 cert-manager,它通过修改或创建 Ingress 规则来增加这个临时校验路径并指向提供 TOKEN 的服务。Let’s Encrypt 会对比 TOKEN 是否符合预期,校验成功后就会颁发证书。此方法仅适用于给使用 Ingress 暴露流量的服务颁发证书,并且不支持泛域名证书。

DNS-01 校验原理

DNS-01 的校验原理是利用 DNS 提供商的 API Key 拿到你的 DNS 控制权限, 在 Let’s Encrypt 为 ACME 客户端提供令牌后,ACME 客户端 (cert-manager) 将创建从该令牌和您的帐户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge.。 然后 Let’s Encrypt 将向 DNS 系统查询该记录,如果找到匹配项,就可以颁发证书。此方法不需要你的服务使用 Ingress,并且支持泛域名证书。

校验方式对比

HTTP-01 的校验方式的优点是: 配置简单通用,不管使用哪个 DNS 提供商都可以使用相同的配置方法;缺点是:需要依赖 Ingress,如果你的服务不是用 Ingress 暴露流量的就不适用,而且不支持泛域名证书。

DNS-01 的校验方式的优点是没有 HTTP-01 校验方式缺点,不依赖 Ingress,也支持泛域名;缺点就是不同 DNS 提供商的配置方式不一样,而且 DNS 提供商有很多,cert-manager 的 Issuer 不可能每个都去支持,支持如下的dns提供商:

  • Akamai

  • AzureDNS

  • CloudFlare

  • Google

  • Route53

  • DigitalOcean

  • RFC2136

Cert-manager 还支持使用外部 webhook 的接入 DNS 提供商,支持如下webhook

  • AliDNS-Webhook

  • cert-manager-webhook-civo

  • cert-manager-webhook-dnspod

  • cert-manager-webhook-dnsimple

  • cert-manager-webhook-gandi

  • cert-manager-webhook-infomaniak

  • cert-manager-webhook-inwx

  • cert-manager-webhook-oci (Oracle 云基础设施)

  • cert-manager-webhook-scaleway

  • cert-manager-webhook-selectel

  • cert-manager-webhook-softlayer

  • cert-manager-webhook-ibmcis

  • cert-manager-webhook-loopia

  • cert-manager-webhook-arvan

  • bizflycloud-certmanager-dns-webhook

HTTP01配置示例

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: tls
spec:
  acme:
    # You must replace this email address with your own.
    # Let's Encrypt will use this to contact you about expiring
    # certificates, and issues related to your account.
    email: xxxxxxx@qq.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      # Secret resource that will be used to store the account's private key.
      name: issuer-account-key
    # Add a single challenge solver, HTTP01 using nginx
    solvers:
    - http01:
        ingress:
          class: nginx

说明:

  • metadata.name: 是我们创建的签发机构的名称,后面我们创建证书的时候会引用它

  • spec.acme.email: 是你自己的邮箱,证书快过期的时候会有邮件提醒,不过 cert-manager 会利用 acme 协议自动给我们重新颁发证书来续期

  • spec.acme.server: 是 acme 协议的服务端,我们这里用 Let’s Encrypt,这个地址就写死成这样就行

  • spec.acme.privateKeySecretRef: 指示此签发机构的私钥将要存储到哪个 Secret 对象中,名称不重要

  • spec.acme.solvers: 这里指示签发机构校验方式,有http01和dns01两种,该字段下配置的class和name只能同时存在一个,class指定使用的ingress class 名称,name比较少用,通常用于云上自带的ingress

我们部署上述示例,并部署一个ingress 代理集群内的grafana服务验证签发证书

kubectl apply -f clusterissuer.yaml 
clusterissuer.cert-manager.io/tls created

cat ingress/ingree-nginx.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: tls
  name: test
  namespace: monitoring
spec:
  rules:
  - host: ingress-nginx.1nth.com
    http:
      paths:
      - backend:
          service:
            name: grafana
            port:
              number: 3000
        path: /
        pathType: Prefix
  tls: # < placing a host in the TLS config will indicate a certificate should be created
  - hosts:
    - ingress-nginx.1nth.com
    secretName: ingress-nginx--tls
    
kubectl apply -f ingress/ingree-nginx.yaml 
ingress.networking.k8s.io/test created

我们可以查看生成的certificate和签发的证书(安全原因删除了部分证书中的字符)

kubectl -n monitoring  get certificate
NAME                 READY   SECRET               AGE
ingress-nginx--tls   True    ingress-nginx--tls   2m26s

kubectl -n monitoring  get secret ingress-nginx--tls -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJT********kMrT0IrYTl2VXZhRUFkZ0QyWEpRdjBYY3dJaFJVR0FndwpsRmFPNDAwVEdUTy8zd3d2SUF2TVR2Rms0d0FBQVhyN3Fzcy9BQUFFQXdCSE1FVUNJQ2svS2VodE1YOUlLZEFyCjhZTVMyZU9ZR05mbXlBSnZQR0tYS3Bxc3NyNkJBaUVBZ1FZM1ZmWFUvZEd0TDQ3VytsOCt3WTRxd0VONkowN3MKUFVTNUhPZm1HNmN3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUxqT1JBQUJPbVMzdUwrTktNWCtPTVBZWXltYwpjSnFkdDRhUFUxUUhvMk5mY2NnbG9PeVl0ci9MclQvSytQOGUxQkN1Q0Jqd2d2MVpBbzhUUWxiVU1POE9BbGhYClB6dWk4YnV3VnF2N0Jvb3BvRVUyNVZuU0FOb3B3ZVVWM1RrNW1DSEs5YW9ORVpBZUF4NEE4T3o0MWdNeVN0SnEKOFpqZnBxZCtJUmNUdzNGL0E4MVhRTmJzYnVTaG5DWUZMZkxQUkpMZDNGeGszOGRpSEsrZ0UxT0JZV1REZSsvdQpJWTFGT1R1TkhFSmoybzBJbEFZTE5ueTM4ZHcxQkEyQ3VDZVFHNE1TWHYxdnhFVFhwWjUrNzNBclFFUDlydXZpClNBSTh2VEtYM2gycGFDS0lhdEZIMEZDTE9uQUZDMU9ia0ZCanRLTUJTWDRMZE5UZDQ3S0pIcHg3bUJVPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlGRmpDQ0F2NmdBd0lCQWdJUkFKRXJDRXJQREJpblUvYldMaVduWDFvd0RRWUpLb1pJaHZjTkFRRUxCUUF3ClR6RUxNQWtHQTFVRUJoTUNWVk14S1RBbkJnTlZCQW9USUVsdWRHVnlibVYwSUZObFkzVnlhWFI1SUZKbGMyVmgKY21Ob0lFZHliM1Z3TVJVd0V3WURWUVFERXd4SlUxSkhJRkp2YjNRZ1dERXdIaGNOTWpBd09UQTBNREF3TURBdwpXaGNOTWpVd09URTFNVFl3TURBd1dqQXlNUXN3Q1FZRFZRUUdFd0pWVXpFV01CUUdBMVVFQ2hNTlRHVjBKM01nClJXNWpjbmx3ZERFTE1Ba0dBMVVFQXhNQ1VqTXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUsKQW9JQkFRQzdBaFVvelBhZ2xOTVBFdXlOVlpMRCtJTHhtYVo2UW9pblhTYXF0U3U1eFV5eHI0NXIrWFhJbzljUApSNVFVVlRWWGpKNm9vamtaOVlJOFFxbE9idlU3d3k3YmpjQ3dYUE5aT09mdHoybndXZ3NidnNDVUpDV0gramR4CnN4UG5IS3pobSsvYjVEdEZVa1dXcWNGVHpqVElVdTYxcnUyUDNtQnc0cVZVcTdadERwZWxRRFJySzlPOFp1dG0KTkh6NmE0dVBWeW1aK0RBWFhicHliL3VCeGEzU2hsZzlGOGZuQ2J2eEsvZUczTUhhY1YzVVJ1UE1yU1hCaUx4ZwpaM1Ztcy9FWTk2SmM1bFAvT29pMlI2WC9FeGpxbUFsM1A1MVQrYzhCNWZXbWNCY1VyMk9rLzVtems1M2NVNmNHCi9raUZIYUZwcmlWMXV4UE1VZ1AxN1ZHaGk5c1ZBZ01CQUFHamdnRUlNSUlCQkRBT0JnTlZIUThCQWY4RUJBTUMKQVlZd0hRWURWUjBsQkJZd0ZBWUlLd1lCQlFVSEF3SUdDQ3NHQVFVRkJ3TUJNQklHQTFVZEV3RUIvd1FJTUFZQgpBZjhDQVFBd0hRWURWUjBPQkJZRUZCUXVzeGUzV0ZiTHJsQUpRT1lmcjUyTEZNTEdNQjhHQTFVZEl3UVlNQmFBCkZIbTBXZVo3dHVYa0FYT0FDSWpJR2xqMjZadHVNRElHQ0NzR0FRVUZCd0VCQkNZd0pEQWlCZ2dyQmdFRkJRY3cKQW9ZV2FIUjBjRG92TDNneExta3ViR1Z1WTNJdWIzSm5MekFuQmdOVkhSOEVJREFlTUJ5Z0dxQVloaFpvZEhSdwpPaTh2ZURFdVl5NXNaVzVqY2k1dmNtY3ZNQ0lHQTFVZElBUWJNQmt3Q0FZR1o0RU1BUUlCTUEwR0N5c0dBUVFCCmd0OFRBUUVCTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElDQVFDRnlrNUhQcVAzaFVTRnZOVm5lTEtZWTYxMVRSNlcKUFRObGNsUXRnYURxdyszNElMOWZ6TGR3QUxkdU8vWmVsTjdrSUorbTc0dXlBK2VpdFJZOGtjNjA3VGtDNTN3bAppa2ZtWlc0L1J2VFo4TTZVSys1VXpoSzhqQ2RMdU1HWUw2S3Z6WEdSU2dpM3lMZ2pld1F0Q1BrSVZ6NkQyUVF6CkNrY2hlQW1DSjhNcXlKdTV6bHp5Wk1qQXZubkFUNDV0UkF4ZWtyc3U5NHNRNGVnZFJDbmJXU0R0WTdraCtCSW0KbEpOWG9CMWxCTUVLSXE0UURVT1hvUmdmZnVEZ2hqZTFXckc5TUwrSGJpc3EveUZPR3dYRDlSaVg4RjZzdzZXNAphdkF1dkRzenVlNUwzc3o4NUsrRUM0WS93RlZETnZabzRUWVhhbzZaMGYrbFFLYzB0OERRWXprMU9YVnU4cnAyCnlKTUM2YWxMYkJmT0RBTFp2WUg3bjdkbzFBWmxzNEk5ZDFQNGpua0RyUW94QjNVcVE5aFZsM0xFS1E3M3hGMU8KeUs1R2hERFg4b1ZmR0tGNXUrZGVjSXNINFlhVHc3bVAzR0Z4SlNxdjMrMGxVRkpvaTVMYzVkYTE0OXA5MElkcwpoQ0V4cm9MMSs3bXJ5SWtYUGVGTTVUZ085cjBydlphQkZPdlYyejBncDM1WjArTDRXUGxidUVqTi9seFBGaW4rCkhsVWpyOGdSc0kzcWZKT1FGeS85cktJSlIwWS84T213dC84b1RXZ3kxbWRlSG1tams3ajFuWXN2QzlKU1E2WnYKTWxkbFRUS0IzemhUaFYxK1hXWXA2cmpkNUpXMXpiVldFa0xOeEU3R0pUaEVVRzNzemdCVkdQN3BTV1RVVHNxWApuTFJid0hPb3E3aEh3Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZZRENDQkVpZ0F3SUJBZ0lRUUFGM0lUZlU2VUs0N25hcVBHUUt0ekFOQmdrcWhraUc5dzBCQVFzRkFEQS8KTVNRd0lnWURWUVFLRXh0RWFXZHBkR0ZzSUZOcFoyNWhkSFZ5WlNCVWNuVnpkQ0JEYnk0eEZ6QVZCZ05WQkFNVApEa1JUVkNCU2IyOTBJRU5CSUZnek1CNFhEVEl4TURFeU1ERTVNVFF3TTFvWERUSTBNRGt6TURFNE1UUXdNMW93ClR6RUxNQWtHQTFVRUJoTUNWVk14S1RBbkJnTlZCQW9USUVsdWRHVnlibVYwSUZObFkzVnlhWFI1SUZKbGMyVmgKY21Ob0lFZHliM1Z3TVJVd0V3WURWUVFERXd4SlUxSkhJRkp2YjNRZ1dERXdnZ0lpTUEwR0NTcUdTSWIzRFFFQgpBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRQ3Q2Q1J6OUJRMzg1dWVLMWNvSEllKzNMZmZPSkNNYmp6bVY2QjQ5M1hDCm92NzFhbTcyQUU4bzI5NW9obXhFazdheFkvMFVFbXUvSDlMcU1ac2hmdEV6UExwSTlkMTUzN080L3hMeElacEwKd1lxR2NXbEtabVpzajM0OGNMK3RLU0lHOCtUQTVvQ3U0a3VQdDVsK2xBT2YwMGVYZkpsSUkxUG9PSzVQQ20rRApMdEZKVjR5QWRMYmFMOUE0alhzRGNDRWJkZkl3UFBxUHJ0M2FZNnZyRmsvQ2poRkxmczhMNlArMWR5NzBzbnRLCjRFd1NKUXh3alFNcG9PRlRKT3dUMmU0WnZ4Q3pTb3cvaWFOaFVkNnNod2VVOUdOeDdDN2liMXVZZ2VHSlhEUjUKYkhidk81QmllZWJicEpvdkpzWFFFT0VPM3RrUWpoYjd0L2VvOThmbEFnZVlqellJbGVmaU41WU5ObldlK3c1eQpzUjJidkFQNVNRWFlnZDBGdENyV1FlbXNBWGFWQ2cvWTM5VzlFaDgxTHlnWGJOS1l3YWdKWkhkdVJ6ZTZ6cXhaClhtaWRmM0xXaWNVR1FTaytXVDdkSnZVa3lSR25XcU5NUUI5R29abTFwenBSYm9ZN25uMXlweElGZUZudFBsRjQKRlFzRGo0M1FMd1d5UG50S0hFdHpCUkw4eHVyZ1VCTjhRNU4wczhwMDU0NGZBUWpRTU5SYmNUYTBCN3JCTURCYwpTTGVDTzVpbWZXQ0tvcU1wZ3N5NnZZTUVHNktEQTBHaDFnWHhHOEsyOEtoOGhqdEdxRWdxaU54Mm1uYS9IMnFsClBSbVA2emp6Wk43SUt3MEtLUC8zMitJVlF0UWkwQ2RkNFhuK0dPZHdpSzFPNXRtTE9zYmRKMUZ1Lzd4azlUTkQKVHdJREFRQUJvNElCUmpDQ0FVSXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QU9CZ05WSFE4QkFmOEVCQU1DQVFZdwpTd1lJS3dZQkJRVUhBUUVFUHpBOU1Ec0dDQ3NHQVFVRkJ6QUNoaTlvZEhSd09pOHZZWEJ3Y3k1cFpHVnVkSEoxCmMzUXVZMjl0TDNKdmIzUnpMMlJ6ZEhKdmIzUmpZWGd6TG5BM1l6QWZCZ05WSFNNRUdEQVdnQlRFcDdHa2V5eHgKK3R2aFM1QjEvOFFWWUlXSkVEQlVCZ05WSFNBRVRUQkxNQWdHQm1lQkRBRUNBVEEvQmdzckJnRUVBWUxmRXdFQgpBVEF3TUM0R0NDc0dBUVVGQndJQkZpSm9kSFJ3T2k4dlkzQnpMbkp2YjNRdGVERXViR1YwYzJWdVkzSjVjSFF1CmIzSm5NRHdHQTFVZEh3UTFNRE13TWFBdm9DMkdLMmgwZEhBNkx5OWpjbXd1YVdSbGJuUnlkWE4wTG1OdmJTOUUKVTFSU1QwOVVRMEZZTTBOU1RDNWpjbXd3SFFZRFZSME9CQllFRkhtMFdlWjd0dVhrQVhPQUNJaklHbGoyNlp0dQpNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUFLY3dCc2xtNy9EbExRcnQyTTUxb0dyUytvNDQrL3lRb0RGVkRDCjVXeEN1MitiOUxSUHdrU0lDSFhNNndlYkZHSnVlTjdzSjdvNVhQV2lvVzVXbEhBUVU3Rzc1Sy9Rb3NNckFkU1cKOU1VZ05UUDUyR0UyNEhHTnRMaTFxb0pGbGNEeXFTTW81OWFoeTJjSTJxQkRMS29ia3gvSjN2V3JhVjBUOVZ1RwpXQ0xLVFZYa2NHZHR3bGZGUmpsQno0cFlnMWh0bWY1WDZEWU84QTRqcXYySWw5RGpYQTZVU2JXMUZ6WFNMcjlPCmhlOFk0SVdTNndZN2JDa2pDV0RjUlFKTUVoZzc2ZnNPM3R4RStGaVlydXE5UlVXaGlGMW15djRRNlcrQ3lCRkMKRGZ2cDdPT0dBTjZkRU9NNCtxUjlzZGpvU1lLRUJwc3I2R3RQQVF3NGR5NzUzZWM1Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  tls.key: LS0tLS1CRUdJTiBSx********************************************VFY2J3SStsNGFCM2NWMjNDMlIyM0wvbFNNY3MzSUIKZHZLQVQ5RUNnWUVBeHVhNlNWV0pyamJ5bmZwRVRQajNWa3ZTRm5rM0lxS1BZS2hUSW9VaGNmOGVSUkkvZzhkWApsVzVJZTNHbjhWaWlTTzB3TFJuZ3lHUVFSZDFDVGk5NEZNMmNabHA5czl3RHhWZFhlRm5FbmhhQVh5ZEVhQThmCkVteG04ek9TNWV0cnBiY2hueEI3eCtOaWo3MktZcFo4cnhobG1XcFRaRVJETzRveExWLzZYa1VDZ1lFQTRWTnMKUlkzME5LWmk2S0IxYWI1RFFYSTJTekJSeVdjbmd6ZjZRT3JEaVpldWsraS9CMGUrM2ZUNkRoSGl3bVNBcWtVUAo3b1Z0L1JNbkNDR1kwb1B1d0NkaSt5b1A0ejNOVTJpNWJDRk45eU12WUNkVWxVRG9KRVQ3YUdBV3QybTJtZDRiClgzaXpId1JaZVkyNk1FRFdUdUltSVFBdlRVdkRRS0RxeTNlSzRBc0NnWUVBZzRzdW9yZDJrZ2gzRnJIZ29BTjgKR00rV1J4U3R1VE5IbmNaVkRSeDlEUmFMbjJTOUt0c1llcFJ3VFd2U2hWUjRKOER1UHJYQnF1WTZ1T25uSXl4VAp2M1pvUEcwV2UzQkQ4aXljaGRUZ3F5ajRoM1hCMFF4SElYa2Q4VFFuci9XdHdQQkh4Um95c3ZVWVJ6WTBvcFVpCkt1NzRxcWplTkE3TlpFQTEyK3VBK3YwQ2dZRUFrVzRobEtieGRrWHAwdEUxMXdFcE1ZV0F5M2l0WVB1R1FpZ1EKQ25RN3JvUEs5c1lpL1pUdCtSNFRncDlDcDByc3pIajB0bk5DTVRSNlhjSXBlNzRSaTg0Z0VaSHRYVExYWWoxVwphQmI2MWtiTVhoZ2tmSXkvQ0NISnptMHVYRVVMeVRYVW53TXRRUml5azBUSlpqbUMyTGtYK1BiQWtQZ1VWcE5GCjEvc1pGRThDZ1lCekhVZE9LWVBjMUtlKzlwcGVvVlR1UjZ4bTlrTGJ0WHpPcXpuRVhQZUNMVmQyOWFBaTRGYUsKMXVocXdwcFVpL2x6N2VIb2pySDFmSXNaMDliTTd0aVBDY0FJK2NRemlGVWJvc2ZCdmxVakFzRVRNREFYbU5GLwpQYUhHWVR3MHVkVVlWL3YzdysxcXNsZG03a1kyN000anI4RGFITENKdlZERlpYMzRCMW9mVVE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
kind: Secret
metadata:
  annotations:
    cert-manager.io/alt-names: ingress-nginx.1nth.com
    cert-manager.io/certificate-name: ingress-nginx--tls
    cert-manager.io/common-name: ingress-nginx.1nth.com
    cert-manager.io/ip-sans: ""
    cert-manager.io/issuer-group: cert-manager.io
    cert-manager.io/issuer-kind: ClusterIssuer
    cert-manager.io/issuer-name: tls
    cert-manager.io/uri-sans: ""
  creationTimestamp: "2021-09-09T08:25:14Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:tls.crt: {}
        f:tls.key: {}
      f:metadata:
        f:annotations:
          .: {}
          f:cert-manager.io/alt-names: {}
          f:cert-manager.io/certificate-name: {}
          f:cert-manager.io/common-name: {}
          f:cert-manager.io/ip-sans: {}
          f:cert-manager.io/issuer-group: {}
          f:cert-manager.io/issuer-kind: {}
          f:cert-manager.io/issuer-name: {}
          f:cert-manager.io/uri-sans: {}
      f:type: {}
    manager: controller
    operation: Update
    time: "2021-09-09T08:25:14Z"
  name: ingress-nginx--tls
  namespace: monitoring
  resourceVersion: "274536"
  selfLink: /api/v1/namespaces/monitoring/secrets/ingress-nginx--tls
  uid: 929f9252-1905-4afc-b622-892151f1bbf3
type: kubernetes.io/tls

此时我们访问我们ingress文件里定义的域名可以看到此时证书已经签发

DNS01配置示例

这里使用的dns服务商为阿里云,需要使用AliDNS-Webhook

安装alidns-webhook

wget https://raw.githubusercontent.com/pragkent/alidns-webhook/master/deploy/bundle.yaml

建议修改文件中的acme.yourcompany.com

sed -i s/'acme.yourcompany.com'/'acme.1nth.com'/g bundle.yaml

创建一个包含阿里dns凭据的secert

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

或者使用如下命令行方式创建

kubectl -n cert-manager create secret generic alidns-secret --from-literal=access-key='YOUR_ACCESS_KEY' --from-literal=secret-key='YOUR_SECRET_KEY'

创建 ClusterIssuer cluster-issuer-letsencrypt-prod.yaml

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-staging
spec:
  acme:
    # Change to your letsencrypt email
    email: 85959493@qq.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-staging-account-key
    solvers:
    - dns01:
        webhook:
          groupName: acme.1nth.com #须和bundle.yaml文件中定义的groupname 一致
          solverName: alidns
          config:
            region: ""
            accessKeySecretRef:
              name: alidns-secret
              key: access-key
            secretKeySecretRef:
              name: alidns-secret
              key: secret-key

我们创建一个 手动去申请证书 certificate.yaml

cat certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: 1nth-com-tls
spec:
  secretName: 1nth-com-tls
  dnsNames:
  - 1nth.com
  - "*.1nth.com"
  issuerRef:
    name: letsencrypt-staging
    kind: ClusterIssuer

kubectl apply -f  certificate.yaml
kubectl get certificate	
AME              READY   SECRET            AGE
1nth-com-tls   False   1nth-com-tls   10s
			  

刚创建后我们查看certificate会发现ready状态为false,此时稍等会自动在我们的dns解析里创建txt 记录,然后去签发证书,该字段就会变为true

kubectl get certificate
NAME           READY   SECRET         AGE
1nth-com-tls   True    1nth-com-tls   59m
kubectl get secrets
NAME                  TYPE                                  DATA   AGE
1nth-com-tls          kubernetes.io/tls                     2      57m   #此时DATA 变为2,说明里面存着真正的证书文件
default-token-gsgmt   kubernetes.io/service-account-token   3      156d
oss-secret            Opaque                                2      52d
qingcloud             kubernetes.io/dockerconfigjson        1      48d

我们可以看到这个证书是个泛域名证书,此时我们ingress 可以直接使用该secert,不需要再去添加注解执行使用的issuer/cluseteissuer了,例如

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: whoami-https
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx # 1.18 以上使用
  tls:
  - hosts:
      - cert.1nth.com
    secretName: 1nth-com-tls
  rules:
  - host: cert.1nth.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          serviceName: whoami
          servicePort: 80