前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kubernetes (K8S) 中Traefik自动申请证书

Kubernetes (K8S) 中Traefik自动申请证书

作者头像
王先森sec
发布2023-10-17 15:25:53
8050
发布2023-10-17 15:25:53
举报
文章被收录于专栏:王先森王先森

Kubernetes (K8S) 中Traefik自动申请证书

王先森2023-08-292023-08-29

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),并与原生IngressGateway资源很好地集成。

cert-manager 在 Kubernetes 机密中存储和缓存证书和私钥,使它们高度可用,可供入口控制器(如 Traefik Proxy)或应用程序进一步使用。

注意:默认情况下,cert-manager 不会自动清除机密,从而允许它重新附加到已颁发的证书并避免颁发新证书。当您需要创建和删除大量资源并且不希望受到速率限制时,这变得非常方便。

cert-manager 可以与各种来源交互来颁发证书,包括 Let's EncryptHashiCorpVault 以及私有 PKI。对于AWS 私有证书颁发机构、Google Cloud 证书颁发机构服务或Cloudflare Origin CA 等不受支持的情况,外部颁发者允许您扩展证书管理器功能。

先决条件

要学习本教程,您需要具备以下条件:

  • Kubernetes 集群 >= v1.20
  • Let’s Encrypt 的公共托管 DNS 域 — 出于本文的目的,我将使用 腾讯云
  • Traefik 2.10,您可以通过这篇文章安装部署 Kubernetes部署升级Traefik2.6

您可以使用以下命令安装 cert-manager 1.12:

代码语言:javascript
复制
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.3/cert-manager.yaml

提供 Web 端口的服务。在本教程中,我将使用 whoami 作为示例

代码语言:javascript
复制
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暂存环境

代码语言:javascript
复制
#测试(staging):https://acme-staging-v02.api.letsencrypt.org/directory
#生产(production):https://acme-v02.api.letsencrypt.org/directory

自动化 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 域名做好了正确的解析。

这里必须要绑定公网IP才可以。

方法一

由于 Let’s Encrypt 的生产环境有着严格的接口调用限制,所以一般我们需要先在 staging 环境测试通过后,再切换到生产环境。首先我们创建一个default范围测试环境和生产环境使用的 HTTP-1 校验方式的证书颁发机构:

测试环境生成环境

代码语言:javascript
复制
cat <<EOF >staging-http.yml 
apiVersion: cert-manager.io/v1
kind: Issuer  # 选择整个集群(ClusterIssuer)还是单个namespace
metadata:
 name: staging-http01
spec:
 acme:
   email: wangxiansen@boysec.cn  # 用于 ACME 注册的邮箱
   # ACME 服务端地址
   server: https://acme-staging-v02.api.letsencrypt.org/directory
   privateKeySecretRef: 
     # 用于存放 ACME 帐号 private key 的 secret
     name: boysec-staging-http01
   solvers:
     - http01:  # ACME HTTP-01 类型
         ingress:
           class: traefik # 指定ingress的名称
EOF
代码语言:javascript
复制
cat <<EOF >production-http.yml 
apiVersion: cert-manager.io/v1
kind: Issuer  # 选择整个集群(ClusterIssuer)还是单个namespace
metadata:
 name: production-http01
spec:
 acme:
   email: wangxiansen@boysec.cn  # 用于 ACME 注册的邮箱
   # ACME 服务端地址
   server: https://acme-v02.api.letsencrypt.org/directory
   privateKeySecretRef: 
     # 用于存放 ACME 帐号 private key 的 secret
     name: boysec-http01
   solvers:
     - http01:  # ACME HTTP-01 类型
         ingress:
           class: traefik # 指定ingress的名称
EOF

创建完成后可以看到两个 issuers 对象:

代码语言:javascript
复制
kubectl get issuers

有了 Issuer/ClusterIssuer 证书颁发机构,接下来我们就可以生成免费证书了,cert-manager 给我们提供了 Certificate 这个用于生成证书的自定义资源对象,不过这个对象需要在一个具体的命名空间下使用,证书最终会在这个命名空间下以 Secret 的资源对象存储。我们这里是要结合 traefik 一起使用,实际上我们只需要修改 Ingress 对象,添加上 cert-manager 的相关注解即可,不需要手动创建 Certificate 对象了,修改上面的 whoami应用的 Ingress 资源对象,如下所示:

代码语言:javascript
复制
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

验证

代码语言:javascript
复制
$ 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文件

代码语言:javascript
复制
entryPoints:
      web:
        address: ":80"          ## 配置 80 端口,并设置入口名称为 web
      websecure:
        address: ":443"         # 配置443端口,并设置入口名称为 websecure
    certificatesResolvers:
      wangxiansen-test: # 可以换成你喜欢的名字
        acme:
          caServer: https://acme-staging-v02.api.letsencrypt.org/directory # ACME 服务端地址
          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

代码语言:javascript
复制
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

打开浏览器就会发现申请测试的证书了,然后修改certResolverwangxiansen

DNS-01 校验

DNS-01 的校验是通过 DNS 提供商的 API 拿到你的 DNS 控制权限, 在 Let’s Encrypt 为 cert-manager 提供 TOKEN 后,cert-manager 将创建从该 TOKEN 和你的帐户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge.。然后 Let’s Encrypt 将向 DNS 系统查询该记录,如果找到匹配项,就可以颁发证书,这种方法是支持泛域名证书的。

方法一

测试环境生成环境

代码语言:javascript
复制
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
   # We use the staging server here for testing to avoid hitting
   server: https://acme-staging-v02.api.letsencrypt.org/directory
   privateKeySecretRef:
     # if not existing, it will register a new account and stores it
     name: boysec-staging-key
   solvers:
     - dns01:
         cloudflare:
           apiTokenSecretRef:
             name: cloudflare-api-token-secret
             key: api-token

EOF
代码语言:javascript
复制
cat <<EOF >production-dns.yml 
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
 name: boysec-dns
 namespace: whoami
spec:
 acme:
   email: user@example.com
   # We use the staging server here for testing to avoid hitting
   server: https://acme-v02.api.letsencrypt.org/directory
   privateKeySecretRef:
     # if not existing, it will register a new account and stores it
     name: boysec-key
   solvers:
     - dns01:
         cloudflare:
           apiTokenSecretRef:
             name: cloudflare-api-token-secret
             key: api-token

EOF

方法二(推荐)

通过修改traefik ConfigMap文件

代码语言:javascript
复制
entryPoints:
      web:
        address: ":80"          ## 配置 80 端口,并设置入口名称为 web
      websecure:
        address: ":443"         # 配置443端口,并设置入口名称为 websecure
      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" # 腾讯云的 DNS 地址
        tencent: # 可以换成你喜欢的名字
          acme:
            email: wangxiansen@boysec.cn # 届时你申请签发证书的邮箱
            storage: acme-dns.json
            dnsChallenge:
              provider: tencentcloud # 腾讯云的编码
              delayBeforeCheck: 0
              resolvers:         
                - "119.29.29.29:53" # 腾讯云的 DNS 地址

然后创建密钥

代码语言:javascript
复制
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

代码语言:javascript
复制
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'        # 匹配所有boysec.cn下的二级域名
EOF

打开可以发现测试证书已下发,可以替换生成环境证书将certResolver替换为生产环境证书

再次访问就会发现证书是受信任的了

由于写文章测试过多被域名重复申请限制,所以先截图测试环境图,后期补上生成环境图

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-08-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Kubernetes (K8S) 中Traefik自动申请证书
  • Traefik自动申请证书
  • 部署cert-manager
    • 先决条件
      • Traefik 代理与 cert-manager 和 Let’s Encrypt
      • 自动化 HTTPS
        • HTTP-01 校验
          • 方法一
          • 方法二(推荐)
        • DNS-01 校验
          • 方法一
          • 方法二(推荐)
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档