From 3632bcda7c27d5bfb76e552d22a90d79a3c4fde7 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Tue, 10 Jan 2017 14:20:07 +0100 Subject: [PATCH 1/6] Revert "Fix SSL setup for haproxy 1.4 release" We have haproxy 1.5.x now, so we can use persistence for SSL sessions. This matters as if we want to allow people to not use "source" as balance algorithm, then we need to make sure that sessions keep going to the same backend to avoid breakages. This reverts commit 32323b0a4b17d64489735d307b9fe65b8bb4ed31. (cherry picked from commit 8cf8ddbd9e7813ee58b593dddb719aee0aaba91c) --- .../haproxy/templates/default/haproxy.cfg.erb | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb index 740da59e..ef33c5ee 100644 --- a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb +++ b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb @@ -38,9 +38,30 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats <% node[:haproxy][:sections][type].keys.sort.each do |name| -%> <% content = node[:haproxy][:sections][type][name] -%> <%= type %> <%= name %> <%= content[:address] %>:<%= content[:port] %> - <% if content[:use_ssl] -%> - mode tcp - balance source + <% if content[:use_ssl] # http://blog.exceliance.fr/2011/07/04/maintain-affinity-based-on-ssl-session-id/ -%> + mode tcp + + # maximum SSL session ID length is 32 bytes. + stick-table type binary len 32 size 30k expire 30m + + acl clienthello req_ssl_hello_type 1 + acl serverhello rep_ssl_hello_type 2 + + # use tcp content accepts to detects ssl client and server hello. + tcp-request inspect-delay 5s + tcp-request content accept if clienthello + + # no timeout on response inspect delay by default. + tcp-response content accept if serverhello + + # SSL session ID (SSLID) may be present on a client or server hello. + # Its length is coded on 1 byte at offset 43 and its value starts + # at offset 44. + # Match and learn on request if client hello. + stick on payload_lv(43,1) if clienthello + + # Learn on response if server hello. + stick store-response payload_lv(43,1) if serverhello <% else -%> mode <%= content[:mode] %> <% end -%> From f394de8e63969f082fdb2534b2c01602ff7a5da8 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Tue, 10 Jan 2017 14:21:00 +0100 Subject: [PATCH 2/6] haproxy: Do not enforce mode as tcp for ssl twice This is done in the LWRP and in the template; let's just do it in the LWRP to simplify the template. (cherry picked from commit 560b110ea93af60ac922e8002d991f62d02430ec) --- chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb index ef33c5ee..20b648b7 100644 --- a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb +++ b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb @@ -38,9 +38,9 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats <% node[:haproxy][:sections][type].keys.sort.each do |name| -%> <% content = node[:haproxy][:sections][type][name] -%> <%= type %> <%= name %> <%= content[:address] %>:<%= content[:port] %> - <% if content[:use_ssl] # http://blog.exceliance.fr/2011/07/04/maintain-affinity-based-on-ssl-session-id/ -%> - mode tcp + mode <%= content[:mode] %> + <% if content[:use_ssl] # http://blog.exceliance.fr/2011/07/04/maintain-affinity-based-on-ssl-session-id/ -%> # maximum SSL session ID length is 32 bytes. stick-table type binary len 32 size 30k expire 30m @@ -62,8 +62,6 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats # Learn on response if server hello. stick store-response payload_lv(43,1) if serverhello - <% else -%> - mode <%= content[:mode] %> <% end -%> <% content[:options].each do |option| -%> From c59e3be1326b4c84dda412e1fcc7a8753c921757 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Wed, 11 Jan 2017 15:50:45 +0100 Subject: [PATCH 3/6] haproxy: Add ability to configure stickiness based on cookies This is useful to achieve persistence for web apps which have a session, which is important in order to allow using a different algorithm than "source" for balancing without breaking sessions. (cherry picked from commit 5420a3e9ee4e2d2e56a73b165a906177d654835d) --- chef/cookbooks/haproxy/providers/loadbalancer.rb | 4 ++++ chef/cookbooks/haproxy/resources/loadbalancer.rb | 1 + .../haproxy/templates/default/haproxy.cfg.erb | 13 ++++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/chef/cookbooks/haproxy/providers/loadbalancer.rb b/chef/cookbooks/haproxy/providers/loadbalancer.rb index 1aa9eb4b..0c5a220e 100644 --- a/chef/cookbooks/haproxy/providers/loadbalancer.rb +++ b/chef/cookbooks/haproxy/providers/loadbalancer.rb @@ -47,6 +47,10 @@ else section["mode"] = new_resource.mode end + + section["stick"] = new_resource.stick + section["stick"]["expire"] ||= "30m" + section["options"] = new_resource.options || [] if section["options"].empty? || section["options"].include?("defaults") section["options"].delete("defaults") diff --git a/chef/cookbooks/haproxy/resources/loadbalancer.rb b/chef/cookbooks/haproxy/resources/loadbalancer.rb index 86fe6b20..b84869f3 100644 --- a/chef/cookbooks/haproxy/resources/loadbalancer.rb +++ b/chef/cookbooks/haproxy/resources/loadbalancer.rb @@ -26,5 +26,6 @@ attribute :port, kind_of: Integer, default: 0 attribute :mode, kind_of: String, default: "http", equal_to: ["http", "tcp", "health"] attribute :use_ssl, kind_of: [TrueClass, FalseClass], default: false +attribute :stick, kind_of: Hash, default: {} attribute :options, kind_of: Array, default: [] attribute :servers, kind_of: Array, default: [] diff --git a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb index 20b648b7..2cbc7356 100644 --- a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb +++ b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb @@ -42,7 +42,7 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats <% if content[:use_ssl] # http://blog.exceliance.fr/2011/07/04/maintain-affinity-based-on-ssl-session-id/ -%> # maximum SSL session ID length is 32 bytes. - stick-table type binary len 32 size 30k expire 30m + stick-table type binary len 32 size 30k expire <%= content[:stick][:expire] %> acl clienthello req_ssl_hello_type 1 acl serverhello rep_ssl_hello_type 2 @@ -62,6 +62,17 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats # Learn on response if server hello. stick store-response payload_lv(43,1) if serverhello + <% elsif content[:mode] == "http" && content[:stick] && content[:stick][:cookie] + # There are various options here, described in: + # http://stackoverflow.com/questions/27094501/haproxy-1-5-8-how-do-i-configure-cookie-based-stickiness + # We go with the stick-table to avoid no-cache and exposing backends + # through cookies. + # Note that appsession is easier, but deprecated: + # http://serverfault.com/questions/550910/haproxy-appsession-vs-cookie-precedence + -%> + stick-table type string len 64 size 100k expire <%= content[:stick][:expire] %> + stick store-response res.cook(<%= content[:stick][:cookie] %>) + stick match req.cook(<%= content[:stick][:cookie] %>) <% end -%> <% content[:options].each do |option| -%> From b1a39e03a3668668e93250c1678c7903696f88b7 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Wed, 8 Feb 2017 13:34:30 +0100 Subject: [PATCH 4/6] haproxy: Add ability to do stickiness based on more than one cookie This allows achieving persistence for a normal session, but also for the login form where there's usually a CSRF token (and which is not associated to a real session in the web app). (cherry picked from commit 1805935b43a13b400b98de1d13064ee496701e66) --- chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb index 2cbc7356..572f23d8 100644 --- a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb +++ b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb @@ -62,7 +62,8 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats # Learn on response if server hello. stick store-response payload_lv(43,1) if serverhello - <% elsif content[:mode] == "http" && content[:stick] && content[:stick][:cookie] + <% elsif content[:mode] == "http" && content[:stick] && + content[:stick][:cookies] && !content[:stick][:cookies].empty? # There are various options here, described in: # http://stackoverflow.com/questions/27094501/haproxy-1-5-8-how-do-i-configure-cookie-based-stickiness # We go with the stick-table to avoid no-cache and exposing backends @@ -71,8 +72,10 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats # http://serverfault.com/questions/550910/haproxy-appsession-vs-cookie-precedence -%> stick-table type string len 64 size 100k expire <%= content[:stick][:expire] %> - stick store-response res.cook(<%= content[:stick][:cookie] %>) - stick match req.cook(<%= content[:stick][:cookie] %>) + <% content[:stick][:cookies].each do |cookie| -%> + stick store-response res.cook(<%= cookie %>) + stick match req.cook(<%= cookie %>) + <% end -%> <% end -%> <% content[:options].each do |option| -%> From 8fc6b263c63808b9f54594ab6fdb8187fcc293e2 Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Tue, 10 Jan 2017 14:58:42 +0100 Subject: [PATCH 5/6] haproxy: Add balance attribute to haproxy_loadbalancer resource This enables customization of the balance strategy for each service. (cherry picked from commit 10ee491ed9b4a7afa2bc2ad8ab81c90dce81c6b7) --- chef/cookbooks/haproxy/providers/loadbalancer.rb | 3 +++ chef/cookbooks/haproxy/resources/loadbalancer.rb | 1 + chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb | 3 +++ 3 files changed, 7 insertions(+) diff --git a/chef/cookbooks/haproxy/providers/loadbalancer.rb b/chef/cookbooks/haproxy/providers/loadbalancer.rb index 0c5a220e..6a416cb3 100644 --- a/chef/cookbooks/haproxy/providers/loadbalancer.rb +++ b/chef/cookbooks/haproxy/providers/loadbalancer.rb @@ -47,6 +47,9 @@ else section["mode"] = new_resource.mode end + unless new_resource.balance.empty? + section["balance"] = new_resource.balance + end section["stick"] = new_resource.stick section["stick"]["expire"] ||= "30m" diff --git a/chef/cookbooks/haproxy/resources/loadbalancer.rb b/chef/cookbooks/haproxy/resources/loadbalancer.rb index b84869f3..f06a652d 100644 --- a/chef/cookbooks/haproxy/resources/loadbalancer.rb +++ b/chef/cookbooks/haproxy/resources/loadbalancer.rb @@ -25,6 +25,7 @@ attribute :address, kind_of: String, default: "0.0.0.0" attribute :port, kind_of: Integer, default: 0 attribute :mode, kind_of: String, default: "http", equal_to: ["http", "tcp", "health"] +attribute :balance, kind_of: String, default: "", equal_to: ["", "roundrobin", "static-rr", "leastconn", "first", "source"] attribute :use_ssl, kind_of: [TrueClass, FalseClass], default: false attribute :stick, kind_of: Hash, default: {} attribute :options, kind_of: Array, default: [] diff --git a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb index 572f23d8..c2da44c2 100644 --- a/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb +++ b/chef/cookbooks/haproxy/templates/default/haproxy.cfg.erb @@ -39,6 +39,9 @@ listen admin-stats <%= node[:haproxy][:stats][:enabled] ? node[:haproxy][:stats <% content = node[:haproxy][:sections][type][name] -%> <%= type %> <%= name %> <%= content[:address] %>:<%= content[:port] %> mode <%= content[:mode] %> + <% unless content[:balance].nil? -%> + balance <%= content[:balance] %> + <% end -%> <% if content[:use_ssl] # http://blog.exceliance.fr/2011/07/04/maintain-affinity-based-on-ssl-session-id/ -%> # maximum SSL session ID length is 32 bytes. From 01ad466f4bfecf4a82332cb924b7b5614625c3ae Mon Sep 17 00:00:00 2001 From: Vincent Untz Date: Wed, 8 Feb 2017 11:23:41 +0100 Subject: [PATCH 6/6] crowbar-pacemaker: Stop changing default haproxy balance strategy The default in the haproxy cookbook is roundrobin, and this should actually work fine. In cases where this may be troublesome (like web apps), we can now configure stickiness to avoid issues. With roundrobin, we spread the load accross the various backends, which results in much improved performance. (cherry picked from commit d714d87c9b57200354100a17d2e519093adb73ce) --- chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb b/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb index 910045ce..5be33738 100644 --- a/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb +++ b/chef/cookbooks/crowbar-pacemaker/recipes/haproxy.rb @@ -20,11 +20,6 @@ #FIXME: delete group when it's not needed anymore #FIXME: need to find/write OCF for haproxy -# Recommendation from the OpenStack HA guide is to use "source" as balance -# algorithm. This obviously is less useful for load balancing, but we care more -# about HA and things working than about load balancing. -node.default["haproxy"]["defaults"]["balance"] = "source" - # With the default bufsize, getting a keystone PKI token from its ID doesn't # work, because the URI path is too long for haproxy node.default["haproxy"]["global"]["bufsize"] = 32768