TLS Bridge¶
This plugin is used to provide secured TLS tunnels for connections between a Client and a Service via two gateway Traffic Server instances. By configuring the Traffic Server instances the level of security in the tunnel can be easily controlled for all communications across the tunnels.
Description¶
The tunnel is sustained by two instances of Traffic Server.
The ingress Traffic Server accepts a connection from the Client. This connection gets intercepted by the
TLS Bridge plugin inside Traffic Server. The plugin then makes a TLS connection to the peer Traffic Server using the
configured level of security. The original request from the Client to the ingress Traffic Server is then sent
to the peer Traffic Server to create a connection from the peer Traffic Server to the Service. After this the
Client has a virtual circut to the Service and can use any TCP based communication (including TLS).
Effectively the plugin causes the connectivity to work as if the Client had done the CONNECT
directly to the peer Traffic Server. Note this means the DNS lookup for the Service is done by the peer Traffic Server,
not the ingress Traffic Server.
The plugin is configured with a mapping of Service names to peer Traffic Server instances. The Service names are URLs which will in the original HTTP request made by the Client after connecting to the ingress Traffic Server. This means the FQDN for the Service is not resolved in the environment of the peer Traffic Server and not the ingress Traffic Server.
Configuration¶
TLS Bridge requires at least two instances of Traffic Server (Ingress and Peer).
Disable caching on Traffic Server in
records.config
:CONFIG proxy.config.http.cache.http INT 0
Configure the ports.
The Peer Traffic Server must be listening on an SSL enabled proxy port. For instance, if the proxy port for the Peer is 4443, then configuration in
records.config
would have:CONFIG proxy.config.http.server_ports STRING 4443:ssl
The Ingress Traffic Server must allow
CONNECT
to the Peer proxy port. This would be set inrecords.config
by:CONFIG proxy.config.http.connect_ports STRING 4443
The Ingress Traffic Server also needs
proxy.config.http.server_ports
configured to have proxy ports to which the Client can connect.
Remap is not required, however, Traffic Server requires remap in order to accept the request. This can be done by disabling the remap requirement:
CONFIG proxy.config.url_remap.remap_required INT 0
In this case Traffic Server will act as an open proxy which is unlikely to be a good idea. Traffic Server will need to run in a restricted environment or use access control (via
ip_allow.config
oriptables
).Configure the Ingress Traffic Server to verify the Peer server certificate:
CONFIG proxy.config.ssl.client.verify.server INT 1
Configure Certificate Authority used by the Ingress Traffic Server to verify the Peer server certificate. If this is a directory all of the certificates in the directory are treated as Certificate Authorites.
CONFIG proxy.config.ssl.client.CA.cert.filename STRING </path/to/CA_certificate_file_name>
Configure the Ingress Traffic Server to provide a client certificate:
CONFIG proxy.config.ssl.client.cert.path STRING </path/to/certificate/dir> CONFIG proxy.config.ssl.client.cert.filename STRING <server_certificate_file_name>
Configure the Peer Traffic Server to verify the Ingress client certificate:
CONFIG proxy.config.ssl.client.certification_level INT 2
Enable the TLS Bridge plugin in
plugin.config
. The plugin is configured by arguments inplugin.config
. These are arguments are in pairs of a destination and a peer. The destination is a anchored regular expression which is matched against the host name in the ClientCONNECT
. The destinations are checked in order and the first match is used to select the Peer Traffic Server. The peer should be an FQDN or IP address with an optional port. For the example above, if the Peer Traffic Server was named “peer.example.com” on port 4443 and the Service at*.service.com
, the peer argument would be “peer.example.com:4443”. Inplugin.config
this would be:tls_bridge.so .*[.]service[.]com peer.example.com:4443
Notes¶
TLS Bridge is distinct from more basic Layer 4 Routing available in Traffic Server. For the latter there is no intercept or change of the TLS exchange between the Client and the Service. The exchange looks like this
The key points are
Traffic Server does no TLS negotiation at all. The properties of the connection between the Ingress Traffic Server and the Service are completely determined by the Client and Server negotation.
No packets are modified, the “”CLIENT HELLO”” sent by the Ingress Traffic Server is an exact copy of that sent to the Ingress Traffic Server by the Client. It is only examined for the SNI data in order to select the Service.
Implementation¶
The TLS Bridge plugin uses TSHttpTxnIntercept
to gain control of the ingress Client session.
If the session is valid then a separate connection to the peer Traffic Server is created using
TSHttpConnect
.
After the ingress Traffic Server connects to the peer Traffic Server it sends a duplicate of the Client CONNECT
request. This is processed by the peer Traffic Server to connect on to the Service. After this both Traffic Server
instances then tunnel data between the Client and the Service, in effect becoming a transparent
tunnel.
The overall exchange looks like the following:
A detailed view of the plugin operation.
A sequence diagram focusing on the request / response data flow. There is a NetVConn
for the
connection to the Peer Traffic Server which is omitted for clarity.
Blue dotted lines are request or response data
Green lines are network connections.
Red lines are programmatic interactions.
Black lines are hook call backs.
The 200 OK
sent from the Peer Traffic Server is parsed and consumed by the plugin. An non-200
response
means there was an error and the tunnel is shut down. To deal with the Client response clean up the
response code is stored and used later during cleanup.
A restartable state machine is used to recognize the end of the Peer Traffic Server response. The initial part of the response is easy because all that is needed is to wait until there is sufficient data for a minimal parse. The end can be an arbitrary distance in to the stream and may not all be in the same socket read.