Ingress Sidecar TLS 终止
在常规 Istio 网格部署中,下游请求的 TLS 终止在入口网关处执行。尽管这满足了大多数用例,但对于某些用例(例如网格中的 API 网关),入口网关并非必需。此任务演示了如何消除 Istio 入口网关引入的额外跳跃,并让与应用程序一起运行的 Envoy sidecar 为来自服务网格外部的请求执行 TLS 终止。
此任务中使用的示例 HTTPS 服务是一个简单的 httpbin 服务。在以下步骤中,您将在服务网格内部署 httpbin 服务并对其进行配置。
开始之前
按照 安装指南 中的说明设置 Istio,并启用实验性功能
ENABLE_TLS_ON_SIDECAR_INGRESS
。$ istioctl install --set profile=default --set values.pilot.env.ENABLE_TLS_ON_SIDECAR_INGRESS=true
创建目标
httpbin
服务将部署到的测试命名空间。确保为命名空间启用 sidecar 注入。$ kubectl create ns test $ kubectl label namespace test istio-injection=enabled
启用全局 mTLS
应用以下 PeerAuthentication
策略以要求网格中所有工作负载的 mTLS 流量。
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
EOF
禁用外部公开的 httpbin 端口的对等身份验证
禁用执行入口 TLS 终止的 sidecar 端 httpbin 服务的端口上的PeerAuthentication
。请注意,这是 httpbin 服务的targetPort
,应专门用于外部通信。
$ kubectl -n test apply -f - <<EOF
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: disable-peer-auth-for-external-mtls-port
namespace: test
spec:
selector:
matchLabels:
app: httpbin
mtls:
mode: STRICT
portLevelMtls:
9080:
mode: DISABLE
EOF
生成 CA 证书、服务器证书/密钥和客户端证书/密钥
对于此任务,您可以使用您喜欢的工具生成证书和密钥。以下命令使用openssl
$ #CA is example.com
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example.com.key -out example.com.crt
$ #Server is httpbin.test.svc.cluster.local
$ openssl req -out httpbin.test.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout httpbin.test.svc.cluster.local.key -subj "/CN=httpbin.test.svc.cluster.local/O=httpbin organization"
$ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in httpbin.test.svc.cluster.local.csr -out httpbin.test.svc.cluster.local.crt
$ #client is client.test.svc.cluster.local
$ openssl req -out client.test.svc.cluster.local.csr -newkey rsa:2048 -nodes -keyout client.test.svc.cluster.local.key -subj "/CN=client.test.svc.cluster.local/O=client organization"
$ openssl x509 -req -days 365 -CA example.com.crt -CAkey example.com.key -set_serial 1 -in client.test.svc.cluster.local.csr -out client.test.svc.cluster.local.crt
为证书和密钥创建 k8s 密钥
$ kubectl -n test create secret generic httpbin-mtls-termination-cacert --from-file=ca.crt=./example.com.crt
$ kubectl -n test create secret tls httpbin-mtls-termination --cert ./httpbin.test.svc.cluster.local.crt --key ./httpbin.test.svc.cluster.local.key
部署 httpbin 测试服务
创建 httpbin 部署时,我们需要在部署中使用userVolumeMount
注释来挂载 istio-proxy sidecar 的证书。请注意,此步骤仅在 Istio 目前不支持 sidecar 配置中的credentialName
时才需要。
sidecar.istio.io/userVolume: '{"tls-secret":{"secret":{"secretName":"httpbin-mtls-termination","optional":true}},"tls-ca-secret":{"secret":{"secretName":"httpbin-mtls-termination-cacert"}}}'
sidecar.istio.io/userVolumeMount: '{"tls-secret":{"mountPath":"/etc/istio/tls-certs/","readOnly":true},"tls-ca-secret":{"mountPath":"/etc/istio/tls-ca-certs/","readOnly":true}}'
使用以下命令部署具有所需userVolumeMount
配置的httpbin
服务
$ kubectl -n test apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- port: 8443
name: https
targetPort: 9080
- port: 8080
name: http
targetPort: 9081
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
annotations:
sidecar.istio.io/userVolume: '{"tls-secret":{"secret":{"secretName":"httpbin-mtls-termination","optional":true}},"tls-ca-secret":{"secret":{"secretName":"httpbin-mtls-termination-cacert"}}}'
sidecar.istio.io/userVolumeMount: '{"tls-secret":{"mountPath":"/etc/istio/tls-certs/","readOnly":true},"tls-ca-secret":{"mountPath":"/etc/istio/tls-ca-certs/","readOnly":true}}'
spec:
serviceAccountName: httpbin
containers:
- image: docker.io/kennethreitz/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80
EOF
配置 httpbin 以启用外部 mTLS
这是此功能的核心步骤。使用Sidecar
API 配置入口 TLS 设置。TLS 模式可以是SIMPLE
或MUTUAL
。此示例使用MUTUAL
。
$ kubectl -n test apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Sidecar
metadata:
name: ingress-sidecar
namespace: test
spec:
workloadSelector:
labels:
app: httpbin
version: v1
ingress:
- port:
number: 9080
protocol: HTTPS
name: external
defaultEndpoint: 0.0.0.0:80
tls:
mode: MUTUAL
privateKey: "/etc/istio/tls-certs/tls.key"
serverCertificate: "/etc/istio/tls-certs/tls.crt"
caCertificates: "/etc/istio/tls-ca-certs/ca.crt"
- port:
number: 9081
protocol: HTTP
name: internal
defaultEndpoint: 0.0.0.0:80
EOF
验证
现在 httpbin 服务器已部署并配置,启动两个客户端以测试从网格内部和外部进行的端到端连接
- 一个内部客户端(curl)与 httpbin 服务位于相同的命名空间(test)中,并注入了 sidecar。
- 一个外部客户端(curl)位于默认命名空间(即服务网格外部)。
$ kubectl apply -f samples/curl/curl.yaml
$ kubectl -n test apply -f samples/curl/curl.yaml
运行以下命令以验证一切是否已启动并运行,以及是否已正确配置。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
curl-557747455f-xx88g 1/1 Running 0 4m14s
$ kubectl get pods -n test
NAME READY STATUS RESTARTS AGE
httpbin-5bbdbd6588-z9vbs 2/2 Running 0 8m44s
curl-557747455f-brzf6 2/2 Running 0 6m57s
$ kubectl get svc -n test
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin ClusterIP 10.100.78.113 <none> 8443/TCP,8080/TCP 10m
curl ClusterIP 10.110.35.153 <none> 80/TCP 8m49s
在以下命令中,将httpbin-5bbdbd6588-z9vbs
替换为您自己的 httpbin pod 的名称。
$ istioctl proxy-config secret httpbin-5bbdbd6588-z9vbs.test
RESOURCE NAME TYPE STATUS VALID CERT SERIAL NUMBER NOT AFTER NOT BEFORE
file-cert:/etc/istio/tls-certs/tls.crt~/etc/istio/tls-certs/tls.key Cert Chain ACTIVE true 1 2023-02-14T09:51:56Z 2022-02-14T09:51:56Z
default Cert Chain ACTIVE true 329492464719328863283539045344215802956 2022-02-15T09:55:46Z 2022-02-14T09:53:46Z
ROOTCA CA ACTIVE true 204427760222438623495455009380743891800 2032-02-07T16:58:00Z 2022-02-09T16:58:00Z
file-root:/etc/istio/tls-ca-certs/ca.crt Cert Chain ACTIVE true 14033888812979945197 2023-02-14T09:51:56Z 2022-02-14T09:51:56Z
验证端口 8080 上的内部网格连接
$ export INTERNAL_CLIENT=$(kubectl -n test get pod -l app=curl -o jsonpath={.items..metadata.name})
$ kubectl -n test exec "${INTERNAL_CLIENT}" -c curl -- curl -IsS "http://httpbin:8080/status/200"
HTTP/1.1 200 OK
server: envoy
date: Mon, 24 Oct 2022 09:04:52 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 5
验证端口 8443 上的外部到内部网格连接
要验证来自外部客户端的 mTLS 流量,首先将 CA 证书和客户端证书/密钥复制到在默认命名空间中运行的 curl 客户端。
$ export EXTERNAL_CLIENT=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
$ kubectl cp client.test.svc.cluster.local.key default/"${EXTERNAL_CLIENT}":/tmp/
$ kubectl cp client.test.svc.cluster.local.crt default/"${EXTERNAL_CLIENT}":/tmp/
$ kubectl cp example.com.crt default/"${EXTERNAL_CLIENT}":/tmp/ca.crt
现在外部 curl 客户端可以使用这些证书了,您可以使用以下命令验证其与内部 httpbin 服务的连接。
$ kubectl exec "${EXTERNAL_CLIENT}" -c curl -- curl -IsS --cacert /tmp/ca.crt --key /tmp/client.test.svc.cluster.local.key --cert /tmp/client.test.svc.cluster.local.crt -HHost:httpbin.test.svc.cluster.local "https://httpbin.test.svc.cluster.local:8443/status/200"
server: istio-envoy
date: Mon, 24 Oct 2022 09:05:31 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 4
x-envoy-decorator-operation: ingress-sidecar.test:9080/*
除了通过入口端口 8443 验证外部 mTLS 连接外,还必须验证端口 8080 是否不接受任何外部 mTLS 流量。
$ kubectl exec "${EXTERNAL_CLIENT}" -c curl -- curl -IsS --cacert /tmp/ca.crt --key /tmp/client.test.svc.cluster.local.key --cert /tmp/client.test.svc.cluster.local.crt -HHost:httpbin.test.svc.cluster.local "http://httpbin.test.svc.cluster.local:8080/status/200"
curl: (56) Recv failure: Connection reset by peer
command terminated with exit code 56
清理双向 TLS 终止示例
删除已创建的 Kubernetes 资源
$ kubectl delete secret httpbin-mtls-termination httpbin-mtls-termination-cacert -n test $ kubectl delete service httpbin curl -n test $ kubectl delete deployment httpbin curl -n test $ kubectl delete namespace test $ kubectl delete service curl $ kubectl delete deployment curl
删除证书和私钥
$ rm example.com.crt example.com.key httpbin.test.svc.cluster.local.crt httpbin.test.svc.cluster.local.key httpbin.test.svc.cluster.local.csr \ client.test.svc.cluster.local.crt client.test.svc.cluster.local.key client.test.svc.cluster.local.csr
从您的集群中卸载 Istio
$ istioctl uninstall --purge -y