Docsright arrowEmissary-ingressright arrowThe Listener CRD

9 min • read

The Listener CRD

The Listener CRD defines where, and how, Emissary-ingress should listen for requests from the network, and which Host definitions should be used to process those requests. For further examples of how to use Listener, see Configuring Emissary-ingress Communications.

Note that Listeners are never created by Emissary-ingress, and must be defined by the user. If you do not define any Listeners, Emissary-ingress will not listen anywhere for connections, and therefore won't do anything useful. It will log a WARNING to this effect.

ElementTypeDefinition
portint32The network port on which Emissary-ingress should listen. Required.
protocolenum; see belowA high-level protocol type, like "HTTPS". Exactly one of protocol and protocolStack must be supplied.
protocolStackarray of enum; see belowA sequence of low-level protocols to layer together. Exactly one of protocol and protocolStack must be supplied.
securityModelenum; see belowHow does Emissary-ingress decide whether requests here are secure? Required.
statsPrefixstring; see belowUnder what name do statistics for this Listener appear? Optional; default depends on protocol.
l7Depthint32How many layer 7 load balancers are between the edge of the network and Emissary-ingress? Optional; default is 0.
hostBindingstruct, see belowMechanism for determining which Hosts will be associated with this Listener. Required

protocol and protocolStack

protocol is the recommended way to tell Emissary-ingress that a Listener expects connections using a well-known protocol. When using protocol, protocolStack may not also be supplied.

Valid protocol values are:

protocolDescription
HTTPCleartext-only HTTP. HTTPS is not allowed.
HTTPSEither HTTPS or HTTP -- Envoy's TLS support can tell whether or not TLS is in use, and it will set X-Forwarded-Proto correctly for later decision-making.
HTTPPROXYCleartext-only HTTP, using the HAProxy PROXY protocol.
HTTPSPROXYEither HTTPS or HTTP, using the HAProxy PROXY protocol.
TCPTCP sessions without HTTP at all. You will need to use TCPMappings to route requests for this Listener.
TLSTLS sessions without HTTP at all. You will need to use TCPMappings to route requests for this Listener.

securityModel

securityModel defines how the Listener will decide whether a request is secure or insecure:

securityModelDescription
XFPRequests are secure if, and only if, X-Forwarded-Proto indicates HTTPS. This is common; see below.
SECURERequests are always secure. You might set this if your load balancer always terminates TLS for you, and you can trust the clients.
INSECURERequests are always insecure. You might set this for an HTTP-only Listener, or a Listener for clients that are expected to be hostile.

The X-Forwarded-Proto header mentioned above is meant to reflect the protocol the original client used to contact Emissary-ingress. When no layer 7 proxies are in use, Envoy will make certain that the X-Forwarded-Proto header matches the wire protocol of the connection the client made to Envoy, which allows Emissary-ingress to trust X-Forwarded-Proto for routing decisions such as deciding to redirect requests made using HTTP over to HTTPS for greater security. When using Emissary-ingress as an edge proxy or a typical API gateway, this is a desirable configuration; setting securityModel to XFP makes this easy.

When layer proxies are in use, the XFP setting is often still desirable; however, you will also need to set l7Depth to allow it to function. See below.

SECURE and INSECURE are helpful for cases where something downstream of Emissary-ingress should be allowing only one kind of request to reach Emissary-ingress. For example, a Listener behind a load balancer that terminates TLS and checks client certificates might use SecurityModel: SECURE, then use Hosts to reject insecure requests if one somehow arrives.

l7Depth

When layer 7 (L7) proxies are in use, the connection to Emissary-ingress comes from the L7 proxy itself rather than from the client. Examining the protocol and IP address of that connection is useless, and instead you need to configure the L7 proxy to pass extra information about the client to Emissary-ingress using the X-Forwarded-Proto and X-Forwarded-For headers.

However, if Emissary-ingress always trusted X-Forwarded-Proto and X-Forwarded-For, any client could use them to lie about itself to Emissary-ingress. As a security mechanism, therefore, you must also set l7Depth in the Listener to the number of trusted L7 proxies in front of Emissary-ingress. If l7Depth is not set in the Listener, the xff_num_trusted_hops value from the ambassador Module will be used. If neither is set, the default l7Depth is 0.

When l7Depth is 0, any incoming X-Forwarded-Proto is stripped: Envoy always provides an X-Forwarded-Proto matching the wire protocol of the incoming connection, so that X-Forwarded-Proto can be trusted. When l7Depth is non-zero, X-Forwarded-Proto is accepted from the L7 proxy, and trusted. The actual wire protocol in use from the L7 proxy to Emissary-ingress is ignored.

l7Depth also affects Emissary-ingress's view of the client's source IP address, which is used as the remote_address field when rate limiting, and for the X-Envoy-External-Address header:

  • When l7Depth is 0, Emissary-ingress uses the IP address of the incoming connection.

  • When l7Depth is some value N that is non-zero, the behavior is determined by the value of use_remote_address in the ambassador Module:

    • When use_remote_address is true (the default) then the trusted client address will be the Nth address from the right end of the X-Forwarded-For header. (If the XFF contains fewer than N addresses, Envoy falls back to using the immediate downstream connection’s source address as a trusted client address.)

    • When use_remote_address is false, the trusted client address is the (N+1)th address from the right end of XFF. (If the XFF contains fewer than N+1 addresses, Envoy falls back to using the immediate downstream connection’s source address as a trusted client address.)

      For more detailed examples of this interaction, refer to Envoy's documentation.

hostBinding

hostBinding specifies how this Listener should determine which Hosts are associated with it:

  • namespace.from allows filtering Hosts by the namespace of the Host:
    • namespace.from: SELF accepts only Hosts in the same namespace as the Listener.
    • namespace.from: ALL accepts Hosts in any namespace.
  • selector accepts only Hosts that has labels matching the selector.

hostBinding is mandatory, and at least one of namespace.from and selector must be set. If both are set, both must match for a Host to be accepted.

statsPrefix

Emissary-ingress produces detailed statistics which can be monitored in a variety of ways. Statistics have hierarchical names, and the Listener will cause a set of statistics to be logged under the name specified by statsPrefix.

The default statsPrefix depends on the protocol for this Listener:

  • If the Listener speaks HTTPS, the default is ingress-https.
  • Otherwise, if the Listener speaks HTTP, the default is ingress-http.
  • Otherwise, if the Listener speaks TLS, the default is ingress-tls-$port.
  • Otherwise, the default is ingress-$port.

Note that it doesn't matter whether you use protocol or protocolStack: what matters is what protocol is actually configured. Also note that the default doesn't take the HAProxy PROXY protocol into account.

Some examples:

will use a statsPrefix of ingress-https.

will use statsPrefix of ingress-8080.

would also use ingress-https, but it explicitly overrides statsPrefix to proxy-8080.

For complete information on which statistics will appear for the Listener, see the Envoy listener statistics documentation. Some important statistics include

Statistic nameTypeDescription
listener.$statsPrefix.downstream_cx_totalCounterTotal connections
listener.$statsPrefix.downstream_cx_activeGaugeTotal active connections
listener.$statsPrefix.downstream_cx_length_msHistogramConnection length in milliseconds

protocolStack

protocolStack is not recommended if you can instead use protocol.

Where protocol allows configuring the Listener to use well-known protocol stacks, protocolStack allows configuring exactly which protocols will be layered together. If protocol allows what you need, it is safer to use Protocol than to risk having the stack broken with an incorrect protocolStack.

The possible stack elements are:

ProtocolStack ElementDescription
HTTPCleartext-only HTTP; must be layered with TLS for HTTPS
PROXYThe HAProxy PROXY protocol
TLSTLS
TCPRaw TCP

protocolStack supplies a list of these elements to describe the protocol stack. Order matters. Some examples:

protocolStackDescription
[ HTTP, TCP ]Cleartext-only HTTP, exactly equivalent to protocol: HTTP.
[ TLS, HTTP, TCP ]HTTPS or HTTP, exactly equivalent to protocol: HTTPS.
[ PROXY, TLS, TCP ]The PROXY protocol, wrapping TLS afterward, wrapping raw TCP. This isn't equivalent to any protocol setting, and may be nonsensical.

Examples

For further examples of how to use Listener, see Configuring Emissary-ingress to Communicate.