めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

KeystoneのUnscoped TokenとScoped Tokenの違い

何の話かというと

ここの説明にあるように、Keystoneが発行するトークンには、「Unscoped Token」と「Scoped Token」があります。

流れとしては、最初に、UserID/Password認証で「Unscoped Token」を取得して、その後は、Unscoped Tokenを使って、自分のテナント情報を取得して、さらに、Unscoped Tokenを使って、該当テナントのサービスを利用するための「Scoped Token」を取得します。

この流れに沿って、Scoped Tokenを取得するまでの処理をPythonで書いて見ました。

tokentest.py

#!/usr/bin/python

import re, json
from httplib import HTTPConnection

username = "demo_user"
password = "xxxxxxxxx"
keystone = "http://xx.xx.xx.xx:5000/v2.0"

def get_unscoped_token():
    u = re.match(r"^(http|https)://([^/]*)(/.*)$", keystone).groups()
    conn = HTTPConnection(u[1])
    header = {"Content-Type":"application/json"}
    request = """
{
  "auth":{
    "passwordCredentials":{
      "username":"%s",
      "password":"%s"
    }
  }
}""" % (username, password)

    print "Header:%s" % header
    print "Request:%s" % request
    conn.request("POST", u[2]+"/tokens", request, header)
    print "\nResponce:"
    print json.dumps(json.load(conn.getresponse()), indent=2)
    conn.close()

def get_tenants(id):
    u = re.match(r"^(http|https)://([^/]*)(/.*)$", keystone).groups()
    conn = HTTPConnection(u[1])
    header = {"X-Auth-Token":"%s" % id, "Content-Type":"application/json"}

    print "Header:%s" % header
    conn.request("GET", u[2]+"/tenants", None, header)
    print "\nResponce:"
    print json.dumps(json.load(conn.getresponse()), indent=2)
    conn.close()

def get_scoped_token(tenant, id):
    u = re.match(r"^(http|https)://([^/]*)(/.*)$", keystone).groups()
    conn = HTTPConnection(u[1])
    header = {"Content-Type":"application/json"}
    request = """
{
  "auth":{
    "tenantName":"%s",
    "token":{
      "id":"%s"
    }
  }
}""" % (tenant, id)

    print "Header:%s" % header
    print "Request:%s" % request
    conn.request("POST", u[2]+"/tokens", request, header)
    print "\nResponce:"
    print json.dumps(json.load(conn.getresponse()), indent=2)
    conn.close()

if __name__ == '__main__':
    get_unscoped_token()
    id = raw_input('\ntoke id: ')
    get_tenants(id)
    tenant = raw_input('\ntenant name: ')
    get_scoped_token(tenant, id)

実行例はこんな感じです。最初に、UserID/passwordでUnscoped Tokenを取得します。

# ./tokentest.py 
Header:{'Content-Type': 'application/json'}
Request:
{
  "auth":{
    "passwordCredentials":{
      "username":"demo_user",
      "password":"xxxxxxxx"
    }
  }
}

Responce:
{
  "access": {
    "token": {
      "issued_at": "2013-11-21T08:36:25.921898", 
      "expires": "2013-11-22T08:36:25Z", 
      "id": "149226c5f191445b90d7bb45925ed9f1"    ←Unscoped TokenのID
    }, 
    "serviceCatalog": [], 
    "user": {
      "username": "demo_user", 
      "roles_links": [], 
      "id": "44be5165fdf64bd5907d07aa1aaa5dab", 
      "roles": [], 
      "name": "demo_user"
    }, 
    "metadata": {
      "is_admin": 0, 
      "roles": []
    }
  }
}

Unscoped TokenのIDを入力して、テナント情報を取得します。

toke id: 149226c5f191445b90d7bb45925ed9f1
Header:{'Content-Type': 'application/json', 'X-Auth-Token': '149226c5f191445b90d7bb45925ed9f1'}

Responce:
{
  "tenants": [
    {
      "enabled": true, 
      "description": "", 
      "name": "production", 
      "id": "ee18bc8d37184ed0b013cd612c92f45a"
    }, 
    {
      "enabled": true, 
      "description": "", 
      "name": "demo", 
      "id": "f057a8457a8144b48fded7e6ba644e92"
    }
  ], 
  "tenants_links": []
}

「demo」「production」の2つのテナントに属していることが分かります。最後にテナント名を入力して、Scoped Tokenを取得します。

tenant name: demo
Header:{'Content-Type': 'application/json'}
Request:
{
  "auth":{
    "tenantName":"demo",
    "token":{
      "id":"149226c5f191445b90d7bb45925ed9f1"
    }
  }
}

Responce:
{
  "access": {
    "token": {
      "issued_at": "2013-11-21T08:36:33.995777", 
      "expires": "2013-11-22T08:36:25Z", 
      "id": "8312676d28b546d0b801b7b44dfdf70f",   ← Scoped TokenのID
      "tenant": {
        "enabled": true, 
        "description": "", 
        "name": "demo", 
        "id": "f057a8457a8144b48fded7e6ba644e92"
      }
    }, 
    "serviceCatalog": [
      {
        "endpoints_links": [], 
        "endpoints": [
          {
            "adminURL": "http://10.64.200.97:8774/v2/f057a8457a8144b48fded7e6ba644e92", 
            "region": "RegionOne", 
            "publicURL": "http://10.64.200.97:8774/v2/f057a8457a8144b48fded7e6ba644e92", 
            "internalURL": "http://10.64.200.97:8774/v2/f057a8457a8144b48fded7e6ba644e92", 
            "id": "9aed292e70e9468499dd6c77e7a258f3"
          }
        ], 
        "type": "compute", 
        "name": "nova"
      }, 
      {
        "endpoints_links": [], 
        "endpoints": [
          {
            "adminURL": "http://10.64.200.97:9696/", 
            "region": "RegionOne", 
            "publicURL": "http://10.64.200.97:9696/", 
            "internalURL": "http://10.64.200.97:9696/", 
            "id": "6f3ba4ff43df4a44aad80756cad4d23a"
          }
        ], 
        "type": "network", 
        "name": "quantum"
      }, 
      {
        "endpoints_links": [], 
        "endpoints": [
          {
            "adminURL": "http://10.64.200.97:9292", 
            "region": "RegionOne", 
            "publicURL": "http://10.64.200.97:9292", 
            "internalURL": "http://10.64.200.97:9292", 
            "id": "2dd545884c9144778ffdcff5d3447b8f"
          }
        ], 
        "type": "image", 
        "name": "glance"
      }, 
      {
        "endpoints_links": [], 
        "endpoints": [
          {
            "adminURL": "http://10.64.200.97:8776/v1/f057a8457a8144b48fded7e6ba644e92", 
            "region": "RegionOne", 
            "publicURL": "http://10.64.200.97:8776/v1/f057a8457a8144b48fded7e6ba644e92", 
            "internalURL": "http://10.64.200.97:8776/v1/f057a8457a8144b48fded7e6ba644e92", 
            "id": "4ae8335bb0054fb9a20009ddc03302f6"
          }
        ], 
        "type": "volume", 
        "name": "cinder"
      }, 
      {
        "endpoints_links": [], 
        "endpoints": [
          {
            "adminURL": "http://10.64.200.97:8773/services/Admin", 
            "region": "RegionOne", 
            "publicURL": "http://10.64.200.97:8773/services/Cloud", 
            "internalURL": "http://10.64.200.97:8773/services/Cloud", 
            "id": "710312d624d546f8ab9fc30e224167c5"
          }
        ], 
        "type": "ec2", 
        "name": "nova_ec2"
      }, 
      {
        "endpoints_links": [], 
        "endpoints": [
          {
            "adminURL": "http://10.64.200.97:35357/v2.0", 
            "region": "RegionOne", 
            "publicURL": "http://10.64.200.97:5000/v2.0", 
            "internalURL": "http://10.64.200.97:5000/v2.0", 
            "id": "32b37f27c01a47a6ae79411f2c160e39"
          }
        ], 
        "type": "identity", 
        "name": "keystone"
      }
    ], 
    "user": {
      "username": "demo_user", 
      "roles_links": [], 
      "id": "44be5165fdf64bd5907d07aa1aaa5dab", 
      "roles": [
        {
          "name": "Member"
        }
      ], 
      "name": "demo_user"
    }, 
    "metadata": {
      "is_admin": 0, 
      "roles": [
        "08b79ba58e2b497cae98e38600aff847"
      ]
    }
  }
}

Scoped TokenのIDと併せて、サービスエンドポイントの情報が返ってくるので、あとは、Scoped Tokenを使ってエンドポイントにリクエストを投げればOKです。