Traefik自动申请证书 Traefik
实现自动申请HTTPS证书
要使用Let’s Encrypt 自动生成证书,需要使用ACME。需要在静态配置中定义 “证书解析器”,Traefik
负责从ACME服务器中检索证书。
然后,每个 “路由器 “被配置为启用TLS,并通过tls.certresolver配置选项与一个证书解析器关联。
Traefik的ACME验证方式主要有以下三种:
tlsChallenge httpChallenge dnsChallenge 如果使用tlsChallenge,则要求Let’s Encrypt到 Traefik 443 端口必须是可达的。如果使用httpChallenge,则要求Let’s Encrypt到 Traefik 80端口必须是可达的。如果使用dnsChallenge,则需要对应的providers。
部署cert-manager 借助 Kubernetes,我们获得了一个强大且可扩展的平台来解决许多复杂的场景。cert-manager 是一个功能强大的解决方案,可以帮助我们自动化和管理与 TLS 证书相关的几乎所有内容。它提供了一套针对各种场景的自定义资源定义(CRD),并与原生Ingress
或Gateway
资源很好地集成。
cert-manager 在 Kubernetes 机密中存储和缓存证书和私钥,使它们高度可用,可供入口控制器(如 Traefik Proxy)或应用程序进一步使用。
注意: 默认情况下,cert-manager 不会自动清除机密,从而允许它重新附加到已颁发的证书并避免颁发新证书。当您需要创建和删除大量资源并且不希望受到速率限制时,这变得非常方便。
cert-manager 可以与各种来源交互来颁发证书,包括 Let's Encrypt
、HashiCorp
、Vault
以及私有 PKI。对于AWS 私有证书颁发机构 、Google Cloud 证书颁发机构服务 或Cloudflare Origin CA 等 不受支持的情况,外部颁发者 允许您扩展证书管理器功能。
先决条件 要学习本教程,您需要具备以下条件:
您可以使用以下命令安装 cert-manager 1.12:
1 kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.3/cert-manager.yaml
提供 Web 端口的服务。在本教程中,我将使用 whoami 作为示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 cat > whoami.yml <<EOF apiVersion: v1 kind: Service metadata: name: whoami spec: ports: - protocol: TCP name: web port: 80 selector: app: whoami --- kind: Deployment apiVersion: apps/v1 metadata: name: whoami labels: app: whoami spec: replicas: 1 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: containous/whoami ports: - name: web containerPort: 80 EOF
Traefik 代理与 cert-manager 和 Let’s Encrypt 让我们探索如何结合 Kubernetes 入口控制器(如 Traefik Proxy 和 cert-manager)来保护 Web 应用程序的安全。Let’s Encrypt 提供多种质询类型 来验证域名的控制权。根据您的要求,您可以选择HTTP-01
您的服务何时可供公共访问或DNS-01
专用端点。
使用 Let Encrypt 时请注意速率限制。为了避免出现令人不快的意外,建议使用 Let’s Encrypt暂存环境 :
自动化 HTTPS Let’s Encrypt 使用 ACME 协议来校验域名是否真的属于你,校验成功后就可以自动颁发免费证书,证书有效期只有 90 天,在到期前需要再校验一次来实现续期,而 cert-manager 是可以自动续期的,所以事实上并不用担心证书过期的问题。目前主要有 HTTP 和 DNS 两种校验方式。
HTTP-01 校验 HTTP-01
的校验是通过给你域名指向的 HTTP 服务增加一个临时 location,:在校验的时候 Let’s Encrypt 会发送http 请求到 http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>
,其中 YOUR DOMAIN 就是被校验的域名,TOKEN 是 ert-manager 生成的一个路径,它通过修改 Ingress 规则来增加这个临时校验路径并指向提供TOKEN 的服务。Let’s Encrypt 会对比 TOKEN 是否符合预期,校验成功后就会颁发证书了,不过这种方法不支持泛域名证书。
使用 HTTP 校验这种方式,首先需要将域名解析配置好,也就是需要保证 ACME 服务端可以正常访闯到你的 HTTP服务。这里我们以上面的 whoami应用为例,我们已经将 whoami.boysec.cn
域名做好了正确的解析。
方法一 由于 Let’s Encrypt 的生产环境有着严格的接口调用限制,所以一般我们需要先在 staging 环境测试通过后,再切换到生产环境。首先我们创建一个default范围测试环境和生产环境使用的 HTTP-1 校验方式的证书颁发机构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cat <<EOF >staging-http.yml apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: staging-http01 spec: acme: email: wangxiansen@boysec.cn server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: name: boysec-staging-http01 solvers: - http01: ingress: class: traefik EOF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cat <<EOF >production-http.yml apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: production-http01 spec: acme: email: wangxiansen@boysec.cn server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: boysec-http01 solvers: - http01: ingress: class: traefik EOF
创建完成后可以看到两个 issuers 对象:
有了 Issuer/ClusterIssuer 证书颁发机构,接下来我们就可以生成免费证书了,cert-manager 给我们提供了 Certificate 这个用于生成证书的自定义资源对象,不过这个对象需要在一个具体的命名空间下使用,证书最终会在这个命名空间下以 Secret 的资源对象存储。我们这里是要结合 traefik
一起使用,实际上我们只需要修改 Ingress 对象,添加上 cert-manager 的相关注解即可,不需要手动创建 Certificate 对象了,修改上面的 whoami应用的 Ingress 资源对象,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 cat << EOF >ing.yml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: whoami annotations: cert-manager.io/issuer: "staging-http01" spec: tls: - hosts: - whoami.boysec.cn secretName: whoami-tls rules: - host: whoami.boysec.cn http: paths: - path: / pathType: Prefix backend: service: name: whoami port: name: web EOF
验证
1 2 3 4 5 6 7 8 9 10 11 $ kubectl get issuer -o wide NAME READY STATUS AGE production-http01 True The ACME account was registered with the ACME server 18m staging-http01 True The ACME account was registered with the ACME server 19m $ kubectl get certificateRequest -o wide NAME APPROVED DENIED READY ISSUER STATUS tls-whoami-ingress-http-fdw2x True True le-example-http Certificate fetched from issuer successfully $ kubectl get certificates NAME READY SECRET ISSUER STATUS tls-whoami-ingress-http True tls-whoami-ingress-http le-example-http Certificate is up to date and has not expired
方法二(推荐) 通过修改traefik ConfigMap
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: wangxiansen-test: acme: caServer: https://acme-staging-v02.api.letsencrypt.org/directory email: wangxiansen@boysec.cn storage: acme-staging-web.json httpChallenge: entryPoint: web wangxiansen: acme: email: wangxiansen@boysec.cn storage: acme-web.json httpChallenge: entryPoint: web
创建ingressroute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoamiauto-tls-http spec: entryPoints: - web routes: - match: Host(`whoami.boysec.cn`) kind: Rule services: - name: whoami port: 80 tls: certResolver: wangxiansen-test
打开浏览器就会发现申请测试的证书了,然后修改certResolver
为 wangxiansen
DNS-01 校验 DNS-01 的校验是通过 DNS 提供商的 API 拿到你的 DNS 控制权限, 在 Let’s Encrypt 为 cert-manager 提供 TOKEN 后,cert-manager 将创建从该 TOKEN 和你的帐户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge.。然后 Let’s Encrypt 将向 DNS 系统查询该记录,如果找到匹配项,就可以颁发证书,这种方法是支持泛域名证书的。
方法一 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cat <<EOF >staging-dns.yml apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: boysec-staging-dns namespace: whoami spec: acme: email: user@example.com server: https://acme-staging-v02.api.letsencrypt.org/directory privateKeySecretRef: name: boysec-staging-key solvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token EOF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 cat <<EOF >production-dns.yml apiVersion: cert-manager.io/v1 kind: Issuer metadata: name: boysec-dns namespace: whoami spec: acme: email: user@example.com server: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: name: boysec-key solvers: - dns01: cloudflare: apiTokenSecretRef: name: cloudflare-api-token-secret key: api-token EOF
方法二(推荐) 通过修改traefik ConfigMap
文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 entryPoints: web: address: ":80" websecure: address: ":443" certificatesResolvers: tencent-test: acme: email: wangxiansen@boysec.cn storage: acme-staging-dns.json caServer: https://acme-staging-v02.api.letsencrypt.org/directory dnsChallenge: provider: tencentcloud delayBeforeCheck: 0 resolvers: - "119.29.29.29:53" tencent: acme: email: wangxiansen@boysec.cn storage: acme-dns.json dnsChallenge: provider: tencentcloud delayBeforeCheck: 0 resolvers: - "119.29.29.29:53"
然后创建密钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 kubectl create secret generic tencent-token --from-literal=TENCENTCLOUD_SECRET_ID=AKIDoSadfsafdsfasdfsdfLBj23 --from-literal=TENCENTCLOUD_SECRET_KEY=lFTP4afafasdfsfdfsgasfgfMK1Ra7NM -n kube-system $ kubectl edit -n kube-system pods traefik-v2-6996759d46-d9czt spec: serviceAccountName: traefik-ingress-controller terminationGracePeriodSeconds: 1 containers: - name: traefik-v2 image: traefik:v2.10 args: - --configfile=/config/traefik.yaml envFrom: # 添加环境变量 - secretRef: name: tencent-token
创建ingressroute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 cat << EOF > auto-tls-dns.yml apiVersion: traefik.containo.us/v1alpha1 kind: IngressRoute metadata: name: whoami-auto-tls-dns spec: entryPoints: - websecure routes: - match: Host(\`who.boysec.cn\`) kind: Rule services: - name: whoami port: 80 tls: certResolver: tencent-test domains: - main: boysec.cn sans: - '*.boysec.cn' EOF
打开可以发现测试证书已下发,可以替换生成环境证书将certResolver
替换为生产环境证书
再次访问就会发现证书是受信任的了