把Web叢集由HTTP轉換為HTTPS(LVS+HAProxy+SSL)

天府雲創發表於2018-01-12

一、環境介紹

    接到通知,要求網站由http改為使用https,目前我的網站前端架構如下圖所示:

wKioL1cfFiviTO_AAAEJI0txodI055.jpg

    假設我們有兩臺物理機,每臺物理機上面有很多的tomcat容器,前端使用的是haproxy進行的http層負載均衡,再前端我們使用了LVS負載均衡,整個LVS使用的是DR模型。

    剛開始我打算把tomcat改成https,設定成之後再設定haproxy的時候,發現haproxy不能再使用負載均衡了,因為SSL是在第四層的,所以這個方案就結束了,下面我就嘗試在haproxy層設定SSL,到後端還使用普通的連線。

 

二、設定步驟

1、概述

    如果你的應用使用SSL證照,則需要決定如何在負載均衡器上使用它們。

    單伺服器的簡單配置通常是考慮客戶端SSL連線如何被接收請求的伺服器解碼。由於負載均衡器處在客戶端和更多伺服器之間,SSL連線解碼就成了需要關注的焦點。

2、有兩種主要的策略

wKiom1cgIdbyyPzfAACvrbg2YNE071.jpg

  •     第一種是我們選擇的模式,在haproxy這裡設定SSL,這樣我們可以繼續使用七層負載均衡。SSL連線終止在負載均衡器haproxy ----->解碼SSL連線併傳送非加密連線到後端應用tomcat,這意味著負載均衡器負責解碼SSL連線,這與SSL穿透相反,它是直接向代理伺服器傳送SSL連線的。

  •     第二種使用SSL穿透,SSL連線在每個tomcat伺服器終止,將CPU負載都分散到tomcat伺服器。然而,這樣做會讓你失去增加或修改HTTP報頭的能力,因為連線只是簡單地從負載均衡器路由到tomcat伺服器,這意味著應用伺服器會失去獲取 X-Forwarded-* 報頭的能力,這個報頭包含了客戶端IP地址、埠和使用的協議。

  •     有兩種策略的組合做法,那就是第三種,SSL連線在負載均衡器處終止,按需求調整,然後作為新的SSL連線代理到後臺伺服器。這可能會提供最大的安全性和傳送客戶端資訊的能力。這樣做的代價是更多的CPU能耗和稍複雜一點的配置。

  •     選擇哪個策略取決於你及應用的需求。SSL終端為我所見過最典型的策略,但SSL穿透可能會更安全。

3、使用HAProxy作為SSL終端

    首先,我們將介紹最典型的解決方案 - SSL 終端。正如前面提到的,我們需要讓負載均衡器處理SSL連線。這就意味著要將SSL證照放在負載均衡伺服器上。

   記住,在生產環境裡使用(而不是自簽名)的SSL證照,是不會需要你自己來生成或簽名 - 你只需要建立證照籤名請求 (csr) 並把它交給那個你向它購買證照的機構即可。

    首先, 我們建立一份自簽名的證照作為示範,並在本地使用同一份證照。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
openssl genrsa -out /etc/haproxy/wzlinux.key 2048
openssl req -new -key /etc/haproxy/wzlinux.key -out /etc/haproxy/wzlinux.csr
  
> Country Name (2 letter code) [AU]:CN
> State or Province Name (full name) [Some-State]:Shanghai
> Locality Name (eg, city) []:Shanghai
> Organization Name (eg, company) [Internet Widgits Pty Ltd]:wzlinux
> Organizational Unit Name (eg, section) []:
> Common Name (e.g. server FQDN or YOUR name) []:www.wzlinux.com
> Email Address []:
> Please enter the following 'extra' attributes to be sent with your certificate request
> A challenge password []:
> An optional company name []:
  
cd /etc/haproxy
openssl x509 -req -days 3655 -in wzlinux.csr -signkey wzlinux.key -out wzlinux.crt

    這就生成了wzlinux.csr,wzlinux.key和wzlinux.crt檔案了。

    接著,在建立了證照之後,我們需要建立pem檔案。pem檔案本質上只是將證照、金鑰及證照認證中心證照(可有可無)拼接成一個檔案。在我們的例子中,我們只是簡單地將證照及金鑰檔案並以這個順序拼接在一樣來建立wzlinux.pem 檔案。這是HAProxy讀取SSL證照首選的方式。

1
cat wzlinux.crt wzlinux.key | tee wzlinux.pem

    當購買真正的證照 時,你不一定會獲取拼接後的檔案。你可以要自己拼接它們。然而,很多機構也會提供一份拼接好的檔案給你。如果你沒有獲取到拼接後的檔案,則它可能不是一個 pem 檔案,而是 bundle、cert、cert、key檔案或一些相同概念但名稱類似的檔案。

    無論如何,只要我們得到了HAProxy使用的pem檔案,我們只需經過簡單配置就是可以處理SSL連線了。

    下面我們將要配置haproxy來安裝SSL證照,配置檔案如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    # local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2 warning
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     400000
    user        haproxy
    group       haproxy
    daemon
    tune.ssl.default-dh-param  2048
#    nbproc      3
    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option                  http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    option                  httpclose
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    stats enable
    stats hide-version
    stats uri     /haproxy?status
    stats realm   Haproxy\ Statistics
    stats auth    admin:asd870719
#   stats admin if TRUE
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
#frontend  main *:5000
#   acl url_static       path_beg       -i /static /images /javascript /stylesheets
#   acl url_static       path_end       -i .jpg .gif .png .css .js
#   use_backend static          if url_static
#   default_backend             app
frontend  wzlinux_ssl
      bind *:80
      bind *:443 ssl crt /etc/haproxy/wzlinux.pem
      mode http
      default_backend  wzlinux
#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
#backend static
#   balance     roundrobin
#   server      static 127.0.0.1:4331 check
backend wzlinux
    mode http
    balance     roundrobin
    option forwardfor
#   option httpchk HEAD / HTTP/1.1\r\nHost:localhost
    server      wzlinux01  10.0.0.9:8080 check inter 15000 rise 2 fall 4
    server      wzlinux02  10.0.0.9:8081 check inter 15000 rise 2 fall 4
    server      wzlinux03  10.0.0.9:8082 check inter 15000 rise 2 fall 4
    server      wzlinux04  10.0.0.9:8083 check inter 15000 rise 2 fall 4
    server      wzlinux05  10.0.0.9:8084 check inter 15000 rise 2 fall 4
    server      wzlinux06  10.0.0.9:8085 check inter 15000 rise 2 fall 4
    server      wzlinux07  10.0.0.9:8086 check inter 15000 rise 2 fall 4
#   http-request set-header X-Forwarded-Port %[dst_port]
#   http-request add-header X-Forwarded-Proto https if { ssl_fc }

    因為 SSL 連線在負載均衡器上終止了,我們依然來傳送正常的 HTTP 請求到後臺伺服器。

只接受SSL連線

    如果你想讓網站只接受SSL連線,你可以新增向前端配置加上redirect導向:

1
2
3
4
5
6
frontend wzlinux_ssl
    bind *:80
    bind *:443 ssl crt /etc/haproxy/wzlinux.pem
    redirect scheme https if !{ ssl_fc }
    mode http
    default_backend wzlinux

    上面,我們新增了 redirect 導向,如果連線不是通過SSL連線的,它將http重定向到https。

4、使用HAProxy實現SSL穿透

    使用SSL穿透,我們將讓後臺伺服器處理SSL連線,而非負載均衡器來處理。

    負載均衡器的工作就只是簡單地將請求轉發到配置好的後臺伺服器。因為連線還保持加密狀態,HAProxy只能將它轉發給其他伺服器,其他事情就沒法做了。

    在這個配置中,我們需要在前端和後臺配置中同時使用TCP模式而不是HTTP模式。HAProxy只會把連線當作資訊流來轉發到其他伺服器,而不會使用在HTTP請求上才能使用的功能。

首先,我們調整一下前端配置:

1
2
3
4
5
6
frontend wzlinux_ssl
    bind *:80
    bind *:443
    option tcplog
    mode tcp
    default_backend wzlinux

    這裡依然同時繫結80和443埠,以保證正常的HTTP連線和SSL連線都能工作。

    正如上述提到的,轉發一個安全連線而伺服器而不作任何解碼,我們需要使用TCP模式(mode tcp)。這也意味著我們需要設定tcp日誌而不是預設的http日誌(option tcplog)。

    接著,我們要調整後臺end配置。注意,我們還要將這個更改成TCP模式,並刪除一些directives以避免因為修改/增加HTTP報頭功能所帶來的衝突: 

1
2
3
4
5
6
7
8
9
10
11
backend wzlinux
    mode tcp
    balance roundrobin
    option ssl-hello-chk
    server      wzlinux01  10.0.0.9:8080 check inter 15000 rise 2 fall 4
    server      wzlinux02  10.0.0.9:8081 check inter 15000 rise 2 fall 4
    server      wzlinux03  10.0.0.9:8082 check inter 15000 rise 2 fall 4
    server      wzlinux04  10.0.0.9:8083 check inter 15000 rise 2 fall 4
    server      wzlinux05  10.0.0.9:8084 check inter 15000 rise 2 fall 4
    server      wzlinux06  10.0.0.9:8085 check inter 15000 rise 2 fall 4
    server      wzlinux07  10.0.0.9:8086 check inter 15000 rise 2 fall 4

    正如你所看到的,這裡設定成了mode tcp - 前端和後臺配置都需要設定成這個模式。

    我們還刪除了option forwardfor和http-request選項 - 這些不能用於TCP模式,而且我們也不能向已加密的請求新增報頭,還有一些前面的預設配置也刪去關於http的配置,這裡不再演示。

    為了檢查正確與否,我們可以使用ssl-hello-chk來檢查連線及它處理SSL(特別是SSLv3)連線的能力。

    在這個例子中,我虛構了兩個接受SSL證照的後臺伺服器。如果你有閱讀過edition SSL certificates,你會看到如何將它們整合到 Apache 或 Nginx 來建立一個網路伺服器後臺,以處理SSL通訊。使用SSL 穿越,不需要給HAProxy建立或使用SSL證照。後臺伺服器都能夠處理SSL連線,如同只有一臺伺服器且沒有使用負載均衡器那樣。 

相關文章