不使用 TLS 終止的入口閘道
「使用 HTTPS 保護閘道安全」任務說明如何設定 HTTPS 入口存取 HTTP 服務。此範例說明如何設定 HTTPS 入口存取 HTTPS 服務,也就是設定入口閘道執行 SNI 直通,而不是終止傳入請求的 TLS。
此任務使用的範例 HTTPS 服務是一個簡單的 NGINX 伺服器。在以下步驟中,您首先在 Kubernetes 叢集中部署 NGINX 服務。然後,您設定一個閘道,以透過主機 nginx.example.com
提供服務的入口存取。
開始之前
依照安裝指南中的說明設定 Istio。
產生用戶端和伺服器憑證與金鑰
對於此任務,您可以使用您最喜歡的工具來產生憑證和金鑰。以下命令使用 openssl
建立根憑證和私鑰,以簽署服務的憑證
$ mkdir example_certs $ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout example_certs/example.com.key -out example_certs/example.com.crt
建立
nginx.example.com
的憑證和私鑰$ openssl req -out example_certs/nginx.example.com.csr -newkey rsa:2048 -nodes -keyout example_certs/nginx.example.com.key -subj "/CN=nginx.example.com/O=some organization" $ openssl x509 -req -sha256 -days 365 -CA example_certs/example.com.crt -CAkey example_certs/example.com.key -set_serial 0 -in example_certs/nginx.example.com.csr -out example_certs/nginx.example.com.crt
部署 NGINX 伺服器
建立 Kubernetes Secret,以保存伺服器的憑證。
$ kubectl create secret tls nginx-server-certs \ --key example_certs/nginx.example.com.key \ --cert example_certs/nginx.example.com.crt
為 NGINX 伺服器建立設定檔
$ cat <<\EOF > ./nginx.conf events { } http { log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; error_log /var/log/nginx/error.log; server { listen 443 ssl; root /usr/share/nginx/html; index index.html; server_name nginx.example.com; ssl_certificate /etc/nginx-server-certs/tls.crt; ssl_certificate_key /etc/nginx-server-certs/tls.key; } } EOF
建立 Kubernetes ConfigMap,以保存 NGINX 伺服器的設定
$ kubectl create configmap nginx-configmap --from-file=nginx.conf=./nginx.conf
部署 NGINX 伺服器
$ cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 443 protocol: TCP selector: run: my-nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx sidecar.istio.io/inject: "true" spec: containers: - name: my-nginx image: nginx ports: - containerPort: 443 volumeMounts: - name: nginx-config mountPath: /etc/nginx readOnly: true - name: nginx-server-certs mountPath: /etc/nginx-server-certs readOnly: true volumes: - name: nginx-config configMap: name: nginx-configmap - name: nginx-server-certs secret: secretName: nginx-server-certs EOF
為了測試 NGINX 伺服器是否成功部署,請從其 sidecar 代理傳送請求至伺服器,而不檢查伺服器的憑證(使用
curl
的-k
選項)。確保伺服器的憑證正確列印,即common name (CN)
等於nginx.example.com
。$ kubectl exec "$(kubectl get pod -l run=my-nginx -o jsonpath={.items..metadata.name})" -c istio-proxy -- curl -sS -v -k --resolve nginx.example.com:443:127.0.0.1 https://nginx.example.com ... SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 ALPN, server accepted to use http/1.1 Server certificate: subject: CN=nginx.example.com; O=some organization start date: May 27 14:18:47 2020 GMT expire date: May 27 14:18:47 2021 GMT issuer: O=example Inc.; CN=example.com SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway. > GET / HTTP/1.1 > User-Agent: curl/7.58.0 > Host: nginx.example.com ... < HTTP/1.1 200 OK < Server: nginx/1.17.10 ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> ...
設定入口閘道
- 定義一個
Gateway
,以直通 TLS 模式公開 443 連接埠。這指示閘道「依原樣」傳遞入口流量,而不終止 TLS
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: mygateway
spec:
selector:
istio: ingressgateway # use istio default ingress gateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: PASSTHROUGH
hosts:
- nginx.example.com
EOF
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: mygateway
spec:
gatewayClassName: istio
listeners:
- name: https
hostname: "nginx.example.com"
port: 443
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: All
EOF
- 設定透過
Gateway
進入的流量路由
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: nginx
spec:
hosts:
- nginx.example.com
gateways:
- mygateway
tls:
- match:
- port: 443
sniHosts:
- nginx.example.com
route:
- destination:
host: my-nginx
port:
number: 443
EOF
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: nginx
spec:
parentRefs:
- name: mygateway
hostnames:
- "nginx.example.com"
rules:
- backendRefs:
- name: my-nginx
port: 443
EOF
- 確定入口 IP 和連接埠
使用以下命令設定 SECURE_INGRESS_PORT
和 INGRESS_HOST
環境變數
$ kubectl wait --for=condition=programmed gtw mygateway
$ export INGRESS_HOST=$(kubectl get gtw mygateway -o jsonpath='{.status.addresses[0].value}')
$ export SECURE_INGRESS_PORT=$(kubectl get gtw mygateway -o jsonpath='{.spec.listeners[?(@.name=="https")].port}')
從叢集外部存取 NGINX 服務。請注意,伺服器會傳回正確的憑證,且已成功驗證(會列印 SSL certificate verify ok)。
$ curl -v --resolve "nginx.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" --cacert example_certs/example.com.crt "https://nginx.example.com:$SECURE_INGRESS_PORT" Server certificate: subject: CN=nginx.example.com; O=some organization start date: Wed, 15 Aug 2018 07:29:07 GMT expire date: Sun, 25 Aug 2019 07:29:07 GMT issuer: O=example Inc.; CN=example.com SSL certificate verify ok. < HTTP/1.1 200 OK < Server: nginx/1.15.2 ... <html> <head> <title>Welcome to nginx!</title>
清理
- 刪除閘道設定和路由
$ kubectl delete gateway mygateway
$ kubectl delete virtualservice nginx
$ kubectl delete gtw mygateway
$ kubectl delete tlsroute nginx
移除 NGINX 資源和設定檔
$ kubectl delete secret nginx-server-certs $ kubectl delete configmap nginx-configmap $ kubectl delete service my-nginx $ kubectl delete deployment my-nginx $ rm ./nginx.conf
刪除憑證和金鑰
$ rm -rf ./example_certs