使用 cert-manager 加密 Kubernetes Ingress
这个例子演示了在 Istio 中使用 Let’s Encrypt 获取 TLS 证书为 Kubernetes Ingress controller 提供安全加固的过程。虽然 Istio 提供了更强大的功能,例如 Gateway 和 Virtual service,它们可以用于更加高级的流量管理功能,而可选的 Kubernetes Ingress 控制器支持则可以简单的把传统应用和第三方解决方案集成到服务网格之中,并由此获得 Istio 提供的遥测和跟踪能力。
首先要从一个全新安装的 Istio 入手,创建一个示例应用,并利用 Kubernetes Ingress
资源将服务开放出去,Istio 可以为这一过程提供加密服务,它调用自带的 cert-manager 管理 TLS 证书的签发和续期,然后把证书分发给 Istio 的 Ingress gateway,并在必要时使用 SDS 进行证书的热交换。
开始之前
安装 Istio 并确认已经启用 Ingress Gateway 的 Kubernetes Ingress 支持、SDS 以及 cert-manager。下面的例子展示了使用 Helm template 完成设置这些依赖项目的方法:
$ helm template $HOME/istio-fetch/istio \
--namespace=istio-system \
--set gateways.istio-ingressgateway.sds.enabled=true \
--set global.k8sIngress.enabled=true \
--set global.k8sIngress.enableHttps=true \
--set global.k8sIngress.gatewayName=ingressgateway \
--set certmanager.enabled=true \
--set certmanager.email=mailbox@donotuseexample.com \
> $HOME/istio-fetch/istio.yaml
配置 DNS 名称和 Gateway
记录一下 istio-ingressgateway
服务的外部 IP 地址:
$ kubectl -n istio-system get service istio-ingressgateway
对你的 DNS 进行设置,给 istio-ingressgateway
服务的外部 IP 地址分配一个合适的域名。为了能让例子正常执行,需要一个真正的域名,用于签署 TLS 证书。可以把域名保存为环境变量,便于后面的使用:
$ INGRESS_DOMAIN=mysubdomain.mydomain.edu
Istio 安装中包含了一个自动生成的 Gateway,用于给 Kubernetes Ingress
资源提供路由服务。缺省情况下,它不会使用 SDS,所以需要对其进行修改,让 SDS 来为 istio-ingressgateway
分发 TLS 证书:
$ kubectl -n istio-system edit gateway
然后修改 https-default
端口对应的 tls
内容:
$ kubectl -n istio-system \
patch gateway istio-autogenerated-k8s-ingress --type=json \
-p='[{"op": "replace", "path": "/spec/servers/1/tls", "value": {"credentialName": "ingress-cert-staging", "mode": "SIMPLE", "privateKey": "sds", "serverCertificate": "sds"}}]'
现在就可以部署一个演示应用了。
部署演示应用
接下来使用一个简单的 helloworld
应用来进行演示。下面的命令会为示例应用创建 Deployment
和 Service
对象,并使用 istio-ingressgateway
所支持的 Ingress
资源开放服务。
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: helloworld
labels:
app: helloworld
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: helloworld
spec:
template:
metadata:
labels:
app: helloworld
spec:
containers:
- name: helloworld
image: istio/examples-helloworld-v1
resources:
requests:
cpu: "100m"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: istio
name: helloworld-ingress
spec:
rules:
- host: "$INGRESS_DOMAIN"
http:
paths:
- path: /hello
backend:
serviceName: helloworld
servicePort: 5000
---
EOF
现在就可以用 HTTP 来访问演示应用了:
$ curl http://$INGRESS_DOMAIN/hello
Hello version: v1, instance: helloworld-5d498979b6-jp2mf
因为没有配置任何的 TLS 证书,所以 HTTPS 访问还未能启用,下面就开始进行配置。
使用 cert-manager 获取 Let’s Encrypt 证书
目前的 Istio 中应该已经启动了 cert-manager,并带有两个 ClusterIssuer
对象(分别对应 Let’s Encrypt 的生产和演练环境)。这个例子中可以使用演练环境(letsencrypt-staging
替换为 letsencrypt
就能获得受浏览器信任的证书),
为了用 cert-manager 进行证书的签发和管理,需要创建一个 Certificate
资源:
$ cat <<EOF | kubectl apply -f -
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
name: ingress-cert-staging
namespace: istio-system
spec:
secretName: ingress-cert-staging
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
commonName: $INGRESS_DOMAIN
dnsNames:
- $INGRESS_DOMAIN
acme:
config:
- http01:
ingressClass: istio
domains:
- $INGRESS_DOMAIN
---
EOF
注意这里的 secretName
要匹配前面配置 Gateway 资源时其中的 credentialName
字段值。Certificate
对象会被 cert-manager 处理,最终会签发新证书。可以通过对 Certificate
对象状态的查询来得知整个过程的进展:
$ kubectl -n istio-system describe certificate ingress-cert-staging
-> 状态最终会切换为 'Certificate issued successfully'
这样一来就可以使用 HTTPS 进行访问了:
$ curl --insecure https://$INGRESS_DOMAIN/hello
Hello version: v1, instance: helloworld-5d498979b6-jp2mf
注意,因为演练环境签发的证书不受信任,这里用了 --insecure
参数。