Skip to content

Commit

Permalink
pre_start_script, config_mode raw_blocks_only, ssl_min/max_ver, raw_b…
Browse files Browse the repository at this point in the history
…locks without names (global, defaults)
  • Loading branch information
kinjelom committed Apr 26, 2024
1 parent 1f72589 commit 9651704
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 45 deletions.
63 changes: 43 additions & 20 deletions jobs/haproxy/spec
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ consumes:
optional: true

properties:
ha_proxy.pre_start_script:
description: |
This script will be appended to the pre-start script and run before the job starts.
The pre-start script allows the job to prepare the machine before starting HAProxy,
for example, by setting the MTU to a custom value.
default: ~
example: |
# customize MTU
CUST_MTU=((custom_mtu))
INTERFACE=$(ip -4 route get 8.8.8.8 | grep -Po '(?<=dev )\S+') #'
CURR_MTU=$(ip link show $INTERFACE | grep -Po 'mtu \K\d+')
if [[ $CURR_MTU -ne $CUST_MTU ]]; then
sudo ip link set dev $INTERFACE mtu $CUST_MTU
echo "MTU changed from $CURR_MTU to $CUST_MTU, interface: $INTERFACE."
fi
CURR_MTU=$(ip link show $INTERFACE | grep -Po 'mtu \K\d+')
echo "MTU: $CURR_MTU, interface: $INTERFACE"
ha_proxy.config_mode:
description: |
'auto' - utilizes raw_config if defined; otherwise, it uses traditional configuration mixed with raw_blocks,
'raw_blocks_only' - uses only raw_blocks, ignoring other configurations.
default: auto
ha_proxy.nbthread:
description: "Optional number of threads per VM"
default: 1
Expand Down Expand Up @@ -237,21 +259,32 @@ properties:
ha_proxy.default_dh_param:
default: 2048
description: "Maximum size of DH params when generating epmehmeral keys during key exchange"
ha_proxy.ssl_min_ver:
example: "TLSv1.2"
description: |
This option enforces the use of 'version' or higher for SSL connections initiated from this listener.
The recommended value is 'TLSv1.2'. It is not the default due to backward compatibility concerns with
the 'disable_tls_*' options. If this option is set, the 'disable_tls_*' options will be ignored.
ha_proxy.ssl_max_ver:
example: "TLSv1.3"
description: |
This option enforces the use of 'version' or lower for SSL connections initiated from this listener.
It will only be set if 'ssl_min_ver' is specified, as the default HAProxy ssl-min-ver may change in future.
ha_proxy.disable_tls_tickets:
default: true
description: "Improve (Perfect) Forward Secrecy by disabling TLS tickets"
description: "Improve (Perfect) Forward Secrecy by disabling TLS tickets. Use 'ssl_min_ver' and 'ssl_max_ver' instead."
ha_proxy.disable_tls_10:
default: false
description: "Disable TLS 1.0 in HA Proxy"
description: "Disable TLS 1.0 in HA Proxy. Use 'ssl_min_ver' and 'ssl_max_ver' instead."
ha_proxy.disable_tls_11:
default: false
description: "Disable TLS 1.1 in HA Proxy"
description: "Disable TLS 1.1 in HA Proxy. Use 'ssl_min_ver' and 'ssl_max_ver' instead."
ha_proxy.disable_tls_12:
default: false
description: "Disable TLS 1.2 in HA Proxy"
description: "Disable TLS 1.2 in HA Proxy. Use 'ssl_min_ver' and 'ssl_max_ver' instead."
ha_proxy.disable_tls_13:
default: false
description: "Disable TLS 1.3 in HA Proxy"
description: "Disable TLS 1.3 in HA Proxy. Use 'ssl_min_ver' and 'ssl_max_ver' instead."
ha_proxy.backend_match_http_protocol:
default: false
description: Uses the same version of HTTP for backend connections that was used for frontend connections (ie HTTP 1.1 or HTTP 2). Ignores the value of enable_http2. HTTP2 backend connections require that `ha_proxy.backend_ssl` is not `off`.
Expand Down Expand Up @@ -673,11 +706,15 @@ properties:
you want. Use at your own risk.
ha_proxy.raw_blocks:
description: |
A hash of block types, where each type contains a hash of specific block names with their respective configurations.
A hash of block types, where each type contains either a configuration
or a hash of specific block names with their respective configurations.
The configurations are provided as either multiline text blobs or arrays of lines.
This structure will be appended to the end of the HAProxy configuration file.
Use at your own risk.
example:
defaults: |
log global
timeout http-request 10s
listen:
my-listen-x: |
bind :81
Expand All @@ -687,20 +724,6 @@ properties:
- bind :82
- mode http
- server-template srv 1-3 q-s0.web.default.deployment-y.bosh:8080 check inter 1000
frontend:
my-frontend-x: |
bind :83
use_backend my-backend-x if { hdr(host) -i x.example.com }
my-frontend-y:
- bind :84
- use_backend my-backend-y if { hdr(host) -i y.example.com }
backend:
my-backend-x: |
mode http
server-template srv-x 1-3 q-s0.web.default.deployment-x.bosh:8080 check inter 1000
my-backend-y:
- mode http
- server-template srv-y 1-3 q-s0.web.default.deployment-y.bosh:8080 check inter 1000

ha_proxy.max_open_files:
description: The number of file descriptors HAProxy can have open at one time
Expand Down
60 changes: 42 additions & 18 deletions jobs/haproxy/templates/haproxy.config.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
end
end

if properties.ha_proxy.raw_config -%>
if properties.ha_proxy.config_mode == "auto"
if properties.ha_proxy.raw_config -%>
<%= p("ha_proxy.raw_config") %>
<%- else -%>
<%-
Expand All @@ -26,8 +27,8 @@ require "digest"

# Stats Binding Variables {{{
stat = p("ha_proxy.stats_bind").split(':')
stat_prefix = stat[0] + ":";
stat_port = stat[1].to_i;
stat_prefix = stat[0] + ":"
stat_port = stat[1].to_i
# }}}
# Accept Proxy {{{
accept_proxy = ""
Expand All @@ -40,21 +41,33 @@ if p("ha_proxy.disable_tcp_accept_proxy")
end
# }}}
# Global SSL Flags {{{
ssl_flags = "no-sslv3"
if p("ha_proxy.disable_tls_10")
ssl_flags = "#{ssl_flags} no-tlsv10"
end
if p("ha_proxy.disable_tls_11")
ssl_flags = "#{ssl_flags} no-tlsv11"
end
if p("ha_proxy.disable_tls_12")
ssl_flags = "#{ssl_flags} no-tlsv12"
end
if p("ha_proxy.disable_tls_13")
ssl_flags = "#{ssl_flags} no-tlsv13"
ssl_flags = ""
use_disable_ssl = true
if_p("ha_proxy.ssl_min_ver") do |ssl_min_ver|
use_disable_ssl = false
ssl_flags = "ssl-min-ver #{ssl_min_ver}"
if_p("ha_proxy.ssl_max_ver") do |ssl_max_ver|
ssl_flags = "#{ssl_flags} ssl-max-ver #{ssl_max_ver}"
end
end
if p("ha_proxy.disable_tls_tickets")
ssl_flags = "#{ssl_flags} no-tls-tickets"

if use_disable_ssl
ssl_flags = "no-sslv3"
if p("ha_proxy.disable_tls_10")
ssl_flags = "#{ssl_flags} no-tlsv10"
end
if p("ha_proxy.disable_tls_11")
ssl_flags = "#{ssl_flags} no-tlsv11"
end
if p("ha_proxy.disable_tls_12")
ssl_flags = "#{ssl_flags} no-tlsv12"
end
if p("ha_proxy.disable_tls_13")
ssl_flags = "#{ssl_flags} no-tlsv13"
end
if p("ha_proxy.disable_tls_tickets")
ssl_flags = "#{ssl_flags} no-tls-tickets"
end
end
# }}}
# TLS Bind Options {{{
Expand Down Expand Up @@ -334,7 +347,9 @@ listen stats
stats hide-version
stats realm "Haproxy Statistics"
stats uri /<%= p("ha_proxy.stats_uri") %>
<%- if_p("ha_proxy.stats_user") do -%>
stats auth <%= p("ha_proxy.stats_user") %>:<%= p("ha_proxy.stats_password") %>
<% end -%>
<% end -%>

<% if p("ha_proxy.enable_health_check_http") %>
Expand Down Expand Up @@ -975,6 +990,7 @@ listen health_check_http_tcp-<%= tcp_proxy["name"] %>

# }}}
<% end -%>
<%- end -%>
<%- if properties.ha_proxy.raw_blocks && !properties.ha_proxy.raw_blocks.empty? -%>
# raw blocks {{{
<%-
Expand All @@ -984,10 +1000,18 @@ listen health_check_http_tcp-<%= tcp_proxy["name"] %>
additional_types = raw_blocks.keys - correct_types_order
all_found_types = ordered_blocks + additional_types
all_found_types.each do |block_type|
raw_blocks[block_type].each do |block_id, block_raw_config|
raw_block = raw_blocks[block_type]
if raw_block.is_a?(Hash)
raw_block.each do |block_id, block_raw_config|
%>
<%= block_type %> <%= block_id %>
<%= format_indented_multiline_config(block_raw_config) %>
<%-
end
else
%>
<%= block_type %>
<%= format_indented_multiline_config(raw_block) %>
<%-
end
end
Expand Down
2 changes: 2 additions & 0 deletions jobs/haproxy/templates/pre-start.erb
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ fi
if [ ! -e /usr/local/bin/socat ]; then
sudo ln -s /var/vcap/packages/haproxy/bin/socat /usr/local/bin/socat
fi

<%= p("ha_proxy.pre_start_script") %>
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,56 @@
end
end

context 'when ha_proxy.ssl_min_ver is provided' do
let(:properties) do
{
'ssl_min_ver' => 'TLSv1.2',
'disable_tls_10' => true,
'disable_tls_11' => true,
'disable_tls_12' => true,
'disable_tls_13' => true,
'disable_tls_tickets' => true
}
end

it 'enables ssl-min-ver and ignores tls_disable_ properties' do
expect(global).to include('ssl-default-server-options ssl-min-ver TLSv1.2')
expect(global).to include('ssl-default-bind-options ssl-min-ver TLSv1.2')
end
end

context 'when ha_proxy.ssl_min_ver is not provided and ha_proxy.ssl_max_ver is provided' do
let(:properties) do
{
'ssl_max_ver' => 'TLSv1.3',
'disable_tls_10' => false,
'disable_tls_11' => false,
'disable_tls_12' => false,
'disable_tls_13' => false,
'disable_tls_tickets' => false
}
end

it 'ignores ssl-min/max-ver properties, tls_disable_ properties are used' do
expect(global).to include('ssl-default-server-options no-sslv3')
expect(global).to include('ssl-default-bind-options no-sslv3')
end
end

context 'when ha_proxy.ssl_min_ver and ha_proxy.ssl_max_ver are provided' do
let(:properties) do
{
'ssl_min_ver' => 'TLSv1.2',
'ssl_max_ver' => 'TLSv1.3'
}
end

it 'enables ssl-min/max-ver and ignores tls_disable_ properties' do
expect(global).to include('ssl-default-server-options ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.3')
expect(global).to include('ssl-default-bind-options ssl-min-ver TLSv1.2 ssl-max-ver TLSv1.3')
end
end

context 'when ha_proxy.disable_tls_10 is provided' do
let(:properties) do
{
Expand Down
48 changes: 41 additions & 7 deletions spec/haproxy/templates/haproxy_config/raw_blocks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@
parse_haproxy_config(template.render({ 'ha_proxy' => properties }))
end

context 'when multiline configurations are provided for some raw blocks' do
context 'when multiline configurations are provided for global, defaults and some raw blocks with ids' do
let(:properties) do
{
'config_mode' => 'raw_blocks_only',
'raw_blocks' => {
'global' => "line 1\nline 2\nline 3",
'defaults' => ['line 1', 'line 2', 'line 3'],
'some' => {
'raw-block-1' => "line 1\nline 2\nline 3",
'raw-block-2' => "\n\nline 1\nline 2\nline 3\n\n",
Expand All @@ -22,15 +25,18 @@

it 'formats the configuration as expected' do
expected_block_content = ['line 1', 'line 2', 'line 3']
expect(haproxy_conf['global']).to eq(expected_block_content)
expect(haproxy_conf['defaults']).to eq(expected_block_content)
expect(haproxy_conf['some raw-block-1']).to eq(expected_block_content)
expect(haproxy_conf['some raw-block-2']).to eq(expected_block_content)
expect(haproxy_conf['some raw-block-3']).to eq(expected_block_content)
end
end

context 'when there are many types of raw blocks' do
context 'when there are many types of raw blocks, ha_proxy.config_mode=raw_blocks_only' do
let(:properties) do
{
'config_mode' => 'raw_blocks_only',
'raw_blocks' => {
'unknown' => {
'raw-test-1' => 'test',
Expand All @@ -42,18 +48,46 @@
'backend' => { 'raw-test' => 'test' },
'frontend' => { 'raw-test' => 'test' },
'listen' => { 'raw-test' => 'test' },
'defaults' => { '# raw-test' => 'test' },
'global' => { '# raw-test' => 'test' }
'defaults' => 'test',
'global' => 'test'
}
}
end

it 'arranges them all in the correct order' do
raw_keys = haproxy_conf.keys.select { |key| key.include?('raw-test') }
expect(raw_keys).to eq(['global # raw-test', 'defaults # raw-test',
it 'return only raw blocks and arranges them in the correct order' do
raw_keys = haproxy_conf.keys
expect(raw_keys).to eq(['global', 'defaults',
'listen raw-test', 'frontend raw-test', 'backend raw-test',
'resolvers raw-test', 'peers raw-test', 'mailers raw-test',
'unknown raw-test-1', 'unknown raw-test-2'])
end
end

context 'when there are many types of raw blocks, classic config mode' do
let(:properties) do
{
'raw_blocks' => {
'unknown' => {
'raw-test-1' => 'test',
'raw-test-2' => 'test'
},
'mailers' => { 'raw-test' => 'test' },
'peers' => { 'raw-test' => 'test' },
'resolvers' => { 'raw-test' => 'test' },
'backend' => { 'raw-test' => 'test' },
'frontend' => { 'raw-test' => 'test' },
'listen' => { 'raw-test' => 'test' }
}
}
end

it 'return static block and then raw blocks arranged in the correct order' do
raw_keys = haproxy_conf.keys
expect(raw_keys).to eq(['global', 'defaults', 'frontend http-in', 'backend http-routers-http1',
'listen raw-test', 'frontend raw-test', 'backend raw-test',
'resolvers raw-test', 'peers raw-test', 'mailers raw-test',
'unknown raw-test-1', 'unknown raw-test-2'])
end
end

end

0 comments on commit 9651704

Please sign in to comment.