AnsibleでOpenLDAP環境構築 -①OpenLDAPサーバ関連のパッケージインストールの次は管理者DNの設定。
LDAP構築 まとめの例にならい、管理者DNを
cn=Manager,dc=abc,dc=def,dc=com
とする。
■管理者DN設定用playbook
以下の内容でplaybookを作成してみた。
[root@ansible_sv ~]# vi /etc/ansible/yml/2_rootDN.yml
1 - hosts: ldap_sv
2 remote_user: root
3
4 vars:
5 rootPasswd: manager
6
7 tasks:
8 - name: copy DB_CONFIG
9 shell: cp -p /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
10
11 - name: create ldif directory
12 file:
13 path=/root/ldif
14 state=directory
15 owner=root
16 group=root
17 mode=0644
18
19 - name: create rootPW
20 file:
21 state=touch
22 path=/root/ldif/rootPW.ldif
23 owner=root
24 group=root
25 mode=0644
26
27 - name: create olcRootPW
28 shell: slappasswd -s {{ rootPasswd }}
29 register: olcrootpass
30
31 - name: create rootPW.ldif
32 lineinfile:
33 dest=/root/ldif/rootPW.ldif
34 state=present
35 line="{{ item }}"
36 with_items:
37 - 'dn: olcDatabase={0}config,cn=config'
38 - 'changetype: modify'
39 - 'replace: olcRootPW'
40 - 'olcRootPW: {{ olcrootpass.stdout }}'
41
42 - name: execute ldapadd
43 shell: ldapmodify -Y EXTERNAL -H ldapi:// -f /root/ldif/rootPW.ldif
44
45 - name: create change-domain
46 shell: >
47 echo "dn: olcDatabase={1}monitor,cn=config" > /root/ldif/change-domain.ldif;
48 echo "changetype: modify" >> /root/ldif/change-domain.ldif;
49 echo "replace: olcAccess" >> /root/ldif/change-domain.ldif;
50 echo 'olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=Manager,dc= abc,dc=def,dc=com" read by * none' >> /root/ldif/change-domain.ldif;
51 echo \ >> /root/ldif/change-domain.ldif;
52 echo "dn: olcDatabase={2}hdb,cn=config" >> /root/ldif/change-domain.ldif;
53 echo "changetype: modify" >> /root/ldif/change-domain.ldif;
54 echo "replace: olcSuffix" >> /root/ldif/change-domain.ldif;
55 echo "olcSuffix: dc=abc,dc=def,dc=com" >> /root/ldif/change-domain.ldif;
56 echo \ >> /root/ldif/change-domain.ldif;
57 echo "dn: olcDatabase={2}hdb,cn=config" >> /root/ldif/change-domain.ldif;
58 echo "changetype: modify" >> /root/ldif/change-domain.ldif;
59 echo "replace: olcRootDN" >> /root/ldif/change-domain.ldif;
60 echo "olcRootDN: cn=Manager,dc=abc,dc=def,dc=com" >> /root/ldif/change-domain.ldif;
61 echo \ >> /root/ldif/change-domain.ldif;
62 echo "dn: olcDatabase={2}hdb,cn=config" >> /root/ldif/change-domain.ldif;
63 echo "changetype: modify" >> /root/ldif/change-domain.ldif;
64 echo "replace: olcRootPW" >> /root/ldif/change-domain.ldif;
65 echo "olcRootPW: {{ olcrootpass.stdout }}" >> /root/ldif/change-domain.ldif
66
67 - name: execute ldapmodify
68 shell: ldapmodify -x -D cn=config -w {{ rootPasswd }} -f /root/ldif/change-domain.ldif
以下、各モジュールの説明。
hosts:(1行目)
処理を実行する対象ホストを指定。「ldap_sv」は/etc/ansible/hostsに記述したホスト名となる。
remote_user:(2行目)
hosts:で指定したホストで処理を実行する際に、どのユーザで処理を実行するかを指定。上記の例では先頭の階層に記述しているため、それ以降の全階層において適用される。
vars:(4行目)
変数を宣言するモジュール。上記例の場合、rootPasswdが変数名で、managerが代入された文字列となる。後の行でこの変数を使用する。変数の宣言は1行だけでなく複数可。またこの場合一番上位のhostsモジュールと同じ階層に位置されているので、それ以下のすべての階層に有効となる。
tasks:(7行目)
処理の内容を、tasks:以降に記述する。tasks:を記述しないとエラーになるので注意。
name:(11、19、27、31、42、45、67行目)
ansible-playbookコマンドを実行した際に、実行結果に出力させる文字列を指定する。
shell:(28、43、46、68行目)
linuxコマンドを直接指定できる。類似モジュールで「command:」もあるが、shellは複数行記述できる。
上記例ではcpコマンドを記述しているが、実はcopyモジュールも存在しており、違いを抑えておかないと単純なところで迷路にはまってしまう。
ここでcopyモジュールを間違って使ってしまうと、本環境で言えばansibleインストールしたサーバ—>別のサーバへファイル転送するという操作になる。shellモジュールでcpコマンドを使えば、OpenLDAPサーバ内でcpコマンドを実行してくれる。copyモジュールをここで使わない理由はその点である。
file:(20行目)
ファイルやディレクトリの作成、アクセス権限の指定ができるモジュール。複数のモジュール引数が存在するので、以下の表に示す。
| モジュール引数 | 条件 | 説明 |
|---|---|---|
| path= | ディレクトリやファイル、シンボリックリンクの位置をフルパスで指定する。 | |
| state= | file | pathで指定した既存のファイルを示す。もしファイルがない場合はcopyモジュールやtemplateモジュールが発動する。 |
| link | pathで指定したシンボリックリンクを示す。 | |
| directory | pathで指定した既存のディレクトリを示す。ディレクトリがない場合はサブディレクトリとして作成され、アクセス権限は上位ディレクトリから継承される。 | |
| hard | ハードリンクを指定する。 | |
| touch | pathで指定したファイルを空の状態で作成する。linuxコマンドのtouchコマンドに相当する。 | |
| absent | pathで指定したファイルやディレクトリ、シンボリックリックを削除する。 | |
| owner= | ファイルのオーナーを指定する。lsコマンド等で表示されるオーナーの部分に当たる。 | |
| group= | ファイルのグループを指定する。lsコマンド等で表示されるグループの部分に当たる。 | |
| mode= | ファイルのアクセス権限を指定する。chmodコマンドに相当する。 |
register:(29行目)
直前で実行したモジュールの標準出力結果を、指定した変数に代入してくれる。上記例の場合は、slappasswd -s manager(varsモジュールでrootPassをmanagerに指定している)の実行結果「{SSHA} ~」が出力されるので、それをolcrootpassに代入している。
※ここで注意することは、registerで得た文字列は40行「olcrootpass.stdout」と記述しているように、.stdoutをつけて使用すること。
lineinfile:(32行目)
指定したファイルの編集を行うモジュール。こちらもモジュール引数を説明する。
| モジュール引数 | 条件 | 説明 |
|---|---|---|
| dest= | 編集するファイルをフルパスで指定する。 | |
| line= | 「dest=」で指定したファイルに挿入する文字列を指定する。 | |
| state= | present | 「line=」で指定した文字列を、「dest=」で指定したファイルに挿入する。 もし「regexp=」で文字列を指定した場合は、「regexp=」で指定した文字列がある行が置換対象となり、「line=」で指定した文字列に行ごと置換される。「regexp=」で指定した文字列がファイルに存在しない場合は、「dest=」で指定したファイルの最後尾に挿入される。 |
| absent | 「regexp=」で指定した文字列に一致する行を削除する。一致しない場合は何も行わない。 削除したい行がなければ指定する必要なし。 |
|
| create= | yes | 「dest=」で指定したファイルが存在しない場合、そのファイルを作成し「line=」で指定した文字列を記述する。 |
| no | 「dest=」で指定したファイルが存在しなくても、ファイルを作成しない。その場合lineinfileモジュールが実行失敗となるので注意。 | |
| regexp= | 置換対象の文字列を指定する。state=presentの場合、「regexp=」で指定した文字列がある行を検索し、文字列があった場合は「line=」で指定した文字列に行ごと変換する。state=absentの場合は、「regexp=」で指定した文字列を行ごと削除する。 | |
| backup= | yes | ファイル編集の前に、「dest=」で指定したファイルと同じディレクトリにバックアップを保存するかどうかを指定する。「yes」を指定した場合、「<ファイル名>.[4~5桁の数字].YYYY-MM-DD@hh:mm:ss~」というファイル名でバックアップが保存される。バックアップしない場合は、「backup=」自体を記述しない。 |
| insertafter= | 「line=」で指定した文字列を、「insertafter=」で指定した文字列がある行の下に挿入する。その文字列がなかった場合は、ファイルの末尾に挿入される。 | |
| insertbefore= | 「line=」で指定した文字列を、「insertbefore=」で指定した文字列がある行の上に挿入する。その文字列がなかった場合は、ファイルの末尾に挿入される。 |
with_items:(36行目)
「item」と記述したところに入る文字列を指定する。文字列は複数指定することができる。
実はここでも行頭に「-」が記述されているが、yml形式においては、ひとつのモジュールに対して複数の処理を当てはめる場合にこのような記述になるらしい。
上記例でも「task:」の中に複数の「- name:」があるのと同じ考えといったところだろうか。
※※※注意点※※※
47~65行を見ると、echoコマンドで標準出力した結果をリダイレクト(>>)を使って一行ずつ書き足している。
lineinfileモジュールで気づいた方もいらっしゃるかもしれないが、
lineinfile:
dest=/root/ldif/change-domain.ldif
state=present
line="{{ item }}"
with_items:
- 'dn: olcDatabase={1}monitor,cn=config'
- 'changetype: modify'
- 'replace: olcAccess'
- 'olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=Manager,dc=abc,dc=def,dc=com" read by * none'
- '\'
- 'dn: olcDatabase={2}hdb,cn=config"'
- 'changetype: modify'
:
:
このように記述することもできるのでは?と思う人もいるかも。
with_itemsモジュールを使った場合、例えば「changetype: modify」のように同じ文字列の行を複数指定すると、最初の「changetype: modify」だけファイルに書き出され、それ以降の「changetype: modify」はansible実行上「ok:」となり、結果スキップされてしまうのだ。つまり、同じ文字列を複数指定すると、2つ目以降の文字列が入らないファイルが出来上がってしまうということだ。
(lineinfileモジュールを使ったやり方で同じ文字列を指定してもちゃんとファイルに書き出される方法を知っている人がいたら教えてほしい 汗)
そのため、あえてechoコマンドを羅列した原始的なやり方にしている。
■ansible-playbookコマンドでplaybookを実行
いよいよansibleの実行。コマンドは
# ansible-playbook <playbook名(フルパス)>
[root@ansible_sv ~]# ansible-playbook /etc/ansible/yml/2_rootDN.yml SSH password: PLAY [ldap_sv] **************************************************************************************************************************** TASK [Gathering Facts] ******************************************************************************************************************** ok: [192.168.3.6] TASK [copy DB_CONFIG] ********************************************************************************************************************* changed: [192.168.3.6] TASK [create ldif directory] ************************************************************************************************************** changed: [192.168.3.6] TASK [create rootPW] ********************************************************************************************************************** changed: [192.168.3.6] TASK [create olcRootPW] ******************************************************************************************************************* changed: [192.168.3.6] TASK [create rootPW.ldif] ***************************************************************************************************************** changed: [192.168.3.6] => (item=dn: olcDatabase={0}config,cn=config) changed: [192.168.3.6] => (item=changetype: modify) changed: [192.168.3.6] => (item=replace: olcRootPW) changed: [192.168.3.6] => (item=olcRootPW: {SSHA}mSRZEumk8O0Ets7TZE+tU9VLOj2o710p) TASK [execute ldapadd] ******************************************************************************************************************** changed: [192.168.3.6] TASK [create change-domain] ************************************************************************************************************* changed: [192.168.3.6] TASK [execute ldapmodify] ***************************************************************************************************************** changed: [192.168.3.6] PLAY RECAP ******************************************************************************************************************************** 192.168.3.6 : ok=9 changed=8 unreachable=0 failed=0 [root@ansible_sv ~]#
どうやらいけたみたい\(^o^)/
実行結果の説明はAnsibleでOpenLDAP環境構築 -①OpenLDAPサーバ関連のパッケージインストールを参照。slappasswdコマンドの出力結果「{SSHA}~」も無事に反映されていることが分かる。
■OpenLDAPサーバで事後確認
念のためansible-playbookコマンドで実行したplaybookの内容がOpenLDAPサーバにちゃんと反映されたか確認。
ここで事後確認するポイントは、playbookに沿って以下。
・/usr/share/openldap-servers/DB_CONFIG.exampleファイルが/var/lib/ldap/DB_CONFIGとしてコピーされていること。
・/root/ldifディレクトリが作成され、アクセス権限がroot:root(644)であること。
・rootPW.ldif、change-domain.ldifが/root/ldif配下に作成され、アクセス権限がroot:root(644)であること。
・rootPW.ldif、change-domain.ldifの内容がldapmodifyコマンドでちゃんと反映されていること。(ldapsearchコマンドで確認)
[root@ldapserver ~]# ls -l /var/lib/ldap/ 合計 324 -rw-r--r--. 1 root root 845 8月 4 23:23 DB_CONFIG -rw-------. 1 ldap ldap 262144 1月 20 23:33 __db.001 -rw-------. 1 ldap ldap 32768 1月 20 23:33 __db.002 -rw-------. 1 ldap ldap 49152 1月 20 23:33 __db.003 -rw-r--r--. 1 ldap ldap 2048 1月 18 23:00 alock -rw-------. 1 ldap ldap 8192 1月 18 23:00 dn2id.bdb -rw-------. 1 ldap ldap 32768 1月 18 23:00 id2entry.bdb -rw-------. 1 ldap ldap 10485760 1月 18 23:00 log.0000000001
[root@ldapserver ~]# ls -l /root
合計 4
-rw-------. 1 root root 1600 1月 17 05:18 anaconda-ks.cfg
drw-r--r--. 2 root root 51 1月 20 19:06 ldif
[root@ldapserver ~]# ls -l /root/ldif
合計 8
-rw-r--r--. 1 root root 569 1月 20 19:06 change-domain.ldif
-rw-r--r--. 1 root root 124 1月 20 19:06 rootPW.ldif
[root@ldapserver ~]# ldapsearch -LLL -Y EXTERNAL -H ldapi:/// -b 'olcDatabase={2}hdb,cn=config'
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
olcSuffix: dc=abc,dc=def,dc=com
olcRootDN: cn=Manager,dc=abc,dc=def,dc=com
olcRootPW: {SSHA}mSRZEumk8O0Ets7TZE+tU9VLOj2o710p
ベースDN、管理者DN、管理者パスワード
しっかり設定されてました!playbook成功!