openstack · openstack identity(keystone)について...
TRANSCRIPT
openstackOpen 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
本セッションの概要
OpenStackが提供する各コンポーネントが利用する認証基盤OpenStack Identity(keystone)の概要と認証・認可の仕組み、利用のされ方について紹介する約30分のセッションです。
OpenStack Study #9
目次
● 自己紹介● OpenStack Identity(keystone)について● keystoneの構造● 認証・認可の仕組み● 普通の利用方法● ちょっと変わった利用方法● まとめ
OpenStack Study #9
自己紹介● なまえ:
– 齊藤 秀喜 (さいとう ひでき)
– TwitterId: @saito_hideki
● しごと:
– クラウド関連のちょっとした開発– クラウド関連のちょっとした運用– クラウド関連のちょっとした火消しとかお詫び
● しゅみ:
– OpenStack(嗜む程度)
OpenStack Study #9
OpenStack Identity(keystone)について
OpenStackの各コンポーネントが利用する共通の認証基盤としてシステム全体に統合認証機能を提供しています。
OpenStackを利用する上では嫌でもダダをこねても避けて通ることはできない重要なサービスです。
OpenStack Study #9
goo辞書によると.... 1 《建築》(アーチ頂上の)かなめ石, くさび石.2 (組織の)中枢, 中心;(学説などの)根本原理.
OpenStack Identity(keystone)について
OpenStack Study #9
各コンポーネントとの相関図は以下のような感じ。コレは動かないと結構ヤバそう。
OpenStack Compute Administration Manualより転載
認証・認可の仕組み
OpenStack Study #9
実際に認証と認可の仕組みを追ってみる。キーワードは以下の4つ。● ユーザID/パスワード
– 認証とトークンを取得するのに必要なユーザIDとパスワード● トークン
– 認証成功時に発行されるAPIアクセスに必須となる許可証● テナント
– 仮想リソースをグループ化したもの。ユーザは所属するテナントに対して認可された操作権を持つ。
● エンドポイント– 指定テナント内でユーザに認可されたサービスとそのAPIのURL情報
認証・認可の仕組み
OpenStack Study #9
keystone-allはクライアントからのリクエスト(RESTベース)を処理することにより認証・認可を行う。POSTする情報はjsonまたはxml形式。
(1)ユーザID/パスワードでトークンを要求
(2)トークン
(3)権限を持つテナント情報を要求
(4)テナントリスト
(5)テナントに対するエンドポイント情報を要求
(6)認可されているエンドポイントリスト
client keystone-all
backend
認証・認可の仕組み
OpenStack Study #9
Openstackのクライアントがendpointを取得する動きをpythonスクリプトで再現してみる。#!/usr/bin/env python#-*- coding: utf-8 -*-
from getpass import getpassfrom httplib import HTTPConnectionImport json
user = raw_input("user: ")password = getpass("password: ")session = HTTPConnection("%s:%s" % (HOST, PORT))
auth_result = get_token(user, password, session)
token = auth_result['access']['token']['id']tenant_result = get_tenant(token, session)
tenant = tenant_result["tenants"][0]["id"]endpoint_result = get_endpoint(token, tenant, session)
session.close()
print "=" * 70print json.dumps(auth_result, sort_keys=True, indent=2)print "-" * 70print json.dumps(tenant_result, sort_keys=True, indent=2)
get_token()(1)ユーザID/パスワードからトークンを要求(2)トークン取得
get_tenant()(3)権限を持つテナント情報を要求(4)テナントリスト取得
get_endpoint()(5)テナントに対するエンドポイント情報を要求(6)認可されているエンドポイントリスト取得
認証・認可の仕組み
OpenStack Study #9
(1)ユーザID/パスワードでトークンを要求(2)トークン取得
def get_token(user, password, session):
token_path = "/v2.0/tokens"
header = { "Content-Type": "application/json" }
request = '''{ "auth": { "passwordCredentials": { "username":"%s", "password":"%s" } }}''' % (user, password)
session.request("POST", token_path, request, header)
return json.load(session.getresponse())
接続先URLはhttp://<host>:<port>/v2.0/tokens
リクエストヘッダでデータ形式をjsonに指定する。
トークンを取得するAPIリクエストを生成する。
リクエスト送信!(POST)
keystone-allからトークンが返される。
認証・認可の仕組み
OpenStack Study #9
(1)ユーザID/パスワードでトークンを要求(2)トークン取得
{ "access": { "serviceCatalog": {}, "token": { "expires": "2012-11-18T05:23:51Z", "id": "84e9f54aef284bf6a8dc79699045ad99" }, "user": { "id": "d60717fe43e94c908bd9248b87d8e045", "name": "foo", "roles": [], "roles_links": [], "username": "foo" } }}
keystone-allから返されるトークン情報。リクエスト時にjson形式を指定しているので形式は当然ながらjson形式となっている。以降のリクエストでは、ヘッダに
X-Auth-Token: トークン ID
を付加することにより認証されたリクエストであること証明する。
認証・認可の仕組み
OpenStack Study #9
(3)権限を持つテナント情報を要求(4)テナントリスト取得
接続先URLはhttp://<host>:<port>/v2.0/tenants
リクエストヘッダでデータ形式をjsonに指定するだけでなく、X-Auth-Tokenに取得済みのトークン IDを指定する。
def get_tenant(token, session):
tenant_path = "/v2.0/tenants"
header = { "Content-Type": "application/json", "X-Auth-Token": token, }
session.request("GET", tenant_path, "", header)
return json.load(session.getresponse())
リクエスト送信!(GET)
keystone-allからトークンが返される。
認証・認可の仕組み
OpenStack Study #9
(3)権限を持つテナント情報を要求(4)テナントリスト取得
keystone-allから返されるテナント情報は、リストとなっているので注意。1つだけでも当然リストとなる。次の段階のエンドポイントリストを取得するには、このテナント IDを利用する。
{ "tenants": [ { "description": "Default Tenant", "enabled": true, "id": "7695c8332c1b4450a6be1376b3a1f5c4", "name": "openstackDemo" } ], "tenants_links": []}
認証・認可の仕組み
OpenStack Study #9
(5)テナントに対するエンドポイント情報を要求(6)認可されているエンドポイントリスト取得def get_endpoint(token, tenant, session):
token_path = "/v2.0/tokens"
header = { "Content-Type": "application/json", "X-Auth-Token": token, }
endpoint_request = '''{ "auth": { "token": { "id":"%s" }, "tenantId": "%s" }}''' % (token, tenant)
session.request( "POST", "/v2.0/tokens" , endpoint_request, header)
return json.load(session.getresponse())
接続先URLはhttp://<host>:<port>/v2.0/tokens
リクエストヘッダでデータ形式をjsonに指定するだけでなく、X-Auth-Tokenに取得済みのトークン IDを指定する。
取得済みのトークンIDとテナントIDでエンドポイント情報を取得するAPIリクエストを生成する。
リクエスト送信!(POST)
keystone-allからトークンが返される。
認証・認可の仕組み
OpenStack Study #9
(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が含まれる
keystoneの構造● 本体: keystone-all
● keystone-allの認証/認可用バックエンド – KVS Backend
– SQL Backend
– PAM Backend
– Template Backend
– LDAP Backend
OpenStack Study #9
<keystone.conf内>driver=keystone.identity.backends.*
REST API
keystone-all
KVS SQL PAM Template LDAP
keystoneの構造
OpenStack Study #9
mysql> show tables;+------------------------+| Tables_in_keystone |+------------------------+| ec2_credential || endpoint || metadata || migrate_version || role || service || tenant || token || user || user_tenant_membership |+------------------------+10 rows in set (0.00 sec)
SQLバックエンドで見るkeystoneのデータ構造● keystoneのSQLバックエンドデータベ
ースのテーブル数はessex / folsom ともに10個
● migrate_versionテーブルに記録されているデータベースのバージョン情報は上がっている。
● essex : 1● folsom: 4
● データ構造的に見ると変更箇所はtokenテーブルにvalidフィールドが追加となったのみ。
● tokenテーブルに発行されたtokenが延々と登録され続けていくんだけど...これ溢れないのかな?
普通の利用方法
OpenStack Study #9
それぞれのコンポーネントでkeystoneを利用するための設定が必要。
1. keystone自身の設定2. novaからkeystoneを利用するための設定3. glanceからkeystoneを利用するための設定
ココを参考に設定してください!
http://d.hatena.ne.jp/pyde/20121111/
普通の利用方法
OpenStack Study #9
keystoneコマンドを利用して初期情報を登録します。
1. テナントの登録2. ユーザの登録3. ロールの登録4. テナント・ユーザ・ロールの関連付け5. ec2互換APIを利用する場合はec2クレデンシャルを登録
ココを参考にして作ってください!
http://aikotobaha.blogspot.jp/2012/04/openstackessex-configuration-02keystone.html
ちょっと変わった利用方法
OpenStack Study #9
$ export OS_USERNAME=foo$ 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 |+----+------------+-----------+------+-----------+------+-------+-------------+
keystone認証させつつ、novaコマンドと同等の動きをするpythonスクリプトを書いてみる。例えばflavorのリスト取得。これが.....
keystone認証のための情報を環境変数に設定する。
ちょっと変わった利用方法
OpenStack Study #9
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
続いて、OSイメージのリストも取得してみる。先ほど既に環境変数としてkeystone認証に必要となる情報を設定しているのでnovaコマンドで取得できる。
$ nova image-list+--------------------------------------+-------------------+--------+--------+| ID | Name | Status | Server |+--------------------------------------+-------------------+--------+--------+| c9ef36c7-e6f4-414e-b603-257e36836e76 | tty-linux | ACTIVE | || 732ccc6c-093f-4ff3-88ec-d2c97df45014 | tty-linux-kernel | ACTIVE | || 1d51d35e-cd1f-4205-9e62-d249e439536b | tty-linux-ramdisk | ACTIVE | |+--------------------------------------+-------------------+--------+--------+
ちょっと変わった利用方法
OpenStack Study #9
もちろん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
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
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')]
まとめ● keystoneは本当に重要なサービスです。大嫌いでもダダをこねて
も逃げられません。● OpenStackの主要コンポーネントが共通の認証基盤として利用し
ています。各コンポーネント側にkeystoneを利用するための設定が必要です。
● keystoneは認証したアカウントにトークンを発行します。● 各コンポーネントでkeystone認証を利用する場合、APIリクエス
トヘッダにはkeystoneが発行したトークンを”X-Auth-Token”として付与する必要があります
● ユーザはkeystoneから認可された操作のみ行うことができます。
OpenStack Study #9
OpenStack Study #9
ご清聴ありがとうございました