{"id":295,"date":"2018-10-17T07:08:52","date_gmt":"2018-10-17T07:08:52","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw92\/index.php\/2018\/10\/17\/configure-haproxy-and-keepalived-with-puppet-lisenet-com-linux-security\/"},"modified":"2018-10-17T07:08:52","modified_gmt":"2018-10-17T07:08:52","slug":"configure-haproxy-and-keepalived-with-puppet-lisenet-com-linux-security","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw92\/index.php\/2018\/10\/17\/configure-haproxy-and-keepalived-with-puppet-lisenet-com-linux-security\/","title":{"rendered":"Configure HAProxy and Keepalived with Puppet | Lisenet.com :: Linux | Security"},"content":{"rendered":"<p>We\u2019re going to use Puppet to install and configure HAProxy to load balance Apache web services. We\u2019ll also configure Keepalived to provide failover capabilities. <\/p>\n<p>This article is part of the <a href=\"https:\/\/www.lisenet.com\/2018\/homelab-project-with-kvm-katello-and-puppet\/\" target=\"_blank\">Homelab Project with KVM, Katello and Puppet<\/a> series. See <a href=\"https:\/\/www.lisenet.com\/2015\/setting-up-a-load-balancing-haproxy-cluster-with-keepalived\/\" target=\"_blank\">here<\/a> for a blog post on how to configure HAProxy and Keepalived manually.<\/p>\n<h2>Homelab<\/h2>\n<p>We have two CentOS 7 servers installed which we want to configure as follows:<\/p>\n<p>proxy1.hl.local (10.11.1.19) \u2013 HAProxy with Keepalived (master router node)<br \/>proxy2.hl.local (10.11.1.20) \u2013 HAProxy with Keepalived (slave router node)<\/p>\n<p>SELinux set to enforcing mode.<\/p>\n<p>See the image below to identify the homelab part this article applies to. <\/p>\n<p><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"793\" src=\"https:\/\/www.lisenet.com\/wp-content\/uploads\/2018\/04\/lisenet-homelab-diagram_haproxy.png\" width=\"1200\" \/><\/p>\n<h2>HAProxy and Virtual IP<\/h2>\n<p>We use 10.11.1.30 as a virtual IP, with a DNS name of blog.hl.local. This is the DNS of our WordPress site.<\/p>\n<p>Below is a GIF representing our HA setup using HAProxy (primary and secondary load balancers).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"449\" src=\"https:\/\/www.lisenet.com\/wp-content\/uploads\/2018\/03\/network-diagram-lisenet.gif\" width=\"1200\" \/><\/p>\n<h2>Configuration with Puppet<\/h2>\n<p>Puppet master runs on the <a href=\"https:\/\/www.lisenet.com\/2016\/install-katello-on-centos-7\/\" target=\"_blank\">Katello<\/a> server.<\/p>\n<h3>Puppet Modules<\/h3>\n<p>We use the following Puppet modules:<\/p>\n<ol>\n<li><a href=\"https:\/\/forge.puppet.com\/arioch\/keepalived\" target=\"_blank\">arioch-keepalived<\/a> \u2013 to configure Keepalived<\/li>\n<li><a href=\"https:\/\/forge.puppet.com\/puppetlabs\/haproxy\" target=\"_blank\">puppetlabs-haproxy<\/a> \u2013 to configure HAProxy<\/li>\n<li><a href=\"https:\/\/forge.puppet.com\/thias\/sysctl\" target=\"_blank\">thias-sysctl<\/a> \u2013 to configure kernel parameters<\/li>\n<\/ol>\n<p>Please see each module\u2019s documentation for features supported and configuration options available.<\/p>\n<h3>Firewall Configuration<\/h3>\n<p>Configure both proxy servers to allow VRRP and HTTP\/S traffic. Port 8080 will be used for HAProxy statistics. <\/p>\n<p>firewall { &#8216;007 allow VRRP&#8217;:&#xD;<br \/>\n source =&gt; &#8216;10.11.1.0\/24&#8217;,&#xD;<br \/>\n proto =&gt; &#8216;vrrp&#8217;,&#xD;<br \/>\n action =&gt; accept,&#xD;<br \/>\n}-&gt;&#xD;<br \/>\nfirewall { &#8216;008 allow HTTP\/S&#8217;:&#xD;<br \/>\n dport =&gt; [80, 443, 8080],&#xD;<br \/>\n source =&gt; &#8216;10.11.1.0\/24&#8217;,&#xD;<br \/>\n proto =&gt; tcp,&#xD;<br \/>\n action =&gt; accept,&#xD;<br \/>\n}<\/p>\n<h3>Kernel Parameters and IP Forwarding<\/h3>\n<p>Load balancing in HAProxy requires the ability to bind to an IP address that is nonlocal. This allows a running load balancer instance to bind to a an IP that is not local for failover.<\/p>\n<p>In order for the Keepalived service to forward network packets properly to the real servers, each router node must have IP forwarding turned on in the kernel.<\/p>\n<p>sysctl { &#8216;net.ipv4.ip_forward&#8217;: value =&gt; &#8216;1&#8217; }&#xD;<br \/>\nsysctl { &#8216;net.ipv4.ip_nonlocal_bind&#8217;: value =&gt; &#8216;1&#8217; }<\/p>\n<h3>Install HAProxy<\/h3>\n<p>This needs to be applied for both proxy servers.<\/p>\n<p>file {&#8216;\/etc\/pki\/tls\/private\/hl.pem&#8217;:&#xD;<br \/>\n ensure =&gt; &#8216;file&#8217;,&#xD;<br \/>\n source =&gt; &#8216;puppet:\/\/\/homelab_files\/hl.pem&#8217;,&#xD;<br \/>\n path =&gt; &#8216;\/etc\/pki\/tls\/private\/hl.pem&#8217;,&#xD;<br \/>\n owner =&gt; &#8216;0&#8217;,&#xD;<br \/>\n group =&gt; &#8216;0&#8217;,&#xD;<br \/>\n mode =&gt; &#8216;0640&#8217;,&#xD;<br \/>\n}-&gt;&#xD;<br \/>\nclass { &#8216;haproxy&#8217;:&#xD;<br \/>\n global_options =&gt; {&#xD;<br \/>\n &#8216;log&#8217; =&gt; &#8220;127.0.0.1 local2&#8243;,&#xD;<br \/>\n &#8216;chroot&#8217; =&gt; &#8216;\/var\/lib\/haproxy&#8217;,&#xD;<br \/>\n &#8216;pidfile&#8217; =&gt; &#8216;\/var\/run\/haproxy.pid&#8217;,&#xD;<br \/>\n &#8216;maxconn&#8217; =&gt; &#8216;4096&#8217;,&#xD;<br \/>\n &#8216;user&#8217; =&gt; &#8216;haproxy&#8217;,&#xD;<br \/>\n &#8216;group&#8217; =&gt; &#8216;haproxy&#8217;,&#xD;<br \/>\n &#8216;daemon&#8217; =&gt; &#8221;,&#xD;<br \/>\n &#8216;ssl-default-bind-ciphers&#8217; =&gt; &#8216;kEECDH+aRSA+AES:kRSA+AES:+AES256:!RC4:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL&#8217;,&#xD;<br \/>\n &#8216;ssl-default-bind-options&#8217; =&gt; &#8216;no-sslv3&#8217;,&#xD;<br \/>\n &#8216;tune.ssl.default-dh-param&#8217; =&gt; &#8216;2048 &#8216;,&#xD;<br \/>\n },&#xD;<br \/>\n defaults_options =&gt; {&#xD;<br \/>\n &#8216;mode&#8217; =&gt; &#8216;http&#8217;,&#xD;<br \/>\n &#8216;log&#8217; =&gt; &#8216;global&#8217;,&#xD;<br \/>\n &#8216;option&#8217; =&gt; [&#xD;<br \/>\n &#8216;httplog&#8217;,&#xD;<br \/>\n &#8216;dontlognull&#8217;,&#xD;<br \/>\n &#8216;http-server-close&#8217;,&#xD;<br \/>\n &#8216;forwardfor except 127.0.0.0\/8&#8217;,&#xD;<br \/>\n &#8216;redispatch&#8217;,&#xD;<br \/>\n ],&#xD;<br \/>\n &#8216;retries&#8217; =&gt; &#8216;3&#8217;,&#xD;<br \/>\n &#8216;timeout&#8217; =&gt; [&#xD;<br \/>\n &#8216;http-request 10s&#8217;,&#xD;<br \/>\n &#8216;queue 1m&#8217;,&#xD;<br \/>\n &#8216;connect 10s&#8217;,&#xD;<br \/>\n &#8216;client 1m&#8217;,&#xD;<br \/>\n &#8216;server 1m&#8217;,&#xD;<br \/>\n &#8216;http-keep-alive 10s&#8217;,&#xD;<br \/>\n &#8216;check 10s&#8217;,&#xD;<br \/>\n ],&#xD;<br \/>\n &#8216;maxconn&#8217; =&gt; &#8216;2048&#8217;,&#xD;<br \/>\n },&#xD;<br \/>\n}&#xD;<br \/>\nhaproxy::listen { &#8216;frontend00&#8217;:&#xD;<br \/>\n mode =&gt; &#8216;http&#8217;,&#xD;<br \/>\n options =&gt; {&#xD;<br \/>\n &#8216;balance&#8217; =&gt; &#8216;source&#8217;,&#xD;<br \/>\n &#8216;redirect&#8217; =&gt; &#8216;scheme https code 301 if !{ ssl_fc }&#8217;,&#xD;<br \/>\n },&#xD;<br \/>\n bind =&gt; {&#xD;<br \/>\n &#8216;10.11.1.30:80&#8217; =&gt; [],&#xD;<br \/>\n &#8216;10.11.1.30:443&#8217; =&gt; [&#8216;ssl&#8217;, &#8216;crt&#8217;, &#8216;\/etc\/pki\/tls\/private\/hl.pem&#8217;],&#xD;<br \/>\n },&#xD;<br \/>\n}-&gt;&#xD;<br \/>\nhaproxy::balancermember { &#8216;web1_web2&#8217;:&#xD;<br \/>\n listening_service =&gt; &#8216;frontend00&#8217;,&#xD;<br \/>\n ports =&gt; &#8216;443&#8217;,&#xD;<br \/>\n server_names =&gt; [&#8216;web1.hl.local&#8217;,&#8217;web2.hl.local&#8217;],&#xD;<br \/>\n ipaddresses =&gt; [&#8216;10.11.1.21&#8242;,&#8217;10.11.1.22&#8217;],&#xD;<br \/>\n options =&gt; &#8216;check ssl verify none&#8217;,&#xD;<br \/>\n}-&gt;&#xD;<br \/>\nhaproxy::listen { &#8216;stats&#8217;:&#xD;<br \/>\n ipaddress =&gt; $::ipaddress,&#xD;<br \/>\n ports =&gt; [&#8216;8080&#8217;],&#xD;<br \/>\n options =&gt; {&#xD;<br \/>\n &#8216;mode&#8217; =&gt; &#8216;http&#8217;,&#xD;<br \/>\n &#8216;stats&#8217; =&gt; [&#8216;enable&#8217;,&#8217;uri \/&#8217;,&#8217;realm HAProxy Statistics&#8217;,&#8217;auth admin:PleaseChangeMe&#8217;],&#xD;<br \/>\n },&#xD;<br \/>\n}<\/p>\n<p>Note how we forward all HTTP traffic to HTTPS. We also enable HAProxy stats.<\/p>\n<p>There are several HAProxy load balancing algorithms available, we use the source algorithm to select a server based on a hash of the source IP. This method helps to ensure that a user will end up on the same server.<\/p>\n<h3>Install Keepalived<\/h3>\n<p>Apply the following to the master node proxy1.hl.local:<\/p>\n<p>include ::keepalived&#xD;<br \/>\nkeepalived::vrrp::script { &#8216;check_haproxy&#8217;:&#xD;<br \/>\n script =&gt; &#8216;\/usr\/bin\/killall -0 haproxy&#8217;,&#xD;<br \/>\n}&#xD;<br \/>\nkeepalived::vrrp::instance { &#8216;LVS_HAP&#8217;:&#xD;<br \/>\n interface =&gt; &#8216;eth0&#8217;,&#xD;<br \/>\n state =&gt; &#8216;MASTER&#8217;,&#xD;<br \/>\n virtual_router_id =&gt; &#8217;51&#8217;,&#xD;<br \/>\n priority =&gt; &#8216;5&#8217;,&#xD;<br \/>\n auth_type =&gt; &#8216;PASS&#8217;,&#xD;<br \/>\n auth_pass =&gt; &#8216;PleaseChangeMe&#8217;,&#xD;<br \/>\n virtual_ipaddress =&gt; &#8216;10.11.1.30\/32&#8217;,&#xD;<br \/>\n track_script =&gt; &#8216;check_haproxy&#8217;,&#xD;<br \/>\n}<\/p>\n<p>Apply the following to the slave node proxy2.hl.local:<\/p>\n<p>include ::keepalived&#xD;<br \/>\nkeepalived::vrrp::script { &#8216;check_haproxy&#8217;:&#xD;<br \/>\n script =&gt; &#8216;\/usr\/bin\/killall -0 haproxy&#8217;,&#xD;<br \/>\n}&#xD;<br \/>\nkeepalived::vrrp::instance { &#8216;LVS_HAP&#8217;:&#xD;<br \/>\n interface =&gt; &#8216;eth0&#8217;,&#xD;<br \/>\n state =&gt; &#8216;SLAVE&#8217;,&#xD;<br \/>\n virtual_router_id =&gt; &#8217;51&#8217;,&#xD;<br \/>\n priority =&gt; &#8216;4&#8217;,&#xD;<br \/>\n auth_type =&gt; &#8216;PASS&#8217;,&#xD;<br \/>\n auth_pass =&gt; &#8216;PleaseChangeMe&#8217;,&#xD;<br \/>\n virtual_ipaddress =&gt; &#8216;10.11.1.30\/32&#8217;,&#xD;<br \/>\n track_script =&gt; &#8216;check_haproxy&#8217;,&#xD;<br \/>\n}<\/p>\n<h3>HAProxy Stats<\/h3>\n<p>If all goes well, we should be able to get some stats from HAProxy.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" alt=\"\" height=\"425\" src=\"https:\/\/www.lisenet.com\/wp-content\/uploads\/2018\/05\/lisenet-homelab-haproxy-stats.png\" width=\"1358\" \/><\/p>\n<h3>WordPress Site<\/h3>\n<p>Our WordPress site should be accessible via https:\/\/blog.hl.local.<\/p>\n<p> <a href=\"https:\/\/www.lisenet.com\/2018\/configure-haproxy-and-keepalived-with-puppet\/\" target=\"_blank\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We\u2019re going to use Puppet to install and configure HAProxy to load balance Apache web services. We\u2019ll also configure Keepalived to provide failover capabilities. This article is part of the Homelab Project with KVM, Katello and Puppet series. See here for a blog post on how to configure HAProxy and Keepalived manually. Homelab We have &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw92\/index.php\/2018\/10\/17\/configure-haproxy-and-keepalived-with-puppet-lisenet-com-linux-security\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Configure HAProxy and Keepalived with Puppet | Lisenet.com :: Linux | Security&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-295","post","type-post","status-publish","format-standard","hentry","category-linux"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts\/295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/comments?post=295"}],"version-history":[{"count":0,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/posts\/295\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/media?parent=295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/categories?post=295"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw92\/index.php\/wp-json\/wp\/v2\/tags?post=295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}