AnsibleでOpenLDAP環境構築 -②管理者DNの設定

投稿者: | 2018年1月25日

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成功!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA