Usage

Define Gateways for HAProxy Unified Gateway

Gateways are Kubernetes objects that relay traffic from outside the cluster to inside, directing the request to the correct service as defined by HTTPRoute or other kinds of route rules. Each Gateway that you define instantiates a proxy. When you define a Gateway that has a gatewayClassName field of haproxy, it will be backed by the HAProxy Unified Gateway controller that you installed.

Prerequisites checklist Jump to heading

Before continuing, ensure that you’ve met these prerequisites:

Add a Gateway for a hostname Jump to heading

You can limit a Gateway so that it will route traffic for specific hostnames only. For instance, you could define a Gateway that handles traffic for the hostname example.com. It will ignore other traffic.

When to use this:

  • You want to limit which services can connect through this Gateway. For instance, this may be a production Gateway for which you want to control usage.

To define a Gateway for a single hostname:

  1. Create a file named gateway.yaml to define your Gateway. In this example, we set these fields:

    Field Description
    name Sets the name of the Gateway, which HTTPRoute resources will use to refer to this Gateway.
    namespace Sets the Kubernetes namespace to deploy this Gateway into.
    gatewayClassName Sets the Gateway’s class. The class maps to the HAProxy Unified Gateway controller.
    listeners Lists TCP ports at which to receive traffic.
    name Sets a name for the listener, which will appear in logs.
    protocol Sets a protocol type for the listener.
    port Matches a targetPort defined on the controller’s Service resource. In this example, we’re using the HTTP port. You’ll use the same port for all HTTP Gateways.
    hostname Sets the hostname to match. This Gateway will route traffic for that hostname only.
    allowedRoutes Restricts the kinds of route resources that can connect to this Gateway. Here, we’ve configured it to accept only HTTPRoute resources that are defined in the same namespace.

    For more information about these fields, see the Gateway API specification for Gateway.

    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    hostname: "example.com"
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    hostname: "example.com"
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f gateway.yaml
    nix
    kubectl apply -f gateway.yaml
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway created
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway created

    Next, define one or more routes.

Add a Gateway for all hostnames Jump to heading

To have the Gateway match traffic for all hostnames, omit the hostname field under listeners. When doing this, you’ll typically configure your HTTPRoute or other kinds of route resources to filter on hostname and route to the correct service.

When to use this:

  • You have a Gateway that it’s permissible to connect any service to. Development teams can manage which hostnames to assign to services and route the traffic through this Gateway. For instance, they could define a service that receives traffic at api.example.com, and another at web.example.com. The Gateway will allow traffic from both to flow through the same proxy.

In the example below, we omit hostname to accept all traffic.

  1. Create a file named gateway.yaml.

    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
  2. Apply the changes with kubectl:

    nix
    kubectl apply -f gateway.yaml
    nix
    kubectl apply -f gateway.yaml
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway created
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway created

    Next, define one or more routes.

Allow routes from other namespaces Jump to heading

When you set allowedRoutes.namespaces.from to Same, then the Gateway will accept only route resources defined in the same namespace as the Gateway. It will ignore others. Use this when you want to deploy a Gateway to a namespace and have it handle traffic for services in that namespace only. You can also deploy Gateways that set from to any of these values:

From Description
All Matches routes from any namespace.
Same Matches routes from the same namespace where the Gateway is deployed.
Selector Matches routes from namespaces matching the selector attribute. In this case, add a selector attribute to define the match criteria.

To match route resources from other namespaces via a selector:

  1. When defining your namespace, add a label. In this example, we set a label named shared-gateway-access.

    namespace.yaml
    yaml
    apiVersion: v1
    kind: Namespace
    metadata:
    name: example-namespace
    labels:
    shared-gateway-access: "true"
    namespace.yaml
    yaml
    apiVersion: v1
    kind: Namespace
    metadata:
    name: example-namespace
    labels:
    shared-gateway-access: "true"
  2. On the Gateway, set namespaces.from to Selector. Also, define the selector. In the example below, the selector uses matchLabels to indicate that only HTTPRoute resources defined in namespaces with the label shared-gateway-access set to true will be used.

    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    hostname: "example.com"
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Selector
    selector:
    matchLabels:
    shared-gateway-access: "true"
    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    hostname: "example.com"
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Selector
    selector:
    matchLabels:
    shared-gateway-access: "true"

Add an HTTPS listener Jump to heading

HAProxy Unified Gateway can terminate TLS at the Gateway level. Using this mechanism, clients connect via HTTPS, HAProxy Unified Gateway terminates TLS with the specified TLS certificate, and then it forwards the requests to the backends over HTTP. This reduces TLS workload on backend services if they don’t require HTTPS.

To terminate TLS using HAProxy Unified Gateway:

  1. For testing, generate a self-signed TLS certificate for the domain example.com with the openssl req command.

    nix
    openssl req -x509 -nodes -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=example.com" -days 365
    nix
    openssl req -x509 -nodes -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=example.com" -days 365
  2. Create the example-tls secret with the kubectl create secret command.

    nix
    kubectl create secret tls example-tls --cert=tls.crt --key=tls.key
    nix
    kubectl create secret tls example-tls --cert=tls.crt --key=tls.key
  3. Update your Gateway to have an HTTPS listener.

    • The tls section sets mode to Termiante and references a TLS secret named example-tls.
    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    - name: https
    protocol: HTTPS
    port: 31443
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    tls:
    mode: Terminate
    certificateRefs:
    - name: example-tls
    gateway.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
    name: example-haproxy-gateway
    namespace: default
    spec:
    gatewayClassName: haproxy
    listeners:
    - name: http
    protocol: HTTP
    port: 31080
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    - name: https
    protocol: HTTPS
    port: 31443
    allowedRoutes:
    kinds:
    - group: gateway.networking.k8s.io
    kind: HTTPRoute
    namespaces:
    from: Same
    tls:
    mode: Terminate
    certificateRefs:
    - name: example-tls

    Apply the changes with kubectl:

    nix
    kubectl apply -f gateway.yaml
    nix
    kubectl apply -f gateway.yaml
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway configured
    output
    text
    gateway.gateway.networking.k8s.io/example-haproxy-gateway configured
  4. Optional: When defining an HTTPRoute, you can force only HTTPS for your application by setting sectionName to the https Gateway listener. Otherwise, all listeners with a matching allowedRoutes entry can be used.

    http-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: http-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: https
    hostnames:
    - "example.com"
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80
    http-route.yaml
    yaml
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
    name: http-route
    namespace: default
    spec:
    parentRefs:
    - name: example-haproxy-gateway
    sectionName: https
    hostnames:
    - "example.com"
    rules:
    - backendRefs:
    - name: web-svc
    namespace: default
    port: 80

    Apply the changes with kubectl:

    nix
    kubectl apply -f http-route.yaml
    nix
    kubectl apply -f http-route.yaml
    output
    text
    httproute.gateway.networking.k8s.io/http-route created
    output
    text
    httproute.gateway.networking.k8s.io/http-route created
  5. Optional: To test connectivity with the Gateway and HTTPRoute, deploy a test application using a Deployment and a Service. Here, we define an example application using the hashicorp/ettp-echo Docker container image. It will receive HTTP traffic on port 5678 (the Gateway terminates the TLS connection and then communicates with backend services over HTTP) and respond with text indicating receipt of the request.

    Note that the Service is named web-svc, the same Service name you specified when you defined your HTTPRoute in the previous steps, listening on port 80, which you defined in the HTTPRoute as well. This is how the HTTPRoute knows what Service to route to.

    app.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: web-svc
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web-svc
    template:
    metadata:
    labels:
    app: web-svc
    spec:
    containers:
    - name: web
    image: hashicorp/http-echo:0.2.3
    args: ["-text=WEB RESPONSE"]
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: web-svc
    namespace: default
    spec:
    selector:
    app: web-svc
    ports:
    - port: 80
    targetPort: 5678
    app.yaml
    yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: web-svc
    namespace: default
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web-svc
    template:
    metadata:
    labels:
    app: web-svc
    spec:
    containers:
    - name: web
    image: hashicorp/http-echo:0.2.3
    args: ["-text=WEB RESPONSE"]
    ports:
    - containerPort: 5678
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: web-svc
    namespace: default
    spec:
    selector:
    app: web-svc
    ports:
    - port: 80
    targetPort: 5678

    Apply the changes with kubectl:

    nix
    kubectl apply -f app.yaml
    nix
    kubectl apply -f app.yaml
    output
    text
    deployment.apps/web-svc created
    service/web-svc created
    output
    text
    deployment.apps/web-svc created
    service/web-svc created
Test the connection (click to expand)

To test the connection to the http-echo instance:

  1. Use the following command to find the HTTPS NodePort configured for your HAProxy Unified Gateway Service. In this example the NodePort is 31443, the NodePort associated with the TCP port 8443.

    nix
    kubectl get service haproxy-unified-gateway -n haproxy-unified-gateway
    nix
    kubectl get service haproxy-unified-gateway -n haproxy-unified-gateway
    output
    text
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    haproxy-unified-gateway NodePort 10.111.136.206 <none> 8080:31080/TCP,8443:31443/TCP,31024:31689/TCP 114m
    output
    text
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    haproxy-unified-gateway NodePort 10.111.136.206 <none> 8080:31080/TCP,8443:31443/TCP,31024:31689/TCP 114m
  2. From a server that has connection to your cluster, such as the server from which you run kubectl, use curl to send a request to the NodePort at the hostname you configured in your Gateway. The HAProxy Unified Gateway service will forward the request to the port you defined in your Gateway.

    If your DNS is configured to resolve example.com, use this command:

    nix
    curl https://example.com/ -k
    nix
    curl https://example.com/ -k

    Otherwise, use this command to set the Host header to example.com:

    nix
    curl https://<NODEPORT_IP>:<NODEPORT> -H "Host: example.com" -k
    nix
    curl https://<NODEPORT_IP>:<NODEPORT> -H "Host: example.com" -k
    output
    text
    WEB RESPONSE
    output
    text
    WEB RESPONSE

    This indicates that the Gateway terminated the TLS connection and then made connection to the HTTP backend.

See also Jump to heading

Do you have any suggestions on how we can improve the content of this page?