快速搭建OpenLDAP环境并对接Rancher认证

简介

如果企业内部有使用LDAP进行用户身份验证,则可以通过配置Rancher与OpenLDAP服务器通信以对用户进行身份验证。

本文将介绍如何通过docker快速搭建OpenLDAP环境,并对接Rancher认证功能

主要用到两个镜像:

  • osixia/openldap:1.5.0:LDAP服务端
  • osixia/phpldapadmin:0.9.0:LDAP web管理工具

步骤

安装OpenLDAP服务

  1. 基于osixia/openldap:1.5.0镜像,创建OpenLDAP服务

    1
    docker run -p 389:389 -p 636:636 --name openldap -itd --env LDAP_ORGANISATION="rancher" --env LDAP_DOMAIN="rancherldap.com" --env LDAP_ADMIN_PASSWORD="Rancher123"   osixia/openldap:1.5.0

    参数说明:

    缺省ldap使用389端口,加密使用636端口

    LDAP_ORGANISATION:Organisation名称,默认是Example Inc.

    LDAP_DOMAIN:LDAP domain,例如默认是example.org,则domain为dc=example,dc=org

    LDAP_ADMIN_PASSWORD:admin用户密码

  1. 创建osixia/phpldapadmin:0.9.0镜像,创建Web服务

    phpldapadmin是一个基于Web的管理LDAP的工具,可以更加直观的查看和管理LDAP信息

    1
    docker run -p 6443:443 --env PHPLDAPADMIN_LDAP_HOSTS=172.16.21.12 -itd --name phpldapadmin osixia/phpldapadmin:0.9.0

    参数说明:

    PHPLDAPADMIN_LDAP_HOSTS:LDAP服务地址,这里如果是将openLDAP容器启动在相同主机上则填写本机的IP地址即可

  2. docker-compose(可选)

    也可以通过docker-compose去创建OpenLDAP环境

    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
    version: '2.3'
    services:
    openldap:
    image: osixia/openldap:1.5.0
    container_name: openldap
    restart: always
    environment:
    - LDAP_ORGANISATION=rancher
    - LDAP_DOMAIN=rancherldap.com
    - LDAP_ADMIN_PASSWORD=Rancher123
    ports:
    - 389:389
    - 636:636
    volumes:
    - ./slapd:/etc/ldap/slapd.d
    - ./data:/var/lib/ldap
    phpldapadmin:
    image: osixia/phpldapadmin:0.9.0
    container_name: phpldapadmin
    restart: always
    environment:
    - PHPLDAPADMIN_LDAP_HOSTS=openldap
    links:
    - openldap:openldap
    depends_on:
    - openldap
    ports:
    - 6443:443
    volumes:
    - ./phpldapadmin-certs:/container/service/phpldapadmin/assets/apache2/certs

    将上诉文件保存到docker-compose.yml中,然后执行docker-compose up -d命令即可

    运行成功后,会在跟docker-compose.yml文件相同的目录下创建三个目录slapddataphpldapadmin-certs

    默认admin domain账号为:cn=admin,dc=rancherldap,dc=com,密码为:Rancher123

  3. 进入openldap容器中,执行ldapsearch命令尝试搜索

    1
    docker exec openldap ldapsearch -x -H ldap://localhost -b dc=rancherldap,dc=com -D "cn=admin,dc=rancherldap,dc=com" -w Rancher123

    可以得到如下输出结果,则说明部署成功

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    # extended LDIF
    #
    # LDAPv3
    # base <dc=rancherldap,dc=com> with scope subtree
    # filter: (objectclass=*)
    # requesting: ALL
    #

    # rancherldap.com
    dn: dc=rancherldap,dc=com
    objectClass: top
    objectClass: dcObject
    objectClass: organization
    o: rancher
    dc: rancherldap

    # search result
    search: 2
    result: 0 Success

    # numResponses: 2
    # numEntries: 1

基于phpldapadmin的web工具创建用户

浏览器访问:https://<IP>:6443,点击左侧login登录

login-1

其中账号密码如下:

1
2
cn=admin,dc=rancherldap,dc=com
Rancher123

login-2

登录进去后,可以看到domain相关信息

创建Organisational Unit

点击dc=rancherldap,dc=com,在其目录下点击Create a child entry创建子条目

ou-1

点击 Generic: Organisational Unit

ou-2

填写OU名称,例如这里填写rancher,填好之后点击Create Object创建该对象

ou-3

点击Commit二次确认

ou-4

创建成功后,就可以在左侧中看到我们创建的OU对象

ou-5

创建Group

ou=rancher下,点击Create a child entry创建子条目,点击 Generic: Posix Group创建Group对象

image-20210429155116459

填写Group名称,例如这里填写group

group-2

填好之后点击Create Object创建该对象,点击Commit二次确认,创建成功后,就可以在左侧中看到我们创建的Group对象

group-3

创建User

cn=group下,点击Create a child entry创建子条目,点击 Generic: User Account创建User对象

user-1

填写对应的user信息,填写First name和Last name,会自动生成Common Name和User ID,其中UserID为后续Rancher登录的用户名

填写Password,后续登录Rancher使用该密码

选择刚刚创建的group

user-2

填好之后点击Create Object创建该对象,点击Commit二次确认,创建成功后,就可以在左侧中看到我们创建的USer对象

user-3

同理,我们用相同的方法再创建一个test用户

user-4

对接Rancher认证

对接OpenLDAP

在Rancher UI中,点击 全局-安全-认证,选择OpenLDAP

rancher-1

参数说明:

主机名或 IP 地址:OpenLDAP服务器的IP地址

端口:默认端口是389

服务帐户专有名称cn=admin,dc=rancherldap,dc=com,这里填写admin用户的domain

服务账号密码:admin用户的密码

用户搜索起点:例如刚刚创建的OU为rancher,则这里的搜索起点为ou=rancher,dc=rancherldap,dc=com

用户名:这个用户会成为管理员,用户名需要基于User Name填写,例如我们刚刚创建的adminuser,则这里填写auser

密码:该用户的密码

参数填写完之后,点击启用OpenLDAP认证,开启OpenLDAP认证

rancher-2

测试LDAP用户登录

rancher-3

登录成功,默认该用户没有权限

rancher-4

OpenLDAP启用TLS

上述情况下,对接LDAP使用389端口,我们可以使用此端口进行LDAP连接。 但是该端口是非安全和未加密的连接,容易造成安全问题,暴露用户相关信息,一般建议是389仅用在内网或者测试环境。

针对这个情况,我们可以使用LDAP的另一个tls加密端口:636端口,来对接LDAP。

创建自签名证书

docker-compose.yml同级目录下,新建一个目录,命名为certs

1
2
mkdir certs
cd certs

新建一个文件create-cert.sh,复制如下脚本至该文件中

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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/bash -e

help ()
{
echo ' ================================================================ '
echo ' --ssl-domain: 生成ssl证书需要的主域名,如不指定则默认为www.rancher.local,如果是ip访问服务,则可忽略;'
echo ' --ssl-trusted-ip: 一般ssl证书只信任域名的访问请求,有时候需要使用ip去访问server,那么需要给ssl证书添加扩展IP,多个IP用逗号隔开;'
echo ' --ssl-trusted-domain: 如果想多个域名访问,则添加扩展域名(SSL_TRUSTED_DOMAIN),多个扩展域名用逗号隔开;'
echo ' --ssl-size: ssl加密位数,默认2048;'
echo ' --ssl-cn: 国家代码(2个字母的代号),默认CN;'
echo ' 使用示例:'
echo ' ./create_self-signed-cert.sh --ssl-domain=www.test.com --ssl-trusted-domain=www.test2.com \ '
echo ' --ssl-trusted-ip=1.1.1.1,2.2.2.2,3.3.3.3 --ssl-size=2048 --ssl-date=3650'
echo ' ================================================================'
}

case "$1" in
-h|--help) help; exit;;
esac

if [[ $1 == '' ]];then
help;
exit;
fi

CMDOPTS="$*"
for OPTS in $CMDOPTS;
do
key=$(echo ${OPTS} | awk -F"=" '{print $1}' )
value=$(echo ${OPTS} | awk -F"=" '{print $2}' )
case "$key" in
--ssl-domain) SSL_DOMAIN=$value ;;
--ssl-trusted-ip) SSL_TRUSTED_IP=$value ;;
--ssl-trusted-domain) SSL_TRUSTED_DOMAIN=$value ;;
--ssl-size) SSL_SIZE=$value ;;
--ssl-date) SSL_DATE=$value ;;
--ca-date) CA_DATE=$value ;;
--ssl-cn) CN=$value ;;
esac
done

# CA相关配置
CA_DATE=${CA_DATE:-3650}
CA_KEY=${CA_KEY:-cakey.pem}
CA_CERT=${CA_CERT:-cacerts.pem}
CA_DOMAIN=cattle-ca

# ssl相关配置
SSL_CONFIG=${SSL_CONFIG:-$PWD/openssl.cnf}
SSL_DOMAIN=${SSL_DOMAIN:-'www.rancher.local'}
SSL_DATE=${SSL_DATE:-3650}
SSL_SIZE=${SSL_SIZE:-2048}

## 国家代码(2个字母的代号),默认CN;
CN=${CN:-CN}

SSL_KEY=$SSL_DOMAIN.key
SSL_CSR=$SSL_DOMAIN.csr
SSL_CERT=$SSL_DOMAIN.crt

echo -e "\033[32m ---------------------------- \033[0m"
echo -e "\033[32m | 生成 SSL Cert | \033[0m"
echo -e "\033[32m ---------------------------- \033[0m"

if [[ -e ./${CA_KEY} ]]; then
echo -e "\033[32m ====> 1. 发现已存在CA私钥,备份"${CA_KEY}"为"${CA_KEY}"-bak,然后重新创建 \033[0m"
mv ${CA_KEY} "${CA_KEY}"-bak
openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
else
echo -e "\033[32m ====> 1. 生成新的CA私钥 ${CA_KEY} \033[0m"
openssl genrsa -out ${CA_KEY} ${SSL_SIZE}
fi

if [[ -e ./${CA_CERT} ]]; then
echo -e "\033[32m ====> 2. 发现已存在CA证书,先备份"${CA_CERT}"为"${CA_CERT}"-bak,然后重新创建 \033[0m"
mv ${CA_CERT} "${CA_CERT}"-bak
openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
else
echo -e "\033[32m ====> 2. 生成新的CA证书 ${CA_CERT} \033[0m"
openssl req -x509 -sha256 -new -nodes -key ${CA_KEY} -days ${CA_DATE} -out ${CA_CERT} -subj "/C=${CN}/CN=${CA_DOMAIN}"
fi

echo -e "\033[32m ====> 3. 生成Openssl配置文件 ${SSL_CONFIG} \033[0m"
cat > ${SSL_CONFIG} <<EOM
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
EOM

if [[ -n ${SSL_TRUSTED_IP} || -n ${SSL_TRUSTED_DOMAIN} || -n ${SSL_DOMAIN} ]]; then
cat >> ${SSL_CONFIG} <<EOM
subjectAltName = @alt_names
[alt_names]
EOM
IFS=","
dns=(${SSL_TRUSTED_DOMAIN})
dns+=(${SSL_DOMAIN})
for i in "${!dns[@]}"; do
echo DNS.$((i+1)) = ${dns[$i]} >> ${SSL_CONFIG}
done

if [[ -n ${SSL_TRUSTED_IP} ]]; then
ip=(${SSL_TRUSTED_IP})
for i in "${!ip[@]}"; do
echo IP.$((i+1)) = ${ip[$i]} >> ${SSL_CONFIG}
done
fi
fi

echo -e "\033[32m ====> 4. 生成服务SSL KEY ${SSL_KEY} \033[0m"
openssl genrsa -out ${SSL_KEY} ${SSL_SIZE}

echo -e "\033[32m ====> 5. 生成服务SSL CSR ${SSL_CSR} \033[0m"
openssl req -sha256 -new -key ${SSL_KEY} -out ${SSL_CSR} -subj "/C=${CN}/CN=${SSL_DOMAIN}" -config ${SSL_CONFIG}

echo -e "\033[32m ====> 6. 生成服务SSL CERT ${SSL_CERT} \033[0m"
openssl x509 -sha256 -req -in ${SSL_CSR} -CA ${CA_CERT} \
-CAkey ${CA_KEY} -CAcreateserial -out ${SSL_CERT} \
-days ${SSL_DATE} -extensions v3_req \
-extfile ${SSL_CONFIG}

echo -e "\033[32m ====> 7. 证书制作完成 \033[0m"
echo
echo -e "\033[32m ====> 8. 以YAML格式输出结果 \033[0m"
echo "----------------------------------------------------------"
echo "ca_key: |"
cat $CA_KEY | sed 's/^/ /'
echo
echo "ca_cert: |"
cat $CA_CERT | sed 's/^/ /'
echo
echo "ssl_key: |"
cat $SSL_KEY | sed 's/^/ /'
echo
echo "ssl_csr: |"
cat $SSL_CSR | sed 's/^/ /'
echo
echo "ssl_cert: |"
cat $SSL_CERT | sed 's/^/ /'
echo

echo -e "\033[32m ====> 9. 附加CA证书到Cert文件 \033[0m"
cat ${CA_CERT} >> ${SSL_CERT}
echo "ssl_cert: |"
cat $SSL_CERT | sed 's/^/ /'
echo

echo -e "\033[32m ====> 10. 重命名服务证书 \033[0m"
echo "cp ${SSL_DOMAIN}.key tls.key"
cp ${SSL_DOMAIN}.key tls.key
echo "cp ${SSL_DOMAIN}.crt tls.crt"
cp ${SSL_DOMAIN}.crt tls.crt

使用示例如下,详细参数说明请参考Rancher一键生成自签名证书脚本

1
2
chmod +x create-cert.sh
./create-cert.sh --ssl-domain=ldap.zerchin.xyz --ssl-trusted-ip=172.16.21.12 --ssl-size=2048 --ssl-date=3650

LDAP 添加相关 TLS 配置参数

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
version: '2.3'
services:
openldap:
image: osixia/openldap:1.5.0
container_name: openldap
restart: always
environment:
- LDAP_ORGANISATION=rancher
- LDAP_DOMAIN=rancherldap.com
- LDAP_ADMIN_PASSWORD=Rancher123
- LDAP_TLS_CRT_FILENAME=tls.crt ## tls
- LDAP_TLS_KEY_FILENAME=tls.key ## tls
- LDAP_TLS_CA_CRT_FILENAME=cacerts.pem ## tls
- LDAP_TLS_VERIFY_CLIENT=try ## tls
ports:
- 389:389
- 636:636
volumes:
- ./slapd:/etc/ldap/slapd.d
- ./data:/var/lib/ldap
- ./certs:/container/service/slapd/assets/certs ## tls
phpldapadmin:
image: osixia/phpldapadmin:0.9.0
container_name: phpldapadmin
restart: always
environment:
- PHPLDAPADMIN_LDAP_HOSTS=openldap
links:
- openldap:openldap
depends_on:
- openldap
ports:
- 6443:443
volumes:
- ./phpldapadmin-certs:/container/service/phpldapadmin/assets/apache2/certs

参数说明:

LDAP_TLS_CRT_FILENAME:ldap证书文件名

LDAP_TLS_KEY_FILENAME:ldap证书key文件名

LDAP_TLS_CA_CRT_FILENAME:CA证书文件名

LDAP_TLS_VERIFY_CLIENT:默认是demand,会对传入的 TLS 会话中的客户端证书强制执行检查,在对接的过程中会报证书相关错误,这里设置为try,没有证书也可以正常会话保持。可参考此文档

然后重新运行docker-compose命令即可:

1
2
docker-compose down -v
docker-compose up -d

Rancher对接TLS OpenLDAP

rancher-5

其中端口要改为636 tls端口,并将加密类型设置为TLS,其中CA证书去certs目录下查看cacerts.pem文件拷贝过来即可,对接成功如下:

rancher-6