ldap

2023-02-13 Views4896字20 min read

ldap

什么是ldap

        首先LDAP是一种通讯协议,LDAP支持TCP/IP。协议就是标准,并且是抽象的。在这套标准下,AD(Active Directory)是微软出的一套实现。
        那AD是什么呢?暂且把它理解成是个数据库。也有很多人直接把LDAP说成数据库(可以把LDAP理解成存储数据的数据库)。像是其他数据库一样,LDAP也是有client端和server端。server端是用来存放资源,client端用来操作增删改查等操作。
        而我们通常说的LDAP是指运行这个数据库的服务器。
        可以简单理解AD =LDAP服务器+LDAP应用。

用途

用于统一认证管理,统一公司内部服务账号密码。

LDAP 模型

基本模型

目录树:在一个目录服务系统中,整个目录信息集可以表示为一个目录信息树,树中的每个节点是一个条目。
条目:每个条目就是一条记录,每个条目有自己的唯一可区别的名称(DN)。
对象类:是某个实体类型对应的一组属性,对象类可以继承,父类的必须属性也会被继承下来。
属性:描述条目的某个方面的信息,一个属性由一个属性类型和一个或多个属性值组成,属性有必须属性和非必须属性。

关键字 英文全称 含义
dc Domain Component 域名的部分,其格式是将完整的域名分成几部分,如域名为example.com变成dc=example,dc=com(一条记录的所属位置)
uid User Id 用户ID songtao.xu(一条记录的ID)
ou Organization Unit 组织单位,组织单位可以包含其他各种对象(包括其他组织单元),如“oa组”(一条记录的所属组织)
cn Common Name 公共名称,如“Thomas Johansson”(一条记录的名称)
sn Surname 姓,如“许”
dn Distinguished Name “uid=songtao.xu,ou=oa组,dc=example,dc=com”,一条记录的位置(唯一)
rdn Relative dn 相对辨别名,类似于文件系统中的相对路径,它是与目录树结构无关的部分,如“uid=tom”或“cn= Thomas Johansson”
dn :一条记录的详细位置。目录位置
dc :一条记录所属区域 (哪一颗树)。根名称
ou :一条记录所属组织 (哪一个分支)。组名称
cn/uid:一条记录的名字/ID (哪一个苹果名字)。用户名称
img

信息模型

LDAP中,信息以树状方式进行组织的,在树状信息中的基本数据单元是条目,而每个条目由属性构成,属性中存储有属性值;

命名模型

即LDAP中的条目定位方式,在LDAP中每个条目均有自己的DN。
DN是该条目在整个树中的唯一名称标识,

如同文件系统中,带路径的文件名就是DN。

功能模型

在LDAP中共有四类10种操作︰
查询类操作:如搜索、比较;
更新类操作:如添加条目、删除条目、修改条目、修改条目名;
认证类操作:如绑定、解绑定;
其它操作:如放弃和扩展操作。

除了扩展操作,另外9种是LDAP的标准操作﹔

扩展操作是LDAP中为了增加新的功能,提供的一种标准的扩展框架,当前已经成为LDAP标准的扩展操作,有修改密码和startTLS扩展,

在新的RFC标准和草案中正在增加一些新的扩展操作,不同的LDAP厂商也均定义了自己的扩展操作。

安全模型

安全模型主要通过身份认证、安全通道和访问控制来实现。

ldap server

一般ldap服务端比较常用的是openldap,这里仅记录openldap的部署及使用。

openldap

k8s部署

直接用yaml部署就行,镜像用的是bitnami的ldap镜像

apiVersion: apps/v1
kind: Deployment
metadata:
  name: openldap
spec:
  replicas: 1
  selector:
    matchLabels:
      app: openldap
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: openldap
    spec:
      containers:
      - env:
        - name: LDAP_ADMIN_USERNAME
          value: admin
        - name: LDAP_ADMIN_PASSWORD
          value: "123456"
        - name: LDAP_USERS
          value: manager
        - name: LDAP_PASSWORDS
          value: "123456"
        - name: LDAP_ROOT
          value: dc=finsiot,dc=com
        image: bitnami/openldap:latest
        imagePullPolicy: Always
        name: openldap
        ports:
        - containerPort: 1389
          name: service
          protocol: TCP
        resources:
          limits:
            cpu: "1"
            memory: 2Gi
          requests:
            cpu: "1"
            memory: 2Gi
        volumeMounts:
        - mountPath: /bitnami/openldap/data
          name: openldap-pvc
          subPath: ldap
        - mountPath: /bitnami/openldap/slapd.d
          name: openldap-pvc
          subPath: slapd.d
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - name: openldap-pvc
        persistentVolumeClaim:
          claimName: ldap-pvc
---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ldap-pvc
  labels:
    app: ldap
spec:
  storageClassName: csi-rbd-sc   #这里的storageclass是我们之前申请的
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: openldap
spec:
  #clusterIP: 192.168.110.29
  #externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30300
    port: 1389
    protocol: TCP
    targetPort: service
  selector:
    app: openldap
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

ldap二进制部署

这里没有尝试过二进制部署ldap,后面会写。

ldap管理

管理操作ldap数据可以使用ldap客户端或者ldap管理服务工具实现。如果使用ldap windows客户端可以下载LDAPSoft Ldap Browser使用,如果使用管理web页面可以部署服务:ldapphpadmin。

ldapphpadmin

k8s部署


apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: kompose convert -f docker-compose.yml
    kompose.version: 1.16.0 (0c01309)
  creationTimestamp: null
  labels:
    io.kompose.service: phpldapadmin
  name: phpldapadmin
spec:
  replicas: 1
  strategy: {}
  selector:                #定义选择器
    matchLabels:           #匹配上面的标签
        io.kompose.service: phpldapadmin         #匹配模板名称
  template:
    metadata:
      creationTimestamp: null
      labels:
        io.kompose.service: phpldapadmin
    spec:
      containers:
      - env:
        - name: PHPLDAPADMIN_HTTPS
          value: "false"
        - name: PHPLDAPADMIN_LDAP_HOSTS
          value: 'ldap://192.168.110.29:30389'
        image: osixia/phpldapadmin:0.7.1
        name: phpldapadmin
        ports:
        - containerPort: 80
        resources: {}
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:ZZ
  labels:
    io.kompose.service: phpldapadmin
  name: phpldapadmin
spec:
  ports:
  - name: "8080"
    port: 8080
    targetPort: 80
  selector:
    io.kompose.service: phpldapadmin

ldap for nexus

本文主要为nexus集成到ldap的配置,由于网上关于该功能的配置大都层次不齐且写的太模糊,故记录此文档。

1、ldap配置

这里ldap用的是openldap,所以首先需要部署好openldap。首先想要在nexus中集成ldap,ldap的服务端必须要有组和用户。

这里的组用来映射与nexus的角色,使其组下面的用户都拥有nexus映射角色的权限,无需额外配置。
这里的用户则用来登录nexus。

所以需要创建好组和用户,这里以映射一个nexus管理员为例子,首先创建准备好ldap的用户和组:

创建一个ou为nexus,组为manager,用户为nexus,先创建组,然后创建用户指定组。
组:cn=manager,ou=nexus,dc=finsiot,dc=com
用户:cn=nexus,ou=nexus,dc=finsiot,dc=com
image-20221110171353237

2、nexus配置

	1.访问nexus-web管理页面,登录管理员账号,进入设置-》secruity-》LDAP-》create connection
	2.connection配置:
		name:这个是要创建的ldap名称,可以随便填,非关键性参数。
		Ldap server address:填入ldap地址
		Search base Dn:填入dn地址(dc的地址)
		Authentication method: Simple Authentication
		Username or DN: 填入登录用户名(一般用admin管理员登录)
		password: 密码
	3.User and group配置:
		configuration template: 选择一个模板,非关键性参数,只是会预先给出下面一些参数的值。这里可以选posix with static groups
		user relative dn(base dn):对应于用作用户条目基础的专有名称集合。此DN与前面的search base相关。例如,如果用户都包含在ou = nexus,dc=finsiot,dc=com中,前面登录时指定了dc=finsiot,dc=com的搜索库,则这里使用值ou = nexus。
		User subtree: 如果基本DN下面的树可以包含用户条目,则值为true;如果所有用户都包含在指定的基本DN中,则为false。例如,如果所有用户都在ou = users,dc = sonatype,dc = com,则此字段应为False。如果用户可以在组织单位内的组织单位中显示,例如ou = development,ou = users,dc = sonatype,dc = com,则此字段应为True。
		Object class: 此值是RFC-2798中定义的标准对象类。它为用户指定对象类。常见值为inetOrgPerson,person,user或posixAccount。这里使用模板默认的posixAccount
		User filter: 这允许您配置过滤器以限制对用户记录的搜索。它可以用作性能改进。这里不用填写。
		User ID attribute: 这是上面指定的对象类的属性,它从LDAP服务器提供用户的标识符。存储库管理器使用此属性作为用户ID值。在ldap创建了用户以后,里面有一个属性值(默认为uid),例如我这里创建了一个nexus的用户,则会有一个uid的值为nexus,nexus服务需要通过这个key:value来找到该用户
		Real name attribute: 这是Object类的属性,它提供用户的真实姓名。存储库管理器在需要显示用户的真实姓名时使用此属性,类似于内部名字和姓氏属性的使用。这个也是去找ldap里面的kv属性,默认是key的名称为cn。
		Email attribute: 同上面的User ID attribute和Real name attribute,默认key的名称为mail。
		Password attribute:不用填写,这里为空则会在登录时读取ldap中用户的password字段。
		Map LDAP groups as roles:这里需要勾选,下面是组的配置,用于将ldap组映射于nexus。
		Group type: static Groups 这里选择静态组
		Group relative DN: 指名组的DN位置,例如我这里manager组在nexus下面,则这里填ou=nexus。
		Group subtree: 勾选,表示是位于group下面的子组。例如我上面ou=nexus,则这里勾选的意思是nexus下面的组。
		Group object class: 组创建时会有这个字段,默认为posixGroup。和上面定义User ID attribute和Real name attribute和Email attribute是一样的。
		Group ID attribute: 这里表示组的id属性,和上面定义User ID attribute和Real name attribute和Email attribute是一样的。
		Group member attribute: 这里表示组里面有哪些成员,和上面两个属性一样,也是ldap组中的字段,但默认不会创建这个字段,请手动创建memberUid的字段并把成员的字段值写入该字段,否则会找不到映射的角色。
		Group member format: 该字段用来找到memberUid中的组员名称的,使用变量${username}。
image-20221110171338946
image-20221110171215302
image-20221110171237900
image-20221110171249864

创建角色

在nexus设置-》security-》roles中添加一个role,type为external role mapping,external role type为ldap。

image-20221110171612944
Mapped Role:请填写为ldap中创建的组名称,两个服务会通过名称进行映射,例如我这里ldap中有一个nexus用户,在manager组下面,于是这里我定义一个mapped role为manager,则nexus以及ldap中manager组中所有用户都会拥有这里定义好的权限,也就是组权限映射。
Role Name: role角色的名称。
Role Description: 角色介绍。
Privileges:定义的是角色的权限。
Roles:可以与其它定义好的role关联权限。

测试

创建好以后回到刚刚的ldap设置,点击刚刚创建的ldap,进入user and group设置,最下方有一个 verify user mapping 。

image-20221110171936912

点击属于ldap密码就可以看到目前定义映射的组和用户情况

image-20221110172056058

这里user id其实就是上面user id attribute配置,name为Real name attribute配置,email为Email attribute,roles是Map LDAP groups as roles及下面所有组配置定义的。如果有没有数据的字段,请检查该项对应配置的字段是否正常配置,例如如果roles没有,请看一下Map LDAP groups as roles下面的配置是否正确。

ldap for jenkins

jenkins集成ldap的方法

1、安装插件

Jenkins安装LDAP插件

2、配置ldap

进入管理设置(manage jenkins)->全局安全设置(configure global security),设置安全域为ldap

image-20230210101753775

配置项

Server:ldap的地址url
root DN:根DN目录路径
User search base:查找用户的目录
User search filter:查找用户的条件
Group search base: 查找用户组的目录
Group search filter: 用户组条件(查找用户的条件)
Group membership:选择 Search for LDAP groups containing user
Manager DN: 管理员所在路径
Manager Password: 管理员密码
Display Name LDAP attribute: jenkins对应ldap用户名的字段
Email Address LDAP attribute:email字段

配置示例:

image-20230210102814010

这里ldap的结构为,用户目录:ou=people,dc=xxx,dc=com,用户组目录:ou=group,dc=xxx,dc=com

image-20230210103422255
image-20230210103437606

这里需要注意的点是:user search filter用于找到用户,如果这里填错了将会找不到用户。group search base则是用于找到用户组,如果这里填错了将找不到用户,而search filter用于找到用户组中的用户(&(objectClass=posixGroup)(memberUid={1})),这里的用户组主要用于授权时使用,对组进行授权。

测试

配置完成可以点击test ldap settings测试一下:

image-20230210104457142
image-20230210104515248

ldap for gitlab

gitlab并不能直接通知页面设置来对接ldap,而是通过配置文件。

1、ldap配置(二进制部署)

这里配置分为两种:一种是二进制包部署的gitlab,这个由于我并没有部署过,所以下面的配置摘抄于网上,不清楚版本有没有配置变化,但配置大致的字段基本应该是一致的;还有一种方法是k8s的配置,这种也是目前我在使用的方式,会在下面列出来。

如果是二进制部署的则直接更改配置文件
vi /etc/gitlab/gitlab.rb

gitlab_rails['ldap_enabled'] = true
gitlab_rails['prevent_ldap_sign_in'] = false
gitlab_rails['ldap_servers'] = {
'main' => {
  'label' => 'LDAP', # 随便自定义
  'host' =>  '10.0.20.19', # ldap的server地址
  'port' => 389, # ldap端口
  'uid' => 'cn', # 配置为cn或者sn都可以,但要注意用户名称将会以此处配置为依据
  'bind_dn' => 'cn=admin,dc=aihelp,dc=net', # 管理员账号
  'password' => '123456', # 管理员密码
  'encryption' => 'plain',  # 加密
  'allow_username_or_email_login' => false,  # 是否启用邮件作为用户名登陆
  'block_auto_created_users' => false, 
  'base' => 'dc=aihelp,dc=net',   # 核心配置,表示从哪一层读取用户信息
  'user_filter' => '(memberof=cn=jenkins,ou=group,dc=aihelp,dc=net)', # LDAP用户进行过滤
  'lowercase_usernames' => false,
  'group_base' => '',
  'admin_group' => '',
  'external_groups' => [],
  'sync_ssh_keys' => false
  }
}


其中:
label 是显示在GitLab登录框的上方文字描述。
host 和 port 是 LDAP 服务的主机地址及端口
bind_dn 和 password 是一个管理 LDAP 的 dn 及密码
base 表示 LDAP 将以该 dn 为 节点,向下查找用户
user_filter 表示以某种过滤条件筛选用户,比如假设我们只希望所属组为 java-platform 的用户来访问 GitLab,则可以在这里设置 (memberOf=ou=java-platform,ou=people,dc=domain,dc=com)

配置添加之后,依旧像安装时候那样,重载一下配置:
gitlab-ctl reconfigure

 
Checking LDAP ...
LDAP: ... Server: ldapmain
LDAP authentication... Success
LDAP users with access to your GitLab server (only showing the first 100 results)
    DN: uid=test01,ou=people,dc=eryajf,dc=net    cn: ceshi
    DN: uid=test02,ou=people,dc=eryajf,dc=net    cn: test02
    DN: uid=test03,ou=people,dc=eryajf,dc=net    cn: test03
    DN: uid=admin,ou=people,dc=eryajf,dc=net     cn: Admin
Checking LDAP ... Finished
使用ldap用户名密码进行登陆即可,此时登陆进去是没有任何项目的权限,如果需要某权限,可以对用户进行组或者单项目的授权。

2、ldap配置(k8s)

ldap这里直接用helm的values.yaml传递配置文件信息,所以在ldap中配置就行了。这里如果是部署也建议采用helm部署,由于gitlab新版本模块过多,如果写yaml文件的话再加上配置文件和需要持久化的存储路径很麻烦,所以使用helm是比较理想的方式。

values.yaml:
----
    ldap:
      # prevent the use of LDAP for sign-in via web.
      preventSignin: false
      servers:
        main:
          label: 'LDAP' 
          host: '192.168.110.29' #ldap地址
          port: 30389 #端口
          uid: 'uid' 
          bind_dn: 'cn=admin,dc=finsiot,dc=com' #管理员路径
          password: #管理员密码
            secret: my-ldap-password-secret
            key: the-key-containing-the-password
          encryption: 'plain'
          base: 'ou=people,dc=finsiot,dc=com' #用户路径
          verify_certificates: true #忽略证书
          active_directory: false
          allow_username_or_email_login: true #支持邮件和用户名登录
          block_auto_created_users: false
          user_filter: ''
          attributes:
            username: ['cn'] #用户名对应ldap字段
            email:    ['mail','email'] #邮箱对应ldap字段
            name:     'description' #用户显示名字对应ldap字段
            fister_name: 'givenName' 
            last_name:  'sn'

需要注意的是,gitlab-ce仅支持ldap的用户配置,不支持ldap用户组的配置,如果想要使用ldap用户组,需要使用gitlab-ee(商业版本)。

ldap的配置文件是configmap:gitlab-webservice下面的gitlab.yml.erb,挂载于gitlab-webservice-default的/var/opt/gitlab/templates/gitlab.yml.erb路径。

gitlab拉取ldap账号数据

问题

ldap与应用结合一般有两种,一种是服务需要登录时去调用ldap的账号数据实现结合,还有一种是服务预先将ldap存在自己数据库中然后通过ldap的账号进行登录。而gitlab则是后者,这种情况会导致新加了账号但是ldap却没办法直接用新账号登录,因为gitlab并非是登录直接去ldap调用,而是从自己数据库中找ldap账号数据。

解决办法

1、定时

​ 可以在gitlab中设置每日定时任务,定时从ldap中拉取数据到自己的数据库。

K8S:
	这里k8s是在helm的部署文件values.yaml添加修改:
	cron_jobs:
	   ldap_sync_worker:
         cron: "30 1 * * *"
       ldap_group_sync_worker:
         cron: "0 * * * *"
二进制部署:
	请查看官方文档:https://docs.gitlab.cn/jh/administration/auth/ldap/ldap_synchronization.html

2、手动拉取
手动拉取使用gitlab-rake gitlab:ldap:check命令就可以,这个是测试ladp的命令,测试的同时会拉取一遍数据。
如果是k8s需要在gitlab-toolbox容器中执行该命令

mindoc for ldap

mindoc是一款开源wiki服务,由于比较冷门,后面可能几乎用不到,这里就简略记录一下,直接贴上配置文件

app.conf #mindoc配置文件
     #是否启用ldap
    ldap_enable=true
    #ldap主机名
    ldap_host=192.168.110.29
    #ldap端口
    ldap_port=30389
    #ldap内哪个属性作为用户名
    ldap_attribute=uid
    #搜索范围
    ldap_base=dc=finsiot,dc=com
    #第一次绑定ldap用户dn
    ldap_user=cn=admin,dc=finsiot,dc=com
    #第一次绑定ldap用户密码
    ldap_password=123456
    #自动注册用户角色:0 超级管理员 /1 管理员/ 2 普通用户
    ldap_user_role=2
    #ldap搜索filter规则,AD服务器: objectClass=User, openldap服务器: objectClass=posixAccount ,也可以定义为其他属性,如: title=mindoc
    ldap_filter=objectClass=posixAccount

直接配置好重启应用就可以使用ldap账号登录了。

zentao for ldap

禅道服务接入ldap

ldap插件部署

禅道本身不支持ldap,需要额外安装ldap插件。插件地址:https://github.com/yihoyoung/zentao-ldap

需要注意的是目前这个版本最高仅支持禅道12,本人测试在禅道18版本上面不兼容。

其安装步骤在github的readme中有说明:

1.打包 ldap 文件夹为 ldap.zip 文件
2.创建文件:
touch /www/zentaopms/www/ok.txt
3.admin 账户登陆禅道,后台 -> 插件 -> 本地安装,选择打包的 ldap.zip 文件安装即可

具体步骤

下载ldap代码,将这个文件打包成zip。

image-20230213152207304

在服务器上面创建该文件:touch /www/zentaopms/www/ok.txt

然后登录禅道管理员账号,部署插件如下:

image-20230213152502090

安装文件时提示版本不兼容点击强制安装即可。

image-20230213152747071

安装成功以后后台会有ldap配置项:

image-20230213140948096

ldap配置说明

LDAP服务器: ldap地址
协议版本: 默认填写3
BindDN: 管理账号地址
BindDN 密码:	管理账户密码
BaseDN: 用户地址
Search filter: 搜索用户的条件,openldap这个服务默认是objectClass=posixAccount,不同的ldap服务不一样
账号字段: 登录用户名字段
EMail 字段: 邮箱字段
姓名字段: 名字字段

ldap配置完以后先点击保存配置,然后点击手动同步,如果有同步的用户信息那就表示没问题了。

image-20230213153228070

最后在组织-》用户中查看已经通过ldap导入的用户信息。

注意:配置了ldap以后系统原账号登录需要在用户名前面加上“”符号,例如admin。

EOF