Contenu connexe Similaire à OpenStack Study#9 JOSUG (20) Plus de Hideki Saito (20) OpenStack Study#9 JOSUG1. openstack
Open source software to build public and private clouds.
About OpenStack Identity (keystone)
Internet Initiative Japan Inc. / Japan OpenStack User Group
さいとうひでき (twitterid: @saito_hideki)
OpenStack Study #9
3. 目次
●
自己紹介
●
OpenStack Identity(keystone)について
●
keystoneの構造
●
認証・認可の仕組み
●
普通の利用方法
●
ちょっと変わった利用方法
●
まとめ
OpenStack Study #9
4. 自己紹介
●
なまえ:
– 齊藤 秀喜 (さいとう ひでき)
– TwitterId: @saito_hideki
●
しごと:
– クラウド関連のちょっとした開発
– クラウド関連のちょっとした運用
– クラウド関連のちょっとした火消しとかお詫び
●
しゅみ:
– OpenStack(嗜む程度)
OpenStack Study #9
7. 認証・認可の仕組み
実際に認証と認可の仕組みを追ってみる。キーワー
ドは以下の4つ。
●
ユーザID/パスワード
– 認証とトークンを取得するのに必要なユーザIDとパスワード
●
トークン
– 認証成功時に発行されるAPIアクセスに必須となる許可証
●
テナント
– 仮想リソースをグループ化したもの。ユーザは所属するテナントに対
して認可された操作権を持つ。
●
エンドポイント
– 指定テナント内でユーザに認可されたサービスとそのAPIのURL情報
OpenStack Study #9
9. 認証・認可の仕組み
Openstackのクライアントがendpointを取得する
動きをpythonスクリプトで再現してみる。
#!/usr/bin/env python
#-*- coding: utf-8 -*- get_token()
(1)ユーザID/パスワードからトークンを要求
from getpass import getpass
from httplib import HTTPConnection (2)トークン取得
Import json
user = raw_input("user: ")
password = getpass("password: ")
get_tenant()
session = HTTPConnection("%s:%s" % (HOST, PORT)) (3)権限を持つテナント情報を要求
auth_result = get_token(user, password, session)
(4)テナントリスト取得
token = auth_result['access']['token']['id']
tenant_result = get_tenant(token, session) get_endpoint()
(5)テナントに対するエンドポイント情報を要求
tenant = tenant_result["tenants"][0]["id"]
endpoint_result = get_endpoint(token, tenant, session) (6)認可されているエンドポイントリスト取得
session.close()
print "=" * 70
print json.dumps(auth_result, sort_keys=True, indent=2)
print "-" * 70
print json.dumps(tenant_result, sort_keys=True, indent=2)
OpenStack Study #9
10. 認証・認可の仕組み
(1)ユーザID/パスワードでトークンを要求
(2)トークン取得
接続先URLは
def get_token(user, password, session):
http://<host>:<port>/v2.0/tokens
token_path = "/v2.0/tokens"
header = { "Content-Type": "application/json" } リクエストヘッダでデータ形式をjson
に指定する。
request = '''
{
"auth": {
"passwordCredentials": { トークンを取得するAPIリクエストを
"username":"%s", 生成する。
"password":"%s"
}
}
}''' % (user, password) リクエスト送信!(POST)
session.request("POST", token_path, request, header)
keystone-allからトークンが返される。
return json.load(session.getresponse())
OpenStack Study #9
11. 認証・認可の仕組み
(1)ユーザID/パスワードでトークンを要求
(2)トークン取得
{
"access": {
keystone-allから返されるトークン
"serviceCatalog": {},
"token": { 情報。リクエスト時にjson形式を
"expires": "2012-11-18T05:23:51Z", 指定しているので形式は当然なが
"id": "84e9f54aef284bf6a8dc79699045ad99" らjson形式となっている。
},
"user": {
以降のリクエストでは、ヘッダに
"id": "d60717fe43e94c908bd9248b87d8e045",
"name": "foo", X-Auth-Token: トークンID
"roles": [],
"roles_links": [],
"username": "foo" を付加することにより認証された
} リクエストであること証明する。
}
}
OpenStack Study #9
12. 認証・認可の仕組み
(3)権限を持つテナント情報を要求
(4)テナントリスト取得
接続先URLは
def get_tenant(token, session):
http://<host>:<port>/v2.0/tenants
tenant_path = "/v2.0/tenants"
リクエストヘッダでデータ形式をjson
header = {
に指定するだけでなく、X-Auth-Token
"Content-Type": "application/json",
"X-Auth-Token": token, に取得済みのトークンIDを指定する。
}
session.request("GET", tenant_path, "", header) リクエスト送信!(GET)
return json.load(session.getresponse())
keystone-allからトークンが返される。
OpenStack Study #9
13. 認証・認可の仕組み
(3)権限を持つテナント情報を要求
(4)テナントリスト取得
{
keystone-allから返されるテナント
"tenants": [ 情報は、リストとなっているので
{ 注意。1つだけでも当然リストと
"description": "Default Tenant",
なる。
"enabled": true,
"id": "7695c8332c1b4450a6be1376b3a1f5c4", 次の段階のエンドポイントリスト
"name": "openstackDemo" を取得するには、このテナントID
} を利用する。
],
"tenants_links": []
}
OpenStack Study #9
14. 認証・認可の仕組み
(5)テナントに対するエンドポイント情報を要求
(6)認可されているエンドポイントリスト取得
def get_endpoint(token, tenant, session):
接続先URLは
token_path = "/v2.0/tokens" http://<host>:<port>/v2.0/tokens
header = {
"Content-Type": "application/json", リクエストヘッダでデータ形式をjson
"X-Auth-Token": token,
}
に指定するだけでなく、X-Auth-Token
に取得済みのトークンIDを指定する。
endpoint_request = '''
{
"auth": { 取得済みのトークンIDとテナントIDで
"token": {
"id":"%s" エンドポイント情報を取得するAPIリク
}, エストを生成する。
"tenantId": "%s"
}
}''' % (token, tenant)
リクエスト送信!(POST)
session.request(
"POST", "/v2.0/tokens" , endpoint_request, header)
keystone-allからトークンが返される。
return json.load(session.getresponse())
OpenStack Study #9
15. 認証・認可の仕組み
(5)テナントに対するエンドポイント情報を要求
(6)認可されているエンドポイントリスト取得
{
"access": {
<!-- 中略 -->
"serviceCatalog": [
{
"endpoints": [
{
"adminURL": "http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4",
"id": "48567a3d0f7a40fc9aa57172b9cc46e8",
"internalURL": "http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4",
"publicURL": "http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4",
"region": "RegionOne"
}
],
"endpoints_links": [],
"name": "nova",
"type": "compute" keystone-allから返されるエンドポイント
},
情報の中にnova/glanceなどのリソースを
<!-- 中略 -->
} 操作するためのAPIのURLが含まれる
OpenStack Study #9
16. keystoneの構造
●
本体: keystone-all
●
keystone-allの認証/認可用バックエンド
– KVS Backend
– SQL Backend REST API
– PAM Backend keystone-all
– Template Backend <keystone.conf内>
driver=keystone.identity.backends.*
– LDAP Backend
KVS SQL PAM Template LDAP
OpenStack Study #9
17. keystoneの構造
SQLバックエンドで見るkeystoneのデータ構造
mysql> show tables; ●
keystoneのSQLバックエンドデータベ
+------------------------+ ースのテーブル数はessex / folsom と
| Tables_in_keystone |
もに10個
+------------------------+ ●
migrate_versionテーブルに記録されて
| ec2_credential |
| endpoint | いるデータベースのバージョン情報は
| metadata | 上がっている。
| migrate_version | ●
essex : 1
| role | ●
folsom: 4
| service | ●
データ構造的に見ると変更箇所はtoken
| tenant | テーブルにvalidフィールドが追加と
| token | なったのみ。
| user | ●
tokenテーブルに発行されたtokenが延
| user_tenant_membership |
々と登録され続けていくんだけど...
+------------------------+
10 rows in set (0.00 sec) これ溢れないのかな?
OpenStack Study #9
20. ちょっと変わった利用方法
keystone認証させつつ、novaコマンドと同等の
動きをするpythonスクリプトを書いてみる。
例えばflavorのリスト取得。これが.....
$ export OS_USERNAME=foo keystone認証のための情報
$ export OS_PASSWORD=bar
$ export OS_TENANT_NAME=openstackDemo を環境変数に設定する。
$ export OS_AUTH_URL="http://172.16.100.14:5000/v2.0"
$ nova flavor-list
+----+------------+-----------+------+-----------+------+-------+-------------+
| ID | Name | Memory_MB | Disk | Ephemeral | Swap | VCPUs | RXTX_Factor |
+----+------------+-----------+------+-----------+------+-------+-------------+
| 1 | m1.tiny | 512 | 0 | 0 | | 1 | 1.0 |
| 2 | m1.small | 2048 | 10 | 20 | | 1 | 1.0 |
| 3 | m1.medium | 4096 | 10 | 40 | | 2 | 1.0 |
| 4 | m1.large | 8192 | 10 | 80 | | 4 | 1.0 |
| 5 | m1.xlarge | 16384 | 10 | 160 | | 8 | 1.0 |
| 6 | m1.minimal | 64 | 0 | 0 | | 1 | 1.0 |
+----+------------+-----------+------+-----------+------+-------+-------------+
OpenStack Study #9
21. ちょっと変わった利用方法
keystoneさえマスターすれば、こんな感じに
pythonでもワンライナーで簡単に書ける!
渾身のワンライナーでflavorリストを取得する
$ python -c 'from httplib import HTTPConnection as c;from json import load as
l;s=c("172.16.100.100:5000");s.request("POST","/v2.0/tokens","{"auth":
{"tenantName":"openstackDemo","passwordCredentials":{"username":"foo","password":"bar"}}}",{"Content-
Type":"application/json"});j=l(s.getresponse());s.close();tk=j["access"]["token"]["id"];tn=j["access"]
["serviceCatalog"][0]["endpoints"][0]["publicURL"].split("/")[-
1];s.close();s=c("172.16.100.100:8774");s.request("GET","/v2/%s/flavors"%tn,"",{"X-Auth-
Token":tk});j=l(s.getresponse());s.close();print [(x["id"],x["name"],x["links"][0]["href"]) for x in j["flavors"]]'
結果(なんかそれっぽい!)
[(u'1', u'm1.tiny', u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/flavors/1'), (u'2',
u'm1.small', u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/flavors/2'), (u'3', u'm1.medium',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/flavors/3'), (u'4', u'm1.large',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/flavors/4'), (u'5', u'm1.xlarge',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/flavors/5'), (u'6', u'm1.minimal',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/flavors/6')]
OpenStack Study #9
23. ちょっと変わった利用方法
もちろんpythonのワンライナーでも簡単。
渾身のワンライナーでimageリストを取得する
$ python -c 'from httplib import HTTPConnection as c;from json import load as
l;s=c("172.16.100.100:5000");s.request("POST","/v2.0/tokens","{"auth":
{"tenantName":"openstackDemo","passwordCredentials":{"username":"foo","password":"bar"}}}",{"Content-
Type":"application/json"});j=l(s.getresponse());s.close();tk=j["access"]["token"]["id"];tn=j["access"]
["serviceCatalog"][0]["endpoints"][0]["publicURL"].split("/")[-
1];s.close();s=c("172.16.100.100:8774");s.request("GET","/v2/%s/images"%tn,"",{"X-Auth-
Token":tk});j=l(s.getresponse());s.close();print [(x["id"],x["links"][0]["href"]) for x in j["images"]]'
結果(これまたなんとなく取れてる気がする!)
[(u'c9ef36c7-e6f4-414e-b603-257e36836e76',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/images/c9ef36c7-e6f4-414e-b603-257e36836e76'),
(u'1d51d35e-cd1f-4205-9e62-d249e439536b',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/images/1d51d35e-cd1f-4205-9e62-d249e439536b'),
(u'732ccc6c-093f-4ff3-88ec-d2c97df45014',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/images/732ccc6c-093f-4ff3-88ec-d2c97df45014')]
OpenStack Study #9
24. ちょっと変わった利用方法
UIなしでVMも作れます!
じゃぁじゃぁ...渾身のワンライナーでVMインスタンスを作成!
※このあたりでsessionって1回張ればいいじゃない?って気がつくけど面倒だからそのまま。
$ python -c 'from httplib import HTTPConnection as c;from json import load as
l;s=c("172.16.100.100:5000");s.request("POST","/v2.0/tokens","{"auth":
{"tenantName":"openstackDemo","passwordCredentials":{"username":"foo","password":"bar"}}}",{"Content-
Type":"application/json"});j=l(s.getresponse());s.close();tk=j["access"]["token"]["id"];tn=j["access"]
["serviceCatalog"][0]["endpoints"][0]["publicURL"].split("/")[-
1];s.close();s=c("172.16.100.100:8774");s.request("POST","/v2/%s/servers"%tn,"{"server":
{"name":"josug009","imageRef":"c9ef36c7-e6f4-414e-b603-
257e36836e76","flavorRef":"6","OS_DCF:diskConfig":"MANUAL"}}",{"Content-Type":"application/json","X-Auth-
Token":tk});j=l(s.getresponse());s.close();print j'
結果(おぉ!できた!のか!?)
{u'server': {u'links': [{u'href':
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/servers/2e81b265-0a33-416d-b60c-afc511395279',
u'rel': u'self'}, {u'href': u'http://172.16.100.100:8774/7695c8332c1b4450a6be1376b3a1f5c4/servers/2e81b265-0a33-
416d-b60c-afc511395279', u'rel': u'bookmark'}], u'OS-DCF:diskConfig': u'MANUAL', u'id': u'2e81b265-0a33-416d-b60c-
afc511395279', u'security_groups': [{u'name': u'default'}], u'adminPass': u'vhcq2X8G4eXz'}}
OpenStack Study #9
25. ちょっと変わった利用方法
VMインスタンスのリスト取得だってUI不要。
渾身のワンライナーでちょいちょいのドーンよ!
$ python -c 'from httplib import HTTPConnection as c;from json import load as
l;s=c("172.16.100.100:5000");s.request("POST","/v2.0/tokens","{"auth":
{"tenantName":"openstackDemo","passwordCredentials":{"username":"foo","password":"bar"}}}",{"Content-
Type":"application/json"});j=l(s.getresponse());s.close();tk=j["access"]["token"]["id"];tn=j["access"]
["serviceCatalog"][0]["endpoints"][0]["publicURL"].split("/")[-
1];s.close();s=c("172.16.100.100:8774");s.request("GET","/v2/%s/servers"%tn,"",{"X-Auth-
Token":tk});j=l(s.getresponse());s.close();print [(x["id"],x["name"],x["links"][0]["href"]) for x in j["servers"]]'
結果(できてるw)
[(u'2e81b265-0a33-416d-b60c-afc511395279', u'josug009',
u'http://172.16.100.100:8774/v2/7695c8332c1b4450a6be1376b3a1f5c4/servers/2e81b265-0a33-416d-b60c-afc511395279')]
OpenStack Study #9
26. まとめ
●
keystoneは本当に重要なサービスです。大嫌いでもダダをこねて
も逃げられません。
●
OpenStackの主要コンポーネントが共通の認証基盤として利用し
ています。各コンポーネント側にkeystoneを利用するための設定
が必要です。
●
keystoneは認証したアカウントにトークンを発行します。
●
各コンポーネントでkeystone認証を利用する場合、APIリクエス
トヘッダにはkeystoneが発行したトークンを”X-Auth-Token”とし
て付与する必要があります
●
ユーザはkeystoneから認可された操作のみ行うことができます。
OpenStack Study #9