使用 Cert-Manager 加密 Kubernetes Ingress
这个例子演示了在 Istio 中使用 Let’s Encrypt 签发 TLS 证书为 Kubernetes Ingress controller 提供安全加固的过程。
您将从全新的 Istio 安装开始,创建示例服务,使用 Kubernetes Ingress 把它开放出去,并使用 cert-manager(与 Istio 捆绑在一起)管理 TLS 证书的签发和续订来确保它的安全,这个证书之后会给 Istio ingress gateway 使用,并根据需要通过 Secrets Discovery Service (SDS) 提供 hot-swapped 功能。
开始之前
$ istioctl manifest apply \
--set values.gateways.istio-ingressgateway.sds.enabled=true \
--set values.global.k8sIngress.enabled=true \
--set values.global.k8sIngress.enableHttps=true \
--set values.global.k8sIngress.gatewayName=ingressgateway
默认情况下, istio-ingressgateway
会以 LoadBalancer
的服务类型开放出来。您可以根据自己的 Kubernetes 环境把 gateways.istio-ingressgateway.type
设置为 NodePort
。
- 安装 cert-manager 以便实现证书的自动管理。
配置 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", "mode": "SIMPLE", "privateKey": "sds", "serverCertificate": "sds"}}]'
现在就可以部署一个演示应用了。
部署演示应用
接下来使用一个简单的 helloworld
应用来进行演示。下面的命令会为示例应用创建 Deployment
和 Service
,并使用 Istio 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: apps/v1
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: networking.k8s.io/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
注意,这里用了前面定义的 INGRESS_DOMAIN
变量。
现在,您应该能够通过 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 的生产和测试 ACME-endpoints)。这个例子中使用测试 ACME-endpoint(将 letsencrypt-staging
替换为 letsencrypt
就能获得浏览器信任的证书)。
为了用 cert-manager 进行证书的签发和管理,需要创建一个 Certificate 对象:
$ cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: ingress-cert
namespace: istio-system
spec:
secretName: ingress-cert
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
-> 状态最终会切换为 'Certificate issued successfully'
这样一来,该服务也应通过 HTTPS 访问了:
$ curl --insecure https://$INGRESS_DOMAIN/hello
Hello version: v1, instance: helloworld-5d498979b6-jp2mf
注意,您需要使用 —insecure
参数,因为测试 ACME-endpoints 签发的证书不受信任。
从测试到生产
现在换成生产 letsencrypt
。首先,我们重新申请一下证书。
$ cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: ingress-cert
namespace: istio-system
spec:
secretName: ingress-cert
issuerRef:
name: letsencrypt
kind: ClusterIssuer
commonName: $INGRESS_DOMAIN
dnsNames:
- $INGRESS_DOMAIN
acme:
config:
- http01:
ingressClass: istio
domains:
- $INGRESS_DOMAIN
---
EOF
certificate.cert-manager.io/ingress-cert configured
现在删除 secret 来强制 cert-manager 从生产 ACME-endpoints 请求新证书:
$ kubectl delete secret -n istio-system ingress-cert
等等看证书是否成功签发了:
$ watch -n1 kubectl describe cert ingress-cert -n istio-system
您应该能看到如下显示:
Normal CertIssued 13m cert-manager Certificate issued successfully
相关内容
把 Istio 入口网关配置为外部服务的代理。
说明了如何为一个 ingress gateway 配置 SNI 透传。
使用 Cert-Manager 部署一个自定义 Ingress 网关
如何使用 cert-manager 手工部署一个自定义 Ingress 网关。
描述如何在 AWS 上使用网络负载均衡器配置 Istio Ingress。
描述基于 Istio Bookinfo 示例的简单场景。
描述如何配置 Istio gateway,以将服务暴露至服务网格之外。