本文发布于Cylon的收藏册,转载请著名原文链接~


环境准备

主机 角色 数量
front-envoy front envoy 1
service envoy 作为内部后端的envoy 2
end 后端应用程序 2

访问 / front-envoy ==> end * 2 访问 /red/colorful ==> end red 不验证客户端证书 单项tls 访问 /gray/colorful ==> end gray 验证客户端证书 双项tls

docker-compose

version: '3'
services:
  front-envoy:
    image: envoyproxy/envoy-alpine:v1.15-latest
    environment: 
    - ENVOY_UID=0
    ports:
    - 80:80
    - 443:443
    - 82:9901
    volumes:
    - ./envoy.yaml:/etc/envoy/envoy.yaml
    - ./certs/front-envoy/:/etc/envoy/certs/
    - ./certs/CA/:/etc/envoy/ca/
    networks:
      envoymesh:
        aliases:
        - front-envoy
    depends_on:
    - webserver1
    - webserver2

  gray-envoy:
    image: envoyproxy/envoy-alpine:v1.15-latest
    environment: 
    - ENVOY_UID=0
    volumes:
    - ./service_gray.yaml:/etc/envoy/envoy.yaml
    - ./certs/service_gray/:/etc/envoy/certs/
    - ./certs/CA1/:/etc/envoy/ca/
    network_mode: "service:webserver1"
    depends_on:
    - webserver1

  red-envoy:
    image: envoyproxy/envoy-alpine:v1.15-latest
    environment: 
    - ENVOY_UID=0
    volumes:
    - ./service_red.yaml:/etc/envoy/envoy.yaml
    - ./certs/service_red/:/etc/envoy/certs/
    - ./certs/CA1/:/etc/envoy/ca/
    network_mode: "service:webserver2"
    depends_on:
    - webserver2


  webserver1:
    image: cylonchau/envoy-end:latest
    networks:
      envoymesh:
        aliases:
        - service_gray
        - front_envoy
    environment: 
    - VERSION=v1
    - COLORFUL=gray
    expose:
    - 90
  webserver2:
    image: cylonchau/envoy-end:latest
    networks:
      envoymesh:
        aliases:
        - service_red
        - front_envoy
    environment: 
    - VERSION=v1
    - COLORFUL=red
    expose:
    - 90

networks:
  envoymesh: {}

front-envoy

admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

static_resources:
  secrets:
  - name: servers
    tls_certificate:
      certificate_chain:
        filename: "/etc/envoy/certs/server.crt"
      private_key:
        filename: "/etc/envoy/certs/server.key"
  - name: clients
    tls_certificate:
      certificate_chain:
        filename: "/etc/envoy/certs/client.crt"
      private_key:
        filename: "/etc/envoy/certs/client.key"
  - name: validation
    validation_context:
      trusted_ca:
        filename: "/etc/envoy/ca/ca.crt"

  listeners:
  - name: listener_http
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: [ "*" ]
              routes:
              - match: { prefix: "/" }
                redirect:
                  https_redirect: true
                  port_redirect: 443
          http_filters:
          - name: envoy.router

  - name: listener_https
    address:
      socket_address: { address: 0.0.0.0, port_value: 443 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_https
          codec_type: AUTO
          route_config:
            name: https_route
            virtual_hosts:
            - name: https_route
              domains: ["*"]
              routes:
              - match: { prefix: "/gray/colorful" }
                route:
                  prefix_rewrite: "/colorful"
                  cluster: gray                                
              - match: { prefix: "/red/colorful" }
                route:
                  prefix_rewrite: "/colorful"
                  cluster: red
              - match: { prefix: "/" }
                route:
                  cluster: front_envoy
          http_filters:
          - name: envoy.router
          access_log:
          - name: envoy.listener.accesslog
            typed_config: 
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
              path: /dev/stdout
              log_format: 
                text_format: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\"\n"
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificate_sds_secret_configs:
            - name: servers

  clusters:
  - name: front_envoy
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: front_envoy
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: front_envoy, port_value: 90 }

  - name: gray
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: gray
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: service_gray, port_value: 443 }
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        common_tls_context:
          tls_certificate_sds_secret_configs:
          - name: clients
          validation_context_sds_secret_config:
            name: validation

  - name: red
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: red
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: service_red, port_value: 443 } 
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
        common_tls_context:
          tls_certificate_sds_secret_configs:
          - name: clients

service gray

admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

static_resources:
  listeners:
  - name: listener_https
    address:
      socket_address: { address: 0.0.0.0, port_value: 443 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_https
          codec_type: AUTO
          route_config:
            name: https_route
            virtual_hosts:
            - name: https_route
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  cluster: service_gray
          http_filters:
          - name: envoy.router
          access_log:
          - name: envoy.listener.accesslog
            typed_config: 
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
              path: /dev/stdout
              log_format: 
                text_format: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\"\n"
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
              certificate_chain:
                filename: "/etc/envoy/certs/server.crt"
              private_key:
                filename: "/etc/envoy/certs/server.key"
            validation_context:
              trusted_ca:
                filename: "/etc/envoy/ca/ca.crt"    
          require_client_certificate: true
          

  clusters:
  - name: service_gray
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: service_gray
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 127.0.0.1, port_value: 90 }

service red

admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 9901

static_resources:
  listeners:
  - name: listener_https
    address:
      socket_address: { address: 0.0.0.0, port_value: 443 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_https
          codec_type: AUTO
          route_config:
            name: https_route
            virtual_hosts:
            - name: https_route
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route:
                  cluster: service_red
          http_filters:
          - name: envoy.router
          access_log:
          - name: envoy.listener.accesslog
            typed_config: 
              "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
              path: /dev/stdout
              log_format: 
                text_format: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\"\n"
      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
            - certificate_chain:
                filename: "/etc/envoy/certs/server.crt"
              private_key:
                filename: "/etc/envoy/certs/server.key"

  clusters:
  - name: service_red
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: service_red
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address: { address: 127.0.0.1, port_value: 90 }

配置说明

docker-compose

network_mode: "service:webserver1" 指定网络类型,使envoy和后端程序运行在一个网络下

  secrets:
  - name: servers
    tls_certificate:
      certificate_chain:
        filename: "/etc/envoy/certs/server.crt"
      private_key:
        filename: "/etc/envoy/certs/server.key"
  - name: clients
    tls_certificate:
      certificate_chain:
        filename: "/etc/envoy/certs/client.crt"
      private_key:
        filename: "/etc/envoy/certs/client.key"
  - name: validation
    validation_context:
      trusted_ca:
        filename: "/etc/envoy/ca/ca.crt"

server

      transport_socket:
        name: envoy.transport_sockets.tls
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
          common_tls_context:
            tls_certificates:
              certificate_chain:
                filename: "/etc/envoy/certs/server.crt"
              private_key:
                filename: "/etc/envoy/certs/server.key"
            validation_context:    # 验证机制的相关配置
              trusted_ca: # 信任的ca证书,未指定时不会验证对端证书
                filename: "/etc/envoy/ca/ca.crt"   # 这里指定的为根ca
          require_client_certificate: true # boolval 设置为ture,Envoy将拒绝没有有效客户端证书的连接。

验证结果

/gray/colorful后端服务开启了验证客户端ca,访问报错,后端程序并没收到请求,因证书无效,envoy销毁了请求

将根ca设置为可信任后

/red/colorful 没开启验证客户端证书

本文发布于Cylon的收藏册,转载请著名原文链接~

链接:https://www.oomkill.com/2020/09/envoy-mutual-tls/

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。