为什么要管理TLS Secret证书

使用ingress将服务以https暴露到集群外边时,需要ssl证书。在https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tls这个例子中, ingress的定义如下:

 1apiVersion: extensions/v1beta1
 2kind: Ingress
 3metadata:
 4  name: foo
 5  namespace: default
 6spec:
 7  tls:
 8  - hosts:
 9    - foo.bar.com
10    secretName: foo-secret
11  rules:
12  - host: foo.bar.com
13    http:
14      paths:
15      - backend:
16          serviceName: echoheaders-x
17          servicePort: 80
18        path: /

对于域名foo.bar.com的证书引用的是相同namespace下的secret foo-secret。 这说明在Kubernetes中管理站点的TLS证书,使用的是Secret。

假设在已经取得foo.bar.com的证书和私钥分别为foo.bar.com.crtfoo.bar.com.key,使用下面的命令就可以在default命名空间中创建TLS类型的Secret:

1kubectl create secret tls foo-secret --cert=foo.bar.com.crt --key=foo.bar.com.key -n default

实际情况中,我们的证书往往都是泛域名的证书,例如对于frognew.com,是支持*.frognew.com所有的二级域名的。 不同的服务的Ingress被创建在不同的namespace中,每个namespace中都需要创建TLS Secret。 因此需要一种更加整合和高效的方式管理TLS Secret。

先来看一下微服务在开发和部署上要考虑的两个问题:

  • 微服务在开发上需要考虑如何“拆”的问题(拆分的时机、拆分的粒度、拆分的方式)
  • 微服务在部署时需要考虑整合与集成的问题,即如何“合”

使用helm管理Ingress的TLS Secret证书

一个产品由多个微服务组成,这个产品部署到Kubernetes上,每个服务都可能需要在Kubernetes上创建下面几种资源:Ingress, Service, Deployment, ConfigMap, Secret,Job,CronJob等等。我们已经使用Helm,将产品的各个微服务在部署上当成一个逻辑整体,即为每个产品创建一个helm chart,这个helmchart包含了产品所有微服务的部署,将前面每个服务所需要的资源模板化。本篇要解决的是如何整合和高效的管理Ingress的TLS Secret,即将TLS Secret的创建也集成到产品的这个helm chart中。

helm的模板功能十分强大,这里演示一下如何使用heml chart在Kubernetes管理TLS证书,先简单实现一下:

chart的模板文件tls-secrets.yaml:

 1{% raw %}
 2{{- range $tlsSecretName, $tlsSecret := .Values.tlsSecrets }}
 3apiVersion: v1
 4kind: Secret
 5type: kubernetes.io/tls
 6metadata:
 7  name: {{ $tlsSecretName }}
 8  labels:
 9    chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }}
10    release: {{ $.Release.Name }}
11    heritage: {{ $.Release.Service }}
12data:
13  tls.crt: {{ $tlsSecret.certificate | b64enc }}
14  tls.key: {{ $tlsSecret.key | b64enc }}
15{{- end }}
16{% endraw %}

values.yaml:

 1tlsSecrets:
 2  foo-secret:
 3    certificate: |-
 4      -----BEGIN CERTIFICATE-----
 5      .....
 6      -----END CERTIFICATE-----
 7      -----BEGIN CERTIFICATE-----
 8      .....
 9      -----END CERTIFICATE-----      
10    key: |-
11      -----BEGIN PRIVATE KEY-----
12      ......
13      -----END PRIVATE KEY-----      

values.yaml中提供每个TLS Secret的证书和私钥的文本内容,在tls-secrets.yaml中使用模板的b64enc函数,将证书内容编码成Secret所需的Base64。 这样TLS Secret也使用helm管理起来了。

我们的实践

我们实际实践中使用的是另一种方式,利用了helm的文件访问功能Accessing Files Inside Templates

将证书文件直接放到Chart目录的files子目录下:

 1.
 2├── charts
 3├── Chart.yaml
 4├── files
 5│   └── frognew.com
 6│       ├── cert.pem
 7│       ├── chain.pem
 8│       ├── fullchain.pem
 9│       ├── privkey.pem
10│       └── README
11├── templates
12    ├── ......
13│   └── tls-secrets.yaml
14├── values.yaml

chart的模板文件tls-secrets.yaml:

 1{% raw %}
 2{{- range $tlsSecretName, $tlsSecret := .Values.tlsSecrets }}
 3apiVersion: v1
 4kind: Secret
 5type: kubernetes.io/tls
 6metadata:
 7  name: {{ $tlsSecretName }}
 8  labels:
 9    chart: {{ $.Chart.Name }}-{{ $.Chart.Version | replace "+" "_" }}
10    release: {{ $.Release.Name }}
11    heritage: {{ $.Release.Service }}
12data:
13  tls.crt: {{ $.Files.Get $tlsSecret.certificate | b64enc }}
14  tls.key: {{ $.Files.Get $tlsSecret.key | b64enc }}
15{{- end }}
16{% endraw %}

values.yaml:

1tlsSecrets:
2  frognew-tls-secret:
3      certificate: "files/frognew.com/fullchain.pem"
4      key: "files/frognew.com/privkey.pem"

使用Files.Get去读取证书文件内容,通过b64enc编码为Base64。

  • 这种将证书文件放到Chart中的使用方式需要注意受限于Kubernetes限制,Chart的大小不能超过1MB。

总结

本文介绍了如何使用Helm在Kubernetes中整合管理Ingress的TLS Secret证书,其实对于其它类型的Secret也是通用的。例如对于Opaque Secretkubernetes.io/dockercfg Secret都可以纳入到helm chart管理中。这样部署一个应用所需要的所有资源就全部纳入Helm Chart管理了。

参考