入口 Sidecar TLS 終止
在一般的 Istio 網格部署中,下游請求的 TLS 終止是在 Ingress Gateway 執行。雖然這滿足了大多數的使用案例,但對於某些情況(例如網格中的 API Gateway),Ingress Gateway 並非必要。此任務展示如何消除 Istio Ingress Gateway 引入的額外跳躍,並讓與應用程式一起執行的 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 連接埠的 PeerAuthentication
針對將在 sidecar 執行 Ingress TLS 終止的 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,設定 Ingress 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/*
除了驗證透過 Ingress 連接埠 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