負荷分散で、マルチドメインSSL処理を組める構成を検討することがあったので、
haproxy1.5 + keepalived
をやってみる。環境は以下の通り
・OSは2台(keeplived + haproxy + Webサーバー)
・
・haproxyはポート443でリスンする
・ドメインは、「host1.hayachi617.jp」と「host2.hayachi617.jp」の2つとする。
・webサーバーは8080でリスンする
・webサーバーのヘルスチェックは、hc.htmlとする
・「host1.hayachi617.jp」は、Active-Standbyの構成
・「host2.hayachi617.jp」は、負荷分散(ラウンドロビン)でSessionStickyとする。
1.haproxy1.5のインストール
rpmがないので、ソースからビルドする。rpm-build環境は
ここで作成したものを使う。
$ sudo yum install pcre-devel openssl-devel
$ mkdir ~/rpmbuild
$ cd ~/rpmbuild/SOURCES/
$ wget http://www.haproxy.org/download/1.5/src/haproxy-1.5.3.tar.gz
$ rpmdev-extract haproxy-1.5.3.tar.gz
$ cp -p haproxy-1.5.3/examples/haproxy.spec ../SPECS/haproxy153.spec
SSLを使えるように修正する
$ vi ../SPECS/haproxy153.spec
(元)
%{__make} USE_PCRE=1 DEBUG="" ARCH=%{_target_cpu} TARGET=linux26
(新)
%{__make} USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 DEBUG="" ARCH=%{_target_cpu} TARGET=linux26
$ mv haproxy-1.5.3.tar.gz ./haproxy-1.5.3-1.src/
$ rpmbuild -bb ./SPECS/haproxy153.spec
出来上がり!でアカウント作って、インストールする
$ useradd haproxy
$ sudo rpm -ivh ./RPMS/x86_64/haproxy-1.5.3-1.x86_64.rpm
$ haproxy -vv
Copyright 2000-2014 Willy Tarreau <w@1wt.eu>
Build options :
TARGET = linux26
CPU = generic
CC = gcc
CFLAGS = -m64 -march=x86-64 -O2 -g -fno-strict-aliasing
OPTIONS = USE_ZLIB=1 USE_OPENSSL=1 USE_PCRE=1
Default settings :
maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200
Encrypted password support via crypt(3): yes
Built with zlib version : 1.2.3
Compression algorithms supported : identity, deflate, gzip
Built with OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013
Running on OpenSSL version : OpenSSL 1.0.1e-fips 11 Feb 2013
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports prefer-server-ciphers : yes
Built with PCRE version : 7.8 2008-09-05
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Built with transparent proxy support using: IP_TRANSPARENT IP_FREEBIND
Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use epoll.
OpenSSLも有効になっているようです。インストール完了。
2.haproxyの設定
haproxyの設定をする。
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# ログの出力(level:debug)
log 127.0.0.1 local6 debug
# pidファイルのパス
pidfile /var/run/haproxy.pid
# 1プロセスに対する最大接続数
maxconn 4096
#SSL鍵長
tune.ssl.default-dh-param 2048
# 実行ユーザとグループ
user haproxy
group haproxy
# 起動プロセスはバックグラウンドで動作します
daemon
# 起動するプロセス数(ログの解析が難しくなるため1つが推奨とのこと)
nbproc 1
# プロセスごとの最大ファイルディスクリプタを設定。書かなくても自動で設定されるらしい
#ulimit-n 12000
# 統計情報(*1)
stats socket /var/run/haproxy/stats.socket user haproxy group haproxy level admin
# 統計情報:アイドル時のタイムアウト(デフォルト10秒)
stats timeout 60s
# 統計情報:最大接続数
stats maxconn 5
#---------------------------------------------------------------------
# デフォルト設定
#---------------------------------------------------------------------
defaults
# L7⇒http、L4⇒TCP。L4のほうが性能がよい
mode http
# ログの設定。globalセクションでの設定が引き継ぐ
log global
# NULLなコネクション(監視用アクセス)のログを書き出さない設定
option dontlognull
# ヘルスチェックのログを書き出す。
option log-health-checks
# backendサーバに接続できない時のタイムアウト値(ミリ秒:デフォルト10000msec)
timeout connect 10000
# クライアントサイドでのタイムアウト数。"timeout server"と同じ値が推奨。
timeout client 30000
# サーバサイドのタイムアウト秒数
timeout server 30000
# 接続に失敗した際のリトライ回数
retries 3
#---------------------------------------------------------------------
# 統計情報のWeb参照用の設定。8088ポートで受ける(*2)
#---------------------------------------------------------------------
listen hastats *:8088
mode http
maxconn 64
timeout connect 5000
timeout client 10000
timeout server 10000
stats enable
stats show-legends
#statsページのパス
stats uri /haproxy?hastats
#statsページに認証を設定
stats auth testid:testpass
#---------------------------------------------------------------------
# 1.複数 SSL 処理
#---------------------------------------------------------------------
frontend ssl
#証明書を複数指定する(*3)
bind *:443 ssl crt /vagrant/web1.cer crt /vagrant/web1.cer
#X-Forwarded-Host ヘッダーを追加する
http-request set-header X-Forwarded-Host %[req.hdr(host)]
# X-Forwarded-For を使う
option forwardfor
# ドメインによってbackupendを切り替える
use_backend host_web1_hayachi617_jp if { ssl_fc_sni web1.hayachi617.jp }
use_backend host_web2_hayachi617_jp if { ssl_fc_sni web2.hayachi617.jp }
# web1の振り分け先はActive-Standbyにする
backend host_web1_hayachi617_jp
balance roundrobin
option httpchk GET /hc.html
server a1 192.168.0.57:8080 check inter 5000 downinter 500 # active node
server a2 192.168.0.58:8080 check inter 5000 backup # passive node
# web2の振り分け先はCookieによるSessionSticky構成とする
backend host_web2_hayachi617_jp
balance roundrobin
option httpchk GET /hc.html
cookie SERVERID insert nocache indirect
server a3 192.168.0.57:8080 cookie ck_a3 check
server a4 192.168.0.58:8080 cookie ck_a4 check
それぞれの設定の意図は、コメントで記載。(*1)(*2)については以下記載する。
3.hapxoyをコマンドで操作する
設定ファイルの(*1)について。
コマンドで操作する場合は、socatを使うらしい。socatはepelのレポジトリにあるので、
まずはそこから。
$ wget http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/6Server/x86_64/epel-release-6-8.noarch.rpm
$ sudo rpm -ivh epel-release-6-8.noarch.rpm
$ sudo yum install --enablerepo=epel socat
これで準備完了。
## (1)で指定したユーザーに変更し、
$ su - haproxy
## haproyの情報を出力してみる
$ echo "show info" | socat stdio /var/run/haproxy/stats.socket
Name: HAProxy
Version: 1.5.3
Release_date: 2014/07/25
Nbproc: 1
Process_num: 1
Pid: 16597
Uptime: 0d 1h38m46s
Uptime_sec: 5926
Memmax_MB: 0
Ulimit-n: 8235
Maxsock: 8235
Maxconn: 4096
Hard_maxconn: 4096
CurrConns: 0
CumConns: 4
CumReq: 4
MaxSslConns: 0
CurrSslConns: 0
CumSslConns: 0
Maxpipes: 0
PipesUsed: 0
PipesFree: 0
ConnRate: 0
ConnRateLimit: 0
MaxConnRate: 1
SessRate: 0
SessRateLimit: 0
MaxSessRate: 1
SslRate: 0
SslRateLimit: 0
MaxSslRate: 0
SslFrontendKeyRate: 0
SslFrontendMaxKeyRate: 0
SslFrontendSessionReuse_pct: 0
SslBackendKeyRate: 0
SslBackendMaxKeyRate: 0
SslCacheLookups: 0
SslCacheMisses: 0
CompressBpsIn: 0
CompressBpsOut: 0
CompressBpsRateLim: 0
ZlibMemUsage: 0
MaxZlibMemUsage: 0
Tasks: 29
Run_queue: 1
Idle_pct: 100
node: web1.hayachi617.jp
description:
## 対話で進めてみる
$ socat readline /var/run/haproxy/stats.socket
prompt
>
## helpを表示
> help
Unknown command. Please enter one of the following commands only :
clear counters : clear max statistics counters (add 'all' for all counters)
clear table : remove an entry from a table
help : this message
prompt : toggle interactive mode with prompt
quit : disconnect
show info : report information about the running process
show pools : report information about the memory pools usage
show stat : report counters for each proxy and server
show errors : report last request and response errors for each proxy
show sess [id] : report the list of current sessions or dump this session
show table [id]: report table usage stats or dump this table's contents
get weight : report a server's current weight
set weight : change a server's weight
set server : change a server's state or weight
set table [id] : update or create a table entry's data
set timeout : change a timeout setting
set maxconn : change a maxconn setting
set rate-limit : change a rate limiting value
disable : put a server or frontend in maintenance mode
enable : re-enable a server or frontend which is in maintenance mode
shutdown : kill a session or a frontend (eg:to release listening ports)
show acl [id] : report avalaible acls or dump an acl's contents
get acl : reports the patterns matching a sample for an ACL
add acl : add acl entry
del acl : delete acl entry
clear acl <id> : clear the content of this acl
show map [id] : report avalaible maps or dump a map's contents
get map : reports the keys and values matching a sample for a map
set map : modify map entry
add map : add map entry
del map : delete map entry
clear map <id> : clear the content of this map
set ssl <stmt> : set statement for ssl
## haproxyの情報出力
> show info
Name: HAProxy
Version: 1.5.3
Release_date: 2014/07/25
Nbproc: 1
Process_num: 1
Pid: 2927
Uptime: 0d 0h06m10s
Uptime_sec: 370
Memmax_MB: 0
Ulimit-n: 8235
Maxsock: 8235
Maxconn: 4096
Hard_maxconn: 4096
CurrConns: 0
CumConns: 6
CumReq: 6
MaxSslConns: 0
CurrSslConns: 0
CumSslConns: 0
Maxpipes: 0
PipesUsed: 0
PipesFree: 0
ConnRate: 0
ConnRateLimit: 0
MaxConnRate: 1
SessRate: 0
SessRateLimit: 0
MaxSessRate: 1
SslRate: 0
SslRateLimit: 0
MaxSslRate: 0
SslFrontendKeyRate: 0
SslFrontendMaxKeyRate: 0
SslFrontendSessionReuse_pct: 0
SslBackendKeyRate: 0
SslBackendMaxKeyRate: 0
SslCacheLookups: 0
SslCacheMisses: 0
CompressBpsIn: 0
CompressBpsOut: 0
CompressBpsRateLim: 0
ZlibMemUsage: 0
MaxZlibMemUsage: 0
Tasks: 29
Run_queue: 1
Idle_pct: 100
node: lvs1.hayachi617.jp
description:
## 統計情報を出力してみる(カンマ区切りで出力される)
>show stat
#pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,
hastats,FRONTEND,,,0,0,64,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,2,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,,0,0,0,0,,,,,,,,
hastats,BACKEND,0,0,0,0,7,0,0,0,0,0,,0,0,0,0,UP,0,0,0,,0,421,0,,1,2,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,
ssl,FRONTEND,,,0,0,2000,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,3,0,,,,0,0,0,0,,,,0,0,0,0,0,0,,0,0,0,,,0,0,0,0,,,,,,,,
host_web1_hayachi617_jp,a1,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,421,0,,1,4,1,,0,,2,0,,0,L7OK,200,0,0,0,0,0,0,0,0,,,,0,0,,,,,-1,OK,,0,0,0,0,
host_web1_hayachi617_jp,a2,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,0,1,0,0,421,0,,1,4,2,,0,,2,0,,0,L7OK,200,1,0,0,0,0,0,0,0,,,,0,0,,,,,-1,OK,,0,0,0,0,
host_web1_hayachi617_jp,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,UP,1,1,1,,0,421,0,,1,4,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,
host_web2_hayachi617_jp,a3,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,1,0,0,0,421,0,,1,5,1,,0,,2,0,,0,L7OK,200,0,0,0,0,0,0,0,0,,,,0,0,,,,,-1,OK,,0,0,0,0,
host_web2_hayachi617_jp,a4,0,0,0,0,,0,0,0,,0,,0,0,0,0,UP,1,0,1,0,0,421,0,,1,5,2,,0,,2,0,,0,L7OK,200,1,0,0,0,0,0,0,0,,,,0,0,,,,,-1,OK,,0,0,0,0,
host_web2_hayachi617_jp,BACKEND,0,0,0,0,200,0,0,0,0,0,,0,0,0,0,UP,1,1,1,,0,421,0,,1,5,0,,0,,1,0,,0,,,,0,0,0,0,0,0,,,,,0,0,0,0,0,0,-1,,,0,0,0,0,
・
・
・
# 終了
>quit
4.hapxoyの統計情報を見る
指定したポートおよびURI(http:///192.168.0.57:8088/haproxy?hastats)にアクセスすることで、コマンドラインのshow statと同じ情報がWebサイトで見ることができる。設定で認証をかけているので、記載しているIDとPASSでログイン。
なるほどですね。
5.haproxyの小ネタ(その他)
その他の小ネタで、設定ファイルの(*3)のサーバ証明書ですが、ここではコモンネーム毎にサーバー証明書と中間証明書と秘密鍵を1つのファイルにまとめて簡素化している。
-----BEGIN CERTIFICATE-----
(サーバー証明書)
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
(中間証明書)
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
(秘密鍵)
-----END RSA PRIVATE KEY-----
6.keepalivedで冗長化する
ここまでで、haproxyの設定は完了したので、あとは冗長化。
## keepalivedのインストール
$ sudo yum install keepalived
設定のポイントは、
・VIPは、192.68.0.61とする
・VIPをつけるインターフェースはeth1とする
・冗長化のみでフォワーディングはしない
・Active条件はhaproxyのプロセス存在とする(haproxy自体がおかしな動きはしない想定)
・2台とも同じ設定にすることで、先に起動したほうがmasterになる(みたい)
・スタータス"master","backup","falut"になった時にそれぞれシェルが実行される
(でも中身は今後)
とする。
# =====================
# Global
# =====================
global_defs {
notification_email {
root@localhost
}
lvs_id virtuals
smtp_server localhost
smtp_connect_timeout 40
notification_email_from root@localhost
}
# =====================
# Check
# =====================
vrrp_script check_haproxy {
script "killall -0 haproxy"
interval 2
}
# =====================
# VRRP
# =====================
vrrp_instance VirtualInstance1 {
state BACKUP
interface eth1
virtual_router_id 1
priority 100
advert_int 5
nopreempt
authentication {
auth_type PASS
auth_pass passwd
}
virtual_ipaddress {
192.168.0.61
}
track_script {
check_haproxy
}
notify_master "/etc/keepalived/master.sh"
notify_backup "/etc/keepalived/backup.sh"
notify_fault "/etc/keepalived/fault.sh"
}
(2015/11/06 追記)
SSLv3(POODLE脆弱性)の対応ということで、SSLv3の無効化を記載
#---------------------------------------------------------------------
・
・
#---------------------------------------------------------------------
# 1.複数 SSL 処理
#---------------------------------------------------------------------
frontend ssl
#証明書を複数指定する(*3)
bind *:443 ssl crt /vagrant/web1.cer crt /vagrant/web1.cer
・
・
こちらの設定を、
#---------------------------------------------------------------------
・
・
#---------------------------------------------------------------------
# 1.複数 SSL 処理
#---------------------------------------------------------------------
frontend ssl
#証明書を複数指定する(*3)
bind *:443 ssl crt /vagrant/web1.cer crt /vagrant/web1.cer no-sslv3
・
・
でいける。
(2015/12/11 追記)
・keepalivedでIPの確認方法を記載
$ ip addr show eth1
4: eth1: mtu 1500 qdisc mq state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.0.5x/24 brd 192.168.0.1 scope global eth1
inet 192.168.0.61/32 scope global eth2
・ssl通信の確認方法を記載
#---------------------------------------------------------------------
$ openssl s_client -connect localhost:443 -ssl3
CONNECTED(00000003)
139752400205640:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1193:SSL alert number 40
139752400205640:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:590:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : SSLv3
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1418264801
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
でSSLv3で接続しに行き、失敗していることが確認できる。