10 min • read

TCPMapping resources

In addition to managing HTTP, gRPC, and WebSockets at layer 7, Emissary-ingress can also manage TCP connections at layer 4. The core abstraction used to support TCP connections is the TCPMapping.

An Emissary-ingress TCPMapping associates TCP connections with upstream services. Cleartext TCP connections are defined by destination IP address and/or destination TCP port; TLS-encrypted TCP connections can also be defined by the hostname presented using SNI. A service is exactly the same as in HTTP Mappings and other Emissary-ingress resources.

TCPMapping configuration

Like all native Emissary-ingress resources, TCPMappings have an ambassador_id field to select which Emissary-ingress installations take notice of it:

AttributeDescriptionTypeDefault value
ambassador_idA list of ambassador_ids which should pay attention to this resourcearray of stringsoptional; default is ["default"]

Downstream configuration

The downstream configuration refers to the connection between the end-client and Emissary-ingress.

AttributeDescriptionTypeDefault value
portWhich TCP port number Emissary-ingress should listen on this TCPMapping; may or may not correspond to a Listener resourcestringrequired; no default
hostIf non-empty, terminate TLS on this port; using this hostglob for SNI-based for routingstringoptional; if not present, do not terminate TLS on this port
addressWhich IP address Emissary-ingress should listen onstringoptional; if not present, accept connections on all IP addresses
weightThe (integer) percentage of traffic for this resource when canarying between multiple TCPMappingsintegeroptional; default is to not canary

If the port does not pair with an actual existing Listener, then an appropriate internal Listener is automatically created.

If the Listener does not terminate TLS (controlled by Listener.spec.protocolStack and by TCPMapping.spec.host), then no Hosts may associate with the Listener, and only one TCPMapping (or set of canaried TCPMappings; see the weight attribute) may associate with the Listener.

If the Listener does terminate TLS, then any number of TCPMappings and Hosts may associate with the Listener, and are selected between using SNI.

It is an error if the TCPMapping.spec.host and Listener.spec.protocolStack do not agree about whether TLS should be terminated, and the TCPMapping will be discarded.

TLS termination

If the host field is non-empty, then the TCPMapping will terminate TLS when listening for connections from end-clients

To do this, Emissary-ingress needs a TLS certificate and configuration; there are two ways that this can be provided:

First, Emissary-ingress checks for any Host resources with TLS configured whose Host.spec.hostname glob-matches the TCPMapping.spec.host; if such a Host exists, then its TLS certificate and configuration is used.

Second, if such a Host is not found, then Emissary-ingress checks for any TLSContext resources who have an item in TLSContext.spec.hosts that exact-matches the TCPMapping.spec.host; if such a TLSContext exists, then it and its certificate are used. These host fields may contain globs, but they are not considered when matching; for example, a TLSContext host string of *.example.com would not match with a TCPMapping host of foo.example.com, but would match with a TCPMapping host of *.example.com.

It is an error if no such Host or TLSContext is found, then the TCPMapping is discarded.

Upstream configuration

The upstream configuration refers to the connection between Emissary-ingress and the service that it is a gateway to.

AttributeDescriptionTypeDefault value
serviceThe service to talk to; a string of the format scheme://host:port, where scheme:// and :port are optional. If the scheme is https, then TLS is originated, otherwise the scheme is ignored.stringrequired; no default; if originating TLS the default port is 443, otherwise the default port is 80
resolverThe resolver to use when resolving the hostname in servicestringoptional
enable_ipv4Whether to enable IPv4 DNS lookups when resolving the hostname in service; has no affect if the hostname is an IP address or using a non-DNS resolver.Booleanoptional; default is true unless set otherwise by the ambassador Module
enable_ipv6Whether to enable IPv6 DNS lookups when resolving the hostname in service; has no affect if the hostname is an IP address or using a non-DNS resolver.Booleanoptional; default is true unless set otherwise by the ambassador Module
tlsThe name of a TLSContext to originate TLS; TLS is originated if tls is non-empty.stringoptional; default is to not use a TLSContext
circuit_breakersCircuit breakers, same as for HTTP Mappingsarray of objectsoptional; default is set by the ambassador Module
idle_timeout_msThe timeout, in milliseconds, after which the connection will be terminated if no traffic is seen.integeroptional; default is no timeout

If both enable_ipv4 and enable_ipv6 are true, Emissary-ingress will prefer IPv6 to IPv4. See the ambassador Module documentation for more information.

The values for the scheme-part of the service are a bit of a misnomer; despite the https:// string being recognized, it does not imply anything about whether the traffic is HTTP; just whether it is encrypted.

If service does not specify a port number: if TLS is not being originated, then a default port number of 80 is used; if TLS is being originated (either because the service says https:// or because tls is set), then a default port number of 443 is used (even if the service says http://).

The default resolver is a KubernetesServiceResolver, which takes a namespace-qualified DNS name. Given that AMBASSADOR_NAMESPACE is correctly set, Emissary-ingress can map to services in other namespaces:

  • service: servicename will route to a service in the same namespace as Emissary-ingress, and
  • service: servicename.namespace will route to a service in a different namespace.

TLS origination

If the TCPMapping.spec.service starts with https://, or if the TCPMapping.spec.tls is set, then the TCPMapping will originate TLS when dialing out to the service.

If originating TLS, but TCPMapping.spec.tls is not set, then Emissary-ingress will use a default TLS client configuration, and will not provide a client certificate.

If TCPMapping.spec.tls is set, then Emissary-ingress looks for a TLSContext resource with that name (the TLSContext may be found in any namespace).

TCPMapping and TLS

The TCPMapping.spec.host attribute determines whether Emissary-ingress will terminate TLS when a client connects to Emissary-ingress. The TCPMapping.spec.service and TCPMapping.spec.tls attributes work together to determine whether Emissary-ingress will originate TLS when connecting to an upstream. The two are totally independent. See the sections on TLS termination and TLS origination, respectively.

Examples

neither terminating nor originating TLS

If host is not set, then TLS is not terminated. If service does not start with https:// and tls is empty, then TLS is not originated. So, if both of these are true, thenEmissary-ingress simply proxies bytes between the client and the upstream; TLS may or may not be involved, Emissary-ingress doesn't care. You should specify in service which port to dial to; if you don't, Emissary-ingress will use port 80 because it is not originating TLS.

So, for example,

could be used to relay an SSH connection on port 2222, or

could proxy a CockroachDB connection.

terminating TLS, but not originating it

If host is set, then TLS is terminated. If service does not start with https:// and tls is empty, then TLS is not originated. In this case, Emissary-ingress will terminate the TLS connection, require that the host offered with SNI match the host attribute, and then make a cleartext connection to the upstream host. You should specify in service which port to dial to; if you don't, Emissary-ingress will use port 80 because it is not originating TLS.

This can be useful for doing host-based TLS proxying of arbitrary protocols, allowing the upstream to not have to care about TLS.

Note that this case requires that you have created a termination TLSContext or Host that matches the TCPMapping.spec.host.

The above will accept a TLS connection with SNI on port 2222. If the client requests SNI host my-host-1, the decrypted traffic will be relayed to upstream-host-1, port 9999. If the client requests SNI host my-host-2, the decrypted traffic will be relayed to upstream-host-2, port 9999. Any other SNI host will cause the TLS handshake to fail.

both terminating and originating TLS, with and without a client certificate

If host is set, then TLS is terminated. In this case, Emissary-ingress will terminate the incoming TLS connection, require that the host offered with SNI match the host attribute, and then make a TLS connection to the upstream host.

If tls is non-empty, then TLS is originated with a client certificate. In this case, Emissary-ingress will use the TLSContext referred to by tls to determine the certificate offered to the upstream service.

If service starts with https://, then then TLS is originated without a client certificate (unless tls is also set)

In either case, you should specify in service which port to dial to; if you don't, Emissary-ingress will use port 443 because it is originating TLS.

This is useful for doing host routing while ensuring that data is always encrypted while in-transit.

Note that this case requires that you have created a termination TLSContext or Host that matches the TCPMapping.spec.host.

The above will accept a TLS connection with SNI on port 2222.

If the client requests SNI host my-host-1, the traffic will be relayed over a TLS connection to upstream-host-1, port 9999. No client certificate will be offered for this connection.

If the client requests SNI host my-host-2, the decrypted traffic will be relayed to upstream-host-2, port 9999. The client certificate from origination-context will be offered for this connection.

Any other SNI host will cause the TLS handshake to fail.

originating TLS, but not terminating it

Here, Emissary-ingress will accept the connection without terminating TLS, then relay traffic over a TLS connection upstream. This is probably useful only to accept unencrypted traffic and force it to be encrypted when it leaves Emissary-ingress.

Example:

The example above will accept any connection to port 2222 and relay it over a TLS connection to upstream-host port 9999. No client certificate will be offered.