使用cert-manager保护你的k8s ingress

214 阅读2分钟

cert-manager 简介

cert-manager 在 Kubernetes 集群中添加了证书和证书发放者等资源类型,并简化了获取、更新和使用这些证书的过程。

它可以从各种支持的来源,包括 Let's EncryptHashiCorp VaultVenafi 以及私有 PKI 发放证书。

它将确保证书有效且最新,并在到期前在配置的时间尝试续订证书。

它松散地基于 kube-lego 的工作,并从其他类似项目如 kube-cert-manager 中借鉴了一些智慧。

high-level-overview.svg

部署

Helm

# 添加 jetstack 仓库
helm repo add jetstack https://charts.jetstack.io
# 更新 helm 仓库信息
helm repo update
# 安装
helm install \
    cert-manager jetstack/cert-manager \
    --namespace cert-manager \
    --create-namespace \
    --version v1.12.0 \
    --set installCRDs=true \
    --set clusterResourceNamespace=cert-manager
  • 需要根据自己的 k8s 版本选择合适的 chart 版本 cert-manager's ArtifactHub page.
  • clusterResourceNamespace 后续指定 ClusterIssuers 需要的 secret 所在命名空间

验证安装结果:

kubectl get pod -n cert-manager

看到所有 pod 是运行中状态,说明安装成功了

NAME                                      READY   STATUS    RESTARTS      AGE
cert-manager-55649d64b4-cr74s             1/1     Running   0             1s
cert-manager-cainjector-666db4777-w72pf   1/1     Running   0             1s
cert-manager-webhook-586f966d4d-tmn2m     1/1     Running   0             1s

DNS token 配置

Cloudflare

从 Cloudflare 后台,我的个人资料 -> API 令牌 -> 创建一个 API 令牌,配置适当的权限,此处使用 YOUR_CF_TOKEN 代替。

直接使用命令行创建

kubectl create secret generic --from-literal=api-token=$(YOUR_CF_TOKEN) -n cert-manager cloudflare-api-token-secret

使用 yaml 创建

apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: YOUR_CF_TOKEN

Issuer 配置

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: cert-manager@example.com # acme需要使用的邮箱,修改为自己的
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - dns01:
          cloudflare:
            apiTokenSecretRef:
              name: cloudflare-api-token-secret
              key: api-token #跟上边secret key对应

这里为了方便直接使用 ClusterIssuer,如果需要更细粒度的控制,需要使用 Issuer

Ingress 配置

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
        - image: docker.io/kong/httpbin
          imagePullPolicy: IfNotPresent
          name: httpbin
          ports:
            - containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  name: httpbin-service
spec:
  selector:
    app: httpbin
  ports:
    - port: 80
      targetPort: 80

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

验证结果:

kubectl get certificates

等待 READY 状态变成 True

curl https://abc.example.com --resolve abc.example.com:127.0.0.1