Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions jobs/haproxy/spec
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ templates:
backend-crt.erb: config/backend-crt.pem
client-revocation-list.erb: config/client-revocation-list.pem
blacklist_cidrs.txt.erb: config/blacklist_cidrs.txt
blocklist_cidrs_tcp.txt.erb: config/blocklist_cidrs_tcp.txt
whitelist_cidrs.txt.erb: config/whitelist_cidrs.txt
expect_proxy_cidrs.txt.erb: config/expect_proxy_cidrs.txt
trusted_domain_cidrs.txt.erb: config/trusted_domain_cidrs.txt
Expand Down Expand Up @@ -593,6 +594,13 @@ properties:
cidr_blacklist:
- 10.0.0.0/8
- 192.168.2.0/24
ha_proxy.cidr_blocklist_tcp:
description: List of CIDRs to block on TCP level. If empty, only a comment is rendered. Format is string array of CIDRs or single string of base64 encoded gzip.
default: ~
example:
cidr_blocklist_tcp:
- 10.0.0.0/8
- 192.168.2.0/24
ha_proxy.cidr_whitelist:
description: "List of CIDRs to allow for http(s). Format is string array of CIDRs or single string of base64 encoded gzip. Note that unless ha_proxy.block_all is true, non-whitelisted traffic will still be allowed, provided that traffic is not also blacklisted"
default: ~
Expand Down
20 changes: 20 additions & 0 deletions jobs/haproxy/templates/blocklist_cidrs_tcp.txt.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# generated from blocklist_cidrs_tcp.txt.erb
<%
require "base64"
require 'zlib'
require 'stringio'

cidrs = p("ha_proxy.cidr_blocklist_tcp", [])
uncompressed = ''
if cidrs.is_a?(Array) && cidrs.any?
cidrs.each do |cidr|
uncompressed << cidr << "\n"
end
elsif cidrs.is_a?(String)
gzplain = Base64.decode64(cidrs)
gz = Zlib::GzipReader.new(StringIO.new(gzplain))
uncompressed = gz.read
end
%>
# This list contains CIDRs that are blocked immediately after TCP connection setup.
<%= uncompressed %>
4 changes: 4 additions & 0 deletions jobs/haproxy/templates/haproxy.config.erb
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,8 @@ frontend http-in
<%- if properties.ha_proxy.frontend_config -%>
<%= format_indented_multiline_config(p("ha_proxy.frontend_config")) %>
<%- end -%>
acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt
tcp-request connection reject if layer4_block
<%- if_p("ha_proxy.connections_rate_limit.table_size", "ha_proxy.connections_rate_limit.window_size") do -%>
tcp-request connection track-sc0 src table st_tcp_conn_rate
<%- if_p("ha_proxy.connections_rate_limit.block", "ha_proxy.connections_rate_limit.connections") do |block, connections| -%>
Expand Down Expand Up @@ -560,6 +562,8 @@ frontend https-in
<%- if properties.ha_proxy.frontend_config -%>
<%= format_indented_multiline_config(p("ha_proxy.frontend_config")) %>
<%- end -%>
acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt
tcp-request connection reject if layer4_block
<%- if_p("ha_proxy.connections_rate_limit.table_size", "ha_proxy.connections_rate_limit.window_size") do -%>
tcp-request connection track-sc0 src table st_tcp_conn_rate
<%- if_p("ha_proxy.connections_rate_limit.block", "ha_proxy.connections_rate_limit.connections") do |block, connections| -%>
Expand Down
78 changes: 78 additions & 0 deletions spec/haproxy/templates/blocklist_cidrs_tcp.txt_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# frozen_string_literal: true

require 'rspec'

describe 'config/blocklist_cidrs_tcp.txt' do
let(:template) { haproxy_job.template('config/blocklist_cidrs_tcp.txt') }

context 'when ha_proxy.cidr_blocklist_tcp is provided' do
context 'when an array of cidrs is provided' do
it 'has the correct contents' do
expect(template.render({
'ha_proxy' => {
'cidr_blocklist_tcp' => [
'10.0.0.0/8',
'192.168.2.0/24'
]
}
})).to eq(<<~EXPECTED)
# generated from blocklist_cidrs_tcp.txt.erb

# This list contains CIDRs that are blocked immediately after TCP connection setup.
10.0.0.0/8
192.168.2.0/24

EXPECTED
end
end

context 'when a base64-encoded, gzipped config is provided' do
it 'has the correct contents' do
expect(template.render({
'ha_proxy' => {
'cidr_blocklist_tcp' => gzip_and_b64_encode(<<~INPUT)
10.0.0.0/8
192.168.2.0/24
INPUT
}
})).to eq(<<~EXPECTED)
# generated from blocklist_cidrs_tcp.txt.erb

# This list contains CIDRs that are blocked immediately after TCP connection setup.
10.0.0.0/8
192.168.2.0/24

EXPECTED
end
end
end

context 'when ha_proxy.cidr_blocklist_tcp is not provided' do
it 'contains only the default comment' do
expect(template.render({})).to eq(<<~EXPECTED)
# generated from blocklist_cidrs_tcp.txt.erb

# This list contains CIDRs that are blocked immediately after TCP connection setup.

EXPECTED
end
end

context 'when ha_proxy.cidr_blocklist_tcp is an empty array' do
it 'contains only the default comment' do
expect(template.render({
'ha_proxy' => {
'cidr_blocklist_tcp' => []
}
})).to eq(<<~EXPECTED)
# generated from blocklist_cidrs_tcp.txt.erb

# This list contains CIDRs that are blocked immediately after TCP connection setup.

EXPECTED
end
end
end



33 changes: 33 additions & 0 deletions spec/haproxy/templates/haproxy_config/frontend_http_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,39 @@
end
end

context 'TCP level blocklist (layer4_block)' do
context 'when ha_proxy.cidr_blocklist_tcp is provided' do
let(:properties) do
{ 'cidr_blocklist_tcp' => ['172.168.4.1/32', '10.2.0.0/16'] }
end

it 'sets the correct acl and connection reject rules' do
expect(frontend_http).to include('acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt')
expect(frontend_http).to include('tcp-request connection reject if layer4_block')
end
end

context 'when ha_proxy.cidr_blocklist_tcp is not provided' do
let(:properties) { {} }

it 'still includes the layer4_block acl and reject rule (always present)' do
expect(frontend_http).to include('acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt')
expect(frontend_http).to include('tcp-request connection reject if layer4_block')
end
end

context 'when ha_proxy.cidr_blocklist_tcp is an empty array' do
let(:properties) do
{ 'cidr_blocklist_tcp' => [] }
end

it 'still includes the layer4_block acl and reject rule (always present)' do
expect(frontend_http).to include('acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt')
expect(frontend_http).to include('tcp-request connection reject if layer4_block')
end
end
end

context 'when ha_proxy.block_all is provided' do
let(:properties) do
{ 'block_all' => true }
Expand Down
33 changes: 33 additions & 0 deletions spec/haproxy/templates/haproxy_config/frontend_https_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,39 @@
end
end

context 'TCP level blocklist (layer4_block)' do
context 'when ha_proxy.cidr_blocklist_tcp is provided' do
let(:properties) do
default_properties.merge({ 'cidr_blocklist_tcp' => ['172.168.4.1/32', '10.2.0.0/16'] })
end

it 'sets the correct acl and connection reject rules' do
expect(frontend_https).to include('acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt')
expect(frontend_https).to include('tcp-request connection reject if layer4_block')
end
end

context 'when ha_proxy.cidr_blocklist_tcp is not provided' do
let(:properties) { default_properties }

it 'still includes the layer4_block acl and reject rule (always present)' do
expect(frontend_https).to include('acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt')
expect(frontend_https).to include('tcp-request connection reject if layer4_block')
end
end

context 'when ha_proxy.cidr_blocklist_tcp is an empty array' do
let(:properties) do
default_properties.merge({ 'cidr_blocklist_tcp' => [] })
end

it 'still includes the layer4_block acl and reject rule (always present)' do
expect(frontend_https).to include('acl layer4_block src -f /var/vcap/jobs/haproxy/config/blocklist_cidrs_tcp.txt')
expect(frontend_https).to include('tcp-request connection reject if layer4_block')
end
end
end

context 'when ha_proxy.block_all is provided' do
let(:properties) do
default_properties.merge({ 'block_all' => true })
Expand Down