一.背景
1.公司有LDAP做统计认证的需求,方式各个中间件重复来创建账号。
2.方便离职后统一管理账号
3.网上没有比较全的集成LDAP的文档
二.LDAP安装部署
1.安装LDAP
方法1:
1.安装 openldap server端
docker run -p 389:389 -p 636:636 --name openldap --detach osixia/openldap:1.4.0
2.安装phpldapadmin
docker run -p 6443:443 --name ldapadmin --link openldap:ldap --env PHPLDAPADMIN_LDAP_HOSTS=ldap --detach osixia/phpldapadmin:0.9.0
访问路径:https://192.168.3.208:6443
在浏览器输入 https://内网IP:6443 ,按下图所示步骤登录 phpLDAPadmin:
字段名称 字段值 字段描述
Login DN: cn=admin,dc=example,dc=org 默认管理员用户
Password : admin
管理员密码123456
3.安装-----自助忘记重置密码
1);docker-compose.yaml
version: '2'
services:
ssp-app:
image: registry.cn-hangzhou.aliyuncs.com/eryajf/self-service-password
container_name: ssp-app
volumes:
- ./data/:/www/ssp
- ./logs/:/www/logs
ports:
- 8888:80
environment:
- VIRTUAL_HOST=http://192.168.3.208
- VIRTUAL_NETWORK=nginx-proxy
- LETSENCRYPT_HOST=http://192.168.3.208
- LETSENCRYPT_EMAIL=[email protected]
- LDAP_SERVER=ldap://192.168.3.208:389
- LDAP_STARTTLS=false
- LDAP_BINDDN=cn=admin,dc=example,dc=org
- LDAP_BINDPASS=123456
- LDAP_BASE_SEARCH=dc=example,dc=org
- LDAP_LOGIN_ATTRIBUTE=cn #这里要注意,都是cn
- LDAP_FULLNAME_ATTRIBUTE=cn
方法2:
1.通过脚本一键启动服务端和管理端
cat start.sh
#!/bin/bash -e
SERVICE=ldap-service
HOST_NAME=ldap-server
LDAP_DOMAIN=example.org
LDAP_DC=example
LDAP_DC_ORG=org
NETWORK_ADAPTER=eth0
PASSWORD=123465
OPENLDAP="1.3.0"
PHPLDAPADMIN="0.9.0"
HTTPS_PORT=88
OPENLDAP_PORT=389
docker run \
-p ${OPENLDAP_PORT}:389 \
--name ${SERVICE} \
--hostname ${HOST_NAME} \
--env LDAP_ORGANISATION="WPT-Group" \
--env LDAP_DOMAIN=${LDAP_DOMAIN} \
--env LDAP_ADMIN_PASSWORD=${PASSWORD} \
--detach osixia/openldap:${OPENLDAP}
docker run \
-p ${HTTPS_PORT}:80 \
--name ${SERVICE}-admin \
--hostname ${HOST_NAME}-admin \
--link ${SERVICE}:${HOST_NAME} \
--env PHPLDAPADMIN_LDAP_HOSTS=${HOST_NAME} \
--env PHPLDAPADMIN_HTTPS=false \
--detach \
osixia/phpldapadmin:${PHPLDAPADMIN}
sleep 1
echo "-----------------------------------"
PHPLDAP_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" ${SERVICE})
docker exec ${SERVICE} ldapsearch -x -H ldap://${PHPLDAP_IP}:389 -b "dc=${LDAP_DC},dc=${LDAP_DC_ORG}" -D "cn=admin,dc=${LDAP_DC},dc=${LDAP_DC_ORG}" -w ${PASSWORD}
echo "-----------------------------------"
PUB_IP=$(ifconfig ${NETWORK_ADAPTER} |grep "inet"|awk '{print $2}')
echo "Go to: https://${PUB_IP}:${HTTPS_PORT}"
echo "Login DN: cn=admin,dc=${LDAP_DC},dc=${LDAP_DC_ORG}"
echo "Password: ${PASSWORD}"
这个脚本会创建一个ldap服务,并创建一个admin用户,启动之后,访问 10.3.0.42:88,输入用户名密码。
2.创建两个基本组织
ldap本质上就是轻量目录协议,那么接下来创建的东西也都可以按目录层级的概念来理解,现在需要先创建两个最外层目录,一个作为人员的所有代理目录,一个作为分组的目录,创建方式如下:
注意需要进入到ldap-server的容器内部执行如下命令:
cat << EOF | ldapadd -x -D "cn=admin,dc=example,dc=org" -w 123456
dn: ou=,dc=example,dc=org
objectClass: organizationalUnit
ou:
dn: ou=zabbix,dc=example,dc=org
objectClass: organizationalUnit
ou: zabbix
EOF
cat << EOF | ldapadd -x -D "cn=admin,dc=example,dc=org" -w 123456
dn: ou=it,dc=example,dc=org
objectClass: organizationalUnit
ou: it
EOF
如果没有报错,则说明创建成功了,这个时候可以去看管理页面上的情况。
3.创建用户
有一些操作是创建一些模拟用户,比较不给力,这里直接模拟真实,创建三个用户,操作如下。
cat << EOF | ldapadd -x -D cn=admin,dc=example,dc=org -w 123456
dn: uid=liqilong,ou=zabbix,dc=example,dc=org
uid: liqilong
cn: liqilong
sn: liqilong
displayName: liqilong
objectClass: posixAccount
objectClass: top
objectClass: person
objectClass: shadowAccount
objectClass: inetOrgPerson
gecos: System Manager
loginShell: /bin/bash
homeDirectory: /home/liqilong
userPassword: liqilong
uidNumber: 1000
gidNumber: 1009
mobile: 15638888888
mail: [email protected]
postalAddress: Hangzhou
EOF
cat << EOF | ldapadd -x -D cn=admin,dc=example,dc=org -w 123456
dn: uid=zhangsan,ou=zabbix,dc=example,dc=org
uid: zhangsan
cn: zhangsan
sn: zhangsan
displayName: zhangsan
objectClass: posixAccount
objectClass: top
objectClass: person
objectClass: shadowAccount
objectClass: inetOrgPerson
gecos: System Manager
loginShell: /bin/bash
homeDirectory: /home/zhangsan
userPassword: zhangsan
uidNumber: 1000
gidNumber: 1009
mobile: 15638888888
mail: [email protected]
postalAddress: Hangzhou
EOF
cat << EOF | ldapadd -x -D cn=admin,dc=example,dc=org -w 123456
dn: uid=zhangsan,ou=,dc=example,dc=org
uid: zhangsan
cn: zhangsan
sn: zhangsan
displayName: zhangsan
objectClass: posixAccount
objectClass: top
objectClass: person
objectClass: shadowAccount
objectClass: inetOrgPerson
gecos: System Manager
loginShell: /bin/bash
homeDirectory: /home/zhangsan
userPassword: zhangsan
uidNumber: 1000
gidNumber: 1009
mobile: 15638888888
mail: [email protected]
postalAddress: Hangzhou
EOF
4.创建组
组的概念帮助我们大大减轻很多人员权限配置的工作量,它是与用户平行的目录等级,至于创建什么样的组,以哪个维度进行划分,都是可以的,只要实际需求合理,都是可以的。
这里就以常见配置环境中的分组维度,分如下几个组zentao,harbor,kibana:
cat << EOF | ldapadd -x -D cn=admin,dc=example,dc=org -w 123456
dn: cn=zentao,ou=it,dc=example,dc=org
cn: zentao
gidNumber: 66
objectClass: top
objectClass: posixGroup
dn: cn=harbor,ou=it,dc=example,dc=org
cn: harbor
gidNumber: 66
objectClass: top
objectClass: posixGroup
dn: cn=kibana,ou=it,dc=example,dc=org
cn: kibana
gidNumber: 66
objectClass: top
objectClass: posixGroup
EOF
adding new entry "cn=zentao,ou=it,dc=example,dc=org"
adding new entry "cn=harbor,ou=it,dc=example,dc=org"
adding new entry "cn=kibana,ou=it,dc=example,dc=org"
#这样就会在it组织中,新建出组zentao,harbor,kibana。
5.现在就来对这些用户进行分组,我称之为各就各位。
通过如下方式可以将一个用户加入到某个组内:
cat << EOF | ldapmodify -x -D cn=admin,dc=example,dc=org -w 123456
dn: cn=harbor,ou=it,dc=example,dc=org
changetype: modify
add: memberuid
memberuid: wangjiabing
dn: cn=zentao,ou=it,dc=example,dc=org
changetype: modify
add: memberuid
memberuid: jinmeng
EOF
modifying entry "cn=harbor,ou=it,dc=example,dc=org"
modifying entry "cn=zentao,ou=it,dc=example,dc=org"
#如上意思表示将 liqilong和 zhaosi加入到ops这个组,操作之后现在可以看下web页面:
三.集成LDAP
1.Confluence
2.Frostmourne(部署在k8s中)
jenkins@ip-10-0-3-224:~$ kubectl get pod frostmourne-5d9bd9b647-wh8cw -n ops -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubernetes.io/psp: eks.privileged
creationTimestamp: "2022-12-18T10:56:39Z"
generateName: frostmourne-5d9bd9b647-
labels:
app: frostmourne
pod-template-hash: 5d9bd9b647
version: v1
name: frostmourne-5d9bd9b647-wh8cw
namespace: ops
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frostmourne-5d9bd9b647
uid: 85343508-6652-47fa-a1be-a109085f5cf2
resourceVersion: "172533336"
uid: 05448d75-f21d-4358-9db4-93606ad98119
spec:
containers:
- command:
- java
- -jar
- app.jar
env:
- name: datasource_frostmourne_url
value: jdbc:mysql://mysql8.ops.abc.com:3306/frostmourne?useSSL=false&verifyServerCertificate=false&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
- name: datasource_frostmourne_username
value: frostmourne
- name: datasource_frostmourne_password
value: abc123
- name: frostmourne_message_title
value: abc监控平台
- name: alarmlog_reserve_days
value: "14"
- name: frostmourne_monitor_address
value: http://frostmourne.abc.com
- name: initial_password
**- name: ldap_enabled
value: "false"
- name: spring_ldap_urls
value: ldap://192.168.3.238:389
- name: spring_ldap_username
value: cn=auth,dc=yintatech,dc=com
- name: spring_ldap_password
value: xxxxx
- name: spring_ldap_base
value: dc=yintatech,dc=com
- name: spring_ldap_auth_searchFilter
value: (&(|(memberOf=cn=it,dc=yintatech,dc=com))(&(objectClass=person)(cn=%u)))**
- name: email.sender
- name: email.sender-password
- name: email.smtp-auth
value: "true"
- name: email.smtp-host
- name: email.smtp-port
- name: wechat.corpid
- name: wechat.agentid
- name: wechat.secret
image: xxxxxxx.dkr.ecr.ap-east-1.amazonaws.com/frostmourne:0.9-1
imagePullPolicy: IfNotPresent
name: frostmourne
ports:
- containerPort: 10054
name: api
protocol: TCP
resources:
limits:
cpu: "4"
memory: 8Gi
requests:
cpu: 10m
memory: 20Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-knpxd
readOnly: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
imagePullSecrets:
- name: ytdocker
nodeName: ip-10-0-142-89.ap-east-1.compute.internal
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 5
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: kube-api-access-knpxd
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
3.Gitlab
docker run --detach \
--hostname gitlab.example.com \
--publish 443:443 --publish 81:80 --publish 22:22 \
--name gitlab \
--restart always \
--volume $GITLAB_HOME/config:/etc/gitlab \
--volume $GITLAB_HOME/logs:/var/log/gitlab \
--volume $GITLAB_HOME/data:/var/opt/gitlab \
--shm-size 256m \
registry.gitlab.cn/omnibus/gitlab-jh:latest
修改gilab.rb:
gitlab_rails['ldap_enabled'] = true
###! **remember to close this block with 'EOS' below**
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
main: # 'main' is the GitLab 'provider ID' of this LDAP server
label: 'LDAP'
host: '192.168.3.208'
port: 389
uid: 'uid' #这里注意是cn 还是uid 登录名会不一样。
bind_dn: 'cn=admin,dc=example,dc=org'
password: 'admin'
encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
verify_certificates: true
smartcard_auth: false
active_directory: true
allow_username_or_email_login: false
lowercase_usernames: false
block_auto_created_users: false
base: 'dc=example,dc=org'
user_filter: ''
EOS
gitlab-ctl stop
gitlab-ctl reconfigure
gitlab-ctl start
或者docker restart gitlab
参考:
https://docs.gitlab.cn/jh/install/docker.html#%E4%BD%BF%E7%94%A8-docker-engine-%E5%AE%89%E8%A3%85%E6%9E%81%E7%8B%90gitlab
https://www.cnblogs.com/yangxiaoni/p/15686417.html
https://blog.csdn.net/chenyu19891124/article/details/115699268
5.Jenkins
必须安装的插件:ldap Role-based Authorization Strategy
7.Kibana
1.用apisix做权限控制
nginx---->apisix--->ldap---->kibana
nginx配置映射到apisix后端的配置:
upstream kibana_server {
#server 10.0.149.145:5601 weight=1 max_fails=3 fail_timeout=60;
server 10.0.139.96:5601 weight=1 max_fails=3 fail_timeout=60;
}
server {
listen 80;
server_name kibana.aws.yintaerp.com;
location / {
proxy_pass http://10.0.3.224:9080; #这是apisix的端口号。
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
apisix 启动ldap-auth插件:
{
"base_dn": "cn=it,dc=yintatech,dc=com",
"disable": false,
"ldap_uri": "ldap.yintaerp.com:389",
"uid": "cn",
"use_tls": false
}
apisix 设置上游服务:目标节点
192.168.3.208:5601
2.nginx 直接集成做总控制
NGINX基于ldap的认证需要 nginx-auth-ldap模块儿,可以在原有已经在用的NGINX中,添加进去,或者直接全新的NGINX进行配置。
1):nginx全局认证
cd /opt && git clone https://github.com/nginxinc/nginx-ldap-auth
tar xf nginx-1.14.0.tar.gz
yum -y install zlib zlib-devel openssl openssl-devel pcre pcre-devel libxslt-devel
./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-http_realip_module --add-module=/opt/nginx-auth-ldap
make && make install
cat /usr/local/nginx/conf/nginx.conf
ldap_server test {
url ldap://10.3.0.42:389/DC=example,DC=org?cn?sub?(objectClass=person);
binddn "cn=admin,dc=example,dc=org";
binddn_passwd 123465;
require valid_user;
}
或者
ldap_server test_ldap1 {
url "ldap://10.3.0.42:389/DC=example,DC=org?uid?sub?(&(objectClass=organizationalPerson))";
binddn "cn=admin,dc=example,dc=org";
binddn_passwd "123456";
require valid_user;
#group_attribute People;
#group_attribute_is_dn on;
#require group "cn=jenkins,ou=Group,dc=eryajf,dc=net";
}
2):基于特定组的认证
ldap_server test_ldap1 {
url "ldap://10.3.0.42:389/DC=example,DC=org?uid?sub?(&(objectClass=organizationalPerson))";
binddn "admin,dc=example,dc=org";
binddn_passwd "123456";
group_attribute member;
group_attribute_is_dn on;
require group "cn=jenkins,ou=Group,dc=example,dc=org";
}
server {
listen 80;
server_name localhost;
location / {
auth_ldap "Forbidden";
auth_ldap_servers test_ldap1;
root /usr/share/nginx/html;
}
}
这样就把权限控制在 jenkins这个组内了,其他人访问的时候,是被拒绝的。openrestry 增加ldap支持:https://wiki.eryajf.net/pages/5019.html
9.Rundeck
#admin组
description: Admin, all access.
context:
project: '.*' # all projects
for:
resource:
- allow: '*' # allow read/create all kinds
adhoc:
- allow: '*' # allow read/running/killing adhoc jobs
job:
- allow: '*' # allow read/write/delete/run/kill of all jobs
node:
- allow: '*' # allow read/run for all nodes
by:
group: admin
---
description: Admin, all access.
context:
application: 'rundeck'
for:
resource:
- allow: '*' # allow create of projects
project:
- allow: '*' # allow view/admin of all projects
project_acl:
- allow: '*' # allow admin of all project-level ACL policies
storage:
- allow: '*' # allow read/create/update/delete for all /keys/* storage content
by:
group: admin
#php组
description: Admin, all access.
context:
project: 'uat-php' # all projects
for:
resource:
- allow: ['read'] # allow read/create all kinds
adhoc:
- allow: ['read', 'killing'] # allow read/running/killing adhoc jobs
job:
- allow: ['read','run','kill'] # allow read/write/delete/run/kill of all jobs
node:
- allow: ['read', 'run'] # allow read/run for all nodes
by:
group: phpdev
---
description: Admin, all access.
context:
application: 'rundeck'
for:
resource:
- allow: ['read'] # allow create of projects
project:
- allow: ['read'] # allow view/admin of all projects
project_acl:
- allow: ['read'] # allow admin of all project-level ACL policies
storage:
- allow: ['read'] # allow read/create/update/delete for all /keys/* storage content
by:
group: phpdev
#各组长权限
description: Admin, all access.
context:
project: '.*' # all projects
for:
resource:
- allow: ['read'] # allow read/create all kinds
adhoc:
- allow: ['read', 'killing'] # allow read/running/killing adhoc jobs
job:
- allow: ['read','run','kill'] # allow read/write/delete/run/kill of all jobs
node:
- allow: ['read', 'run'] # allow read/run for all nodes
by:
group: ytdev
---
description: Admin, all access.
context:
application: 'rundeck'
for:
resource:
- allow: ['read'] # allow create of projects
project:
- allow: ['read'] # allow view/admin of all projects
project_acl:
- allow: ['read'] # allow admin of all project-level ACL policies
storage:
- allow: ['read'] # allow read/create/update/delete for all /keys/* storage content
by:
group: ytdev
11.YAPI接口平台
{
"port": "3000",
"closeRegister":true,
"adminAccount": "[email protected]",
"db": {
"servername": "127.0.0.1",
"DATABASE": "yinta-yapi",
"port": "27017"
},
"ldapLogin": {
"enable": true,
"server": "ldap://ldap.abc.com:389/",
"baseDn": "cn=auth,dc=abc,dc=com",
"bindPassword": "abc123",
"searchDn": "CN=it,DC=yintatech,DC=com",
"searchStandard": "mail",
"emailPostfix": "",
"emailKey": "",
"usernameKey": ""
},
"mail": {
"enable": false,
"host": "smtp.163.com",
"port": 465,
"from": "***@163.com",
"auth": {
"user": "***@163.com",
"pass": "*****"
}
}
}
12.夜莺监控系统
Enable = true
Host = 'ldap.abc.com'
Port = 389
BaseDn = 'CN=it,DC=abc,DC=com'
BindUser = 'CN=auth,DC=abc,DC=com'
BindPass = '123456'
# openldap format e.g. (&(uid=%s))
# AD format e.g. (&(sAMAccountName=%s))
AuthFilter = '(&(mail=%s))'
CoverAttributes = false
TLS = false
StartTLS = false
DefaultRoles = ['Standard']
[Attributes]
Nickname = 'cn'
Phone = 'mobile'
Email = 'mail'
四.总结
1.LDAP集成是一个很好用的单点登录工具,运维不需要进行二次开发即可使用,节约工资人力成本。
2.避免运维重复创建账号和权限管控问题。