Sign inSign up

ergomentum/haproxy

By ergomentum

Updated about 10 years ago

Provides a [HAProxy](http://www.haproxy.org/) image.

Image
0

1.9K

ergomentum/haproxy repository overview

Docker Image Stars Docker Image Pulls

Ergomentum HAProxy

Provides a HAProxy image based on the Ergomentum CentOS image.

This is the gatekeeper for a docker service orchestration. The HAProxy acts a router which dispatches incoming requests to the corresponding services.

Responsibilities

  1. Logging: Log incoming requests
  2. Encryption: Redirect non TLS connections to TLS one.
  3. Virtual TLS hosting: Inspecting the hostname provided via SNI extension and route the request to the corresponding docker service. This allows end to end encryption.
  4. Sorry Backend: Provide as default backend where all clients without SNI support will be routed to. This can be used to explain why the client can't receive the required resource.
  5. Act as Transparent proxy: Only in transparent proxy mode each docker service will see the real client IP. This might be important for logging issues, authorization or to defeat SPAM.

Preconditions

Example

+----------------+
|     Client     |
+----------------+
| 192.168.99.1   |
+----------------+
        |
+----------------+
|  Docker Host   |
+----------------+
| 192.168.99.100 |---\
+----------------+   NAT
|   172.17.0.1   |---/
+----------------+
        |
+----------------+
|     HAProxy    |
+----------------+
|   172.17.0.2   |---\
+----------------+   NAT
|   172.18.0.2   |---/
+----------------+
        |
        +---------------------+
        |                     |
+----------------+   +----------------+
|  tls-default   |   |  example.com   |
+----------------+   +----------------+
|   172.18.0.2   |   |   172.18.0.3   |
+----------------+   +----------------+

Volumes

/etc/haproxy/haproxy.cfg
The HAProxy configuration, see Usage.

Environment Variables

None.

Exposed Ports

80
The HTTP default port.
443
The HTTPS default port.

Configuration

General requirements

The container expects a HAProxy configuration file mounted to /etc/haproxy/haproxy.cfg. this must contain:

global
  # Uses the patched feature!
  log /dev/stdout local0
  pidfile /var/run/haproxy.pid

defaults
  mode tcp
  log global
  log-format %ci:%cp\ ->\ %fi:%fp\ ->\ %bi:%bp\ ->\ %si:%sp\ (%f->%b->%s)
  timeout connect 10s
  timeout client 1m
  timeout server 1m
  source 0.0.0.0 usesrc clientip
Rewrite HTTP to HTTPS requests

Add the following to the file /etc/haproxy/haproxy.cfg:

frontend http-to-https-rewrite
  bind *:80
  mode http
  redirect scheme https code 301 if !{ ssl_fc }
HTTPS frontend

Add the following to the file /etc/haproxy/haproxy.cfg:

frontend https-in
  # Bind to HTTPS default port:
  bind *:443

  # Use tcp content accepts to detects ssl client and server hello:
  tcp-request inspect-delay 5s

  tcp-request content accept if { req.ssl_hello_type 1 }

  # Map to a default backend if no more appropriate found:
  default_backend tls-default

  # Map to a backend depending from the hostname. Add as much mappings as needed:
  use_backend example.com if { req.ssl_sni -i example.com }
Define the default backend

Add the following to the file /etc/haproxy/haproxy.cfg:

backend tls-default
  stick-table type binary len 32 size 30k expire 30m
  acl clienthello req.ssl_hello_type 1
  acl serverhello res.ssl_hello_type 2

  # Use tcp content accepts to detects ssl client and server hello:
  tcp-request inspect-delay 5s

  tcp-request content accept if clienthello

  # No timeout on response inspect delay by default.

  tcp-response content accept if serverhello

  # Extract a binary block. The block length is defined at offset 43 with length 1. The block offset is at 43 + 1.
  # Offset start with 0. All values are decimals. This is to extract the TLS session ID from the TLS handshake record.
  #
  # TLS handshake record:
  # Offset              Length Content
  #      0                   1 Record type
  #      1                   2 TLS version
  #      3                   2 Record length
  #      5                   1 Handshake type
  #      6                   3 Record length
  #      9                   2 TLS Version
  #     11                   4 Unix timestamp
  #     15                  28 Random bytes
  #     43                   1 Session ID length
  #     44 <Session ID length> Session ID
  stick on req.payload_lv(43,1) if clienthello

  # Learn on response if server hello:
  stick store-response payload_lv(43,1) if serverhello

  # Map to a backend with name "sorry" and hostname "sorry":
  server sorry sorry:443
Define a backend

Add the following to the file /etc/haproxy/haproxy.cfg:

backend example.com
  stick-table type binary len 32 size 30k expire 30m
  acl clienthello req.ssl_hello_type 1
  acl serverhello res.ssl_hello_type 2

  # Use tcp content accepts to detects ssl client and server hello:
  tcp-request inspect-delay 5s

  # http://cbonte.github.io/haproxy-dconv/configuration-1.5.html#tcp-request%20content
  tcp-request content accept if clienthello

  # No timeout on response inspect delay by default.

  tcp-response content accept if serverhello

  # Extract a binary block. The block length is defined at offset 43 with length 1. The block offset is at 43 + 1.
  # Offset start with 0. All values are decimals. This is to extract the TLS session ID from the TLS handshake record.
  #
  # TLS handshake record:
  # Offset              Length Content
  #      0                   1 Record type
  #      1                   2 TLS version
  #      3                   2 Record length
  #      5                   1 Handshake type
  #      6                   3 Record length
  #      9                   2 TLS Version
  #     11                   4 Unix timestamp
  #     15                  28 Random bytes
  #     43                   1 Session ID length
  #     44 <Session ID length> Session ID
  stick on req.payload_lv(43,1) if clienthello

  # Learn on response if server hello:
  stick store-response payload_lv(43,1) if serverhello

  # Map to a backend with name "example.com" and hostname "myhttpd":
  server example.com myhttpd:443

Usage

Is is not necessary to use this image as base image. Simply create a container from it.

Run the example setup
docker network \
  create \
  --driver bridge \
  backend-network

docker \
  create \
  --name dispatcher \
  -v "$PWD/haproxy.cfg:/etc/haproxy/haproxy.cfg" \
  -p '80:80' \
  -p '443:443' \
  --cap-add=NET_ADMIN \
  ergomentum/haproxy
docker network \
  connect \
  backend-network \
  dispatcher
docker \
  run \
  -d \
  --name example.com \
  --net=backend-network \
  --cap-add=NET_ADMIN \
  ergomentum/httpd
docker \
  run \
  -d \
  --name tls-default \
  --net=backend-network \
  --cap-add=NET_ADMIN \
  ergomentum/httpd

# Must be started after all configured backends to resolve hostnames:
docker \
  start \
  dispatcher

# Must be run after the dispatcher is started to resolve the IP of the dispatcher:
docker \
  exec \
  -ti \
  example.com \
  bash -c 'yum -y install iproute && ip route replace default via $(getent hosts dispatcher | cut -d " " -f 1)'
docker \
  exec \
  -ti \
  tls-default \
  bash -c 'yum -y install iproute && ip route replace default via $(getent hosts dispatcher | cut -d " " -f 1)'

The iptables and the ip command require the NET_ADMIN capability.

Contributing

To contribute a feature or a bugfix please open a pull request on GitHub.

See CONTRIBUTING for details.

License

See the LICENSE file for license rights and limitations (Apache License, Version 2.0).

References

Tag summary

Content type

Image

Digest

Size

66.7 MB

Last updated

about 10 years ago

docker pull ergomentum/haproxy