这个场景非常的有意思:

公司内部有若干个kubernetes集群,属于测试环境,研发搭建了一套SAAS的环境,这个环境需要xxx.abc.com的域名来访问,域名解析记录全都是192.168.0.x,供内部访问,域名会动态生成,需要证书也随之生成,且dns域名托管在cloudflare上。

基本环境如上,麻烦的是 cert-manager 不可能签发私网的证书,只能曲线救国,用dns验证的方式来签发证书了,如果配上 external-dns,那dns解析也不用做了;只要发布一个ingress,就直接生成dns解析记录和对应的https证书。

具体做法如下:

一、配置 cloudflare API token

登录cloudflare,去生成API Token,路径是:User Profile > API Tokens > API Tokens.

  • Permissions:

    • Zone - DNS - Edit
  • Zone Resources:

    • Include - All Zones

cert-manager的官方文档居然是错的,https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/

推荐的 Zone - Zone - Read 是加不上的,有Edit就足够了

image-20250709104459501

然后获得Token的字符串xxxxxx

二、安装cert-manager

这个简单,直接用helm安装

现在这个时间节点,2025.07.09,cert-manager 是 v1.18.2,所以用新命令执行安装

helm repo add jetstack https://charts.jetstack.io
helm repo update

#老版本比如1.0
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true

#新版本v1.18.2
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set crds.enabled=true

三、准备签发机构Issuer

下面要特别注意,secret必须在namespace:cert-manager中,因为上一步我们创建了ns cert-manager,pod也在这个ns中,签发的过程中是由cert-manager中的pod发起请求的

# secret
---
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: xxxxxxxx
# Issuer
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: zhangranrui@gmail.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - dns01:
        cloudflare:
          email: zhangranrui@gmail.com
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

四、准备pod和ingress

# nginx deployment
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
---
# nginx Service
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  type: ClusterIP

然后我们直接发布一个ingress,就会自动签发证书了

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - test.abc.com
    secretName: test-tls
  rules:
  - host: test.abc.com
    http:
      paths:
      - path: /
        pathType: Prefix 
        backend:
          service:
            name: nginx
            port:
              number: 80

四、一些调试命令:

$ kubectl get issuer
$ kubectl get clusterissuer
$ kubectl get challenges
$ kubectl describe challenge
$ kubectl describe certificaterequest
$ kubectl describe order

五、直接申请证书

上面讲了通过ingress来自动申请证书,那我们如果不通过ingress,直接申请该怎么做呢?

也很简单,直接来个申请即可

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: tls-normal
  namespace: default
spec:
  secretName: tls-normal
  commonName: abc.cde.com
  dnsNames:
  - abc.cde.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer