编程技术分享平台

网站首页 > 技术教程 正文

使用cert-manager实现Ingress https--详解

xnh888 2024-09-21 06:26:51 技术教程 32 ℃ 0 评论

cert-manger官方部署文档: https://cert-manager.io/docs/installation/reinstall/

什么是https

超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

什么是cert-manager

cert-manager 是一个云原生证书管理开源项目,用于在 Kubernetes 集群中提供 HTTPS 证书并自动续期,支持 Let’s Encrypt, HashiCorp Vault 这些免费证书的签发。在Kubernetes集群中,我们可以通过 Kubernetes IngressLet’s Encrypt 实现外部服务的自动化 HTTPS

Kubernetes集群中使用 HTTPS 协议,需要一个证书管理器、一个证书自动签发服务,主要通过 Ingress 来发布 HTTPS 服务,因此需要Ingress Controller并进行配置,启用 HTTPS 及其路由。

环境依赖

  • 本文使用 Helm 安装,所以请确保 Helm 已安装,且版本最好>2.10
  • 集群必须已经装有 Ingress Controller
  • 外部客户端配置hostsIP 指向 Ingress Controller 对外暴露的地址(如果IP是公网地址并做了域名解析,则无需配置)

部署cert-manager

方式1: 使用KubeCtl命令安装cert-manager(use)

安装命令

#安装 CustomResourceDefinition资源
# use
# 地址: https://github.com/cert-manager/cert-manager/releases/tag/v1.14.3
$. wget https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.crds.yaml
# 执行
$. kubectl apply -f cert-manager.crds.yaml

# or
$. kubectl apply \
-f https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.crds.yaml

# old
# kubectl apply \
-f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.7/deploy/manifests/00-crds.yaml
# kubectl apply -f 00-crds.yaml

下载页面截图

地址: cert-manager-v1.14.3

cert-manager.crds.yaml和cert-manager.yaml之间的区别

方式2: 使用helm安装cert-manager

添加 Jetstack Helm repository

cert-manager HUB地址:https://artifacthub.io/packages/helm/cert-manager/cert-manager

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

更新chart repository

更新本地Helm chart repository

helm repo update

安装cert-manager

使用Helm chart安装cert-manager

$. helm install \
--name cert-manager \
--namespace cert-manager \
--version v0.7.0 \
jetstack/cert-manager

# use
## Install the cert-manager helm chart
$. helm install my-release \
--namespace cert-manager \
--version v1.14.3 \
jetstack/cert-manager

# 其它安装命令可参考:
https://cert-manager.io/docs/installation/helm/
# =========================== 参考 ============================== #
# Uninstalling the Chart
# The command removes all the Kubernetes 
# components associated with the chart and deletes the release.
$ helm delete my-release

# If you want to completely uninstall cert-manager 
# from your cluster, 
# you will also need to delete the previously 
# installed CustomResourceDefinition resources:
$ kubectl delete -f \
https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.crds.yaml

查看cert-manager部署结果

# kubectl get pods --namespace cert-manager
NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-5658b7db79-824lt              1/1     Running   0          11h
cert-manager-cainjector-768fd47f68-ls6zh   1/1     Running   0          11h
cert-manager-webhook-5b4bc6b547-8qk2v      1/1     Running   0          11h

创建ns等资源

创建cert-managernamespace

kubectl create namespace cert-manager

标记cert-Manager

标记cert-Manager命名空间以禁用资源验证

kubectl label \
namespace cert-manager \
certmanager.k8s.io/disable-validation=true

创建ClusterIssuer

需要先创建一个签发机构,cert-manager 提供了 IssuerClusterIssuer 两种用于创建签发机构的自定义资源对象:

    • Issuer 只能用来签发自己所在 namespace 下的证书,
    • ClusterIssuer 可以签发任意 namespace 下的证书。

创建issuer.yaml

官网地址: https://cert-manager.io/docs/configuration/issuers/

这里以 ClusterIssuer 为例创建一个签发机构:

# use
# cat issuer.yaml 
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: my-cluster-issue
spec:
  acme:
    # Replace the email address with your own contact email
    email: fluxcdbot@users.noreply.github.com
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: my-cluster-issue-secret # 会自动创建该secret
    solvers:
      - http01:
          ingress:
            class: nginx

# old
# cat issuer.yaml 
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: xxxx@126.com
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}

---
# ========================== 官方参考 ========================== # 
# 地址: https://github.com/fluxcd/flux2-kustomize-helm-example
# the Let's Encrypt issuer example:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    # Replace the email address with your own contact email
    email: fluxcdbot@users.noreply.github.com
    # Let's Encrypt 生产环境 URL
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-nginx
    solvers:
      - dns01:
          cloudDNS:
            project: my-project
              serviceAccountSecretRef:
                name: google-dns-service-account
                key: key.json

---
# replace the Let's Encrypt server value to point to the production API:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: infra-configs
  namespace: flux-system
spec:
  # ...omitted for brevity
  dependsOn:
    - name: infra-controllers
  patches:
    - patch: |
        - op: replace
          path: /spec/acme/server
          value: https://acme-v02.api.letsencrypt.org/directory
      target:
        kind: ClusterIssuer
        name: letsencrypt
# ======================== 其它配置参考 ======================== # 
apiVersion: cert-manager.io/v1
kind: ClusterIssuer # 或者 Issuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # ...
    solvers:
    # http01: 使用 HTTP-01 验证,通过 Ingress 控制器自动配置验证路径。
    # dns01: 使用 DNS-01 验证,配置了 Cloudflare DNS 提供商,需要提供 API Key 作为 Secret。
    - dns01:
        <dns-provider-specific-config>
      # 或者
    - http01:
        ingress:
          class: nginx
      # 或者多个solver同时配置,cert-manager会选择合适的进行验证
    - selector:
        matchLabels:
          solver-type: example
      dns01:
        <dns-provider-specific-config>
    # ...
# 说明
# 1. HTTP-01 Solver:
- http01:
    ingress:
      class: nginx
# 配置表明 cert-manager 将通过修改 Kubernetes Ingress 资源来完成 HTTP-01 验证。
# Ingress 控制器(如 Nginx Ingress Controller)将处理 .
# well-known/acme-challenge/ 路径下的验证请求,
# Let's Encrypt 会向这个路径发送请求来验证域名所有权。

# 2. DNS-01 Solver:
- dns01:
    cloudDNS:
      project: my-project
      serviceAccountSecretRef:
        name: google-dns-service-account
        key: key.json
# DNS-01 解决方案涉及到修改 DNS TXT 记录以证明域名所有权。
# 这里的配置示例是指使用 Google Cloud DNS,
# cert-manager 会使用指定的 Service Account 凭证来更新相应的 DNS 记录以完成验证。

# 每个 Solver 可能包含特定于 DNS 提供商或其他认证机制的配置细节。
# 在实际应用中,你需要根据所使用的 DNS 服务商或 HTTP 服务暴露方式来填写相应的配置信息。
# cert-manager 支持多种 DNS 供应商的适配器,
# 例如 AWS Route53、Cloudflare、Azure DNS 等。

说明:

  • metadata.name 是我们创建的签发机构的名称,后面我们创建证书的时候会引用它
  • spec.acme.email 是你自己的邮箱,证书快过期的时候会有邮件提醒,不过 cert-manager 会利用 acme 协议自动给我们重新颁发证书来续期
  • spec.acme.server 是 acme 协议的服务端,我们这里用 Let’s Encrypt,这个地址就写死成这样就行
  • spec.acme.privateKeySecretRef 指示此签发机构的私钥将要存储到哪个 Secret 对象中,名称不重要
  • spec.acme.solvers[0].http01 这里指示签发机构使用 HTTP-01 的方式进行 acme 协议 (还可以用 DNS 方式,acme 协议的目的是证明这台机器和域名都是属于你的,然后才准许给你颁发证书)

部署issuer.yaml

kubectl apply -f issuer.yaml

查看clusterissuer创建结果

# kubectl get clusterissuer
NAME               READY   AGE
my-cluster-issue   True    32s

创建Certificate

有了签发机构,就可以生成免费证书了,cert-manager 提供了 Certificate

Certificate用于生成证书的自定义资源对象,它必须局限在某一个 namespace 下,证书最终会在这个 namespace 下以 Secret 的资源对象存储。

创建Certificate对象:

cert.yaml:

# use
# vi cert.yaml 
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-certificate
  namespace: cert-manager
spec:
  secretName: my-cert-secret # 需要手动创建该secret
  duration: 2160h # 证书有效期限(时间)
  renewBefore: 360h # 在过期之前多久开始续订证书
  issuerRef:
    name: my-cluster-issue
    kind: ClusterIssuer
  dnsNames:
  - rpp.master.com

---
# ========================== 参考 =========================== # 
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: example-com-tls
  namespace: default
spec:
  secretName: example-com-tls-secret
  commonName: example.com
  dnsNames:
  - example.com
  - www.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

# 说明: 在此例中,cert-manager 将自动为 
# example.com 和 www.example.com 两个域名获取并管理 Let's Encrypt 证书,
# 然后将证书存储在名为 example-com-tls-secret 的 Kubernetes Secret 中。

# old
# cat cert.yaml 
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: dashboard-imroc-io
  namespace: istio-system
spec:
  secretName: dashboard-imroc-io
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - istio.kiali.com
  acme:
    config:
    - http01:
        ingressClass: traefik
      domains:
      - istio.kiali.com

说明:

  • spec.secretName 指示证书最终存到哪个 Secret 中
  • spec.issuerRef.kind 值为 ClusterIssuer 说明签发机构不在本 namespace 下,而是在全局
  • spec.issuerRef.name 创建的签发机构的名称 (ClusterIssuer.metadata.name)
  • spec.dnsNames 指示该证书的可以用于哪些域名
  • spec.acme.config.http01.ingressClass 使用 HTTP-01 方式校验该域名和机器时,cert-manager 会尝试创建Ingress 对象来实现该校验。
    • 如果指定该值,会给创建的 Ingress 加上 annotation: kubernetes.io/ingress.class ;
    • 如果 Ingress Controllertraefik Ingress Controller,该字段可以让创建的 Ingresstraefik Ingress Controller 处理。
  • spec.acme.config.http01.domains 指示该证书的可以用于哪些域名

执行部署命令

kubectl apply -f cert.yaml

查看certificate创建结果

# kubectl get certificate -n cert-manager
NAME             READY   SECRET           AGE
my-certificate   False   my-cert-secret   7m17s

排查问题

执行上述步骤,如有问题,可使用如下命令排查原因

$. kubectl describe \
-n cert-manager \
certificate my-certificate

$. kubectl describe \
clusterissuer my-cluster-issue

查看生成的secret结果

# kubectl get secret -n cert-manager | grep my-cert-secret
dashboard-imroc-io      kubernetes.io/tls    3      2m32s

测试Ingress使用https

创建一个nginx ingress

test-nginx.yaml

# cat test-nginx.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 1
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx
        ports:
        - containerPort: 443
---
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    app: my-nginx
spec:
  ports:
  - port: 443
    protocol: TCP
    name: https
  selector:
    run: my-nginx
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-nginx
  annotations:
    kubernetes.io/ingress.class: "traefik"
    kubernetes.io/tls-acme: "true"
    certmanager.k8s.io/cluster-issuer: "letsencrypt-prod"
spec:
  rules:
  - host: test.nginx.com
    http:
      paths:
      - backend:
          serviceName: my-nginx
          servicePort: 443
        path: /
  tls:
  - secretName: dashboard-imroc-io
    hosts:
    - test.nginx.com

需要注意的是上面添加的两个annotations非常重要,这个将告诉 Cert Manager 去生成证书,由于要使用 HTTPS,需要添加一个 tls 证书,证书就是通过k8sui-tls这个 Secret 对象来提供的,注意这个 Secret 对象并不是手动创建的,而是 Cert Manager自动创建的证书对应的对应。

创建资源对象

然后直接创建这个资源对象即可:

kubectl apply -f test-nginx.yaml

查看Ingress资源对象

创建完成后过一段时间会看到多出现一个随机名称的 Ingress 对象,该对象即是用来专门验证证书的。

# kubectl get ingress -n istio-system
NAME                        HOSTS                    ADDRESS   PORTS     AGE
cm-acme-http-solver-z562f   test.nginx.com                     80        62s

可以通过 TraefikDashboard 可以观察到这一变化,验证成功后,这个 Ingress 对象也自动删除了:

查看Ingress 对象详情

describe Ingress 对象,查看有无报错

kubectl describe ingress my-nginx

查看 Cert manager 的 Pod 日志信息

同样我们可以去查看 Cert manager 的 Pod 日志信息:

$. kubectl logs \
-f cert-manager-5658b7db79-824lt \
--namespace cert-manager

最后,打开浏览器使用https访问服务

到这里就完成了使用Let’s Encrypt实现Kubernetes Ingress自动化 HTTPS

参考资料

项目地址:https://github.com/jetstack/cert-manager

文档地址:https://cert-manager.readthedocs.io

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表