实现 Ingress Https 常用工具

什么是 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 Ingress 和 Let’s Encrypt 实现外部服务的自动化 HTTPS。

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

部署 Cert-Manager

  • 安装 CustomResourceDefinition 资源

    1
    kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.8/deploy/manifests/00-crds.yaml
  • 创建 Cert-Manager Namespace

    1
    kubectl create namespace cert-manager
  • 标记 Cert-Manager 命名空间以禁用资源验证

    1
    kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
  • 添加 Jetstack Helm repository

    1
    helm repo add jetstack https://charts.jetstack.io
  • 更新本地 Helm Chart Repository

    1
    helm repo update
  • 使用Helm chart安装cert-manager

    1
    2
    3
    4
    5
    6
    helm install jetstack/cert-manager \
    --set ingressShim.defaultIssuerKind=ClusterIssuer \
    --set ingressShim.defaultIssuerName=letsencrypt-prod \
    --name cert-manager \
    --version v0.8.0 \
    --namespace cert-manager
  • 创建 ClusterIssuer
    我们需要先创建一个签发机构,Cert-Manager 给我们提供了 Issuer 和 ClusterIssuer 这两种用于创建签发机构的自定义资源对象,Issuer 只能用来签发自己所在 Namespace 下的证书,ClusterIssuer 可以签发任意 Namespace 下的证书,这里以 ClusterIssuer 为例创建一个签发机构:

    • letsencrypt-prod-issuer.yaml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      apiVersion: certmanager.k8s.io/v1alpha1
      kind: ClusterIssuer
      metadata:
      name: letsencrypt-prod
      spec:
      acme:
      server: https://acme-v02.api.letsencrypt.org/directory
      email: yourname@gmail.com
      privateKeySecretRef:
      name: letsencrypt-prod
      http01: {}
    • 说明:

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

      1
      $ kubectl apply -f letsencrypt-prod-issuer.yaml
    • 查看 ClusterIssuer 创建结果

      1
      2
      3
      $ kubectl get clusterissuer
      NAME AGE
      letsencrypt-prod 11m
  • 创建 Certificate
    有了签发机构,接下来我们就可以生成免费证书了,Cert-Manager 给我们提供了 Certificate 这个用于生成证书的自定义资源对象,它必须局限在某个 Namespace 下,证书最终会在这个 Namespace 下以 Secret 的资源对象存储,创建一个 Certificate 对象:

    • certificate.yaml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      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 加上 kubernetes.io/ingress.class 这个 annotation,如果我们的 Ingress Controller 是 Traefik Ingress 。Controller,指定这个字段可以让创建的 Ingress 被 Traefik Ingress Controller 处理。
      • spec.acme.config.http01.domains 指示该证书的可以用于哪些域名。
    • 执行部署命令

      1
      $ kubectl apply -f cert.yaml
    • 查看 Certificate 创建结果

      1
      2
      3
      $ kubectl get certificate -n istio-system
      NAME AGE
      dashboard-imroc-io 54s
    • 执行上述步骤,如有问题,可使用如下命令排查原因

      1
      2
      $ kubectl describe -n istio-system certificate dashboard-imroc-io
      $ kubectl describe clusterissuer letsencrypt-prod
    • 查看生成的 Secret 结果

      1
      2
      $ kubectl get secret -n istio-system | grep dashboard-imroc-io
      dashboard-imroc-io kubernetes.io/tls

测试 Ingress 使用 HTTPS

  • 创建一个 Nginx

    1
    2
    3
    4
    $ kubectl run nginx --image=nginx --port=80 --expose
    kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
    service/nginx created
    deployment.apps/nginx created
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    $ cat ingress.yaml
    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: nginx
    servicePort: 80
    path: /
    tls:
    - secretName: dashboard-imroc-io
    hosts:
    - test.nginx.com

    需要注意的是上面我们添加的两个 annotations 非常重要,这个将告诉 Cert Manager 去生成证书,然后由于我们这里要使用 HTTPS,所以我们需要添加一个 TLS 证书,而证书就是通过 k8sui-tls 这个 Secret 对象来提供的,要注意的是这个 Secret 对象并不是我们手动创建的,而是 Cert Manager 自动创建的证书对应的对应。然后直接创建这个资源对象即可:

    1
    $ kubectl apply -f test-nginx.yaml
  • 创建完成后隔一会儿我们可以看到会多出现一个随机名称的 Ingress 对象,这个 Ingress 对象就是用来专门验证证书的:

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

    我们可以通过 Traefik 的 Dashboard 可以观察到这一变化,验证成功后,这个 Ingress 对象也自动删除了:
    这个时候我们可以去 describe 下我们的 Ingress 对象,查看有无报错。

    1
    $ kubectl describe ingress my-nginx

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

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

    最后,我们来打开浏览器使用 HTTPS 访问服务。
    到这里我们就完成了使用 Let’s Encrypt 实现 Kubernetes Ingress 自动化 HTTPS。

setzero wechat