HAProxy Load Balancing cho web server sử dụng SSL

Posted: Tháng Một 30, 2019 in HAProxy, Load Balancing
Thẻ:, ,

Trong mô hình Load Balancing, HAProxy đứng giữa client và các backend servers, vì vậy kết nối mã hóa SSL giữa client và server sẽ có thể được thực hiện theo các cách thức sau:

  • Thực hiện yêu cầu kết nối mã hóa SSL giữa Client và HAProxy, còn từ HAProxy thực hiện các kết nối không mã hóa với backend servers. Phương thức này gọi là SSL Termination

  • Thực hiện yêu cầu kết nối trực tiếp giữa Client và các backend servers. Tuy nhiên, khi đó chúng ta lại không thể thực hiện Add/Set phần Header. Phương thức này gọi là SSL Passthrough

  • Một cách thức khác là kết hợp cả 02 cách thức trên mà vừa đảm bảo phân tải xử lý của CPU, cũng như cho phép thực hiện chỉnh sửa thông tin Header.

Bài viết đi vào mô hình thực hiện ở cách thức kết nối SSL theo cách thức SSL Termination.

haproxy-ssl

Trong bài viết này, tôi sẽ hướng dẫn cấu hình HAProxy sử dụng SSL với  self-signed certificate và LetsEncrypt

1. Tự tạo self-signed certificate

Đây là certificate mà ta sẽ tự tạo ra trên chính server. Certificate này không được xác thực bởi các nhà cung cấp chứng chỉ số (CA). Mục đích tạo self-signed certificate là để kiểm tra hoặc sử dụng trong môi trường mạng local.

Các bước tạo self-signed certificate và cấu hình HAProxy sử dụng SSL như sau:

Step1: Tạo private key

Thực hiện tạo key cho local domain “example.local”.

  • Tạo thư mục chứa certificate
mkdir -p /etc/ssl/example.local
cd /etc/ssl/example.local
  • Tạo key với mã hóa RSA
openssl genrsa -des3 -out example.key 2048

root@vnsys:/etc/ssl/example.local# openssl genrsa -des3 -out example.key 2048
Generating RSA private key, 2048 bit long modulus
…………………………………………………+++
……………………………..+++
e is 65537 (0x10001)
Enter pass phrase for example.key:
Verifying – Enter pass phrase for example.key:

Quá trình tạo key ở trên yêu cầu nhập pass phrase. Để remove passphrase (mục đích là bỏ qua quá trình hỏi pass phrase) thực hiện như sau:

openssl rsa -in example.key -out example.key

root@vnsys:/etc/ssl/example.local# openssl rsa -in example.key -out example.key
Enter pass phrase for example.key:
writing RSA key

Step2: Đăng ký certificate (Certificate Signing Request -CSR)

Dựa vào key đã tạo ở Step1, chúng ta thực hiện đăng ký certificate

openssl req -new -key example.key -out example.csr

root@vnsys:/etc/ssl/example.local# openssl req -new -key example.key -out example.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
Country Name (2 letter code) [AU]:VN
State or Province Name (full name) [Some-State]:HN
Locality Name (eg, city) []:CG
Organization Name (eg, company) [Internet Widgits Pty Ltd]:IT
Organizational Unit Name (eg, section) []:Example Inc
Common Name (e.g. server FQDN or YOUR name) []:example.local
Email Address []:

Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Step3: Tạo certificate – CRT

Dựa vào CSR ở trên, chúng ta tạo một self-signed certificate, với hiệu lực 365 ngày

openssl x509 -req -days 365 -in example.csr -signkey example.key -out example.crt

root@vnsys:/etc/ssl/example.local# openssl x509 -req -days 365 -in example.csr -signkey example.key -out example.crt
Signature ok
subject=/C=VN/ST=HN/L=CG/O=IT/OU=Example Inc/CN=example.local
Getting Private key

Step4: Mở rộng key và cert thành tệp pem

Tệp pem là tệp tin chứa định dạng có thể chỉ public certificate hoặc có thể gồm tập public key, private key và root certificate kết hợp với nhau.

Chúng ta thực hiện nối private key và certificate ở trên để tạo thành tệp pem

cat example.key example.crt >>example.pem

Step5: Cấu hình HAProxy với SSL cho website

Sau khi đã có tệp pem, chúng ta cấu hình HAProxy để cho phép xử lý luồng kết nối với SSL.

Phần frontend

Chúng ta gán listen port cho https với port default là 443, không sử dụng giao thức sslv3, và chỉ định vị trí tệp pem “example.pem”.

  • Sử dụng đồng thời cả 02 giao thức HTTP và HTTPS
#Frontend Section
frontend http-in
        bind *:80
    bind *:443 ssl no-sslv3 crt /etc/ssl/example.local/example.pem 
        acl example-acl hdr(host) -i example.local
        use_backend example if example-acl

Ở đây chúng ta sử dụng tham số “crt” (certificate) trong bind. Thiết lập này được sử dụng khi cấu hình SSL, chỉ định đường dẫn tệp pem. Chúng ta có thể khai báo nhiều “crt” với nhiều tệp pem được chỉ định cho nhiều site mà sử dụng SSL.

  • Chỉ sử dụng HTTPS

Khi đó chúng ta cần thêm tùy chọn redirect khi truy cập http đến https

Redirect toàn bộ các site trong cấu hình HAProxy, thì sử dụng:

redirect scheme https code 301 if !{ ssl_fc }

Redirect với site chỉ định

redirect scheme https if { hdr(Host) -i example.local } !{ ssl_fc }

Khi đó, cấu hình frontend như sau:

## Frontend section
frontend http-in
        bind *:80
        bind *:443 ssl no-sslv3 crt /etc/ssl/example.local/example.pem
        redirect scheme https if { hdr(Host) -i example.local } !{ ssl_fc } 
        acl example-acl hdr(host) -i example.local
        use_backend example if example-acl

Note: Thay vì sử dụng default port cho https là 443, chúng ta muốn redirect đến https với một cổng tùy chọn, chẳng hạn 8443. Khi đó cấu hình tùy chọn như sau:

## Frontend section
frontend http-in
        bind *:80
        bind *:8443 ssl no-sslv3 crt /etc/ssl/example.local/example.pem
        http-request replace-value Host (.*):80 \1
        http-request redirect location https://%[req.hdr(Host)]:8443%[capture.req.uri] if !{ ssl_fc }
        acl example-acl hdr(host) -i   example.local
        use_backend example if example-acl

Phần Backend

Phần này, chúng ta sẽ khai báo thông tin thuật toán load balancing sẽ sử dụng, các thông tin web server , các tùy chọn về log và thiết lập tùy chọn header.

backend example
        balance roundrobin
        server server1 192.168.10.111:8080 weight 1 check
        server server2 192.168.10.112:8080 weight 1 check
        server server3 192.168.10.113:8080 weight 1 check
        option httplog
        option forwardfor
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }

Ở đây, chúng ta có một số tùy chọn:

option forwardfor : Được sử dụng để thêm header “X-Forwarded-For”, vì vậy backend có thể nhận được địa chỉ IP thực của client truy cập. Nếu không có tùy chọn này thì backend sẽ chỉ nhận được thông tin IP của HAProxy.

http-request set-header X-Forwarded-Port %[dst_port] : thiết lập một header “X-Forwarded-Port” vì vậy mà backend biết được port nào để sử dụng khi redirect URLs.

http-request add-header X-Forwarded-Proto https if { ssl_fc } : Thêm header X-Forwarded-Proto với thiết lập scheme là https nếu yêu cầu truy cập https. Cái này, cho phép backend xác định được scheme để sử dụng khi gửi URL lúc redirect

Khi đó, nội dung tệp cấu hình HAProxy đầy đủ cho site example.local sử dụng SSL như sau:

# Global settings
global
        log 127.0.0.1   local0
        pidfile     /var/run/haproxy.pid
        stats socket /var/lib/haproxy/stats
        maxconn 100000
        user haproxy
        group haproxy
        daemon
        quiet
# Proxies settings
## Defaults section
defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option      redispatch
        maxconn     100000
        retries                 3
        timeout http-request    5s
        timeout queue           30s
        timeout connect         30s
        timeout client          30s
        timeout server          30s
        timeout http-keep-alive 30s
        timeout check           30s
## Frontend section
frontend http-in
        bind *:80
        bind *:443 ssl no-sslv3 crt /etc/ssl/example.local/example.pem
        redirect scheme https if { hdr(Host) -i example.local } !{ ssl_fc } 
        acl example-acl hdr(host) -i example.local
        use_backend example if example-acl
backend example
        balance roundrobin
        server server1 192.168.10.111:8080 weight 1 check
        server server2 192.168.10.112:8080 weight 1 chec
        server server3 192.168.10.113:8080 weight 1 check
        option httplog
        option forwardfor
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
## Statistics settings
listen statistics
        bind *:1986
        stats enable
        stats admin if TRUE
        stats hide-version
        stats realm Haproxy\ Statistics
        stats uri /stats
        stats refresh 30s
        stats auth keepwalking86:ILoveVietnam$

2. Sử SSL sử dụng LetsEncrypt

Trong phần này, chúng ta sẽ sử dụng certificate được cung cấp bởi một nhà cung cấp certificate (certificate authority – CA). Sử dụng certificate này cho phép website được xác thực khi truy cập internet. Với điều kiện hạn chế, chúng ta có thể sử dụng certificate miễn phí của một số nhà cung cấp.

Trong phần cấu hình này, chúng ta sử dụng Let’s Encrypt để nhận certificate miễn phí với mỗi lần renew là 90 ngày.

Yêu cầu:

  • Website publish với tên miền internet.

Step1: Cài đặt Certbot

Để lấy certificate từ Let’s Encrypt chúng ta sử dụng công cụ Certbot

  • Cài đặt LetsEncrypt trên Ubuntu-16.04+
sudo add-apt-repository -y ppa:certbot/certbot
sudo apt-get update
sudo apt-get install -y certbot
  • Cài đặt LetsEncrypt trên CentOS 7
yum -y install epel-release
yum -y install certbot

Step2: Cấu hình HAProxy khi chưa https

Certbot có thể tự động lấy certificate, nhưng điều kiện cần là nó phải xác minh được domain hợp lệ. Tôi cấu hình haproxy cho website với tên miền mymusic.vn (thay mymusic.vn với thông tin website thực cần cấu hình) như sau:

# Global settings
global
        pidfile     /var/run/haproxy.pid
        maxconn 100000
        user haproxy
        group haproxy
        daemon
        quiet
        stats socket /var/lib/haproxy/stats
        log 127.0.0.1   local0

# Proxies settings
## Defaults section
defaults
        log     global
        mode    http
        option  httplog
        option  forwardfor
        option  dontlognull
        retries 3
        option      redispatch
        maxconn     100000
        retries                 3
        timeout http-request    5s
        timeout queue           10s
        timeout connect         10s
        timeout client          10s
        timeout server          10s
        timeout http-keep-alive 10s
        timeout check           10s

## Frontend section
frontend http-in
        bind *:80
        acl mymusic-acl hdr(host) -i mymusic.vn
        use_backend mymusic if mymusic-acl
## Backend section
backend mymusic
        balance roundrobin
        server server1 192.168.10.111:8080 weight 1 check
        server server2 192.168.10.112:8080 weight 1 check
        server server3 192.168.10.113:8080 weight 1 check
## Statistics settings
listen statistics
        bind *:1986
        stats enable
        stats admin if TRUE
        stats hide-version
        stats realm Haproxy\ Statistics
        stats uri /stats
        stats refresh 30s
        stats auth keepwalking86:ILoveVietnam$

Step3: Tạo New letsencrypt certificate bằng certbot

Nếu muốn tạo certificate và cấu hình haproxy, chúng ta cần cấp phép cho LetsEncrypt. Khi đó cần thiết lập một site stand-alone để listen khi ủy quyền cho LetsEncrypt.

Khi yêu cầu một certificate từ LetsEncrypt, nó sẽ yêu cầu được truy cập vào tệp tin được ủy quyền theo dạng đường dẫn “http://your-domain/well-known/acme-challenge/” và đường dẫn này bind đến cổng 80 cho yêu cầu http và 443 cho https. Khi đó chúng ta thực hiện yêu cầu certificate với một trong hai cách sau:

Cách 1: Stop HAProxy

Chẳng hạn haproxy đang listen ở port 80, khi đó stop haproxy và thực hiện chạy dòng lệnh sau để yêu cầu certificate từ LetsEncrypt

systemctl stop haproxy
certbot certonly --standalone -d mymusic.vn --non-interactive --agree-tos --email keepwalking86@mymusic.vn

root@vnsys:/home/keepwalking# certbot certonly –standalone -d mymusic.vn –non-interactive –agree-tos –email keepwalking86@mymusic.vn
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for mymusic.vn
Waiting for verification…
Cleaning up challenges

IMPORTANT NOTES:
– Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/mymusic.vn/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/mymusic.vn/privkey.pem
Your cert will expire on 2019-04-29. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew all of your certificates, run
“certbot renew”
– Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
– If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

Sau khi kết thúc quá trình nhận certificate cho site mymusic.vn từ LetsEncrypt thành công, khi đó thư mục chứa các tệp certificate, key nằm ở /etc/letsencrypt/live/mymusic.vn/

Cách 2: Haproxy vẫn hoạt động trên port 80

Để tránh xung đột port 80 với HAProxy, chúng ta sẽ cấu hình haproxy để bảo cho LetsEncrypt listen với một port khác, chẳng hạn 8080. Thực hiện cấu hình haproxy như sau:

  • Thêm tùy chọn acl trong phần frontend

Sử dụng cổng 80 cùng với site mymusic.vn nhưng khi đó, cần tạo acl để truy cập URL mà chứa chuỗi “/.well-known/acme-challenge/”

acl letsencrypt-acl path_beg /.well-known/acme-challenge/
use_backend letsencrypt if letsencrypt-acl
  • Cấu hình phần backend

Khai báo cổng listen sẽ sử dụng

backend letsencrypt
    server letsencrypt 127.0.0.1:8080

Khi đó reload haproxy và thực hiện tạo certificate như sau:

certbot certonly --standalone -d mymusic.vn --non-interactive --agree-tos --email keepwalking86@mymusic.vn --http-01-port=8080

root@vnsys:/home/keepwalking# certbot certonly –standalone -d mymusic.vn –non-interactive –agree-tos –email keepwalking86@mymusic.vn –http-01-port=8080
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for mymusic.vn
Waiting for verification…
Cleaning up challenges

IMPORTANT NOTES:
– Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/mymusic.vn/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/mymusic.vn/privkey.pem
Your cert will expire on 2019-04-29. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew all of your certificates, run
“certbot renew”
– If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

Trong đó, thuộc tính các tham số truyền vào như sau:

–standalone: Sử dụng chế độ standalone để đạt một certificate khi chúng ta không muốn sử dụng hoặc không có web server đang tồn tại. Sử dụng standalone, chúng ta kết hợp gồm lệnh “certonly”

-d mymusic.vn: chỉ định public domain hợp lệ “mymusic.vn” mà trỏ bản ghi “A” vào địa chỉ IP Public của haproxy. Tùy chọn “-d” có thể được sử dụng cho nhiều domain và yêu cầu cùng một certificate.

–non-interactive –agree-tos –email keepwalking86@mymusic.vn: Cho phép xác nhận các điều khoản, cũng như vào thông tin email tự động khi LetsEncrypt yêu cầu

–http-01-port=8080: Cái này bảo cho stand-alone server sẽ listen trên port 8080 của một request HTTP.

Step4: Mở rộng key và cert thành tệp pem

Tệp pem là tệp tin chứa định dạng có thể chỉ public certificate hoặc có thể gồm tập public key, private key và root certificate kết hợp với nhau.

Chúng ta thực hiện nối private key và certificate ở trên để tạo thành tệp pem.

cd /etc/letsencrypt/live/mymusic.vn/
cat fullchain.pem privkey.pem | tee mymusic.vn.pem

Step5: Cấu hình HAProxy sử dụng LetsEncrypt SSL

Sau khi đã có tệp pem, chúng ta cấu hình HAProxy để cho phép xử lý luồng kết nối với SSL.

Phần frontend

Chúng ta gán listen port cho https với port default là 443, không sử dụng giao thức sslv3, và chỉ định vị trí tệp pem “mymusic.vn.pem”.

  • Nếu HAProxy sử dụng đồng thời cả HTTP và HTTPS, khi đó cấu hình như sau:
## Frontend section
frontend http-in
        bind *:80
          bind *:443 ssl no-sslv3 crt /etc/letsencrypt/live/mymusic.vn/mymusic.vn.pem
        acl mymusic-acl hdr(host) -i mymusic.vn
        use_backend mymusic if mymusic-acl
  • HAProxy chỉ sử dụng HTTPS

Khi đó chúng ta cần thêm tùy chọn redirect khi truy cập http đến https

Redirect với site mymusic.vn

redirect scheme https if { hdr(Host) -i mymusic.vn } !{ ssl_fc }

Khi đó, cấu hình frontend như sau:

## Frontend section
frontend http-in
        bind *:80
        bind *:443 ssl no-sslv3 crt /etc/letsencrypt/live/mymusic.vn/mymusic.vn.pem
        redirect scheme https if { hdr(Host) -i mymusic.vn } !{ ssl_fc } 
        acl mymusic-acl hdr(host) -i mymusic.vn
        use_backend mymusic if mymusic-acl

Phần Backend

Chúng ta sẽ khai báo thông tin thuật toán load balancing sẽ sử dụng, các thông tin web server , các tùy chọn về log và thiết lập tùy chọn header.

backend mymusic
        balance roundrobin
        server server1 192.168.10.111:8080 weight 1 check
        server server2 192.168.10.112:8080 weight 1 chec
        server server3 192.168.10.113:8080 weight 1 check
        option httplog
        option forwardfor
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }

Ở đây, chúng ta có một số tùy chọn:

option forwardfor : Được sử dụng để thêm header “X-Forwarded-For”, vì vậy backend có thể nhận được địa chỉ IP thực của client truy cập. Nếu không có tùy chọn này thì backend sẽ chỉ nhận được thông tin IP của HAProxy.

http-request set-header X-Forwarded-Port %[dst_port] : thiết lập một header “X-Forwarded-Port” vì vậy mà backend biết được port nào để sử dụng khi redirect URLs.

http-request add-header X-Forwarded-Proto https if { ssl_fc } : Thêm header X-Forwarded-Proto với thiết lập scheme là https nếu yêu cầu truy cập https. Cái này, cho phép backend xác định được scheme để sử dụng khi gửi URL lúc redirect

Khi đó, nội dung tệp cấu hình HAProxy đầy đủ cho site mymusic.vn sử dụng SSL như sau:

# Global settings
global
        log 127.0.0.1   local0
        pidfile     /var/run/haproxy.pid
        stats socket /var/lib/haproxy/stats
        maxconn 100000
        user haproxy
        group haproxy
        daemon
        quiet
# Proxies settings
## Defaults section
defaults
        log     global
        mode    http
        option  httplog
        option  dontlognull
        retries 3
        option      redispatch
        maxconn     100000
        retries                 3
        timeout http-request    5s
        timeout queue           30s
        timeout connect         30s
        timeout client          30s
        timeout server          30s
        timeout http-keep-alive 30s
        timeout check           30s
## Frontend section
frontend http-in
        bind *:80
        bind *:443 ssl no-sslv3 crt /etc/letsencrypt/live/mymusic.vn/mymusic.vn.pem
        redirect scheme https if { hdr(Host) -i mymusic.vn } !{ ssl_fc } 
        acl mymusic-acl hdr(host) -i mymusic.vn
        use_backend mymusic if mymusic-acl
backend mymusic
        balance roundrobin
        server server1 192.168.10.111:8080 weight 1 check
        server server2 192.168.10.112:8080 weight 1 chec
        server server3 192.168.10.113:8080 weight 1 check
        option httplog
        option forwardfor
        http-request set-header X-Forwarded-Port %[dst_port]
        http-request add-header X-Forwarded-Proto https if { ssl_fc }
## Statistics settings
listen statistics
        bind *:1986
        stats enable
        stats admin if TRUE
        stats hide-version
        stats realm Haproxy\ Statistics
        stats uri /stats
        stats refresh 30s
        stats auth keepwalking86:ILoveVietnam$

Tham khảo thêm về LetsEncrypt

 

Bình luận

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s