在RHEL 8上安装HA Proxy

保護是我們共同的責任,我們應該努力保護我們的環境。

我使用了RHEL 8.2。

# cat /etc/redhat-release 
Red Hat Enterprise Linux release 8.2 (Ootpa)
#

2. 安装

yum -y  install haproxy

或者

dnf -y  install haproxy

只需要这些。

做作业所需的基本命令。

由于HA Proxy可以通过systemctl进行操作,所以基本操作几乎都可以想象得到。
为了在工作过程中方便复制粘贴,我们将列出常用的命令。

# 起動  
$ systemctl start haproxy

# 停止
$ systemctl stop haproxy

# 設定のリロード
$ systemctl reload haproxy

# ステータスの確認
$ systemctl status haproxy

#自動起動
$ systemctl enable haproxy

#自動起動設定確認
$ systemctl is-enabled haproxy

# haproxy.cfg の書式確認 (書いた設定ファイルにエラーが無いか確認するコマンド)
$ haproxy -f /etc/haproxy/haproxy.cfg -c

# ログの tail 
tail -f tail -f /var/log/haproxy.log

4.设置 => 设定

image.png

这个步骤不涉及到安装和配置用于转发请求的nginx。

4.1. Haproxy配置文件的设置

只需编辑/etdc/haproxy/haproxy.cfg的配置。

在RHEL上,默认(示例)设置下启用的端口5001〜5004等,由于SELinux不允许HAProxy访问,会导致错误,所以需要将相关部分注释掉。

#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   https://www.haproxy.org/download/1.8/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
    #
    #    localdomain2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

    # utilize system-wide crypto-policies
    ssl-default-bind-ciphers PROFILE=SYSTEM
    ssl-default-server-ciphers PROFILE=SYSTEM

#---------------------------------------------------------------------
# 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
    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
    maxconn                 3000

#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
# 以下はコメントアウト
# frontend main
#    bind *: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 http_80
    default_backend http_80
    mode http
    bind *:80

 frontend http_443
    default_backend http_443
    mode http
    bind *:443

#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
# backend static
#    balance     roundrobin
#    server      static 127.0.0.1:4331 check

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
# 以下はコメントアウト (SELinux に怒られる)
#  backend app
#    balance     roundrobin
#    server  app1 127.0.0.1:5001 check
#    server  app2 127.0.0.1:5002 check
#    server  app3 127.0.0.1:5003 check
#    server  app4 127.0.0.1:5004 check

backend http_80
    mode http
    balance   roundrobin
    server nginx1 nginx1.example.localdomain:80 check
    server nginx2 nginx2.example.localdomain:80 check

backend http_443
    mode http
    balance   roundrobin
    server nginx1 nginx1.example.localdomain:443 check
    server nginx2 nginx2.example.localdomain:443 check
image.png

请确认格式是否正确。

因为设置文件(/etc/haproxy/haproxy.cfg)很长,您可以使用以下命令来检查语法错误。

# haproxy.cfg の書式の確認(エラーがあった場合)
$ haproxy -f /etc/haproxy/haproxy.cfg -c
[WARNING] 226/115610 (34205) : parsing [/etc/haproxy/haproxy.cfg:124] : backend 'worker_http', another server named 'worker1' was defined without an explicit ID at line 123, this is not recommended.
[WARNING] 226/115610 (34205) : parsing [/etc/haproxy/haproxy.cfg:129] : backend 'worker_https', another server named 'worker1' was defined without an explicit ID at line 128, this is not recommended.
Configuration file is valid
$

#確認が上手く行ったケース
$ haproxy -f /etc/haproxy/haproxy.cfg -c
Configuration file is valid
$ 

如果没有问题,应该显示“配置文件有效”。

5. 针对HTTP/HTTPS的防火墙设置

RHELでは標準で firewalldが有効になっているので、ロードバランシングするサービスに応じて穴開けをしてあげる必要があります。

5.1.确认当前设置

我会检查当前的设置。

$ firewall-cmd --get-active-zones
libvirt
  interfaces: virbr0
public
  interfaces: ens192
$

interfaces: ens192は、public ゾーンに存在しています。
とりあえず、設定が必要なのは「public」のゾーンであると記憶します。
次は「public」に設定されている「サービス」を確認します。

$ firewall-cmd --list-services --zone=public
cockpit dhcpv6-client ssh
$

5.2. 在网络的协议 http / https中开辟一个漏洞。

http (80) と https (443)については、デフォルトで「サービス」の事前定義が存在しているので、それを追加するだけで firewalldに穴を開ける事ができます。

$ firewall-cmd --add-service=https --zone=public  --permanent
success
$ firewall-cmd --add-service=http --zone=public  --permanent
success

重新加载firewalld的设置。如果使用”–permanent”选项进行了添加,需要重新加载才能使设置生效。

$ firewall-cmd --reload

我会确认设置已经生效。

$ firewall-cmd --list-services --zone=public
cockpit dhcpv6-client http https ssh

已添加了httphttps。

在这里,我们没有特别更改其他默认开放的服务,但可以根据需要对其进行强化处理。

可以删除不必要的“服务”如下。

firewall-cmd --remove-service=<サービス名> --zone=public --permanent

6.Haproxy の起動と動作の確認

6.1 启动Haproxy

启动Haproxy。

#  haproxy を起動
$ systemctl start haproxy

自動起動を有効化します。

$ systemctl enable haproxy
$ systemctl is-enabled haproxy
enabled       

6.2 動作の確認

http(s)://haproxy.example.localdomain にアクセスしてみます。

この例では、トラフィックを割り振るバックエンドの nginxの画面をわかりやすいように変更していますが、リロードする度に接続先が切り替わるはずです。これは、haproxy.cfg に roundrobinを設定しているせいです。

image.png

如果只是想查看HA Proxy的运行情况,可以暂时避免设置7.Security。

HA Proxyの設定は、複雑になってくると、まずはRHELのセキュリティ設定をOFFにしてhaproxy.cfgの設定を確認したい時がどうしても出てきます。

以下は、RHELの標準のセキュリティ設定(SELinux と Firewalld) を停止させる方法です。

7.1.SELinux を停止

SELinux を一時的に停止する

$ setenforce 0   # 反対に稼働させるには 1 を指定

永久停用 SELinux

$ vim /etc/selinuxconig
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=enforcing  # ここを disabled に
・・・
・・
・

7.2. 停止 Firewalld

暫時停下當前正在運行的事物。

$ systemctl stop firewalld

确保在系统启动时也不会弹出来。

$ systemctl disable firewalld

8.一般的なfirewalldの穴あけ方法

HA Proxy は L4 (TCP)レベルのロードバランサーなので、HTTP/HTTPS 以外のプロトコルのロードバランスも行う事ができます。

8.1.事前定義された「サービス」の穴開けを行う

前述の通り http (80) と https (443)については、デフォルトで「サービス」の定義が存在しているので、その定義を使用して比較的簡単に firewalld に穴を開ける事ができます。

您可以使用 firewall-cmd –get-services 命令来查看预定义的默认“服务”。

$ firewall-cmd  --get-services
RH-Satellite-6 amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc bittorrent-lsd ceph ceph-mon cfengine cockpit condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns dns-over-tls docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger freeipa-4 freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master git grafana gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kdeconnect kerberos kibana klogin kpasswd kprop kshell kube-apiserver ldap ldaps libvirt libvirt-tls lightning-network llmnr machine-config managesieve matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy prometheus proxy-dhcp ptp pulseaudio puppetmaster quassel radius rdp redis redis-sentinel rpc-bind rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync spotify-sync squid ssdp ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tentacle tftp tftp-client tile38 tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server
$

仅通过看这些名字,也不知道它们到底是什么定义。

实际的预定义“服务”配置文件存储在/usr/lib/firewalld/services/目录下。

$ ls  /usr/lib/firewalld/services/
RH-Satellite-6.xml       freeipa-4.xml            libvirt-tls.xml           pop3.xml               ssh.xml
amanda-client.xml        freeipa-ldap.xml         libvirt.xml               pop3s.xml              steam-streaming.xml
amanda-k5-client.xml     freeipa-ldaps.xml        lightning-network.xml     postgresql.xml         svdrp.xml
amqp.xml                 freeipa-replication.xml  llmnr.xml                 privoxy.xml            svn.xml
amqps.xml                freeipa-trust.xml        managesieve.xml           prometheus.xml         syncthing-gui.xml
apcupsd.xml              ftp.xml                  matrix.xml                proxy-dhcp.xml         syncthing.xml
<省略>

例えばkube-apiserver という名前の事前定義の「サービス」があります。
このサービスは、「サービス」名と同じフィル名の/usr/lib/firewalld/services/kube-apiserver.xmlというファイルの中で定義されています。中身は読むとなんとなく判別できるものになっています。

$ cat /usr/lib/firewalld/services/kube-apiserver.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Kubernetes Api Server</short>
  <description>The Kubernetes API server validates and configures data for the api objects which include pods, services, replicationcontrollers, and others.</description>
  <port protocol="tcp" port="6443"/>
</service>
$

「サービス」の定義ファイルの中身は上記のようなものなので、自分が使いたい「サービス」が事前定義されているかは、ファイルの中身を検索する事で発見できます。例えばポート6443を使うサービスが事前定義されているかどうかは、以下のコマンドで検索できます。

$ find /usr/lib/firewalld/services -type f -print | xargs grep 6443
/usr/lib/firewalld/services/kube-apiserver.xml:  <port protocol="tcp" port="6443"/>
$

事前定義されている「サービス」の firewalld への穴開けの方法は、基本的に全て同じで、例えばkube-apiserverをpublicゾーンに追加するには以下のようにコマンドを実行します。

# permanent (再起動後も有効)に、設定を追加
$ firewall-cmd --add-service=kube-apiserver --zone=public  --permanent
success

# 設定の再読込
$ firewall-cmd --reload

8.2.カスタムの「サービス」を作成して穴開けを行う

例として「Machine Config」というサービスがあり、22623 /tcp というポートを使用したいとします。
まずは、以下のコマンドで自分の使用しいたいportがデフォルトで事前定義されてないか探してみます。

 find /usr/lib/firewalld/services -type f -print | xargs grep <自分の使用したいサービスのポート>

もし存在しない場合は、自分で新しい「サービス」を定義します。

在这里,我们将创建一个名为”machine-config”并使用22623/tcp的新服务。

添加新服务名称

$ firewall-cmd --permanent --new-service machine-config
success

「サービス」「machine-config」の説明を追加

$ firewall-cmd --permanent --service=machine-config --set-description="OpenShift machine config access"
success

增加新的“服务”“machine-config”的端口定义

$ firewall-cmd --service=machine-config --add-port=22623/tcp --permanent 
success

确认新建了一个名为“服务”的配置文件。用户定义的“服务”与预定义的“服务”文件的路径不同,它们被创建在/etc/firewalld/services/目录下。

$ cat /etc/firewalld/services/machine-config.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
  <description>OpenShift machine config access</description>
  <port port="22623" protocol="tcp"/>
</service>

读取新创建的“服务”文件。

$ firewall-cmd --reload

作成した「サービス」を firewalld を透過させる「サービス」として、ここではpublicゾーンに追加します。

$ firewall-cmd --add-service=machine-config --zone=public 
success

现在,我们要确认哪些“服务”已经设置为透过firewalld。我们要检查是否已添加了machine-config。

$ firewall-cmd --list-services
cockpit dhcpv6-client http https kube-apiserver machine-config ssh
$

再起動しても設定が外れないように、現在の設定を permanent にするコマンドを実行します。

$ firewall-cmd --runtime-to-permanent
success

9. SELinux的设置

特種なポートを使うアプリケーションのロードバランスを行う場合、HA Proxyがそのポートを使用する事が許可されていない場合は、SELinuxがHA Proxyの動きをブロックするため、haproxy が起動しません。

例えば設定を変更して、systemctlで再起動しようとすると、以下のように起動できないはずです。

$ systemctl restart haproxy.service
Job for haproxy.service failed because the control process exited with error code.
See "systemctl status haproxy.service" and "journalctl -xe" for details.
$

9.1 审计日志的验证

如果haproxy无法运行,请检查是否已停止运行,或检查audit.log日志文件,该日志文件被输出到/var/log/audit/audit.log。

但是 audit.log 文件本身不易读取,因此通过 ausearch 命令提供了一个工具来查看经过格式化的 audit.log。

haproxy 関連の audit.log のエラーは以下のコマンドで確認する事ができます。

[root@lb1 ~]# ausearch -c 'haproxy' --raw
type=AVC msg=audit(1602169554.880:195): avc:  denied  { name_bind } for  pid=2903 comm="haproxy" src=6443 scontext=system_u:system_r:haproxy_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0
type=AVC msg=audit(1602169554.880:196): avc:  denied  { name_bind } for  pid=2903 comm="haproxy" src=22623 scontext=system_u:system_r:haproxy_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0
[root@lb1 ~]# 

我可以看到字词”拒绝”,所以可以理解有某件事被否决了。

9.2 使用 audit2allow

ausearch での出力された denied のログを audit2allow というコマンドにパイプで渡す事で、行うべき SELinuxの設定を提案してくれます。ここでは、my-haproxyというファイル名にします。

$ ausearch -c 'haproxy' --raw | audit2allow -M my-haproxy
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i my-haproxy.pp

$ ls -ltr
-rw-r--r--. 1 root root  308 Oct  8 11:12 my-haproxy.te
-rw-r--r--. 1 root root  969 Oct  8 11:12 my-haproxy.pp
$

.ppと.te というファイルができますが、.teは可読なので中身を確認してみます。

$ cat my-haproxy.te 

module my-haproxy 1.0;

require {
        type haproxy_t;
        type unreserved_port_t;
        class tcp_socket name_bind;
}

#============= haproxy_t ==============

#!!!! This avc can be allowed using one of the these booleans:
#     nis_enabled, haproxy_connect_any
allow haproxy_t unreserved_port_t:tcp_socket { name_bind name_connect };
$

建议执行 `allow haproxy_t unreserved_port_t:tcp_socket name_bind;` 这个设置。

この設定を適用するには、以下のコマンドを実行します。

semodule -i my-haproxy.pp

这样应该可以启动haproxy了。

启用rsyslog

HA Proxy がきちんと動いているかどうか、確認したいなと思い、ログはどこか・・・と探した所、rsyslog で外に吐く設定をしてあげる必要があるようです。/var/log/haproxy.log  というファイルにログを吐くようにします。

/etc/rsyslog.conf を以下のように編集します。

・・・
# Provides UDP syslog reception
# for parameters see http://www.rsyslog.com/doc/imudp.html
#
#module(load="imudp") # needs to be done just once
#input(type="imudp" port="514")
# 以下の2行を追加
$ModLoad imudp
$UDPServerRun 514

<省略>

# *.info;mail.none;authpriv.none;cron.none                /var/log/messages
# 以下に書き換え (local2 が /var/log/message に出力されないようにするため。 /var/log/haproxy.log に出力したい)
*.info;mail.none;authpriv.none;cron.none;local2.none                /var/log/messages

<省略>

# Save boot messages also to boot.log
local7.*                                                /var/log/boot.log

# ここも追加 /var/log/haproxy.log にログを出力する。
# Save HAProxy maessage to haproxy.log
local2.*                                                /var/log/haproxy.log

编辑设置后,将重新启动 rsyslog。

systemctl restart rsyslog
广告
将在 10 秒后关闭
bannerAds