Quantum周りのたった1つの問題に1週間以上ハマって絶望するも、
絞りだすような勘で生還してブログ再開!!
今回はなんとっ!KeystoneデータをLDAPで管理するという一風変わった情報をお届けします!
どうしてわざわざLDAPにしたのか、というと、
まず、既にLDAPが存在し、他の複数のソフトウェアのアカウント管理に用いていたため、OpenStackも同様に既存のLDAPユーザでログインしたかった、というのが1つ。
次に、LDAPユーザから削除された(例えば退職したとか)場合に、そのユーザが管理していたVMを自動的に(もしくは一括して)削除できるようにするこ とで、VMをより管理しやすくしたかったから。Horizonの表示上は見えませんが、実は novadb.instances テーブルには user_id が保存されているし、nova-manage vm list でも確認できるので、実現することは容易いです。
ということで、ユーザデータだけは既存LDAPのデータを使用し、それ以外のテナントやロールは新規に作成。さらに、一部を除いてデータ管理は keystone コマンドではなく、LDAP Account Manager(LAM)で行うというルールの元に構築していっています。
テストデータとなる slapd をControllerNodeにでも作成します。
apt-get install slapd ldap-utils |
設定は以下のようにしています。
組織DNS : openstack.org
バックエンド : HDB
DN管理者 : admin / rootpass
dpkg-reconfigure slapd # データ確認slapcat | less |
パスワードのSSHAを取得し、設定ファイルに利用します。
slappasswd{SSHA}PNof4WRW8ckd7bWQRfof1CVmgeQ14B09 |
設定ファイルを作成します。
include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/inetorgperson.schema include /etc/ldap/schema/nis.schema pidfile /var/run/slapd/slapd.pid argsfile /var/run/slapd/slapd.args loglevel 0 modulepath /usr/lib/ldap moduleload back_hdb tool-threads 1 backend hdb database hdb suffix "dc=openstack,dc=org" rootdn "cn=admin,dc=openstack,dc=org" rootpw {SSHA}PNof4WRW8ckd7bWQRfof1CVmgeQ14B09 directory /var/lib/ldap |
今回は slapd.conf で設定したため、slapd.d はどけておく必要があります。
mv /etc/ldap/slapd.d /etc/ldap/__slapd.d~orig |
Keystone+LDAPが必要としている項目 enabled をスキーマに追加します。
編集対象が core.schema なのが心苦しいですが、仕方ありません。
(参考)Re: [Keystone] Creating tenant failed when using ldap as identity backend: ‘attribute type undefined’
# 追加 360行目あたり attributetype ( 2.5.4.66 NAME 'enabled' DESC 'RFC2256: enabled of a group' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) # 変更 443行目あたり objectclass ( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of names (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description $ enabled ) ) # MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) ) |
これは好みで設定しておきます。
set_cachesize 0 268435456 2 set_flags DB_TXN_NOSYNC set_lg_regionmax 20971520 set_lg_max 10485760 set_lg_bsize 524288 set_lk_max_objects 5000 set_lk_max_locks 5000 set_lk_max_lockers 5000 |
設定したら再起動します。
/etc/init.d/slapd restart |
必要な ou を入れます。
domains はGrizzlyから必要になっています。
全て同じ階層に作成していますが、users だけ別の階層にしたりしても、問題なく動作します。
usersのみ既存データを想定しているので、実際は、わかりやすくするためにusers以外は1つdc階層を下げました
suffix を別にすることは slapd において可能ではありますが、1つのLAMで管理できなくなるので不採用にしています
dn: ou=groups,dc=openstack,dc=org objectClass: top objectClass: organizationalUnit ou: groups dn: ou=users,dc=openstack,dc=org objectClass: top objectClass: organizationalUnit ou: users dn: ou=roles,dc=openstack,dc=org objectClass: top objectClass: organizationalUnit ou: roles dn: ou=machines,dc=openstack,dc=org objectClass: top objectClass: organizationalUnit ou: machines dn: ou=domains,dc=openstack,dc=org objectClass: top objectClass: organizationalUnit ou: domains |
LDIFを作成したら、追加します。
ldapadd -h localhost -x -D "cn=admin,dc=openstack,dc=org" -W -f /etc/keystone/openstack.ldif # データの確認slapcat | lessldapsearch -x -LLL -h localhost -p 389 -b dc=openstack,dc=org | less |
apt-get install ldap-account-manager cronolog |
管理ユーザ や OU を編集します。
# slapdの管理ユーザ serverURL: ldap://localhost:389 admins: cn=admin,dc=openstack,dc=org passwd: {SSHA}PNof4WRW8ckd7bWQRfof1CVmgeQ14B09 treesuffix: dc=openstack,dc=org # 表示言語 defaultLanguage: ja_JP.utf8:UTF-8:日本語 (日本) # ユーザ/グループIDの最小値変更してみたり modules: posixAccount_minUID: 5000 modules: posixGroup_minGID: 5000 # 基本OUのsuffixを変更 types: suffix_user: ou=users,dc=openstack,dc=org types: suffix_group: ou=groups,dc=openstack,dc=org types: suffix_host: ou=machines,dc=openstack,dc=org types: suffix_smbDomain: dc=openstack,dc=org |
ログ排除条件を指定して、
SetEnvIf Request_URI \.(gif|jpg|png|js|css|ida|exe)$ no_log |
元のサイト設定を削除して
rm /etc/apache2/conf.d/ldap-account-manager |
VirtualHostでちゃんと指定しておきます。(※プライベートDNSに追加できれば)
<VirtualHost *:80> ServerName ldap.openstack.org CustomLog "|/usr/bin/cronolog /var/log/apache2/lam/access/%Y%m/%Y%m.log" combined env=!no_log ErrorLog "|/usr/bin/cronolog /var/log/apache2/lam/error/%Y%m/%Y%m.log" Alias /lam /usr/share/ldap-account-manager <Directory /usr/share/ldap-account-manager> Options +FollowSymLinks AllowOverride All Order allow,deny Allow from all DirectoryIndex index.html </Directory> <Directory /var/lib/ldap-account-manager/tmp> Options -Indexes </Directory> <Directory /var/lib/ldap-account-manager/tmp/internal> Options -Indexes Order allow,deny Deny from all </Directory> <Directory /var/lib/ldap-account-manager/sess> Options -Indexes Order allow,deny Deny from all </Directory> <Directory /var/lib/ldap-account-manager/config> Options -Indexes Order allow,deny Deny from all </Directory> <Directory /usr/share/ldap-account-manager/lib> Options -Indexes Order allow,deny Deny from all </Directory> <Directory /usr/share/ldap-account-manager/help> Options -Indexes Order allow,deny Deny from all </Directory> <Directory /usr/share/ldap-account-manager/locale> Options -Indexes Order allow,deny Deny from all </Directory> </VirtualHost> |
他、security系とか好みで編集したら、
設定を有効にしてリロードします。
a2ensite lamapache2ctl configtest/etc/init.d/apache2 reload |
LAMにアクセスしてみます。
http://ldap.openstack.org/lam/
LAMでOpenStack管理ユーザと、一般ユーザのグループ/ユーザを作成しておきます。
openstack:10000 グループを作る
OpenStackAdmin:10000、パスワード:root、openstackグループ所属、業種:default でユーザを作る
member:10001、パスワード:member、openstackグループ所属、業種:default でユーザを作る
『業種』は businessCategory の項目となっています
既存ユーザデータに小文字の admin を混ぜるのが嫌だったので OpenStackAdmin を管理者にしています
さらにLAMでdefaultドメインを作成しておきます。
domains の子エントリを作成
デフォルト -> groupOfNames
RDN:cn, cn=default, member:uid=OpenStackAdmin,ou=users,dc=openstack,dc=org
usersデータの businessCategory と紐付いたデータです
お互いの default が一致していないとアカウントは有効になりません
keystone.conf をLDAP仕様に変更します。
設定は関連部のみ、それとメモを書いておきます。
[identity] driver = keystone.identity.backends.ldap.Identity [ldap] url = ldap://192.168.0.11 user = cn=admin,dc=openstack,dc=org password = rootpass #user = uid=OpenStackAdmin,ou=users,dc=drecom,dc=co,dc=jp #password = adminpass suffix = dc=openstack,dc=org use_dumb_member = True dumb_member = cn=dumb,dc=nonexistent allow_subtree_delete = False query_scope = one page_size = 0 alias_dereferencing = default user_tree_dn = ou=users,dc=openstack,dc=org user_objectclass = inetOrgPerson user_filter = user_id_attribute = uid user_name_attribute = cn user_mail_attribute = mail user_pass_attribute = userPassword user_domain_id_attribute = businessCategory user_enabled_attribute = enabled user_enabled_mask = 0 user_enabled_default = True user_attribute_ignore = tenant_id,tenants user_allow_create = False user_allow_update = False user_allow_delete = False user_enabled_emulation = False user_enabled_emulation_dn = tenant_tree_dn = ou=groups,dc=openstack,dc=org tenant_objectclass = groupOfNames tenant_filter = tenant_id_attribute = cn tenant_name_attribute = ou tenant_member_attribute = member tenant_desc_attribute = description tenant_enabled_attribute = enabled tenant_domain_id_attribute = businessCategory tenant_attribute_ignore = tenant_allow_create = True tenant_allow_update = True tenant_allow_delete = True tenant_enabled_emulation = False tenant_enabled_emulation_dn = role_tree_dn = ou=roles,dc=openstack,dc=org role_objectclass = organizationalRole role_filter = role_id_attribute = cn role_name_attribute = ou role_member_attribute = roleOccupant role_attribute_ignore = role_allow_create = True role_allow_update = True role_allow_delete = True domain_tree_dn = ou=domains,dc=openstack,dc=org domain_filter = domain_objectclass = groupOfNames domain_id_attribute = cn domain_name_attribute = ou domain_member_attribute = member domain_desc_attribute = description domain_enabled_attribute = enabled domain_attribute_ignore = domain_allow_create = True domain_allow_update = True domain_allow_delete = True domain_enabled_emulation = False domain_enabled_emulation_dn = |
編集したら再起動します。
/etc/init.d/keystone restart |
LDAPの管理者権限は、プロジェクトやロール操作をする時だけ記述して、通常時はOpenStack管理者ユーザにでもして読み込み権限だけにしておく(ポリシー次第)
user_objectclass = person にしたら内部でobjectClassがperson,personで重複してエラーになる
Grizzlyでは description の値のデフォが desc になっているので明示的に設定する
use_dumb_member = True でないと tenant-create ができないので dumb_member とともに設定する
dumb_member は roleOccupant に仮で入るデータなので値はなんでもよい
user_name_attribute は cn が理想だが、日本語だと取得の際にエラーになるので、その場合は uid にでもする
user_enabled_attribute のために enabled を core.schema に入れたが、入れずに済む方法を探しても、他にちょうどよいboolean型が無いため無理っぽかった
domain関連はGrizzlyから必要になった
プロジェクトなど最初必要なものを追加していきます。
初めて追加する時は、LAMのツリービューを見ながらやるとデータの所在がわかってよいです。
TENANT_NAME=admin keystone tenant-create --name=$TENANT_NAMEkeystone tenant-list |
外道運用ルールでは keystone user-create はせず、LAM上での作成とするため実際にはコマンドは不要ですが、動作確認のために書いておきます。
LAMでは businessCategory : default 属性の追加が必要。LAMの表示上は”業種”
USER_NAME=OpenStackAdmin keystone user-create \ --tenant-id $(keystone tenant-list | grep " $TENANT_NAME " | awk '{print $2}') \ --name $USER_NAME --pass adminpass --email [email protected] --enabled truekeystone user-list |
管理者と一般ユーザ用のロールを追加しておきます。
admin, KeystoneAdmin, KeystoneServiceAdmin はソース直書きの固定管理者用ロールです
それ以外の一般ユーザが必要なので Member を作成しておきます
policy.json はいったんそのままで、別記事で書きます
keystone role-create --name="admin"keystone role-create --name="KeystoneAdmin"keystone role-create --name="KeystoneServiceAdmin"keystone role-create --name="Member"keystone role-list |
管理者ユーザを全ての固定管理ロールに入れておきます。
keystone user-role-add \ --tenant-id $(keystone tenant-list | grep " $TENANT_NAME " | awk '{print $2}') \ --user-id $(keystone user-list | grep " $USER_NAME " | awk '{print $2}') \ --role-id $(keystone role-list | grep " admin " | awk '{print $2}') keystone user-role-add \ --tenant-id $(keystone tenant-list | grep " $TENANT_NAME " | awk '{print $2}') \ --user-id $(keystone user-list | grep " $USER_NAME " | awk '{print $2}') \ --role-id $(keystone role-list | grep " KeystoneAdmin " | awk '{print $2}') keystone user-role-add \ --tenant-id $(keystone tenant-list | grep " $TENANT_NAME " | awk '{print $2}') \ --user-id $(keystone user-list | grep " $USER_NAME " | awk '{print $2}') \ --role-id $(keystone role-list | grep " KeystoneServiceAdmin" | awk '{print $2}') |
# 全データslapcat | less # 動作確認。取得できなかったら見直しcurl -d '{"auth": {"tenantName": "admin", "passwordCredentials":{"username": "OpenStackAdmin", "password": "rootpass" }}}' \ -H "Content-type:application/json" http://192.168.0.11:35357/v2.0/tokens \ | python -mjson.tool | less |
基本的に admin プロジェクトはネットワーク設定やスナップショット編集などをするためのものにして普段は放置し、2つ目以降のプロジェクトをガリガリ使うようにしています。
# プロジェクト追加TENANT_NAME=testkeystone tenant-create --name=$TENANT_NAME # ユーザ名定義だけ。実際の追加はLAMでUSER_NAME=member # ユーザロールに追加ROLE_NAME=Member keystone user-role-add \ --tenant-id $(keystone tenant-list | grep " $TENANT_NAME " | awk '{print $2}') \ --user-id $(keystone user-list | grep " $USER_NAME " | awk '{print $2}') \ --role-id $(keystone role-list | grep " $ROLE_NAME " | awk '{print $2}') # 確認keystone tenant-list keystone user-list curl -d '{"auth": {"tenantName": "test", "passwordCredentials":{"username": "member", "password": "memberpass" }}}' \ -H "Content-type:application/json" http://192.168.0.11:35357/v2.0/tokens \ | python -mjson.tool | less |
LAMでユーザを追加したら、OpenStackでも認証できるように、手動で user-role のデータを追加する必要があります。
ツリービューの ou=groups を選択
testプロジェクトのcnを選択
Memberロールのcnを選択
roleOccupant にユーザの uid を追加
LDAPのデータをKeystoneでも有効にするには、ユーザのbusinessCategoryにdefaultが入っていて、かつ、上記 user-role データが存在する必要があります。それ以外のユーザは OpenStack を触ることができない、ということです。
色々終わったら、LDAPユーザを切り替えておきます。
さきほども書きましたが、これはお好みで、私はできるだけLDAP管理者権限を撒き散らしたくないのでパスワードを消しておき、読み込みのみでKeystoneで利用するようにしています。
[ldap] url = ldap://192.168.0.11 #user = cn=admin,dc=openstack,dc=org user = uid=OpenStackAdmin,ou=users,dc=openstack,dc=org password = adminpass |
編集したら再起動します。
/etc/init.d/keystone restart |
LDAPをそこそこ知らないと厳しい設定かもしれませんが、やってみると意外に悪くなく、特に問題なく運用できています。
ただ、FolsomからGrizzlyにするとスキーマが変わって古いデータは使えなかったりしたので、その辺の対応は覚悟しておく必要がありそうです。