Ingress tutorials

Terminate SSL / TLS

In this section, you will learn how to configure SSL/TLS in HAProxy Kubernetes Ingress Controller.

HAProxy Kubernetes Ingress Controller can terminate SSL/TLS for services in your cluster, meaning it will handle encrypting traffic when it leaves the network and decrypting it when it enters. The ingress controller uses a self-signed TLS certificate by default, if you installed with Helm, but you can replace it with your own.

If all of your services reside under the same hostname, you may decide to configure just one TLS certificate. Or, you can set a certificate per Ingress rule. Note that the TLS certificate you use should match your web application’s hostname to be considered valid by web browsers.

Configure a TLS certificate for all services Jump to heading

To add a TLS certificate that applies to all backend services:

  1. Acquire a TLS certificate and key. Be sure that your certificate and key files use the PEM format.

    Want to try it out in a non-production environment? Use the following OpenSSL command to create your own self-signed certificate and key:

    nix
    openssl req -x509 -newkey rsa:2048 -keyout example.key -out example.crt -days 365 -nodes -subj "/C=US/ST=Ohio/L=Columbus/O=MyCompany/CN=example.com"
    nix
    openssl req -x509 -newkey rsa:2048 -keyout example.key -out example.crt -days 365 -nodes -subj "/C=US/ST=Ohio/L=Columbus/O=MyCompany/CN=example.com"
  2. Create a new TLS secret in your cluster by calling kubectl create secret with your TLS certificate and private key files as the --cert and --key arguments:

    nix
    kubectl create secret tls example-cert --cert="example.crt" --key="example.key"
    nix
    kubectl create secret tls example-cert --cert="example.crt" --key="example.key"
  3. To associate this TLS secret with the ingress controller, you must update the ingress controller’s ConfigMap. First, get the name of the ConfigMap by calling kubectl get configmaps. Below, the ConfigMap exists in the haproxy-controller namespace and is named haproxy-kubernetes-ingress:

    nix
    kubectl get configmaps --namespace haproxy-controller
    nix
    kubectl get configmaps --namespace haproxy-controller
    output
    text
    NAME DATA AGE
    haproxy-kubernetes-ingress 0 15h
    output
    text
    NAME DATA AGE
    haproxy-kubernetes-ingress 0 15h
  4. Replace the ConfigMap with your own. You can either:

    • Call kubectl edit configmap to edit the existing ConfigMap:

      nix
      kubectl edit configmap --namespace haproxy-controller haproxy-kubernetes-ingress
      nix
      kubectl edit configmap --namespace haproxy-controller haproxy-kubernetes-ingress

      Then add an ssl-certificate field to the data section. Set it to your TLS secret’s namespace and name.

    or

    • Create a YAML file that replaces the ConfigMap. Set the ssl-certificate field in the data section to your TLS secret’s namespace and name.

      example-configmap.yaml
      yaml
      apiVersion: v1
      kind: ConfigMap
      metadata:
      name: haproxy-kubernetes-ingress
      namespace: haproxy-controller
      data:
      ssl-certificate: "default/example-cert"
      example-configmap.yaml
      yaml
      apiVersion: v1
      kind: ConfigMap
      metadata:
      name: haproxy-kubernetes-ingress
      namespace: haproxy-controller
      data:
      ssl-certificate: "default/example-cert"

      Then deploy this to your Kubernetes cluster using kubectl.

      nix
      kubectl apply -f example-configmap.yaml
      nix
      kubectl apply -f example-configmap.yaml

    The ingress controller will now use your certificate when serving HTTPS traffic.

Configure a TLS certificate for an Ingress rule Jump to heading

This section describes how to configure a TLS certificate for a specific Ingress rule, which allows you to set a different certificate for each hostname.

  1. Acquire a TLS certificate and key. Be sure that your certificate and key files use the PEM format.

  2. Create a new TLS secret in your cluster by calling kubectl create secret with your TLS certificate and private key files as the --cert and --key arguments.

    nix
    kubectl create secret tls example-cert --cert="example.crt" --key="example.key"
    nix
    kubectl create secret tls example-cert --cert="example.crt" --key="example.key"
  3. Prepare an Ingress resource that sets the secret’s name as the secretName field’s value in the tls section. Note that you will specify the hostnames for which this certificate should apply. The hostnames in the tls section should match the hostnames in the rules section.

    example-ingress.yaml
    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: example-ingress
    spec:
    ingressClassName: haproxy
    tls:
    - secretName: example-cert
    hosts:
    - "example.com"
    rules:
    - host: "example.com"
    http:
    paths:
    - path: /
    pathType: Prefix
    backend:
    service:
    name: example-service
    port:
    number: 8080
    example-ingress.yaml
    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: example-ingress
    spec:
    ingressClassName: haproxy
    tls:
    - secretName: example-cert
    hosts:
    - "example.com"
    rules:
    - host: "example.com"
    http:
    paths:
    - path: /
    pathType: Prefix
    backend:
    service:
    name: example-service
    port:
    number: 8080

    Deploy it with kubectl apply:

    nix
    kubectl apply -f example-ingress.yaml
    nix
    kubectl apply -f example-ingress.yaml

    The ingress controller will now use your certificate when serving HTTPS traffic for the example.com web application.

Configure a TLS certificate for a TCP service Jump to heading

Available since

  • HAProxy Kubernetes Ingress Controller 3.0
  • HAProxy Enterprise Kubernetes Ingress Controller - not yet available

This section describes how to configure a TLS certificate when using the TCP custom resource.

  1. Acquire a TLS certificate and key. Be sure that your certificate and key files use the PEM format.

  2. Create a new TLS secret in your cluster by calling kubectl create secret with your TLS certificate and private key files as the --cert and --key arguments. Be sure to create the secret in the same namespace where you have your TCP custom resource.

    nix
    kubectl create secret tls example-cert --namespace default --cert="example.crt" --key="example.key"
    nix
    kubectl create secret tls example-cert --namespace default --cert="example.crt" --key="example.key"
  3. Create or update your TCP custom resource so that it includes the ssl and ssl_certificate fields, where ssl_certificate indicates the name of your secret.

    tcp-customresource.yaml
    yaml
    apiVersion: ingress.v1.haproxy.org/v1
    kind: TCP
    metadata:
    name: example-service1-tcp
    spec:
    - name: example-tcp
    frontend:
    name: example-frontend
    tcplog: true
    binds:
    - name: bind1
    port: 2000
    ssl: true
    ssl_certificate: example-cert
    service:
    name: example-service1
    port: 3000
    tcp-customresource.yaml
    yaml
    apiVersion: ingress.v1.haproxy.org/v1
    kind: TCP
    metadata:
    name: example-service1-tcp
    spec:
    - name: example-tcp
    frontend:
    name: example-frontend
    tcplog: true
    binds:
    - name: bind1
    port: 2000
    ssl: true
    ssl_certificate: example-cert
    service:
    name: example-service1
    port: 3000
  4. Apply the changes:

    nix
    kubectl apply -f tcp-customresource.yaml
    nix
    kubectl apply -f tcp-customresource.yaml
    output
    tcp.ingress.v1.haproxy.org/example-service1-tcp configured
    output
    tcp.ingress.v1.haproxy.org/example-service1-tcp configured

Enable verification of a backend service’s TLS certificate Jump to heading

You can use the server-ca Ingress annotation to specify the certificate authority that the load balancer will use to check backend certificates. To enable verification of a backend service’s TLS certificate:

Generate certificates for testing

You can generate self-signed certificates for testing.

Caution

You should use these self-signed certificates for testing purposes only in a non-production environment.

Use the following openssl command to generate a CA certificate and key:

nix
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=loadbalancer1'
nix
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=loadbalancer1'
  1. Create a Secret of generic type, providing the location of your CA certificate (ca.crt in this example). Here we create a secret in the default namespace named ca-secret:

    nix
    kubectl create secret generic ca-secret --from-file=tls.crt=ca.crt
    nix
    kubectl create secret generic ca-secret --from-file=tls.crt=ca.crt
    output
    text
    secret/ca-secret created
    output
    text
    secret/ca-secret created

    Note that when creating the secret, you must assign the certificate to the tls.crt data field, as the example above shows.

  2. Add the following annotations to your Ingress definition and apply the changes:

    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: example-ingress
    annotations:
    haproxy.org/server-ssl: "true"
    haproxy.org/server-ca: "default/ca-secret"
    spec:
    ingressClassName: haproxy
    [...]
    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: example-ingress
    annotations:
    haproxy.org/server-ssl: "true"
    haproxy.org/server-ca: "default/ca-secret"
    spec:
    ingressClassName: haproxy
    [...]
    • server-ssl enables SSL for backend services.
    • server-ca sets the name of the secret containing the CA certificate that the load balancer will use for verification of backend certificates. Be sure to include the secret’s namespace (default in this example).

Your load balancer configuration should look similar to following with ca-file added to the server line:

haproxy
backend default_example-service_http
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check ssl alpn h2,http/1.1 ca-file /etc/haproxy/certs/ca/default_ca-secret.pem verify required
server SRV_1 100.36.0.1:8080 enabled
haproxy
backend default_example-service_http
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check ssl alpn h2,http/1.1 ca-file /etc/haproxy/certs/ca/default_ca-secret.pem verify required
server SRV_1 100.36.0.1:8080 enabled

Enable client certificate authentication to a backend service Jump to heading

You can use the server-crt Ingress annotation to specify the client certificate the load balancer should use with backend services. To enable client certificate authentication:

Generate certificates for testing

To test TLS authentication with your backend services, you can generate self-signed certificates.

Caution

You should use these self-signed certificates for testing purposes only in a non-production environment.

Use the following openssl command to generate a CA certificate:

nix
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=loadbalancer1'
nix
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=loadbalancer1'

You can then use this CA certificate to generate client certificates. For example, we create a client certificate (client.crt) and key (client.key) using our CA certificate (ca.crt):

nix
openssl req -new -newkey rsa:4096 -keyout client.key -out client.csr -nodes -subj '/CN=loadbalancer1'
openssl x509 -req -sha256 -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
nix
openssl req -new -newkey rsa:4096 -keyout client.key -out client.csr -nodes -subj '/CN=loadbalancer1'
openssl x509 -req -sha256 -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
  1. Create a Secret of tls type, providing the location of your client certificate and key. For example, here we create a secret named server-secret:

    nix
    kubectl create secret tls server-secret --cert=client.crt --key=client.key
    nix
    kubectl create secret tls server-secret --cert=client.crt --key=client.key
    output
    text
    secret/server-secret created
    output
    text
    secret/server-secret created
  2. Add the following annotations to your Ingress definition and apply the changes:

    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: example-ingress
    annotations:
    haproxy.org/server-ssl: "true"
    haproxy.org/server-crt: "default/server-secret"
    spec:
    ingressClassName: haproxy
    [...]
    yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: example-ingress
    annotations:
    haproxy.org/server-ssl: "true"
    haproxy.org/server-crt: "default/server-secret"
    spec:
    ingressClassName: haproxy
    [...]
    • server-ssl enables SSL for backend services.
    • server-crt sets the name of the secret containing the client certificate and key that the load balancer will use for backend certificates. Be sure to include the secret’s namespace (default in this example).

Your load balancer configuration should look similar to following with crt added to the server line:

haproxy
backend default_example-service_http
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check ssl alpn h2,http/1.1 crt /etc/haproxy/certs/backend/default_server-secret.pem verify none
server SRV_1 100.36.0.1:8080 enabled
haproxy
backend default_example-service_http
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check ssl alpn h2,http/1.1 crt /etc/haproxy/certs/backend/default_server-secret.pem verify none
server SRV_1 100.36.0.1:8080 enabled

Enable mTLS for a backend service Jump to heading

To enable mTLS (Mutual TLS) for your backend services, you must both enable verification of a backend service’s TLS certificate and enable client certificate authentication to a backend service.

Once you have completed both of those steps, configuring your certificate authority and client certificate, your resulting automatically generated backend load balancer configuration should look similar to the following:

haproxy
backend default_example-service_http
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check ssl alpn h2,http/1.1 ca-file /etc/haproxy/certs/ca/default_ca-secret.pem crt /etc/haproxy/certs/backend/default_server-secret.pem verify required
server SRV_1 100.36.0.2:8080 enabled
haproxy
backend default_example-service_http
mode http
balance roundrobin
option forwardfor
no option abortonclose
default-server check ssl alpn h2,http/1.1 ca-file /etc/haproxy/certs/ca/default_ca-secret.pem crt /etc/haproxy/certs/backend/default_server-secret.pem verify required
server SRV_1 100.36.0.2:8080 enabled

This enables mTLS between the load balancer and backend services.

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