LDAP proxy support

it enables support of ldap proxy in HA-mode.

Change-Id: I24bb5c8033d202dfc56d3779c93b42a36881d95b
This commit is contained in:
Maksym Yatsenko 2016-06-11 00:51:13 +03:00
parent 6707739fbe
commit 331e3239b7
14 changed files with 439 additions and 47 deletions

View File

@ -0,0 +1,55 @@
module Puppet::Parser::Functions
newfunction(:proxy_config_parser, :type => :rvalue, :doc => <<-EOS
This function parses text area of custom openldap proxy configs and
text area of additional domains, returns an array with two elements,
1st element contains all custom openldap proxy configs, 2nd element
contains list of domains that use default (from template) proxy config.
EOS
) do |args|
# args[0]: additional LDAP domains
# args[1]: custom openldap proxy configs
# args[2]: default domain
domains_with_proxy = ['base_config']
domains_custom_proxy_configs = {}
slapd_custom_conf = ''
domains_default_conf = []
function_returns = []
array_of_domain_configs = args[0].split(/^$/)
array_of_slapd_configs = args[1].split(/^$/)
domains_with_proxy = domains_with_proxy.push(args[2])
#find domain with proxy enabled
array_of_domain_configs.each do |domain_config|
if domain_config.include? "ldap_proxy=true"
domain_item = domain_config.slice(/(domain=.*)[^\n]/)
domain = domain_item.split(/=/)
domains_with_proxy = domains_with_proxy.push(domain[1])
end
end
#find domains with specified custom ldap proxy configs
array_of_slapd_configs.each do |custom_config|
custom_config_item = custom_config.slice!(/(config_for=.*)[^\n]/)
custom_config_domain = custom_config_item.split(/=/)
domains_custom_proxy_configs[custom_config_domain[1]] = custom_config
end
#find domains with custom/default proxy configs
domains_with_proxy.each do |domain|
if domains_custom_proxy_configs[domain]
slapd_custom_conf += domains_custom_proxy_configs[domain]
else
domains_default_conf = domains_default_conf.push(domain)
end
end
function_returns = function_returns.push(slapd_custom_conf)
function_returns = function_returns.push(domains_default_conf)
return function_returns
end
end

View File

@ -12,7 +12,7 @@ class plugin_ldap::controller {
} }
$identity_driver = 'keystone.identity.backends.ldap.Identity' $identity_driver = 'keystone.identity.backends.ldap.Identity'
$url = $::fuel_settings['ldap']['url'] $ldap_url = $::fuel_settings['ldap']['url']
$suffix = $::fuel_settings['ldap']['suffix'] $suffix = $::fuel_settings['ldap']['suffix']
$user = $::fuel_settings['ldap']['user'] $user = $::fuel_settings['ldap']['user']
$password = $::fuel_settings['ldap']['password'] $password = $::fuel_settings['ldap']['password']
@ -25,6 +25,8 @@ class plugin_ldap::controller {
$user_pass_attribute = $::fuel_settings['ldap']['user_pass_attribute'] $user_pass_attribute = $::fuel_settings['ldap']['user_pass_attribute']
$user_enabled_attribute = $::fuel_settings['ldap']['user_enabled_attribute'] $user_enabled_attribute = $::fuel_settings['ldap']['user_enabled_attribute']
$additional_domains = $::fuel_settings['ldap']['additional_domains'] $additional_domains = $::fuel_settings['ldap']['additional_domains']
$ldap_proxy_custom_conf = $::fuel_settings['ldap']['ldap_proxy_custom_conf']
$ldap_proxy = $::fuel_settings['ldap']['ldap_proxy']
$user_allow_create = false $user_allow_create = false
$user_allow_update = false $user_allow_update = false
@ -49,6 +51,52 @@ class plugin_ldap::controller {
$use_tls = $::fuel_settings['ldap']['use_tls'] $use_tls = $::fuel_settings['ldap']['use_tls']
$ca_chain = pick($::fuel_settings['ldap']['ca_chain'], false) $ca_chain = pick($::fuel_settings['ldap']['ca_chain'], false)
###############################################################################
#Install ldap_proxy and generate slapd.conf file
if $ldap_proxy {
$url = "ldap://${management_vip}"
$proxy_data = proxy_config_parser($additional_domains, $ldap_proxy_custom_conf, $domain)
class {'plugin_ldap::ldap_proxy_install':
slapd_custom_config => $proxy_data[0],
slapd_config_template => $proxy_data[1],
domain_name => $domain,
use_tls => $use_tls,
}
class {'plugin_ldap::ldap_proxy_init':
internal_virtual_ip => $management_vip,
}
Class['plugin_ldap::ldap_proxy_install'] -> Plugin_ldap::Keystone<||> -> Class['plugin_ldap::ldap_proxy_init']
Service['httpd'] -> Class['plugin_ldap::ldap_proxy_init']
if $use_tls {
plugin_ldap::tls { "${domain}_tls_certificate" :
domain_tls => $domain,
ca_chain => $ca_chain,
}
}
$tls = false
} else {
$url = $::fuel_settings['ldap']['url']
$proxy_data = []
$tls = $use_tls
}
#Create domains using info from text area 'List of additional Domains'
if $additional_domains {
$domains_list = split($additional_domains, '^$')
plugin_ldap::multiple_domain { $domains_list:
identity_driver => $identity_driver,
ldap_proxy => $ldap_proxy,
management_vip => $management_vip,
slapd_config_template => $proxy_data[1],
}
}
file { '/etc/keystone/domains': file { '/etc/keystone/domains':
ensure => 'directory', ensure => 'directory',
owner => 'keystone', owner => 'keystone',
@ -60,11 +108,10 @@ class plugin_ldap::controller {
"identity/domain_specific_drivers_enabled": value => 'True'; "identity/domain_specific_drivers_enabled": value => 'True';
} }
plugin_ldap::keystone {$domain: plugin_ldap::keystone { $domain:
domain => $domain,
identity_driver => $identity_driver, identity_driver => $identity_driver,
url => $url, url => $url,
use_tls => $use_tls, use_tls => $tls,
ca_chain => $ca_chain, ca_chain => $ca_chain,
suffix => $suffix, suffix => $suffix,
user => $user, user => $user,
@ -96,37 +143,33 @@ class plugin_ldap::controller {
chase_referrals => $chase_referrals, chase_referrals => $chase_referrals,
} }
Plugin_ldap::Keystone<||> ~>
service { 'httpd': service { 'httpd':
name => "$apache::params::service_name", name => $apache::params::service_name,
ensure => running, ensure => running,
} }
#Create domains using info from text area 'List of additional Domains'
if $additional_domains {
$domains_list = split($additional_domains, '^$')
plugin_ldap::multiple_domain { $domains_list:
identity_driver => $identity_driver,
}
}
file_line { 'OPENSTACK_KEYSTONE_URL': file_line { 'OPENSTACK_KEYSTONE_URL':
path => '/etc/openstack-dashboard/local_settings.py', path => '/etc/openstack-dashboard/local_settings.py',
line => "OPENSTACK_KEYSTONE_URL = \"http://${management_vip}:5000/v3/\"", line => "OPENSTACK_KEYSTONE_URL = \"http://${management_vip}:5000/v3/\"",
match => "^OPENSTACK_KEYSTONE_URL = .*$", match => "^OPENSTACK_KEYSTONE_URL = .*$",
tag => 'ldap-horizon',
} }
file_line { 'OPENSTACK_API_VERSIONS': file_line { 'OPENSTACK_API_VERSIONS':
path => '/etc/openstack-dashboard/local_settings.py', path => '/etc/openstack-dashboard/local_settings.py',
line => "OPENSTACK_API_VERSIONS = { \"identity\": 3 }", line => "OPENSTACK_API_VERSIONS = { \"identity\": 3 }",
match => "^# OPENSTACK_API_VERSIONS = {.*$", match => "^# OPENSTACK_API_VERSIONS = {.*$",
tag => 'ldap-horizon',
} }
file_line { 'OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT': file_line { 'OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT':
path => '/etc/openstack-dashboard/local_settings.py', path => '/etc/openstack-dashboard/local_settings.py',
line => "OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True", line => "OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True",
match => "^# OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = .*$", match => "^# OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = .*$",
tag => 'ldap-horizon',
} }
File_line<||> ~> Service ['httpd'] File_line<| tag == 'ldap-horizon'|> ~> Service['httpd']
Keystone_config <||> ~> Service['httpd']
Plugin_ldap::Tls<||> ~> Service['httpd']
} }

View File

@ -1,5 +1,5 @@
define plugin_ldap::keystone ( define plugin_ldap::keystone (
$domain = undef, $domain = $name,
$identity_driver = undef, $identity_driver = undef,
$url = undef, $url = undef,
$use_tls = undef, $use_tls = undef,
@ -35,33 +35,24 @@ define plugin_ldap::keystone (
){ ){
if $use_tls { if $use_tls {
$cacertfile = "/usr/local/share/ca-certificates/cacert-ldap-${domain}.crt"
plugin_ldap::tls { "${domain}_tls_certificate" :
domain_tls => $domain,
ca_chain => $ca_chain,
}
if $ca_chain { if $ca_chain {
$tls_cacertdir = '/etc/ssl/certs' $tls_cacertdir = '/etc/ssl/certs'
} }
else { else {
$tls_cacertdir = '' $tls_cacertdir = ''
} }
if $ca_chain {
file { $cacertfile:
ensure => file,
mode => 0644,
content => $ca_chain,
}
~>
exec { "$domain" :
command => '/usr/sbin/update-ca-certificates'
}
}
} }
file { "/etc/keystone/domains/keystone.${domain}.conf": file { "/etc/keystone/domains/keystone.${domain}.conf":
ensure => 'file', ensure => 'file',
owner => 'root', owner => 'root',
group => 'root', group => 'root',
mode => '644', mode => '0644',
require => File['/etc/keystone/domains'], require => File['/etc/keystone/domains'],
} }

View File

@ -0,0 +1,75 @@
class plugin_ldap::ldap_proxy_init (
$internal_virtual_ip = undef,
$slapd_defaults_match = '^SLAPD_SERVICES=',
$slapd_defaults_path = '/etc/default/slapd',
$bin_paths = '/usr/sbin/:/usr/local/bin/:/bin/:/usr/bin',
$slaptest_run = 'slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d',
$slapd_rsyslog = '/etc/rsyslog.d/slapd.conf',
) {
$network_metadata = hiera_hash('network_metadata', {})
$controller_hash = get_node_to_ipaddr_map_by_network_role(get_nodes_hash_by_roles($network_metadata, ['primary-controller', 'controller']), 'management')
$controller_nodes = keys($controller_hash)
$controller_ip = values($controller_hash)
$network_scheme = hiera_hash('network_scheme', {})
prepare_network_config($network_scheme)
$local_address = get_network_role_property('management', 'ipaddr')
$cidr = hiera('management_network_range')
$slapd_defaults_services = "SLAPD_SERVICES=\"ldap://${local_address}\""
file_line { 'slapd_defaults':
ensure => present,
path => $slapd_defaults_path,
line => $slapd_defaults_services,
replace => true,
match => $slapd_defaults_match,
} ->
exec { 'run_slaptest':
command => $slaptest_run,
path => $bin_paths,
user => 'openldap',
group => 'openldap',
notify => Service['slapd'],
} ->
service { 'slapd':
ensure => 'running',
enable => true,
}
service { 'rsyslog':
ensure => 'running',
enable => true,
}
file { $slapd_rsyslog:
ensure => present,
content => template('plugin_ldap/slapd_rsyslog.erb'),
notify => Service['rsyslog'],
}
firewall { '255 allow ldap-proxy':
source => $cidr,
destination => $baremetal_ipaddr,
proto => 'tcp',
dport => '389',
state => ['NEW', 'RELATED', 'ESTABLISHED'],
action => 'accept',
} ->
openstack::ha::haproxy_service { 'slapd':
internal_virtual_ip => $internal_virtual_ip,
ipaddresses => $controller_ip,
server_names => $controller_nodes,
haproxy_config_options => {
mode => 'tcp',
stats => 'enable',
option => ['ldap-check',]
},
balancermember_options => 'maxconn 10000 check',
order => '180',
listen_port => '389',
} ~> Service<| title == 'haproxy' |>
}

View File

@ -0,0 +1,66 @@
class plugin_ldap::ldap_proxy_install (
$domain_name,
$slapd_custom_config = undef,
$slapd_config_template = undef,
$use_tls = false,
$base_config_label = 'base_config',
$slapd_dir = '/etc/ldap/slapd.d/*',
$slapd_config = '/etc/ldap/slapd.conf',
) {
package { 'ldap-utils':
ensure => 'installed',
} ->
file { '/etc/init/slapd.conf':
ensure => present,
content => template('plugin_ldap/slapd_upstart.erb'),
} ->
package { 'slapd':
ensure => 'installed',
} ->
exec { 'clean_slapd_d':
command => "/bin/rm -rf ${slapd_dir}",
} ->
concat { "${slapd_config}" :
owner => 'root',
group => 'root',
mode => '0644',
}
if $base_config_label in $slapd_config_template {
concat::fragment { "base_fragment" :
target => $slapd_config,
content => template('plugin_ldap/slapd_base.erb'),
order => '10',
}
}
if $domain_name in $slapd_config_template {
if ! $use_tls {
concat::fragment { "${domain_name}_fragment" :
target => $slapd_config,
content => template('plugin_ldap/slapd_conf.erb'),
order => '20',
}
}
else {
concat::fragment { "${domain_name}_tls_fragment" :
target => $slapd_config,
content => template('plugin_ldap/slapd_tls_conf.erb'),
order => '20',
}
}
}
if $slapd_custom_config {
concat::fragment { 'ldap_proxy_init' :
target => $slapd_config,
content => $slapd_custom_config,
order => '30',
}
}
}

View File

@ -1,19 +1,66 @@
define plugin_ldap::multiple_domain ( define plugin_ldap::multiple_domain (
$domain_info = $title, $domain_info = $title,
$identity_driver = undef $identity_driver = undef,
$ldap_proxy = undef,
$management_vip = undef,
$slapd_config_template = undef,
$slapd_conf = '/etc/ldap/slapd.conf',
){ ){
$domain_params_hash = parse_it($domain_info) $domain_params_hash = parse_it($domain_info)
$domain = $domain_params_hash['domain']
$suffix = $domain_params_hash['suffix']
$user_tree_dn = $domain_params_hash['user_tree_dn']
$user = $domain_params_hash['user']
$password = $domain_params_hash['password']
$ldap_url = $domain_params_hash['url']
$use_tls = $domain_params_hash['use_tls']
$ldap_proxy_multidomain = $domain_params_hash['ldap_proxy']
$ca_chain = $domain_params_hash['ca_chain']
if $ldap_proxy_multidomain =~ /^[Tt]rue$/ {
$url = "ldap://${management_vip}"
if $domain in $slapd_config_template {
if $use_tls =~ /^[Ff]alse$/ {
concat::fragment { "${domain}_fragment" :
target => $slapd_conf,
content => template('plugin_ldap/slapd_conf.erb'),
}
}
elsif $use_tls =~ /^[Tt]rue$/ {
concat::fragment { "${domain}_tls_fragment" :
target => $slapd_conf,
content => template('plugin_ldap/slapd_tls_conf.erb'),
}
plugin_ldap::tls { "${domain}_tls_certificate" :
domain_tls => $domain,
ca_chain => $ca_chain,
}
}
}
$tls = false
} else {
$url = $domain_params_hash['url']
$tls = $use_tls ? { /^[Tt]rue$/ => true, default => false }
}
plugin_ldap::keystone { "$domain_params_hash['domain']" : plugin_ldap::keystone { "$domain_params_hash['domain']" :
domain => $domain_params_hash['domain'], domain => $domain,
identity_driver => $identity_driver, identity_driver => $identity_driver,
url => $domain_params_hash['url'], url => $url,
use_tls => $domain_params_hash['use_tls'], use_tls => $tls,
ca_chain => $domain_params_hash['ca_chain'], ca_chain => $ca_chain,
suffix => $domain_params_hash['suffix'], suffix => $suffix,
user => $domain_params_hash['user'], user => $user,
password => $domain_params_hash['password'], password => $password,
query_scope => $domain_params_hash['query_scope'], query_scope => $domain_params_hash['query_scope'],
user_tree_dn => $domain_params_hash['user_tree_dn'], user_tree_dn => $user_tree_dn,
user_filter => $domain_params_hash['user_filter'], user_filter => $domain_params_hash['user_filter'],
user_objectclass => $domain_params_hash['user_objectclass'], user_objectclass => $domain_params_hash['user_objectclass'],
user_id_attribute => $domain_params_hash['user_id_attribute'], user_id_attribute => $domain_params_hash['user_id_attribute'],

View File

@ -0,0 +1,18 @@
define plugin_ldap::tls (
$domain_tls,
$ca_chain,
){
$cacertfile = "/usr/local/share/ca-certificates/cacert-ldap-${domain_tls}.crt"
file { $cacertfile:
ensure => file,
mode => 0644,
content => $ca_chain,
}
~>
exec { "$domain_tls" :
command => '/usr/sbin/update-ca-certificates'
}
}

View File

@ -0,0 +1,12 @@
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/nis.schema
modulepath /usr/lib/ldap
moduleload back_ldap
pidfile /var/run/slapd/slapd.pid
argsfile /var/run/slapd/slapd.args
loglevel 0

View File

@ -0,0 +1,14 @@
################################################
##template config
database ldap
suffix "<%= @suffix %>"
readonly yes
protocol-version 3
uri "<%= @ldap_url %>"
rootdn "<%= @user_tree_dn %>"
idassert-bind bindmethod=simple
binddn="<%= @user %>"
credentials="<%= @password %>"
mode=none
idassert-authzFrom "*"

View File

@ -0,0 +1,3 @@
#slapd logs
if $programname startswith 'slapd' then /var/log/ldap_proxy.log
&~

View File

@ -0,0 +1,18 @@
################################################
#template config
database ldap
suffix "<%= @suffix %>"
readonly yes
protocol-version 3
uri "<%= @ldap_url %>"
rootdn "<%= @user_tree_dn %>"
tls start
idassert-bind bindmethod=simple
binddn="<%= @user %>"
credentials="<%= @password %>"
mode=self
tls_reqcert=demand
starttls="yes"
tls_cacert=/etc/ssl/certs/
idassert-authzFrom "*"

View File

@ -0,0 +1,38 @@
description "OpenLDAP standalone server"
start on runlevel [23]
stop on shutdown
respawn
kill signal SIGINT
kill timeout 60
limit nofile 100000 100000
pre-start script
. /etc/default/slapd
if [ -n "$SLAPD_NO_START" ]; then
echo 'Not starting slapd: SLAPD_NO_START set in /etc/default/slapd'
stop
fi
if [ -n "$SLAPD_SENTINEL_FILE" ] && [ -e "$SLAPD_SENTINEL_FILE" ]; then
echo "Not starting slapd: $SLAPD_SENTINEL_FILE exists"
stop
fi
mkdir -p /var/run/slapd
chown openldap:openldap /var/run/slapd
end script
script
. /etc/default/slapd
/usr/sbin/slapd -h "${SLAPD_SERVICES}" -u "${SLAPD_USER}" -g "${SLAPD_GROUP}" -F /etc/ldap/slapd.d -d 0
end script
post-stop script
rm -rf /var/run/slapd
end script

View File

@ -17,15 +17,21 @@ attributes:
regex: regex:
source: '^ldap[si]?:\/\/([a-zA-Z0-9._-]+)(:[0-9]+)?$' source: '^ldap[si]?:\/\/([a-zA-Z0-9._-]+)(:[0-9]+)?$'
error: "LDAP URL is not valid. Should be e.g. 'ldap://example.com'." error: "LDAP URL is not valid. Should be e.g. 'ldap://example.com'."
ldap_proxy:
value: false
label: "LDAP proxy"
description: "Enable LDAP proxy."
weight: 26
type: "checkbox"
use_tls: use_tls:
value: false value: false
label: "Use TLS" label: "Use TLS"
description: "Enable TLS for communicating with the LDAP server." description: "Enable TLS for communicating with the LDAP server."
weight: 26 weight: 27
type: "checkbox" type: "checkbox"
ca_chain: ca_chain:
type: "textarea" type: "textarea"
weight: 27 weight: 28
value: '' value: ''
label: "CA Chain" label: "CA Chain"
description: "CA trust chain in PEM format." description: "CA trust chain in PEM format."
@ -39,7 +45,7 @@ attributes:
value: 'cn=example,cn=com' value: 'cn=example,cn=com'
label: 'LDAP Suffix' label: 'LDAP Suffix'
description: 'LDAP server suffix.' description: 'LDAP server suffix.'
weight: 26 weight: 29
type: "text" type: "text"
user: user:
value: 'cn=admin,dc=local' value: 'cn=admin,dc=local'
@ -176,4 +182,10 @@ attributes:
weight: 120 weight: 120
value: '' value: ''
label: "List of additional Domains" label: "List of additional Domains"
description: "Blocks of additional domains/parameters that should be created" description: "Blocks of additional domains/parameters that should be created."
ldap_proxy_custom_conf:
type: "textarea"
weight: 125
value: ''
label: "List of custom LDAP proxy configs"
description: "List of custom LDAP proxy configs."

View File

@ -1,15 +1,15 @@
name: ldap name: ldap
title: LDAP plugin for Keystone title: LDAP plugin for Keystone
version: '2.0.0' version: '3.0.0'
description: Enable to use LDAP authentication backend for Keystone description: Enable to use LDAP authentication backend for Keystone
fuel_version: ['8.0'] fuel_version: ['9.0']
licenses: ['Apache License Version 2.0'] licenses: ['Apache License Version 2.0']
authors: ['Mirantis'] authors: ['Mirantis']
homepage: 'https://github.com/stackforge/fuel-plugin-ldap' homepage: 'https://github.com/stackforge/fuel-plugin-ldap'
groups: ['network'] groups: ['network']
releases: releases:
- os: ubuntu - os: ubuntu
version: liberty-8.0 version: mitaka-9.0
mode: ['ha'] mode: ['ha']
deployment_scripts_path: deployment_scripts/ deployment_scripts_path: deployment_scripts/
repository_path: repositories/ubuntu repository_path: repositories/ubuntu