Kubernetes Ingress 自动化 HTTPS

使用 Let's Encrypt 实现 Kubernetes Ingress 自动化 HTTPS

Kubernetes Ingress 自动化 HTTPS

使用 Let's Encrypt 实现 Kubernetes Ingress 自动化 HTTPS

标签: kubernetes   ingress   traefik  

我们知道HTTPS的服务非常安全,Google 现在对非HTTPS的服务默认是拒绝的,而且还能避免国内各种乱七八糟的劫持,所以启用HTTPS服务是真的非常有必要的。一些正规机构颁发的CA证书费用又特别高,不过比较幸运的是也有免费的午餐 - Let's Encrypt,虽然只有90天的证书有效期,但是我们完全可以在证书失效之前,重新生成证书替换掉。在Kubernetes集群中就更方便了,我们可以通过 Kubernetes Ingress 和 Let’s Encrypt 实现外部服务的自动化 HTTPS。

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

cert-manager-structrue
cert-manager-structrue

部署

我们这里用来管理 SSL/TLS 证书的组件是Cert manager,它对于每一个 ingress endpoint 将会自动创建一个新的证书,当 certificates 过期时还能自动更新,除此之外,Cert manager 也可以和其它的 providers 一起工作,例如 HashiCorp Vault。为了方便我们这里使用Helm来部署即可。

如果你对Helm还不是很熟悉,可以参考前面我的Helm 系列文章

在使用的时候我们需要配置一个缺省的cluster issuer,当部署Cert manager的时候,用于支持kubernetes.io/tls-acme: "true"annotation 来自动化 TLS:

ingressShim.defaultIssuerName=letsencrypt-prod
ingressShim.defaultIssuerKind=ClusterIssuer

运行下面的命令部署 Cert manager:

$ helm install --name cert-manager --namespace kube-system --set ingressShim.defaultIssuerName=letsencrypt-prod --set ingressShim.defaultIssuerKind=ClusterIssuer stable/cert-manager --version v0.5.2
NAME:   cert-manager
LAST DEPLOYED: Wed Dec  5 18:04:56 2018
NAMESPACE: kube-system
STATUS: DEPLOYED

RESOURCES:
==> v1/ServiceAccount
NAME          SECRETS  AGE
cert-manager  1        0s

==> v1beta1/CustomResourceDefinition
NAME                               AGE
certificates.certmanager.k8s.io    0s
clusterissuers.certmanager.k8s.io  0s
issuers.certmanager.k8s.io         0s

==> v1beta1/ClusterRole
cert-manager  0s

==> v1beta1/ClusterRoleBinding
NAME          AGE
cert-manager  0s

==> v1beta1/Deployment
NAME          DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
cert-manager  1        1        1           0          0s

==> v1/Pod(related)
NAME                          READY  STATUS             RESTARTS  AGE
cert-manager-dd6856945-9ltk9  0/1    ContainerCreating  0         0s


NOTES:
cert-manager has been deployed successfully!

In order to begin issuing certificates, you will need to set up a ClusterIssuer
or Issuer resource (for example, by creating a 'letsencrypt-staging' issuer).

More information on the different types of issuers and how to configure them
can be found in our documentation:

https://cert-manager.readthedocs.io/en/latest/reference/issuers.html

For information on how to configure cert-manager to automatically provision
Certificates for Ingress resources, take a look at the `ingress-shim`
documentation:

https://cert-manager.readthedocs.io/en/latest/reference/ingress-shim.html

安装完成后,然后查看Pod运行状态:

$ kubectl get pod -n kube-system --selector=app=cert-manager
NAME                                        READY     STATUS    RESTARTS   AGE
cert-manager-cert-manager-7797579f9-m4dbc   1/1       Running   0          1m

除此之外,安装完成后Cert manager还提供了一些Kubernetes custom resources

$ kubectl get crd
NAME                                         AGE
certificates.certmanager.k8s.io              1m
clusterissuers.certmanager.k8s.io            1m
issuers.certmanager.k8s.io                   1m

创建证书签发服务

Cert manager安装后,接下来需要定义上面的letsencrypt-prod这个cluster issuer,这里使用上面的clusterissuers.certmanager.k8s.io这个CRD来定义:(cluster-issuer.yaml)

apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: icnych@gmail.com
    privateKeySecretRef:
      name: letsencrypt-prod
    http01: {}

然后直接创建这个ClusterIssuer资源:

$ kubectl create -f cluster-issuer.yaml
clusterissuer.certmanager.k8s.io "letsencrypt-prod" created
$ kubectl get clusterissuer
NAME               AGE
letsencrypt-prod   16s

测试

上面我们已经安装了Cert manager,定义了ClusterIssuer,接下来我们来配置 HTTPS 去访问我们的 Kubernetes Dashboard 的服务,Dashboard 的部署我们这里就不多说了,直接添加一个 Ingress 资源对象即可:(dashboard-ingress.yaml)

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: kube-ui
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: "traefik"
    kubernetes.io/tls-acme: "true"
spec:
  tls:
  - hosts:
    - k8sui.k8stech.net
    secretName: k8sui-tls
  rules:
  - host: k8sui.k8stech.net
    http:
      paths:
      - path: '/'
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 443

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

$ kubectl create -f dashboard-ingress.yaml

当然如果需要在公网中进行访问,我们还需要将我们这里的域名解析到 Ingress Controller 所在的任意一个节点,或者在本地的/etc/hosts中加上映射也是可以的。

创建完成后隔一会儿我们可以看到会多出现一个随机名称的 Ingress 对象,这个 Ingress 对象就是用来专门验证证书的:

$ kubectl get ingress -n kube-system
NAME                        HOSTS                   ADDRESS   PORTS     AGE
cm-acme-http-solver-hl5sx   k8sui.k8stech.net             80        37s
kube-ui                     k8sui.k8stech.net             80, 443   41s

我们可以通过 Traefik 的 Dashboard 可以观察到这一变化,验证成功后,这个 Ingress 对象也自动删除了: traefik-dashboard-acme

这个时候我们可以去describe下我们的 Ingress 对象:

$ Name:             kube-ui
Namespace:        kube-system
Address:
Default backend:  default-http-backend:80 (<none>)
TLS:
  k8sui-tls terminates k8sui.k8stech.net
Rules:
  Host               Path  Backends
  ----               ----  --------
  k8sui.k8stech.net
                     /   kubernetes-dashboard:443 (10.244.0.31:8443)
Annotations:
  kubernetes.io/tls-acme:       true
  kubernetes.io/ingress.class:  traefik
Events:
  Type    Reason             Age   From          Message
  ----    ------             ----  ----          -------
  Normal  CreateCertificate  13m   cert-manager  Successfully created Certificate "k8sui-tls"

可以看到最后提示成功创建了 Certificate 对象,同样我们可以通过下面的命令获取:

$ kubectl get certificate -n kube-system
NAME        AGE
k8sui-tls   15m

这个时候 Let’s Encrypt 生成的证书文件就已经创建成功了,内容被添加到了上面 Ingress 中声明的 Secret 对象中:

$ kubectl get secret -n kube-system
k8sui-tls                                        kubernetes.io/tls                     2         32m

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

$ kubectl logs -f cert-manager-dd6856945-4drmr -n kube-system
......
 1 sync.go:124] Certificate "k8sui-tls" for ingress "kube-ui" already exists
I1205 16:27:21.372285       1 sync.go:127] Certificate "k8sui-tls" for ingress "kube-ui" is up to date
I1205 16:27:21.372362       1 controller.go:166] ingress-shim controller: Finished processing work item "kube-system/kube-ui"
I1205 16:27:23.371967       1 controller.go:181] certificates controller: syncing item 'kube-system/k8sui-tls'
I1205 16:27:23.372682       1 sync.go:174] Certificate kube-system/k8sui-tls scheduled for renewal in 1430 hours
I1205 16:27:23.372769       1 controller.go:195] certificates controller: Finished processing work item "kube-system/k8sui-tls"

这个时候我们就可以通过 HTTPS 去访问上面我们配置的 Dashboard 的服务了,在浏览器中输入:https://k8sui.k8stech.net,就可以看到会跳转到登录界面了,更重要的是浏览器左上角出现了绿色的认证小图标了: dashboard https

需要注意的是 Dashboard 会使用自己自建的证书,所以我们需要在 Traefik 的配置中添加上配置insecureSkipVerify = true,不去校验后端的证书服务,否则访问会有问题。如果你使用的是其他的 Ingress Controller,这里配置基本上也是一致的,只需要做相应的修改即可。

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

微信公众号

扫描下面的二维码关注我的微信公众号,在微信公众帐号中回复'群'即可加入到我的"kubernetes技术栈"讨论群里面共同学习。

wechat-account-qrcode

「真诚赞赏,手有余香」

青牛踏雪

请我喝杯咖啡?

使用微信扫描二维码完成支付

相关文章