envoyproxy / envoy-tools

Companion tooling for Envoy proxy
Apache License 2.0
49 stars 24 forks source link

feature: adds support for go-control-plane based xDS implementations #41

Open owayss opened 2 years ago

owayss commented 2 years ago

šŸ‘‹ This proposal adds support for OSS implementations of the xDS control plane.

Kindly let me know whether this is something you would like integrated into envoy-tools/csds-client, and what are your thoughts on this approach.

platform go

This patch adds support for a second type of platform, named go. It does so by providing utility function ConnToXDS and DialOptions to initiate gRPCs to the address specified by the flag service_uri.

authentication options for platform go

Support is added for mTLS via the introduction of the following new flags:

  -authority string
        the :authority header to use when connecting to uri
  -cacert string
        filepath to the CAs certs used to verify the server's certificate
  -cert string
        filepath to the client TLS certificate
  -key string
        filepath to the client TLS private key

The the client certificate/private key pair are included in the ClientHello message for establishing a connection over TLS.

If a certificate authority is provided via cacert, it is used to validate the server's certificate identity.

Additionally, the -authority flag allows for setting the HTTP/2 :authority header to use for SNI.

Example

$ ~/github/owayss/envoy-tools/csds-client/csds-client \
    -request_file ~/github/owayss/envoy-tools/csds-client/client/v3/test_request.yaml \
    -cert client.crt \
    -key client.key \
    -cacert ca.crt \
    -service_uri localhost:18000 \
    -platform go \
    -api_version v3 
Click to expand response output ``` Client ID xDS stream type Config Status api-gateway CDS SYNCED LDS SYNCED Detailed Config: { "config": [ { "node": { "id": "api-gateway" }, "xdsConfig": [ { "status": "SYNCED", "clusterConfig": { "staticClusters": [ { "cluster": { "@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster", "name": "service_api-gateway-stg", "type": "STRICT_DNS", "connectTimeout": "5s", "loadAssignment": { "clusterName": "service_api-gateway-stg", "endpoints": [ { "lbEndpoints": [ {}, { "endpoint": { "address": { "socketAddress": { "address": "envoyproxy.io", "portValue": 443 } } } } ] } ] }, "healthChecks": [ { "timeout": "5s", "interval": "5s", "unhealthyThreshold": 3, "healthyThreshold": 3, "reuseConnection": true, "httpHealthCheck": { "host": "api-gateway-stg.mydomain.com", "path": "/api/health", "expectedStatuses": [ { "start": "200", "end": "405" } ] }, "noTrafficInterval": "60s", "eventLogPath": "/dev/stdout", "alwaysLogHealthCheckFailures": true } ], "dnsLookupFamily": "V4_ONLY", "transportSocket": { "name": "envoy.transport_sockets.tls" } } } ] } }, { "status": "SYNCED", "listenerConfig": { "staticListeners": [ { "listener": { "@type": "type.googleapis.com/envoy.config.listener.v3.Listener", "name": "listener_api-gateway-stg", "address": { "socketAddress": { "address": "0.0.0.0", "portValue": 4455 } }, "filterChains": [ { "filters": [ { "name": "envoy.filters.network.http_connection_manager", "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager", "statPrefix": "http", "routeConfig": { "name": "route_api-gateway-stg", "virtualHosts": [ { "name": "route_api-gateway-stg", "domains": [ "*" ], "routes": [ { "match": { "path": "/__envoy__/status" }, "directResponse": { "status": 200, "body": { "inlineString": "OK" } } }, { "match": { "prefix": "/" }, "route": { "cluster": "service_api-gateway-stg", "hostRewriteLiteral": "api-gateway-stg.mydomain.com" } } ] } ] }, "httpFilters": [ { "name": "envoy.filters.http.router" } ], "accessLog": [ { "name": "envoy.access_loggers.file", "typedConfig": { "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog", "path": "/dev/stdout", "logFormat": { "jsonFormat": { "bytes_received": "%BYTES_RECEIVED%", "bytes_sent": "%BYTES_SENT%", "downstream_local_address": "%DOWNSTREAM_LOCAL_ADDRESS%", "downstream_local_uri_san": "%DOWNSTREAM_LOCAL_URI_SAN%", "downstream_peer_uri_san": "%DOWNSTREAM_PEER_URI_SAN%", "downstream_remote_address": "%DOWNSTREAM_REMOTE_ADDRESS%", "duration": "%DURATION%", "envoy_upstream_service_time": "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%", "epoch_micro": "%START_TIME(%s.%6f)%", "jwt_aud": "%DYNAMIC_METADATA(envoy.filters.http.jwt_authn\\:config)%", "protocol": "%PROTOCOL%", "req_authority": "%REQ(:AUTHORITY)%", "req_envoy_original_path": "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%", "req_path": "%REQ(:PATH)%", "req_user_agent": "%REQ(USER-AGENT)%", "req_x_request_id": "%REQ(X-REQUEST-ID)%", "req_xff": "%REQ(X-FORWARDED-FOR)%", "request_method": "%REQ(:METHOD)%", "response_code": "%RESPONSE_CODE%", "response_duration": "%RESPONSE_DURATION%", "response_flags": "%RESPONSE_FLAGS%", "response_tx_duration": "%RESPONSE_TX_DURATION%", "start_time": "%START_TIME(%Y/%m/%d %H:%M:%S)%", "upstream_cluster": "%UPSTREAM_CLUSTER%", "upstream_host": "%UPSTREAM_HOST%", "upstream_local_address": "%UPSTREAM_LOCAL_ADDRESS%", "upstream_transport_failure_reason": "%UPSTREAM_TRANSPORT_FAILURE_REASON%" } } } } ] } } ] } ] } } ] } } ] } ] } ```

Testing coverage

The patch does not include any additional tests. The various test functions in the client/v2 and client/v3 seem to cover the existing utility functions (for parsing and printing out detailed responses) with golden JSON data files.

The part that I think would benefit from a unit test is the DialOptions functions that configures the HTTP/2 connection depending on the provided command-line flags for authentication.


Best, Owayss.