哦我的老伙计你居然在配置 OpenLDAP

ToC

架构

Docker → OpenLDAP server ← (Let’s Encrypt 证书) ← OpenLDAP client

NGINX → (Let’s Encrypt 证书) → Docker → phpldapadmin

phpldapadmin (同一个 docker 内网)→ OpenLDAP server

版本

Host: Ubuntu 18.04.5 LTS x86_64

Linux kernel: 4.15.0-122-generic

Docker: 19.03.6 linux/amd64

安装

因为是 docker 安装, 基本看的是镜像本身的 repo 说明: osixia/openldap, osixia/phpldapadmin. 中间也参考了一下过来人的配法.

花点时间对照后得到 docker-compose 文件如下. 可以看出两个应用配置在相同的 docker 子网.

version: '2'

networks:
  ldap:
    external: false

services:
  openldap-server:
    hostname: foo
    ports:
      - '389:389'
      - '636:636'
    environment:
      - LDAP_ORGANISATION=example
      - LDAP_DOMAIN=example.com
      - LDAP_ADMIN_PASSWORD=password
      - 'LDAP_BASE_DN=dc=example,dc=com'
      # Remember to enable TLS later
      - LDAP_TLS=false
      # See https://www.openldap.org/doc/admin24/slapdconf2.html for debug level
      - LDAP_LOG_LEVEL=4
    volumes:
      - '/foo/bar/openldap/database:/var/lib/ldap'
      - '/foo/bar/openldap/config:/etc/ldap/slapd.d'
    networks:
      - ldap
    container_name: openldap-server
    image: osixia/openldap:stable

  phpldapadmin:
    ports:
      - '8072:80'
      - '8073:443'
    environment:
      - PHPLDAPADMIN_LDAP_HOSTS=openldap-server
      # We use NGINX to enable HTTPS, so keep disable here.
      - PHPLDAPADMIN_HTTPS=false
      # Set to true to trust NGINX X-Forwarded-Proto header
      - PHPLDAPADMIN_TRUST_PROXY_SSL=true
      # Enable ldap client tls config, ldap server certificate check and set client certificate. Defaults to true. Switch to true if testing over.
      - PHPLDAPADMIN_LDAP_CLIENT_TLS=false
    networks:
      - ldap
    container_name: phpldapadmin-service
    image: osixia/phpldapadmin:stable

因为关了 TLS, phpldapadmin 的 443 端口暂时在外网是进不去的, 可以用 80 端口测试. 因为我是公网的服务器, 直接访问 http://服务器公网IP:8072 端口, 验证 phpldapadmin, 可以正常登录.

再在外网用 ApacheDS 访问 服务器公网IP:389 端口, 验证 LDAP 本身暴露的端口, 可以登录并操作.

当然以上都只是临时验证服务器部署成功, 明文传输不安全, 后续都需要加上 TLS.

启用 memberOf

一开始不知道, 被这里提醒需要开启 memberOf, 那就开搞.

因为我们是 docker 安装, 需要先进 docker 命令行才能执行一般的教程提到的命令.

docker exec -it openldap-server /bin/bash

以下 ldap* 程序相关的操作均为 docker 内命令行操作.

启用模块

参考这里列出现在已经启用的模块.

ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b  cn=config -LLL | grep -i module

命令具体某个参数是什么意思可以先不纠结.

如无意外可以得到如下结果.

SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_mdb
olcModuleLoad: {1}memberof
olcModuleLoad: {2}refint
olcAttributeTypes: ( OLcfgGlAt:30 NAME 'olcModuleLoad' EQUALITY caseIgnoreMatc
olcAttributeTypes: ( OLcfgGlAt:31 NAME 'olcModulePath' SYNTAX OMsDirectoryStri
olcObjectClasses: ( OLcfgGlOc:8 NAME 'olcModuleList' DESC 'OpenLDAP dynamic mo
 dule info' SUP olcConfig STRUCTURAL MAY ( cn $ olcModulePath $ olcModuleLoad
olcAttributeTypes: {15}( 1.3.6.1.4.1.4754.1.99.1 NAME 'pwdCheckModule' DESC 'L
 oadable module that instantiates "check_password() function' EQUALITY caseExa
  AUXILIARY MAY pwdCheckModule )

可以留意到我这里 olcModulePath/usr/lib/ldap , 跟参考教程不一样, 以自己显示的为准.

也可以看到这里 olcModuleLoad 已经包含了 memberofrefint, 在上述两篇参考教程里都提到要配置这两个, 但本文用到的镜像已经默认配好了, 所以可以直接进入在 phpldapadmin 配置的阶段.

phpldapadmin 配置用户结构

参考教程这里其实说得差不多了, 但有些细节欠缺, 补充一下.

先访问 http://服务器公网IP:8072 , 登录 phpldapadmin. 用户名是 cn=admin,dc=example,dc=com , 密码是在上面 docker-compose 文件设置的密码 LDAP_ADMIN_PASSWORD.

新增 ou(架构单元)

这个每个系统一般只会设置一遍, 后续都不用动.

  1. 在左侧的树, dc=example,dc=com 下级, 也即是 cn=admin 同级那里, 点击 Create new entry here
  2. Templates 当然是选 Generic: Organisational Unit
  3. 输入 users

重复上面步骤, 第 3 步输入 groups

新增用户(终于)

  1. 点击上节创建出来的 ou=users 节点, 选 Create a child entry
  2. Templates 选 Default
  3. 别的保持默认, ObjectClassesinetOrgPerson
  4. 输入各种用户属性, 以叫”张三”的用户为例子说明如下

inetOrgPerson

属性名属性值说明
RDNUser Name (uid)就是用户的唯一识别码, 这里用了用户名
cnZhang Sancommon name, 一般就是用作应用显示用户的名字, 注意和 User Name (uid) 区分.
snZhangsur name, 指姓氏
password密码, 加密方式一般保持 MD5 不用改, 有需要自行阅读文档.
User Namezhangsan同上, 这里作为这个帐号的唯一识别码. 一般统一填用户拼音全称, 全小写

其他栏目想填就填, 最后按 Create Object, 完成.

新增 group(部门)

其实就是新增各种部门, 或者叫分组, 或者你喜欢叫什么, 大概是这个意思.

  1. 点击上节创建出来的 ou=groups 节点, 选 Create a child entry
    2. TemplatesDefault
  2. 别的保持默认, ObjectClassesgroupOfUniqueNames (不要跟 groupOfNames 搞混)
  3. 输入各种属性, 以叫”developer”的 group 为例子说明如下

groupOfUniqueNames

属性名属性值说明
RDNcn(cn)意思是使用这个 group 的 cn 作为唯一识别码
cndeveloper(按实际情况填写)common name, 这个 group 的名字, 这里用作唯一识别码
uniqueMember(按实际情况填写)就是 group 成员, 根据实际情况添加, 可以点击右侧放大镜图标进入图形化选择.

其他栏目想填就填, 最后按 Create Object, 完成.

给 group 分配成员

就是给部门/分组分配成员.

  1. 在左侧的树状菜单点击上节创建出来的 cn=developer 节点, 这一步就是”选中 developer 这个部门”
  2. 在右侧的”uniqueMember”下找到 modify group members 按钮, 点击.
  3. 根据实际需求, 在 Available members 栏目选择你要分配的成员, 点击 Add selected 添加选中的成员, 或者直接选择 Add all 添加所有成员.
  4. 最后点击 Save changes 保存.

phpldapadmin 配置公钥储存(可选)

这个是个人需求了, 不过还是很有现实意义的, 毕竟管理员一般都管着一堆机, 每台机都要配一遍公钥(初次 ssh-copy-id 无法避免), 但如果机子都配置了读取 LDAP 的 sshPublickey 的话, 后续公钥的增删改都直接在 LDAP 后台做一次就可以了.

理论上我们这个镜像已经包含了 objectClass=ldapPublickey, 不过重复操作一下也没什么影响.

新增 objectClass

新增一个 add_ssh_public_key.ldif 文件, 内容如下

dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
    DESC 'MANDATORY: OpenSSH Public key'
    EQUALITY octetStringMatch
    SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
    DESC 'MANDATORY: OpenSSH LPK objectclass'
    MAY ( sshPublicKey $ uid )
    )

然后执行命令

ldapadd -Y EXTERNAL -H ldapi:/// -f add_ssh_public_key.ldif

在用的 osxia/openldap 镜像已经有了, 所以会报重复属性:

SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=openssh-lpk,cn=schema,cn=config"
ldap_add: Other (e.g., implementation specific) error (80)
        additional info: olcAttributeTypes: Duplicate attributeType: "1.3.6.1.4.1.24552.500.1.1.1.13"

在 phpldapadmin 添加公钥

跟着上面的新增用户章节建个用户, 也可以在已有用户上添加.

找到目标用户的 objectClass 属性, 点击 add value 为用户新增一个 objectClass=ldapPublickey 的属性, 提交.

回到编辑用户页面, 点击 Add new Attribute, 新增 sshPublicKey 属性, 提交.

再次回到编辑用户页面, 填写实际公钥内容, 提交, 搞定.

有多个公钥自然在 sshPublicKey 下 add value 就好了.

开启 TLS

上面的基本测试都调通之后, 就可以配证书开启 TLS, 正式上线了.

OpenLDAP

也是跟着镜像的说明走就行, 最后补充得出的 docker-compose 文件

environment:
  - LDAP_TLS_CRT_FILENAME=cert.pem
  - LDAP_TLS_KEY_FILENAME=key.pem
  - LDAP_TLS_CA_CRT_FILENAME=ca.pem
  # Workaround, see https://github.com/osixia/docker-openldap/issues/199
  - LDAP_TLS_VERIFY_CLIENT=try
volumes:
  - /etc/letsencrypt/example.com:/container/service/slapd/assets/certs

phpldapadmin

NGINX 配置就是最普通的 reverse proxy 配法, 注意开 proxy_set_header X-Forwarded-Proto $scheme;, 上面的 docker-compose 也写了对应的环境变量 PHPLDAPADMIN_TRUST_PROXY_SSL=true

一些可能有用的零散命令

# 搜索当前的 ACL 策略
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase=*)' olcAccess

# 应用 xxx.ldif 文件
ldapmodify -Y EXTERNAL -H ldapi:/// -f xxx.ldif

参考

Setting up OpenLDAP server with OpenSSH-LPK on Ubuntu 14.04

CentOS 7 搭建 OpenLDAP Server

Ubuntu16.04下配置OpenLdap