Support shared LDAP share in region config
This patch enhanced region configuration to support LDAP as shared service optionally for both IPv4 and IPV6 management network. By sharing LDAP service, management of system users can be centralized at primary region. A LDAP_SERVICE_URL=<[ldap://]ip_address[:port]> can be specified in the [SHARED_SERVICES] section of region configuration file, the secondary regions will then be setup and share the LDAP service running at the specified URL of the primary region. If no LDAP_SERVICE_URL is specified in the [SHARED_SERVICES] section, the secondary regions will setup and use local LDAP service running at the region's controllers. Decouple NSLCD from the open-ldap SM service and manage it by PMOND instead. This is needed because in the Shared LDAP case, we deprovision the open-ldap service on the Secondary Region which renders NSLCD unmanaged. Additionally, we allow the Secondary Region or Sub Clouds to bind anonymously, but still need to support LDAP read operations in these regions such as ldapfinger or lsldap. For this purpose, the ldapscripts runtime library has been modified to allow anonymous binds during LDAP search operations. Change-Id: Ic9f4d157c0eab02a8dabbdae28d508d4aef05fa2
This commit is contained in:
parent
8761006706
commit
d8c8412cb4
|
@ -502,6 +502,9 @@ class ConfigAssistant():
|
|||
self.mtce_ks_password = ""
|
||||
self.nfv_ks_user_name = ""
|
||||
self.nfv_ks_password = ""
|
||||
self.ldap_region_name = ""
|
||||
self.ldap_service_name = ""
|
||||
self.ldap_service_uri = ""
|
||||
|
||||
# Subcloud config (only valid when region configured)
|
||||
self.system_controller_subnet = None
|
||||
|
@ -2694,6 +2697,15 @@ class ConfigAssistant():
|
|||
if config.has_option('cREGION', 'GLANCE_PUBLIC_URI'):
|
||||
self.glance_public_uri = config.get(
|
||||
'cREGION', 'GLANCE_PUBLIC_URI')
|
||||
if config.has_option('cREGION', 'LDAP_REGION_NAME'):
|
||||
self.ldap_region_name = config.get(
|
||||
'cREGION', 'LDAP_REGION_NAME')
|
||||
if config.has_option('cREGION', 'LDAP_SERVICE_NAME'):
|
||||
self.ldap_service_name = config.get(
|
||||
'cREGION', 'LDAP_SERVICE_NAME')
|
||||
if config.has_option('cREGION', 'LDAP_SERVICE_URI'):
|
||||
self.ldap_service_uri = config.get(
|
||||
'cREGION', 'LDAP_SERVICE_URI')
|
||||
self.nova_ks_user_name = config.get(
|
||||
'cREGION', 'NOVA_USER_NAME')
|
||||
self.nova_ks_password = config.get(
|
||||
|
@ -2981,6 +2993,9 @@ class ConfigAssistant():
|
|||
print "Glance admin URI: " + self.glance_admin_uri
|
||||
print "Glance internal URI: " + self.glance_internal_uri
|
||||
print "Glance public URI: " + self.glance_public_uri
|
||||
print "LDAP service name: " + self.ldap_service_name
|
||||
print "LDAP region: " + self.ldap_region_name
|
||||
print "LDAP service URI:" + self.ldap_service_uri
|
||||
print "Nova user name: " + self.nova_ks_user_name
|
||||
print "Nova service name: " + self.nova_service_name
|
||||
print "Nova service type: " + self.nova_service_type
|
||||
|
@ -3275,6 +3290,15 @@ class ConfigAssistant():
|
|||
self.glance_internal_uri)
|
||||
f.write("GLANCE_PUBLIC_URI=%s\n" %
|
||||
self.glance_public_uri)
|
||||
if self.ldap_service_name:
|
||||
f.write("LDAP_SERVICE_NAME=%s\n" %
|
||||
self.ldap_service_name)
|
||||
if self.ldap_region_name:
|
||||
f.write("LDAP_REGION_NAME=%s\n" %
|
||||
self.ldap_region_name)
|
||||
if self.ldap_service_uri:
|
||||
f.write("LDAP_SERVICE_URI=%s\n" %
|
||||
self.ldap_service_uri)
|
||||
f.write("NOVA_USER_NAME=%s\n" %
|
||||
self.nova_ks_user_name)
|
||||
f.write("NOVA_PASSWORD=%s\n" %
|
||||
|
@ -3724,6 +3748,16 @@ class ConfigAssistant():
|
|||
'capabilities': capabilities}
|
||||
client.sysinv.sm_service.service_create(**values)
|
||||
|
||||
# if ldap is a shared service
|
||||
if self.ldap_service_uri:
|
||||
capabilities = {'service_name': self.ldap_service_name}
|
||||
capabilities.update({'service_uri': self.ldap_service_uri})
|
||||
values = {'name': self.ldap_service_name,
|
||||
'enabled': True,
|
||||
'region_name': self.ldap_region_name,
|
||||
'capabilities': capabilities}
|
||||
client.sysinv.sm_service.service_create(**values)
|
||||
|
||||
# neutron service config
|
||||
capabilities = {'service_name': self.neutron_service_name,
|
||||
'service_type': self.neutron_service_type,
|
||||
|
|
|
@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0
|
|||
|
||||
import ConfigParser
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
|
@ -473,6 +474,19 @@ def validate_region_one_keystone_config(region_config, token, api_url, users,
|
|||
endpointtype, expected, endpointtype, found))
|
||||
|
||||
|
||||
def validate_region_one_ldap_config(region_config):
|
||||
"""Validate ldap on region one by a ldap search"""
|
||||
|
||||
ldapserver_uri = region_config.get('SHARED_SERVICES', 'LDAP_SERVICE_URL')
|
||||
cmd = ["ldapsearch", "-xH", ldapserver_uri,
|
||||
"-b", "dc=cgcs,dc=local", "(objectclass=*)"]
|
||||
try:
|
||||
with open(os.devnull, "w") as fnull:
|
||||
subprocess.check_call(cmd, stdout=fnull, stderr=fnull)
|
||||
except subprocess.CalledProcessError:
|
||||
raise ConfigFail("LDAP configuration error: not accessible")
|
||||
|
||||
|
||||
def set_subcloud_config_defaults(region_config):
|
||||
"""Set defaults in region_config for subclouds"""
|
||||
|
||||
|
@ -645,6 +659,12 @@ def configure_region(config_file, config_type=REGION_CONFIG):
|
|||
user_config=user_config)
|
||||
print "DONE"
|
||||
|
||||
# validate ldap if it is shared
|
||||
if region_config.has_option('SHARED_SERVICES', 'LDAP_SERVICE_URL'):
|
||||
print "Validating ldap configuration... ",
|
||||
validate_region_one_ldap_config(region_config)
|
||||
print "DONE"
|
||||
|
||||
# Create cgcs_config file
|
||||
print "Creating config apply file... ",
|
||||
try:
|
||||
|
|
|
@ -201,6 +201,14 @@ def create_cgcs_config_file(output_file, system_config,
|
|||
cgcs_config.set('cREGION', 'GLANCE_INTERNAL_URI',
|
||||
glance_internal_url)
|
||||
|
||||
# if ldap is a shared service
|
||||
if (system_config.has_option('SHARED_SERVICES', 'LDAP_SERVICE_URL')):
|
||||
ldap_service_url = system_config.get('SHARED_SERVICES',
|
||||
'LDAP_SERVICE_URL')
|
||||
cgcs_config.set('cREGION', 'LDAP_SERVICE_URI', ldap_service_url)
|
||||
cgcs_config.set('cREGION', 'LDAP_SERVICE_NAME', 'open-ldap')
|
||||
cgcs_config.set('cREGION', 'LDAP_REGION_NAME', region_1_name)
|
||||
|
||||
# The domains are not available in the validation phase
|
||||
heat_admin_domain = system_config.get('REGION_2_SERVICES',
|
||||
'HEAT_ADMIN_DOMAIN')
|
||||
|
|
|
@ -68,6 +68,8 @@ CINDER_V2_SERVICE_TYPE=volumev2
|
|||
CINDER_V3_SERVICE_NAME=cinderv3
|
||||
CINDER_V3_SERVICE_TYPE=volumev3
|
||||
|
||||
LDAP_SERVICE_URL=ldap://192.168.204.12:389
|
||||
|
||||
[REGION_2_SERVICES]
|
||||
REGION_NAME=RegionTwo
|
||||
NOVA_USER_NAME=novaTWO
|
||||
|
|
|
@ -116,6 +116,9 @@ KEYSTONE_PUBLIC_URI = http://10.10.10.2:8081/keystone/main/v2.0
|
|||
GLANCE_ADMIN_URI = http://192.168.204.12:9292/v2
|
||||
GLANCE_PUBLIC_URI = http://10.10.10.2:9292/v2
|
||||
GLANCE_INTERNAL_URI = http://192.168.204.12:9292/v2
|
||||
LDAP_SERVICE_URI = ldap://192.168.204.12:389
|
||||
LDAP_SERVICE_NAME = open-ldap
|
||||
LDAP_REGION_NAME = RegionOne
|
||||
HEAT_ADMIN_DOMAIN_NAME = heat
|
||||
|
||||
[cAUTHENTICATION]
|
||||
|
|
|
@ -58,8 +58,11 @@ class platform::ldap::server::local
|
|||
onlyif => '/usr/bin/test -e /etc/openldap/slapd.conf'
|
||||
}
|
||||
|
||||
file { "/usr/local/etc/ldapscripts/ldapscripts.passwd":
|
||||
content => $admin_pw,
|
||||
# don't populate the adminpw if binding anonymously
|
||||
if ! $bind_anonymous {
|
||||
file { "/usr/local/etc/ldapscripts/ldapscripts.passwd":
|
||||
content => $admin_pw,
|
||||
}
|
||||
}
|
||||
|
||||
file { "/usr/share/cracklib/cracklib-small":
|
||||
|
@ -99,6 +102,14 @@ class platform::ldap::client
|
|||
hasstatus => true,
|
||||
hasrestart => true,
|
||||
}
|
||||
|
||||
if $::personality == 'controller' {
|
||||
file { "/usr/local/etc/ldapscripts/ldapscripts.conf":
|
||||
ensure => 'present',
|
||||
replace => true,
|
||||
content => template('platform/ldapscripts.conf.erb'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class platform::ldap::bootstrap
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
# Copyright (C) 2005 Gana<6E>l LAPLANCHE - Linagora
|
||||
# Copyright (C) 2006-2013 Gana<6E>l LAPLANCHE
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||
# USA.
|
||||
#
|
||||
# Copyright (c) 2018 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# LDAP server
|
||||
SERVER="ldap://<%= @ldapserver_host %>"
|
||||
|
||||
# Suffixes
|
||||
SUFFIX="dc=cgcs,dc=local" # Global suffix
|
||||
GSUFFIX="ou=Group" # Groups ou (just under $SUFFIX)
|
||||
USUFFIX="ou=People" # Users ou (just under $SUFFIX)
|
||||
MSUFFIX="ou=Machines" # Machines ou (just under $SUFFIX)
|
||||
|
||||
# Authentication type
|
||||
# If empty, use simple authentication
|
||||
# Else, use the value as an SASL authentication mechanism
|
||||
SASLAUTH=""
|
||||
#SASLAUTH="GSSAPI"
|
||||
|
||||
# Simple authentication parameters
|
||||
# The following BIND* parameters are ignored if SASLAUTH is set
|
||||
#BINDDN="cn=proxyuser,dc=example,dc=com"
|
||||
# The following file contains the raw password of the BINDDN
|
||||
# Create it with something like : echo -n 'secret' > $BINDPWDFILE
|
||||
# WARNING !!!! Be careful not to make this file world-readable
|
||||
#BINDPWDFILE="/foo/ldapscripts.passwd"
|
||||
|
||||
<%- if @bind_anonymous != true -%>
|
||||
BINDDN="cn=ldapadmin,dc=cgcs,dc=local"
|
||||
BINDPWDFILE="/usr/local/etc/ldapscripts/ldapscripts.passwd"
|
||||
<%- end -%>
|
||||
|
||||
# For older versions of OpenLDAP, it is still possible to use
|
||||
# unsecure command-line passwords by defining the following option
|
||||
# AND commenting the previous one (BINDPWDFILE takes precedence)
|
||||
#BINDPWD="secret"
|
||||
|
||||
# Start with these IDs *if no entry found in LDAP*
|
||||
GIDSTART="10000" # Group ID
|
||||
UIDSTART="10000" # User ID
|
||||
MIDSTART="20000" # Machine ID
|
||||
|
||||
# Group membership management
|
||||
# ObjectCLass used for groups
|
||||
# Possible values : posixGroup, groupOfNames, groupOfUniqueNames (case-sensitive !)
|
||||
# Warning : when using groupOf*, be sure to be compliant with RFC 2307bis (AUXILIARY posixGroup).
|
||||
# Also, do not mix posixGroup and groupOf* entries up in you directory as, within RFC 2307bis,
|
||||
# the former is a subset of the latter. The ldapscripts wouldn't cope well with this configuration.
|
||||
GCLASS="posixGroup" # Leave "posixGroup" here if not sure !
|
||||
# When using groupOfNames or groupOfUniqueNames, creating a group requires an initial
|
||||
# member. Specify it below, you will be able to remove it once groups are populated.
|
||||
#GDUMMYMEMBER="uid=dummy,$USUFFIX,$SUFFIX"
|
||||
|
||||
# User properties
|
||||
USHELL="/bin/sh"
|
||||
UHOMES="/home/%u" # You may use %u for username here
|
||||
CREATEHOMES="no" # Create home directories and set rights ?
|
||||
HOMESKEL="/etc/skel" # Directory where the skeleton files are located. Ignored if undefined or nonexistant.
|
||||
HOMEPERMS="700" # Default permissions for home directories
|
||||
|
||||
# User passwords generation
|
||||
# Command-line used to generate a password for added users.
|
||||
# You may use %u for username here ; special value "<ask>" will ask for a password interactively
|
||||
# WARNING !!!! This is evaluated, everything specified here will be run !
|
||||
# WARNING(2) !!!! Some systems (Linux) use a blocking /dev/random (waiting for enough entropy).
|
||||
# In this case, consider using /dev/urandom instead.
|
||||
#PASSWORDGEN="cat /dev/random | LC_ALL=C tr -dc 'a-zA-Z0-9' | head -c8"
|
||||
#PASSWORDGEN="pwgen"
|
||||
#PASSWORDGEN="echo changeme"
|
||||
PASSWORDGEN="echo %u"
|
||||
#PASSWORDGEN="<ask>"
|
||||
|
||||
# User passwords recording
|
||||
# you can keep trace of generated passwords setting PASSWORDFILE and RECORDPASSWORDS
|
||||
# (useful when performing a massive creation / net rpc vampire)
|
||||
# WARNING !!!! DO NOT FORGET TO DELETE THE GENERATED FILE WHEN DONE !
|
||||
# WARNING !!!! DO NOT FORGET TO TURN OFF RECORDING WHEN DONE !
|
||||
RECORDPASSWORDS="no"
|
||||
PASSWORDFILE="/var/log/ldapscripts_passwd.log"
|
||||
|
||||
# Where to log
|
||||
LOGFILE="/var/log/ldapscripts.log"
|
||||
|
||||
# Temporary folder
|
||||
TMPDIR="/tmp"
|
||||
|
||||
# Various binaries used within the scripts
|
||||
# Warning : they also use uuencode, date, grep, sed, cut, which...
|
||||
# Please check they are installed before using these scripts
|
||||
# Note that many of them should come with your OS
|
||||
|
||||
# OpenLDAP client commands
|
||||
LDAPSEARCHBIN="/usr/bin/ldapsearch"
|
||||
LDAPADDBIN="/usr/bin/ldapadd"
|
||||
LDAPDELETEBIN="/usr/bin/ldapdelete"
|
||||
LDAPMODIFYBIN="/usr/bin/ldapmodify"
|
||||
LDAPMODRDNBIN="/usr/bin/ldapmodrdn"
|
||||
LDAPPASSWDBIN="/usr/bin/ldappasswd"
|
||||
|
||||
# OpenLDAP client common additional options
|
||||
# This allows for adding more configuration options to the OpenLDAP clients, e.g. '-ZZ' to enforce TLS
|
||||
#LDAPBINOPTS="-ZZ"
|
||||
|
||||
# OpenLDAP ldapsearch-specific additional options
|
||||
# The following option disables long-line wrapping (which makes the scripts bug
|
||||
# when handling long lines). The option was introduced in OpenLDAP 2.4.24, so
|
||||
# comment it if you are using OpenLDAP < 2.4.24.
|
||||
LDAPSEARCHOPTS="-o ldif-wrap=no"
|
||||
# And here is an example to activate paged results
|
||||
#LDAPSEARCHOPTS="-E pr=500/noprompt"
|
||||
|
||||
# Character set conversion : $ICONVCHAR <-> UTF-8
|
||||
# Comment ICONVBIN to disable UTF-8 conversion
|
||||
# ICONVBIN="/usr/bin/iconv"
|
||||
# ICONVCHAR=""
|
||||
|
||||
# Base64 decoding
|
||||
# Comment UUDECODEBIN to disable Base64 decoding
|
||||
#UUDECODEBIN="/usr/bin/uudecode"
|
||||
|
||||
# Getent command to use - choose the ones used
|
||||
# on your system. Leave blank or comment for auto-guess.
|
||||
# GNU/Linux
|
||||
GETENTPWCMD="getent passwd"
|
||||
GETENTGRCMD="getent group"
|
||||
# FreeBSD
|
||||
#GETENTPWCMD="pw usershow"
|
||||
#GETENTGRCMD="pw groupshow"
|
||||
# Auto
|
||||
#GETENTPWCMD=""
|
||||
#GETENTGRCMD=""
|
||||
|
||||
# You can specify custom LDIF templates here
|
||||
# Leave empty to use default templates
|
||||
# See *.template.sample for default templates
|
||||
#GTEMPLATE="/path/to/ldapaddgroup.template"
|
||||
#UTEMPLATE="/path/to/ldapadduser.template"
|
||||
#MTEMPLATE="/path/to/ldapaddmachine.template"
|
||||
GTEMPLATE="/usr/local/etc/ldapscripts/ldapaddgroup.template.cgcs"
|
||||
UTEMPLATE="/usr/local/etc/ldapscripts/ldapadduser.template.cgcs"
|
||||
UMTEMPLATE="/usr/local/etc/ldapscripts/ldapmoduser.template.cgcs"
|
||||
STEMPLATE="/usr/local/etc/ldapscripts/ldapaddsudo.template.cgcs"
|
||||
SMTEMPLATE="/usr/local/etc/ldapscripts/ldapmodsudo.template.cgcs"
|
||||
MTEMPLATE=""
|
|
@ -13,6 +13,7 @@ from . import base
|
|||
|
||||
class LdapPuppet(base.BasePuppet):
|
||||
"""Class to encapsulate puppet operations for ldap configuration"""
|
||||
SERVICE_NAME = 'open-ldap'
|
||||
|
||||
def get_secure_static_config(self):
|
||||
password = self._generate_random_password()
|
||||
|
@ -53,6 +54,15 @@ class LdapPuppet(base.BasePuppet):
|
|||
ldapserver_host = self._format_url_address(ldapserver_addr)
|
||||
bind_anonymous = True
|
||||
|
||||
elif self._region_config():
|
||||
service_config = self.get_service_config(self.SERVICE_NAME)
|
||||
if service_config is not None:
|
||||
ldapserver_remote = True
|
||||
ldapserver_uri = service_config.capabilities.get('service_uri')
|
||||
addr_index = ldapserver_uri.rfind('/')
|
||||
ldapserver_host = ldapserver_uri[addr_index + 1:]
|
||||
bind_anonymous = True
|
||||
|
||||
if host.personality != constants.CONTROLLER:
|
||||
# if storage/compute, use bind anonymously
|
||||
bind_anonymous = True
|
||||
|
@ -80,3 +90,9 @@ class LdapPuppet(base.BasePuppet):
|
|||
'platform::ldap::params::ldapserver_host': ldapserver_host,
|
||||
'platform::ldap::params::bind_anonymous': bind_anonymous,
|
||||
}
|
||||
|
||||
def get_service_config(self, service):
|
||||
configs = self.context.setdefault('_service_configs', {})
|
||||
if service not in configs:
|
||||
configs[service] = self._get_service(service)
|
||||
return configs[service]
|
||||
|
|
Loading…
Reference in New Issue