统一账号

Openshift上部署OpenLDAP也并不仅仅只是为了部署,更重要的是要用它来为各种应用统一账号管理。比如GitLab,Gogs, Nexus, Sonarqube等等,同时结合之前的Openshift使用OpenLDAP做账号管理。理想的世界是,一套Openshift,各种应用,它们的用户认证都在一套OpenLDAP上,同时这套OpenLDAP也是非常方便地部署在Openshift上。

为账号一统的第一步,就是我们需要部署OpenLDAP,这也是该篇主题。以下是之前分享的几篇与OpenLDAP有关的文章。

CentOS上搭建双主高可用OpenLDAP Server
Openshift使用OpenLDAP作为统一用户认证
CentOS上OpenLDAP Server使用cn=config方式配置

之前分享的与Openldap相关的几篇文章中,它的部署都是在虚拟机中进行的。那么在Openshift上能否完成部署呢,如果可以的话,那么那些复杂的部署我们都可以将它封装到镜像中去,岂不是更方便?那就一起来操作吧。

应用要求点

  1. 方便自定义域及管理员用户名与密码
    通过环境变量secret进行自定义配置
  2. 对pod添加健康检查,如果发现问题,主动重启恢复
    监听389端口
  3. 数据持久化,pod重启后,该pod自动恢复数据
    持久化目录为:数据目录 /var/lib/ldap, 配置目录 /etc/openldap

以上是在Openshift运行Openldap的最基本的要求了,如果更苛刻点,需要添加Openldap的监控、Openldap的日志审计、多pod高可用方案等。

制作镜像

如果不希望自己构建,可以直接使用构建好的镜像:docker.io/xhuaustc/openldap-2441-centos7:latest
步骤如下:

  1. 基础镜像centos:centos7
  2. 安装openldap相关应用:openldap, openldap-clients, openldap-servers
  3. 部署:根据环境变量更新openldap的配置文件,并初始化基础结构,最后启动openldap
    运行:启动openldap

说明,部署与运行的区别在于该应用是否是第一次启动。如果是第一次启动的话,相关配置还未更新。在第一次配置更新后,在持久化文件夹中创建一个新文件,来标记已完成配置更新。以后的每次启动都会检查该文件,如果存在,则不作初始化操作,而直接运行openldap

对应的Dockerfile参考:https://github.com/openshift/openldap/blob/master/2.4.41/Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
FROM centos:centos7

# OpenLDAP server image for OpenShift Origin
#
# Volumes:
# * /var/lib/ldap/data - Datastore for OpenLDAP
# * /etc/openldap/ - Config directory for slapd
# Environment:
# * $OPENLDAP_ADMIN_PASSWORD - OpenLDAP administrator password
# * $OPENLDAP_DEBUG_LEVEL (Optional) - OpenLDAP debugging level, defaults to 256

MAINTAINER Steve Kuznetsov <skuznets@redhat.com>

LABEL io.k8s.description="OpenLDAP is an open source implementation of the Lightweight Directory Access Protocol." \
io.k8s.display-name="OpenLDAP 2.4.41" \
io.openshift.expose-services="389:ldap,636:ldaps" \
io.openshift.tags="directory,ldap,openldap,openldap2441" \
io.openshift.non-scalable="true"

# Add defaults for config
COPY ./contrib/config /opt/openshift/config
COPY ./contrib/lib /opt/openshift/lib
# Add startup scripts
COPY run-*.sh /usr/local/bin/
COPY contrib/*.ldif /usr/local/etc/openldap/
COPY contrib/*.schema /usr/local/etc/openldap/
COPY contrib/DB_CONFIG /usr/local/etc/openldap/

# Install OpenLDAP Server, give it permissionst to bind to low ports
RUN yum install -y openldap openldap-servers openldap-clients && \
yum clean all -y && \
setcap 'cap_net_bind_service=+ep' /usr/sbin/slapd && \
mkdir -p /var/lib/ldap && \
chmod a+rwx -R /var/lib/ldap && \
mkdir -p /etc/openldap && \
chmod a+rwx -R /etc/openldap && \
mkdir -p /var/run/openldap && \
chmod a+rwx -R /var/run/openldap && \
chmod -R a+rw /opt/openshift

# Set OpenLDAP data and config directories in a data volume
VOLUME ["/var/lib/ldap", "/etc/openldap"]

# Expose default ports for ldap and ldaps
EXPOSE 389 636

CMD ["/usr/local/bin/run-openldap.sh"]

对应的部署及运行脚本参考:
https://github.com/openshift/openldap/blob/master/2.4.41/run-openldap.sh
但是有所修改,如果用root用户启动时,会先初始化openldap配置。原来的脚本如果用root用户启动时,会报错,而用非root用户启动,则自定义配置无法生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/bin/bash

# Reduce maximum number of number of open file descriptors to 1024
# otherwise slapd consumes two orders of magnitude more of RAM
# see https://github.com/docker/docker/issues/8231
ulimit -n 1024

OPENLDAP_ROOT_PASSWORD=${OPENLDAP_ROOT_PASSWORD:-admin}
OPENLDAP_ROOT_DN_PREFIX=${OPENLDAP_ROOT_DN_PREFIX:-'cn=Manager'}
OPENLDAP_ROOT_DN_SUFFIX=${OPENLDAP_ROOT_DN_SUFFIX:-'dc=example,dc=com'}
OPENLDAP_DEBUG_LEVEL=${OPENLDAP_DEBUG_LEVEL:-256}

# Only run if no config has happened fully before
if [ ! -f /etc/openldap/CONFIGURED ]; then

user=`id | grep -Po "(?<=uid=)\d+"`
if (( user == 0 ))
then
# We are root, we can use user input!
# Bring in default databse config
cp /usr/local/etc/openldap/DB_CONFIG /var/lib/ldap/DB_CONFIG

if [ -f /opt/openshift/config/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif ]
then
# Use provided default config, get rid of current data
rm -rf /var/lib/ldap/*
rm -rf /etc/openldap/*
# Bring in associated default database files
mv -f /opt/openshift/lib/* /var/lib/ldap
mv -f /opt/openshift/config/* /etc/openldap
else
# Something has gone wrong with our image build
echo "FAILURE: Default configuration files from /contrib/ are not present in the image at /opt/openshift."
exit 1
fi

# start the daemon in another process and make config changes
slapd -h "ldap:/// ldaps:/// ldapi:///" -d $OPENLDAP_DEBUG_LEVEL &
for ((i=30; i>0; i--))
do
ping_result=`ldapsearch 2>&1 | grep "Can.t contact LDAP server"`
if [ -z "$ping_result" ]
then
break
fi
sleep 1
done
if [ $i -eq 0 ]
then
echo "slapd did not start correctly"
exit 1
fi

# Generate hash of password
OPENLDAP_ROOT_PASSWORD_HASH=$(slappasswd -s "${OPENLDAP_ROOT_PASSWORD}")

# Update configuration with root password, root DN, and root suffix
sed -e "s OPENLDAP_ROOT_PASSWORD ${OPENLDAP_ROOT_PASSWORD_HASH} g" \
-e "s OPENLDAP_ROOT_DN ${OPENLDAP_ROOT_DN_PREFIX} g" \
-e "s OPENLDAP_SUFFIX ${OPENLDAP_ROOT_DN_SUFFIX} g" /usr/local/etc/openldap/first_config.ldif |
ldapmodify -Y EXTERNAL -H ldapi:/// -d $OPENLDAP_DEBUG_LEVEL

# add test schema
ldapadd -Y EXTERNAL -H ldapi:/// -f /usr/local/etc/openldap/testPerson.ldif -d $OPENLDAP_DEBUG_LEVEL

# add useful schemas
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif -d $OPENLDAP_DEBUG_LEVEL
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif -d $OPENLDAP_DEBUG_LEVEL

# load memberOf and refint modules
ldapadd -Y EXTERNAL -H ldapi:/// -f /usr/local/etc/openldap/load_modules.ldif -d $OPENLDAP_DEBUG_LEVEL

# configure memberOf module
ldapadd -Y EXTERNAL -H ldapi:/// -f /usr/local/etc/openldap/configure_memberof.ldif -d $OPENLDAP_DEBUG_LEVEL

# configure refint module
ldapadd -Y EXTERNAL -H ldapi:/// -f /usr/local/etc/openldap/configure_refint.ldif -d $OPENLDAP_DEBUG_LEVEL

# extract dc name from root DN suffix
dc_name=$(echo "${OPENLDAP_ROOT_DN_SUFFIX}" | grep -Po "(?<=^dc\=)[\w\d]+")
# create base organization object
sed -e "s OPENLDAP_SUFFIX ${OPENLDAP_ROOT_DN_SUFFIX} g" \
-e "s FIRST_PART ${dc_name} g" \
usr/local/etc/openldap/base.ldif |
ldapadd -x -D "$OPENLDAP_ROOT_DN_PREFIX,$OPENLDAP_ROOT_DN_SUFFIX" -w "$OPENLDAP_ROOT_PASSWORD"

# stop the daemon
pid=$(ps -A | grep slapd | awk '{print $1}')
kill -2 $pid || echo $?

# ensure the daemon stopped
for ((i=30; i>0; i--))
do
exists=$(ps -A | grep $pid)
if [ -z "${exists}" ]
then
break
fi
sleep 1
done
if [ $i -eq 0 ]
then
echo "slapd did not stop correctly"
exit 1
fi
else
# We are not root, we need to populate from the default bind-mount source
if [ -f /opt/openshift/config/slapd.d/cn\=config/olcDatabase\=\{0\}config.ldif ]
then
# Use provided default config, get rid of current data
rm -rf /var/lib/ldap/*
rm -rf /etc/openldap/*
# Bring in associated default database files
mv -f /opt/openshift/lib/* /var/lib/ldap
mv -f /opt/openshift/config/* /etc/openldap
else
# Something has gone wrong with our image build
echo "FAILURE: Default configuration files from /contrib/ are not present in the image at /opt/openshift."
exit 1
fi
fi

# Test configuration files, log checksum errors. Errors may be tolerated and repaired by slapd so don't exit
LOG=`slaptest 2>&1`
CHECKSUM_ERR=$(echo "${LOG}" | grep -Po "(?<=ldif_read_file: checksum error on \").+(?=\")")
for err in $CHECKSUM_ERR
do
echo "The file ${err} has a checksum error. Ensure that this file is not edited manually, or re-calculate the checksum."
done

rm -rf /opt/openshift/*

touch /etc/openldap/CONFIGURED
fi

# Start the slapd service
exec slapd -h "ldap:/// ldaps:///" -d $OPENLDAP_DEBUG_LEVEL

说明,本来我是准备按照之前部署经验自己写一个镜像构建,但是写到一半的时候,发现整个逻辑与openshift官方提供的差不多,所以就直接用官方的了。
从脚本中可以看到管理员(一般为cn=Manager)密码数据库管理员(一般为cn=config)密码是一样的,都是通过环境变量OPENLDAP_ROOT_PASSWORD配置。

变量名 说明 默认值
OPENLDAP_ROOT_PASSWORD OpenLDAP olcRootPW 密码 admin
OPENLDAP_ROOT_DN_SUFFIX OpenLDAP olcSuffix 域前缀 dc=example,dc=com
OPENLDAP_ROOT_DN_PREFIX OpenLDAP olcRootDN 前缀 cn=Manager
OPENLDAP_DEBUG_LEVEL OpenLDAP服务日志级别 256

使用openshift/openldap进行构建镜像操作

1
2
3
$ git clone https://github.com/openshift/openldap.git
$ cd openldap
$ export SKIP_SQUASH=1 && make build #构建出的镜像名为:openshift/openldap-2441-centos7:latest

部署Openldap

两种方法实现部署:
第一种. 使用openshift的client工具部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ #创建项目
$ oc new-project openldap --display-name=OpenLDAP
$ #创建单独的serviceaccount为方便以root用户启动pod
$ oc create serviceaccount openldap
$ #为openldap serviceaccount赋予以root启动pod的权限
$ oc adm policy add-scc-to-user anyuid -z openldap
$ #创建secret,设置openldap的域与密码
$ oc create secret generic openldap --from-literal=OPENLDAP_ROOT_PASSWORD=admin --from-literal=OPENLDAP_ROOT_DN_SUFFIX=dc=fcloudy,dc=com
$ # 部署应用(默认会是以default serviceaccount运行)
$ oc new-app --docker-image=xhuaustc/openldap-2441-centos7 --name=openldap
$ #为应用设置环境变量,即为openldap的域与密码
$ oc env --from=secret/openldap dc/openldap
$ #为应用设置以openldap serviceaccount启动
$ cat << EOF | oc apply -f -
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
name: openldap
spec:
template:
spec:
serviceAccount: openldap
EOF

当然以上配置没有添加健康检查,以及持久化是使用的emptyDir。这个可以后序自己补充。

第二种:使用yaml配置文件部署,主要是DeploymentConfig的配置。添加了健康检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
$ cat << EOF | oc create -f -
apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
labels:
app: openldap
name: openldap
spec:
replicas: 1
selector:
app: openldap
deploymentconfig: openldap
template:
metadata:
labels:
app: openldap
deploymentconfig: openldap
spec:
containers:
- env:
- name: OPENLDAP_ROOT_DN_SUFFIX
valueFrom:
secretKeyRef:
key: OPENLDAP_ROOT_DN_SUFFIX
name: openldap
- name: OPENLDAP_ROOT_PASSWORD
valueFrom:
secretKeyRef:
key: OPENLDAP_ROOT_PASSWORD
name: openldap
image: 'xhuaustc/openldap-2441-centos7:latest'
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 3
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 389
timeoutSeconds: 1
name: openldap
ports:
- containerPort: 389
protocol: TCP
- containerPort: 636
protocol: TCP
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 3
periodSeconds: 10
successThreshold: 1
tcpSocket:
port: 389
timeoutSeconds: 1
name: openldap
ports:
- containerPort: 389
protocol: TCP
- containerPort: 636
protocol: TCP
volumeMounts:
- mountPath: /etc/openldap
name: openldap-volume-1
- mountPath: /var/lib/ldap
name: openldap-volume-2
volumes:
- emptyDir: {}
name: openldap-volume-1
- emptyDir: {}
name: openldap-volume-2
triggers:
- type: ConfigChange

测试验证

按照以上部署的配置,管理员账号为:cn=Manager,dc=fcloudy,dc=com,密码为:admin
使用LDAPBrowser连接

连接设置

连接成功

最后一步,做成模板

将资源导出为模板文件

1
$ oc export dc,svc,secret  --as-template=openldap > openldap-template.yaml

在此基础上手动编辑,最后得到可用的模板文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
apiVersion: template.openshift.io/v1
kind: Template
message: |-
OpenLDAP服务将会根据指定的参数创建
metadata:
annotations:
description: |-
OpenLDAP服务将会根据指定的参数创建
name: openldap
objects:
- apiVersion: apps.openshift.io/v1
kind: DeploymentConfig
metadata:
labels:
app: openldap
name: openldap
spec:
replicas: 1
selector:
app: openldap
deploymentconfig: openldap
strategy:
type: Rolling
template:
metadata:
labels:
app: openldap
deploymentconfig: openldap
spec:
containers:
- env:
- name: OPENLDAP_ROOT_DN_SUFFIX
valueFrom:
secretKeyRef:
key: OPENLDAP_ROOT_DN_SUFFIX
name: openldap
- name: OPENLDAP_ROOT_PASSWORD
valueFrom:
secretKeyRef:
key: OPENLDAP_ROOT_PASSWORD
name: openldap
- name: OPENLDAP_ROOT_DN_PREFIX
valueFrom:
secretKeyRef:
key: OPENLDAP_ROOT_DN_PREFIX
name: openldap
- name: OPENLDAP_DEBUG_LEVEL
valueFrom:
secretKeyRef:
key: OPENLDAP_DEBUG_LEVEL
name: openldap
image: xhuaustc/openldap-2441-centos7:latest
imagePullPolicy: IfNotPresent
name: openldap
ports:
- containerPort: 389
protocol: TCP
- containerPort: 636
protocol: TCP
volumeMounts:
- mountPath: /etc/openldap
name: openldap-volume-1
- mountPath: /var/lib/ldap
name: openldap-volume-2
restartPolicy: Always
serviceAccount: openldap
serviceAccountName: openldap
volumes:
- emptyDir: {}
name: openldap-volume-1
- emptyDir: {}
name: openldap-volume-2
triggers:
- type: ConfigChange
- apiVersion: v1
kind: Service
metadata:
labels:
app: openldap
name: openldap
spec:
ports:
- name: 389-tcp
port: 389
protocol: TCP
targetPort: 389
- name: 636-tcp
port: 636
protocol: TCP
targetPort: 636
selector:
app: openldap
deploymentconfig: openldap
sessionAffinity: None
type: ClusterIP
- apiVersion: v1
stringData:
OPENLDAP_ROOT_DN_SUFFIX: ${OPENLDAP_ROOT_DN_SUFFIX}
OPENLDAP_ROOT_DN_PREFIX: ${OPENLDAP_ROOT_DN_PREFIX}
OPENLDAP_ROOT_PASSWORD: ${OPENLDAP_ROOT_PASSWORD}
OPENLDAP_DEBUG_LEVEL: ${OPENLDAP_DEBUG_LEVEL}
kind: Secret
metadata:
name: openldap
type: Opaque
parameters:
- description: Openldap Root DN Suffix
displayName: Openldap Root DN Suffix
name: OPENLDAP_ROOT_DN_SUFFIX
value: dc=example,dc=com
- description: Openldap Root DN Manager Prefix
displayName: Openldap Root DN Manager Prefix
name: OPENLDAP_ROOT_DN_PREFIX
value: cn=Manager
- description: Openldap Root Password
displayName: Openldap Root Password
name: OPENLDAP_ROOT_PASSWORD
from: '[a-zA-Z0-9]{16}'
generate: expression
- description: Openldap Debug Level
displayName: Openldap Debug Level
name: OPENLDAP_DEBUG_LEVEL
value: "256"

在Openshift上将模板导入,完成后,创建Openldap就非常简单了,看截图。

Openshift模板创建OpenLDAP

ps:OpenLDAP的整个构建及部署过程可以作为Openshift的一种类型案例。当然该案例中没有使用PV、PVC做持久化。相信对Openshift有所了解的,在这个基础上做持久化应该不在话下。

千里之行,始于足下。完成OpenLDAP的部署,这只是一个开始,账号一统还有相当多的工作要去做。