基于Kubenetes 1.32.3部署cert-manager并配合Cloudflare签发泛域名证书

需求来源 博主需要为自己的部署在Kubenetes上的服务通过Traefik配置IngressRoute,实现通过域名建立HTTPS访问。 需求分析 博主的需求本质上是签发证书的问题,所以需要一个能自动签发泛域名证书的工具。这类工具有很多,例如Certimate、acme.sh等。在Kubenete

需求来源

博主需要为自己的部署在Kubenetes上的服务通过Traefik配置IngressRoute,实现通过域名建立HTTPS访问。

需求分析

博主的需求本质上是签发证书的问题,所以需要一个能自动签发泛域名证书的工具。这类工具有很多,例如Certimate、acme.sh等。在Kubenetes上比较流行且经过验证的方案是cert-manager。

工具介绍

cert-manage是一款可以给Kubenetes的工作负载签发并自动需求证书的工具。支持ACME的两种Challenge方式,即HTTP Challenge和DNS Challenge。

cert-manager部署

本文使用Helm部署cert-manager,博主默认读者已掌握Helm命令的基本使用方法,并能阅读values文件。

添加chart仓库

首先需要添加chart仓库,仓库地址: https://charts.jetstack.io

修改values文件

以下是博主使用的values文件,读者可参考。

acmesolver:
  image:
    pullPolicy: IfNotPresent
    repository: quay.io/jetstack/cert-manager-acmesolver
affinity: {}
approveSignerNames:
  - issuers.cert-manager.io/*
  - clusterissuers.cert-manager.io/*
cainjector:
  affinity: {}
  config: {}
  containerSecurityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop:
        - ALL
    readOnlyRootFilesystem: true
  enableServiceLinks: false
  enabled: true
  extraArgs: []
  extraEnv: []
  featureGates: ''
  image:
    pullPolicy: IfNotPresent
    repository: quay.io/jetstack/cert-manager-cainjector
  nodeSelector:
    kubernetes.io/os: linux
  podDisruptionBudget:
    enabled: false
  podLabels: {}
  replicaCount: 1
  resources: {}
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  serviceAccount:
    automountServiceAccountToken: true
    create: true
  serviceLabels: {}
  strategy: {}
  tolerations: []
  topologySpreadConstraints: []
  volumeMounts: []
  volumes: []
clusterResourceNamespace: ''
config: {}
containerSecurityContext:
  allowPrivilegeEscalation: false
  capabilities:
    drop:
      - ALL
  readOnlyRootFilesystem: true
crds:
  enabled: false
  keep: true
creator: helm
disableAutoApproval: false
dns01RecursiveNameservers: ''
dns01RecursiveNameserversOnly: false
enableCertificateOwnerRef: false
enableServiceLinks: false
enabled: true
extraArgs: []
extraEnv: []
extraObjects: []
featureGates: ''
global:
  commonLabels: {}
  imagePullSecrets: []
  leaderElection:
    namespace: kube-system
  logLevel: 2
  podSecurityPolicy:
    enabled: false
    useAppArmor: true
  priorityClassName: ''
  rbac:
    aggregateClusterRoles: true
    create: true
  cattle:
    systemProjectId: p-mz6m6
hostAliases: []
image:
  pullPolicy: IfNotPresent
  repository: quay.io/jetstack/cert-manager-controller
ingressShim: {}
installCRDs: false
livenessProbe:
  enabled: true
  failureThreshold: 8
  initialDelaySeconds: 10
  periodSeconds: 10
  successThreshold: 1
  timeoutSeconds: 15
maxConcurrentChallenges: 60
namespace: ''
nodeSelector:
  kubernetes.io/os: linux
podDisruptionBudget:
  enabled: false
podLabels: {}
prometheus:
  enabled: true
  podmonitor:
    annotations: {}
    enabled: false
    endpointAdditionalProperties: {}
    honorLabels: false
    interval: 60s
    labels: {}
    path: /metrics
    prometheusInstance: default
    scrapeTimeout: 30s
  servicemonitor:
    annotations: {}
    enabled: false
    endpointAdditionalProperties: {}
    honorLabels: false
    interval: 60s
    labels: {}
    path: /metrics
    prometheusInstance: default
    scrapeTimeout: 30s
    targetPort: 9402
replicaCount: 1
resources: {}
securityContext:
  runAsNonRoot: true
  seccompProfile:
    type: RuntimeDefault
serviceAccount:
  automountServiceAccountToken: true
  create: true
startupapicheck:
  affinity: {}
  backoffLimit: 4
  containerSecurityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop:
        - ALL
    readOnlyRootFilesystem: true
  enableServiceLinks: false
  enabled: true
  extraArgs:
    - '-v'
  extraEnv: []
  image:
    pullPolicy: IfNotPresent
    repository: quay.io/jetstack/cert-manager-startupapicheck
  jobAnnotations:
    helm.sh/hook: post-install
    helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
    helm.sh/hook-weight: '1'
  nodeSelector:
    kubernetes.io/os: linux
  podLabels: {}
  rbac:
    annotations:
      helm.sh/hook: post-install
      helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
      helm.sh/hook-weight: '-5'
  resources: {}
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  serviceAccount:
    annotations:
      helm.sh/hook: post-install
      helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
      helm.sh/hook-weight: '-5'
    automountServiceAccountToken: true
    create: true
  timeout: 1m
  tolerations: []
  volumeMounts: []
  volumes: []
strategy: {}
tolerations: []
topologySpreadConstraints: []
volumeMounts: []
volumes: []
webhook:
  affinity: {}
  config: {}
  containerSecurityContext:
    allowPrivilegeEscalation: false
    capabilities:
      drop:
        - ALL
    readOnlyRootFilesystem: true
  enableServiceLinks: false
  extraArgs: []
  extraEnv: []
  featureGates: ''
  hostNetwork: false
  image:
    pullPolicy: IfNotPresent
    repository: quay.io/jetstack/cert-manager-webhook
  livenessProbe:
    failureThreshold: 3
    initialDelaySeconds: 60
    periodSeconds: 10
    successThreshold: 1
    timeoutSeconds: 1
  mutatingWebhookConfiguration:
    namespaceSelector: {}
  networkPolicy:
    egress:
      - ports:
          - port: 80
            protocol: TCP
          - port: 443
            protocol: TCP
          - port: 53
            protocol: TCP
          - port: 53
            protocol: UDP
          - port: 6443
            protocol: TCP
        to:
          - ipBlock:
              cidr: 0.0.0.0/0
    enabled: false
    ingress:
      - from:
          - ipBlock:
              cidr: 0.0.0.0/0
  nodeSelector:
    kubernetes.io/os: linux
  podDisruptionBudget:
    enabled: false
  podLabels: {}
  readinessProbe:
    failureThreshold: 3
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 1
  replicaCount: 1
  resources: {}
  securePort: 10250
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  serviceAccount:
    automountServiceAccountToken: true
    create: true
  serviceIPFamilies: []
  serviceIPFamilyPolicy: ''
  serviceLabels: {}
  serviceType: ClusterIP
  strategy: {}
  timeoutSeconds: 30
  tolerations: []
  topologySpreadConstraints: []
  url: {}
  validatingWebhookConfiguration:
    namespaceSelector:
      matchExpressions:
        - key: cert-manager.io/disable-validation
          operator: NotIn
          values:
            - 'true'
  volumeMounts: []
  volumes: []

此文件博主未进行任何修改,直接使用官方默认配置部署。

部署

读者请自行使用helm命令行或其他工具进行部署,此处不赘述。

配置

使用cert-manager签发证书,仅需要配置三个资源即可使用。分别是包含了cloudflare的Secret、cert-manager的ClusterIssuer和cerr-manager的Certificate。

完整的yaml文件如下。

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: your-token
---
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
  namespace: cert-manager
spec:
  acme:
    # Change to your letsencrypt email
    email: your-email@example.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-account-key
    solvers:
    - dns01:
        cloudflare:
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com
  namespace: traefik
spec:
  # Secret names are always required.
  secretName: example-com
  duration: 2160h # 90d
  renewBefore: 360h # 15d
  dnsNames:
    - "*.example.com"
    - "example.com"
  # Issuer references are always required.
  issuerRef:
    name: letsencrypt
    kind: ClusterIssuer

读者仅须注意以下几点。

  1. your-token替换为自己在Cloudflare申请的token。

  2. your-email@example.com替换为自己的电子邮箱地址。

  3. cloudflare-api-token-secret和声明的存储token的Secret的name保持一致。

  4. *.example.comexample.com修改为自己需要签发证书的域名。

验证

至此为止,已经完成了cert-manager的部署和配置,在配置好Ingress或者IngressRoute等入口后,即可通过域名建立HTTPS连接。

LICENSED UNDER CC BY-NC-SA 4.0
Comment