通过ASM网关启用TLS透传

在ASM网关和Sideca代理之间,所有数据均通过mTLS隧道传输。如果应用注入了Sidecar,建议在网关处配置TLS终止,此时仍能保证全程加密。如果应用没有注入Sidecar或者有其他特殊情况,ASM网关同样支持TLS透传。本文介绍如何通过ASM网关启用TLS透传,以实现对集群内HTTPS服务的安全入口访问。

前提条件

步骤一:生成服务器证书和私钥

如果您已经拥有针对sample.aliyun.com可用的证书和私钥,需要将密钥命名为sample.aliyun.com.key,证书命名为sample.aliyun.com.crt。如果没有,可以通过openssl执行以下操作来生成证书和密钥。

  1. 执行以下命令,创建根证书和私钥。

    openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=mynginx Inc./CN=aliyun.com' -keyout aliyun.root.key -out aliyun.root.crt 
  2. 执行以下命令,为sample.aliyun.com服务器生成证书和私钥。

    openssl req -out sample.aliyun.com.csr -newkey rsa:2048 -nodes -keyout sample.aliyun.com.key -subj "/CN=sample.aliyun.com/O=mynginx sample organization"
    openssl x509 -req -days 365 -CA aliyun.root.crt -CAkey aliyun.root.key -set_serial 0 -in sample.aliyun.com.csr -out sample.aliyun.com.crt

步骤二:定义内部服务

示例中的内部服务是基于Nginx实现的,首先为Nginx服务器创建配置文件。以域名aliyun.com的内部服务为例,定义请求根路径直接返回字样Welcome to aliyun.com without TLS Termination!及状态码200。mynginx.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;
    location / {
        return 200 'Welcome to aliyun.com without TLS Termination!';
        add_header Content-Type text/plain;
    }
    server_name www.aliyun.com;
    ssl_certificate /etc/nginx-server-certs/tls.crt;
    ssl_certificate_key /etc/nginx-server-certs/tls.key;
  }
}
  1. 在入口网关Pod所在的集群对应的kubeconfig环境下,执行以下命令,创建Kubernetes ConfigMap存储Nginx服务器的配置。

    kubectl create configmap mynginx-configmap --from-file=nginx.conf=./mynginx.conf​
  2. 在入口网关Pod所在的集群对应的kubeconfig环境下,执行以下命令,将在default命名空间中创建包含证书和私钥的Secret。

    kubectl create secret tls nginx-server-certs --key sample.aliyun.com.key --cert sample.aliyun.com.crt​
  3. 为default命名空间启用Sidecar网格代理自动注入。具体操作,请参见启用自动注入

  4. 创建并拷贝以下内容到mynginxapp.yaml文件中,并执行kubectl apply -f mynginxapp.yaml命令,创建域名aliyun.com的内部服务。

    展开查看mynginxapp.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: mynginxapp
      labels:
        app: mynginxapp
    spec:
      ports:
      - port: 443
        protocol: TCP
      selector:
        app: mynginxapp
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mynginxapp
    spec:
      selector:
        matchLabels:
          app: mynginxapp
      replicas: 1
      template:
        metadata:
          labels:
            app: mynginxapp
        spec:
          containers:
          - name: nginx
            image: nginx:1.15
            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: mynginx-configmap
          - name: nginx-server-certs
            secret:
              secretName: nginx-server-certs    
  5. 确认Nginx服务器已成功部署,执行以下命令从其sidecar代理向服务器发送请求。

    kubectl exec -it $(kubectl get pod  -l app=mynginxapp -o jsonpath={.items..metadata.name}) -c istio-proxy -- curl -v -k --resolve sample.aliyun.com:443:127.0.0.1 https://sample.aliyun.com

步骤三:创建网关规则

  1. 登录ASM控制台

  2. 在左侧导航栏,选择服务网格 > 网格管理

  3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

  4. 在网格详情页面左侧导航栏,选择ASM网关 > 网关规则,然后在右侧页面,单击使用YAML创建

  5. 按以下步骤定义网关规则,然后单击创建

    1. 选择相应的命名空间。本文以选择default命名空间为例。

    2. 在弹出窗口的文本框中,定义服务网关。可参考以下YAML定义。

      apiVersion: networking.istio.io/v1alpha3
      kind: Gateway
      metadata:
        name: istio-mynginx-customingressgateway
      spec:
        selector:
          istio: ingressgateway
        servers:
        - hosts:
          - 'sample.aliyun.com'
          port:
            name: https
            number: 443
            protocol: HTTPS
          tls:
            mode: PASSTHROUGH

    在网关规则(Gateway)页面可以看到新建的网关。

步骤四:创建虚拟服务

  1. 登录ASM控制台

  2. 在左侧导航栏,选择服务网格 > 网格管理

  3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

  4. 在网格详情页面左侧导航栏,选择流量管理中心 > 虚拟服务,然后在右侧页面,单击使用YAML创建

  5. 按以下步骤定义虚拟服务,然后单击创建

    1. 选择相应的命名空间。本文以选择default命名空间为例。

    2. 在文本框中,定义Istio虚拟服务。可参考以下YAML定义。

      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: istio-mynginx-customvirtualservice
      spec:
        hosts:
        - "sample.aliyun.com"
        gateways:
        - istio-mynginx-customingressgateway
        tls:
        - match:
          - port: 443
            sniHosts:
            - sample.aliyun.com
          route:
          - destination:
              host: mynginxapp.default.svc.cluster.local
              port:
                number: 443

    在虚拟服务(VirtualService)页面可以看到新建的虚拟服务。

执行结果

  1. 通过以下任意方式获取入口网关的地址。

    1. 方式一:通过控制台获取。具体操作,请参见获取入口网关地址

    2. 方式二:通过kubectl命令获取。

      在入口网关Pod所在的集群对应的KubeConfig环境下,执行以下命令,获取入口网关的地址。

      kubectl get svc -n istio-system -l istio=ingressgateway
  2. 执行以下命令,通过HTTPS协议访问aliyun.com服务。

    curl -v --cacert aliyun.root.crt --resolve sample.aliyun.com:443:xx.xx.xx.xx   https://sample.aliyun.com

    预期输出:

    Welcome to aliyun.com without TLS Termination!%