diff --git a/manifests/haproxy/endpoint.pp b/manifests/haproxy/endpoint.pp index 4436e199d..7da78ac9a 100644 --- a/manifests/haproxy/endpoint.pp +++ b/manifests/haproxy/endpoint.pp @@ -91,6 +91,11 @@ # (false means disabled, and true means enabled) # Defaults to hiera('tripleo::firewall::manage_firewall', true) # +# [*authorized_userlist*] +# (optional) Userlist that may access the endpoint. Activate Basic Authentication. +# You'll need to create a tripleo::haproxy::userlist in order to use that option. +# Defaults to undef +# define tripleo::haproxy::endpoint ( $internal_ip, $service_port, @@ -109,6 +114,7 @@ define tripleo::haproxy::endpoint ( $internal_certificates_specs = {}, $service_network = undef, $manage_firewall = hiera('tripleo::firewall::manage_firewall', true), + $authorized_userlist = undef, ) { if $public_virtual_ip { # service exposed to the public network @@ -163,13 +169,27 @@ define tripleo::haproxy::endpoint ( $internal_bind_opts = list_to_hash(suffix(any2array($internal_ip), ":${service_port}"), $haproxy_listen_bind_param) } } + if $authorized_userlist { + $access_rules = { + 'acl' => "acl Auth${name} http_auth(${authorized_userlist})", + 'http-request' => "auth realm ${name} if !Auth${name}", + } + Haproxy::Listen[$name] { + require => Tripleo::Haproxy::Userlist[$authorized_userlist], + } + } else { + $access_rules = {} + } + + $_real_options = merge($listen_options_real, $access_rules) + $bind_opts = merge($internal_bind_opts, $public_bind_opts) haproxy::listen { "${name}": bind => $bind_opts, collect_exported => false, mode => $mode, - options => $listen_options_real, + options => $_real_options, } haproxy::balancermember { "${name}": listening_service => $name, diff --git a/manifests/haproxy/service_endpoints.pp b/manifests/haproxy/service_endpoints.pp index f15dbef3b..e4d305db1 100644 --- a/manifests/haproxy/service_endpoints.pp +++ b/manifests/haproxy/service_endpoints.pp @@ -24,19 +24,25 @@ # define tripleo::haproxy::service_endpoints ($service_name = $title) { - $underscore_name = regsubst($service_name, '-', '_') + $underscore_name = regsubst($service_name, '-', '_', 'G') # This allows each composable service to load its own custom rules by # creating its own flat hiera key named: # tripleo..haproxy_endpoints + # tripleo..haproxy_userlists $dots_endpoints = hiera("tripleo.${underscore_name}.haproxy_endpoints", {}) + $dots_userlists = hiera("tripleo.${underscore_name}.haproxy_userlists", {}) # Supports standard "::" notation # tripleo::::haproxy_endpoints + # tripleo::::haproxy_userlists $colons_endpoints = hiera("tripleo::${underscore_name}::haproxy_endpoints", {}) + $colons_userlists = hiera("tripleo::${underscore_name}::haproxy_userlists", {}) # Merge hashes $service_endpoints = merge($colons_endpoints, $dots_endpoints) + $service_userlists = merge($colons_userlists, $dots_userlists) + create_resources('tripleo::haproxy::userlist', $service_userlists) create_resources('tripleo::haproxy::endpoint', $service_endpoints) } diff --git a/manifests/haproxy/userlist.pp b/manifests/haproxy/userlist.pp new file mode 100644 index 000000000..106d02509 --- /dev/null +++ b/manifests/haproxy/userlist.pp @@ -0,0 +1,54 @@ +# Copyright 2017 Camptocamp SA. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Definition: tripleo::haproxy::userlist +# +# Configure an HAProxy userlist. It wrapps haproxy::userlist definition. +# +# [*groups*] +# List of groups +# +# [*users*] +# List of users +# +# == Example +# ::tripleo::haproxy::userlist {'starwars': +# groups => [ +# 'aldebaran users leia,luke', +# 'deathstar users anakin,sith', +# ], +# users => [ +# 'leia insecure-password sister', +# 'luke insecure-password jedi', +# 'anakin insecure-password darthvador', +# 'sith password $5$h9LsKUOeCr$UlD62CNEpuZQkGYdBoiFJLsM6TlXluRLBlhEnpjDdaC', # mkpasswd -m sha-256 darkSideOfTheForce +# ] +# } +# +# Please refer to the following HAProxy documentation for more options: +# http://cbonte.github.io/haproxy-dconv/configuration-1.4.html#3.4-user +# http://cbonte.github.io/haproxy-dconv/configuration-1.4.html#3.4-group +# +# +define tripleo::haproxy::userlist( + Optional[Array] $groups = [], + Optional[Array] $users = [], +) { + + ::haproxy::userlist {$name: + users => $users, + groups => $groups, + } +} diff --git a/releasenotes/notes/haproxy-basic-auth-e2839941c806c615.yaml b/releasenotes/notes/haproxy-basic-auth-e2839941c806c615.yaml new file mode 100644 index 000000000..3ab4f1bd9 --- /dev/null +++ b/releasenotes/notes/haproxy-basic-auth-e2839941c806c615.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Adds Basic Authentication support for HAProxy endpoints. +fixes: + - Fixes `bug 1736132 + `__ by implementing + Basic Authentication in HAProxy endpoint. diff --git a/spec/defines/tripleo_haproxy_endpoint_spec.rb b/spec/defines/tripleo_haproxy_endpoint_spec.rb index 62c8fa1db..e072fc67d 100644 --- a/spec/defines/tripleo_haproxy_endpoint_spec.rb +++ b/spec/defines/tripleo_haproxy_endpoint_spec.rb @@ -28,7 +28,8 @@ describe 'tripleo::haproxy::endpoint' do :bind => [ ['10.0.0.1:9696', ['transparent']], ['192.168.0.1:9696', ['transparent']] - ] + ], + :options => {'option' => []}, ) end end @@ -50,6 +51,29 @@ describe 'tripleo::haproxy::endpoint' do ) end end + + context 'with userlist' do + before :each do + params.merge!({ + :authorized_userlist => 'starwars', + }) + end + let :pre_condition do + 'include ::haproxy + ::tripleo::haproxy::userlist {"starwars": users => ["leia password sister"]} + ' + end + it 'should configure an ACL' do + is_expected.to compile.with_all_deps + is_expected.to contain_haproxy__listen('neutron').with( + :options => { + 'option' => [], + 'acl' => 'acl Authneutron http_auth(starwars)', + 'http-request' => 'auth realm neutron if !Authneutron', + } + ) + end + end end on_supported_os.each do |os, facts| diff --git a/spec/defines/tripleo_haproxy_service_endpoints_spec.rb b/spec/defines/tripleo_haproxy_service_endpoints_spec.rb index 1b2a607d9..83d4e8d4b 100644 --- a/spec/defines/tripleo_haproxy_service_endpoints_spec.rb +++ b/spec/defines/tripleo_haproxy_service_endpoints_spec.rb @@ -23,6 +23,18 @@ describe 'tripleo::haproxy::service_endpoints' do is_expected.to compile.with_all_deps end end + context 'with userlist' do + let(:title) {'haproxy-basic-auth'} + it 'should compile' do + is_expected.to compile.with_all_deps + end + it 'should create haproxy endpoint' do + is_expected.to contain_tripleo__haproxy__endpoint('starwars') + end + it 'should create userlist' do + is_expected.to contain_tripleo__haproxy__userlist('starwars') + end + end end on_supported_os.each do |os, facts| diff --git a/spec/defines/tripleo_haproxy_userlist_spec.rb b/spec/defines/tripleo_haproxy_userlist_spec.rb new file mode 100644 index 000000000..bc465a45b --- /dev/null +++ b/spec/defines/tripleo_haproxy_userlist_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe 'tripleo::haproxy::userlist' do + + let(:title) { 'starwars' } + + let :pre_condition do + 'include ::haproxy' + end + + let :params do { + :groups => [ + 'aldebaran users leia,luke', + 'deathstar users anakin,sith', + ], + :users => [ + 'leia insecure-password sister', + 'luke insecure-password jedi', + 'anakin insecure-password darthvador', + 'sith password $5$h9LsKUOeCr$UlD62CNEpuZQkGYdBoiFJLsM6TlXluRLBlhEnpjDdaC', # mkpasswd -m sha-256 darkSideOfTheForce + ], + } + end + + shared_examples_for 'tripleo haproxy userlist' do + context 'with basic parameters to configure neutron binding' do + it 'should compile' do + is_expected.to compile.with_all_deps + end + it 'should configure haproxy' do + is_expected.to contain_haproxy__userlist('starwars').with( + :users => [ + 'leia insecure-password sister', + 'luke insecure-password jedi', + 'anakin insecure-password darthvador', + 'sith password $5$h9LsKUOeCr$UlD62CNEpuZQkGYdBoiFJLsM6TlXluRLBlhEnpjDdaC', + ], + :groups => [ + 'aldebaran users leia,luke', + 'deathstar users anakin,sith', + ] + ) + end + end + end + + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge({}) + end + + it_behaves_like 'tripleo haproxy userlist' + end + end +end diff --git a/spec/fixtures/hieradata/default.yaml b/spec/fixtures/hieradata/default.yaml index 276f00207..1c32bf732 100644 --- a/spec/fixtures/hieradata/default.yaml +++ b/spec/fixtures/hieradata/default.yaml @@ -77,3 +77,26 @@ tripleo::dynamic_stuff::haproxy_endpoints: public_ssl_port: 19696 member_options: [ 'check', 'inter 2000', 'rise 2', 'fall 5' ] haproxy_listen_bind_param: ['transparent'] +tripleo::haproxy_basic_auth::haproxy_endpoints: + starwars: + public_virtual_ip: '192.168.0.1' + internal_ip: '10.0.0.1' + service_port: 9696 + ip_addresses: ['10.0.0.2', '10.0.0.3', '10.0.0.4'] + server_names: ['controller1', 'controller2', 'controller3'] + public_ssl_port: 19696 + member_options: [ 'check', 'inter 2000', 'rise 2', 'fall 5' ] + haproxy_listen_bind_param: ['transparent'] + authorized_userlist: 'starwars' +# HAProxy userlists +tripleo::haproxy_basic_auth::haproxy_userlists: + starwars: + groups: + - 'aldebaran users leia,luke' + - 'deathstar users anakin,sith' + users: + - 'leia insecure-password sister' + - 'luke insecure-password jedi' + - 'anakin insecure-password darthvador' + - 'sith password $5$h9LsKUOeCr$UlD62CNEpuZQkGYdBoiFJLsM6TlXluRLBlhEnpjDdaC' +