เตาะแตะไปกับ Docker ตอนที่ 9 Dockerfile (OpenLDAP)

วันนี้เราจะเรียนรู้การใช้ dockerfile สร้าง image ชื่อ openldap เพื่อใช้เป็น LDAP database
ผมทดสอบด้วย Oracle VM VirtualBox เป็น VM ที่ตั้งค่า Network adapter เป็นแบบ NAT network ที่ติดตั้ง Ubuntu 16.04 และ docker เรียบร้อยแล้ว ในตัวอย่างนี้ผมตั้งชื่อ host ว่า ldap.example.com โดยแก้ไขที่ไฟล์ /etc/hosts และ /etc/hostname ให้เรียบร้อย แล้วรีบูตเครื่องด้วย

ผมจะขอแยกขั้นตอนออกเป็น 3 ขั้นตอนหลัก คือ 1.ขั้นตอนเตรียมไฟล์ที่เกี่ยวข้องซึ่งรวมไฟล์ ldif ด้วย 2.ขั้นตอนสร้างไฟล์ dockerfile และ 3.ขั้นตอนการรัน container

 

1.ขั้นตอนเตรียมไฟล์ที่เกี่ยวข้อง
สร้างไดเรกทอรีของ image ที่เราจะสร้าง

$ mkdir openldap

สร้างไดเรกทอรีที่เก็บไฟล์ ldif (โครงสร้าง และ ตัวอย่างข้อมูล)

$ cd openldap
$ mkdir src

สร้างไฟล์ ./src/create-schema.ldif ด้วยเอติเตอร์ที่ถนัด เช่น vi หรือ nano ก็ได้

$ vi ./src/create-schema.ldif 
# Starter kit for create user in domain dc=example,dc=com
# Create 1st tree OU=groups
dn: ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: groups

# Create sub tree OU=execs,OU=groups
dn: ou=execs,ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: execs

# Create sub tree OU=staffs,OU=groups
dn: ou=staffs,ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: staffs

# Create sub tree OU=students,OU=groups
dn: ou=students,ou=groups,dc=example,dc=com
objectClass: organizationalUnit
ou: students

# Create 2nd tree OU=people
dn: ou=people,dc=example,dc=com
objectClass: organizationalUnit
ou: people

สร้างไฟล์ ssl.ldif

$ vi src/ssl.ldif
dn: cn=config
changetype: modify
add: olcTLSCipherSuite
olcTLSCipherSuite: NORMAL
-
add: olcTLSCRLCheck
olcTLSCRLCheck: none
-
add: olcTLSVerifyClient
olcTLSVerifyClient: never
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap-ca-cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap-ca-key.pem

สร้างไฟล์ ./src/create-users.ldif

$ vi ./src/create-users.ldif 
# Create 1 user in tree OU=execs,OU=groups
dn: cn=nana,ou=execs,ou=groups,dc=example,dc=com
objectClass: inetOrgPerson
uid: nana
sn: Na
givenName: Na
cn: nana
displayName: Na Na
userPassword: 123456
mail: nana@example.com

# Create 2 users in tree OU=staffs,OU=groups
dn: cn=koko,ou=staffs,ou=groups,dc=example,dc=com
objectClass: inetOrgPerson
uid: koko
sn: Ko
givenName: Ko
cn: koko
displayName: Ko Ko
userPassword: 123456
mail: koko@example.com

dn: cn=momo,ou=staffs,ou=groups,dc=example,dc=com
objectClass: inetOrgPerson
uid: momo
sn: Mo
givenName: Mo
cn: momo
displayName: Mo Mo
userPassword: 123456
mail: momo@example.com

# Create 2 users in tree OU=people
dn: cn=lala,ou=people,dc=example,dc=com
objectClass: inetOrgPerson
uid: lala
sn: La
givenName: La
cn: lala
displayName: La La
userPassword: 123456
mail: lala@example.com

dn: cn=lulu,ou=people,dc=example,dc=com
objectClass: inetOrgPerson
uid: lulu
sn: Lu
givenName: Lu
cn: lulu
displayName: Lu Lu
userPassword: 123456
mail: lulu@example.com

สร้างไฟล์ ./src/create-students.ldif

$ vi ./src/create-students.ldif 
# Create 2 students in tree OU=students,OU=groups
dn: cn=5310110293,ou=students,ou=groups,dc=example,dc=com
objectClass: inetOrgPerson
uid: 5310110293
sn: 5310110293
givenName: somsak
cn: 5310110293
displayName: somsak somsaknaja
userPassword: 123456
mail: 5310110293@example.com

dn: cn=5410110308,ou=students,ou=groups,dc=example,dc=com
objectClass: inetOrgPerson
uid: 5410110308
sn: 5410110308
givenName: somsri
cn: 5410110308
displayName: somsri somsrisiya
userPassword: 123456
mail: 5410110308@example.com

ต่อไปเป็นการเตรียม self-signed certificate เพื่อให้ใช้งาน LDAPS ได้

$ sudo apt install ssl-cert
$ mkdir cert
$ cp /etc/ssl/certs/ssl-cert-snakeoil.pem cert/ldap-ca-cert.pem
$ sudo cp /etc/ssl/private/ssl-cert-snakeoil.key cert/ldap-ca-key.pem
$ sudo chmod +r cert/ldap-ca-key.pem

 

2.ขั้นตอนสร้างไฟล์ dockerfile
ตอนนี้ก็มาถึงขั้นตอนการเขียน dockerfile ด้วยเอดิเตอร์ที่ถนัดเช่น vi หรือ nano ก็ได้

$ vi dockerfile
# Composer: Comments

FROM ubuntu:16.04

# Change apt source
RUN sed -i 's/\/us.archive/\/th.archive/g' /etc/apt/sources.list && \
 sed -i 's/\/archive/\/th.archive/g' /etc/apt/sources.list

# Update ubuntu, then install packages
RUN apt-get update && \
echo 'slapd slapd/root_password password 123456' | debconf-set-selections && \
echo 'slapd slapd/root_password_again password 123456' | debconf-set-selections && \
echo "slapd slapd/internal/adminpw password 123456" |debconf-set-selections && \
echo "slapd slapd/internal/generated_adminpw password 123456" |debconf-set-selections && \
echo "slapd slapd/password2 password 123456" |debconf-set-selections && \
echo "slapd slapd/password1 password 123456" |debconf-set-selections && \
echo "slapd slapd/domain string example.com" |debconf-set-selections && \
echo "slapd shared/organization string example" |debconf-set-selections && \
echo "slapd slapd/backend string HDB" |debconf-set-selections && \
echo "slapd slapd/purge_database boolean true" |debconf-set-selections && \
echo "slapd slapd/move_old_database boolean true" |debconf-set-selections && \
echo "slapd slapd/allow_ldap_v2 boolean false" |debconf-set-selections && \
echo "slapd slapd/no_configuration boolean false" |debconf-set-selections && \
DEBIAN_FRONTEND=noninteractive apt install -y slapd

# LDAP utils, self-signed certificates
RUN apt-get install -y ldap-utils ssl-cert

# Timezone Asia/Bangkok
RUN apt-get install -y tzdata && \
 ln -sf /usr/share/zoneinfo/Asia/Bangkok /etc/localtime && \
 dpkg-reconfigure -f noninteractive tzdata

# Cleaning
RUN apt-get autoremove -y && apt-get clean -y

# LDAP
COPY ./src/*.ldif /tmp/
## Schema only, no user. 
RUN service slapd start && \
 ldapadd -H ldapi:/// -f /tmp/create-schema.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456
## Schema and add users.
## RUN service slapd start && \ 
## ldapadd -H ldapi:/// -f /tmp/create-schema.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456 && \
## ldapadd -H ldapi:/// -f /tmp/create-users.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456 && \
## ldapadd -H ldapi:/// -f /tmp/create-students.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

EXPOSE 389 
#CMD slapd -h 'ldap:///' -g openldap -u openldap -d 0

#
# LDAPS
COPY ./cert/ldap-ca-cert.pem /etc/ssl/certs/
COPY ./cert/ldap-ca-key.pem /etc/ssl/private/

RUN chgrp ssl-cert /etc/ssl/private/ldap-ca-key.pem && \
 chmod g+r /etc/ssl/private/ldap-ca-key.pem && \
 adduser openldap ssl-cert

RUN echo 'SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"' >> /etc/default/slapd && \
 echo 'TLS_REQCERT never' >> /etc/ldap/ldap.conf

RUN service slapd start && \
 ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/ssl.ldif -v

EXPOSE 636
##CMD slapd -h 'ldaps:///' -g openldap -u openldap -d 0

CMD RUN ulimit -n 1024
CMD /usr/sbin/slapd -h 'ldap:/// ldaps:/// ldapi:///' -g openldap -u openldap -d 0

 

3.ขั้นตอนการรัน container
สร้าง image ด้วยคำสั่งนี้

$ docker build -t openldap .

รัน container และ ตรวจสอบ ด้วยคำสั่งนี้

$ docker run -d -p 636:636 -p 389:389 --name openldap openldap
$ docker ps

อธิบายได้ดังนี้ container จะรันแบบ detach (-d) เปิด port 636 และ 389 ตั้งชื่อ(–name) ว่า openldap และรันจาก image ชื่อ openldap

ทดสอบการนำเข้าข้อมูล ซึ่งเราจะใช้เครื่องที่กำลังทำอยู่นี้เป็น ldap client ไม่ต้องไปหาอีกเครื่องก็ได้ โดยเพิ่มแพ็กเกจ ldap-utils

$ sudo apt install ldap-utils

ทดสอบการเพิ่มตัวอย่างข้อมูล โดยเลือกใช้ port 389 (LDAP)

$ ldapadd -H ldap://ldap.example.com -f ./src/create-users.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

ทดสอบการเพิ่มตัวอย่างข้อมูล โดยเลือกใช้ port 636 (LDAPS)

$ ldapadd -H ldaps://ldap.example.com -f ./src/create-students.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

จะพบข้อความว่า

ldap_sasl_bind(SIMPLE): Can’t contact LDAP server (-1)

ให้ทำคำสั่ง 2 บรรทัดข้างล่างนี้ เพื่อเพิ่ม certificate จาก LDAP server แล้วลองคำสั่งนั้นอีกครั้งจะทำได้

$ openssl s_client -connect ldap.example.com:636 -showcerts </dev/null 2>/dev/null | openssl x509 -outform PEM | sudo tee /usr/local/share/ca-certificates/ldap.example.com.crt
$ sudo update-ca-certificates

ทดสอบค้นหาข้อมูล

$ ldapsearch -xLLL -b "dc=example,dc=com" uid=lulu
$ ldapsearch -xLLL -b "dc=example,dc=com" uid=5310110293

ลบ container

$ docker stop openldap
$ docker rm openldap

 

เรื่องสุดท้ายของบล็อกในวันนี้คือ ต้องการเก็บตัวอย่างข้อมูลที่เพิ่มไว้จะทำอย่างไร ทำได้โดยการสร้างที่เก็บ persistent data แบบ named volume โดยที่ oldata สำหรับข้อมูล และ olconfig สำหรับไฟล์คอนฟิกกูเรชัน

$ docker volume create oldata
oldata
$ docker volume create olconfig
olconfig

เช็คดูรายการ volume

$ docker volume ls
DRIVER VOLUME NAME
local olconfig
local oldata

รัน container (เขียนคำสั่งให้อยู่ในบรรทัดเดียว)

$ docker run -d -p 636:636 -p 389:389 --name openldap --volume oldata:/var/lib/ldap --volume olconfig:/etc/ldap/slapd.d openldap

อธิบายได้ดังนี้ container จะรันแบบ detach (-d) เปิด port 636 และ 389 ตั้งชื่อ(–name) ว่า openldap เก็บข้อมูลไว้นอก container เอาไว้ที่ volume ชื่อ oldata ที่ mapped ไปยัง /var/lib/ldap ใน container กับ olconfig ที่ mapped ไปยัง /etc/ldap/slapd.d ใน container และรันจาก image ชื่อ openldap

เพิ่มข้อมูลตัวอย่าง

$ ldapadd -H ldaps://ldap.example.com -f ./src/create-students.ldif -x -D "cn=admin,dc=example,dc=com" -w 123456

ค้นหาข้อมูล

$ ldapsearch -xLLL -b "dc=example,dc=com" uid=5310110293

ลบ container เมื่อจะไม่ใช้งานแล้ว

$ docker stop openldap
$ docker rm openldap

หลังจากลบ container ข้อมูลของเราจะยังคงอยู่ในที่เก็บข้อมูลแบบ volume อยู่ที่ path /var/lib/docker/volumes

ในตอนต่อไปจะเป็นการสร้าง dockerfile เพื่อรัน phpldapadmin ใช้ในการเข้า admin ผ่านหน้าเว็บเพจ