不使用 TLS 終止的入口閘道

使用 HTTPS 保護閘道安全」任務說明如何設定 HTTPS 入口存取 HTTP 服務。此範例說明如何設定 HTTPS 入口存取 HTTPS 服務,也就是設定入口閘道執行 SNI 直通,而不是終止傳入請求的 TLS。

此任務使用的範例 HTTPS 服務是一個簡單的 NGINX 伺服器。在以下步驟中,您首先在 Kubernetes 叢集中部署 NGINX 服務。然後,您設定一個閘道,以透過主機 nginx.example.com 提供服務的入口存取。

開始之前

依照安裝指南中的說明設定 Istio。

產生用戶端和伺服器憑證與金鑰

對於此任務,您可以使用您最喜歡的工具來產生憑證和金鑰。以下命令使用 openssl

  1. 建立根憑證和私鑰,以簽署服務的憑證

    $ 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
    
  2. 建立 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 伺服器

  1. 建立 Kubernetes Secret,以保存伺服器的憑證。

    $ kubectl create secret tls nginx-server-certs \
      --key example_certs/nginx.example.com.key \
      --cert example_certs/nginx.example.com.crt
    
  2. 為 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
    
  3. 建立 Kubernetes ConfigMap,以保存 NGINX 伺服器的設定

    $ kubectl create configmap nginx-configmap --from-file=nginx.conf=./nginx.conf
    
  4. 部署 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
    
  5. 為了測試 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>
    ...
    

設定入口閘道

  1. 定義一個 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
  1. 設定透過 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
  1. 確定入口 IP 和連接埠
依照確定入口 IP 和連接埠中的說明設定 SECURE_INGRESS_PORTINGRESS_HOST 環境變數。
  1. 從叢集外部存取 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>
    

清理

  1. 刪除閘道設定和路由
$ kubectl delete gateway mygateway
$ kubectl delete virtualservice nginx
  1. 移除 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
    
  2. 刪除憑證和金鑰

    $ rm -rf ./example_certs
    
這項資訊對您有幫助嗎?
您是否有任何改進建議?

感謝您的回饋!