togatttiのエンジニアメモ

過度な期待はしないでください.

OpenStack Keystoneで、Designateを認証する

Designateは、既にインストールされていることを前提とする。

OpenStack Designate を試す : あかぎメモ

ちなみに、これで、Designate の仮装環境を用意した。

ここで紹介すること

  • KeyStone セットアップ
  • テナント登録
  • DesignateへのKeystone設定
  • Keystoneを使った認証デモ

OSは、Ubuntu14.04を使う。

Keystone セットアップ

インストール
# apt-get -y update 
# apt-get -y install keystone
データベース、ユーザ作成

データベースは、MariaDBを使う。

# mysql -uroot -e "CREATE DATABASE keystone;"
# mysql -uroot -e "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY 'keystone';"
# mysql -uroot -e "GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY 'keystone';"
管理トークン発行
# openssl rand -hex 10
b5fca4a6d7e3ba1d69ac
設定ファイル変更

管理トークン、データベース、ログディレクトリ情報を追記する。

# diff -u /etc/keystone.conf.sample /etc/keystone/keystone.conf
--- /etc/keystone.conf.sample    2016-01-14 16:59:04.665864893 +0900
+++ /etc/keystone.conf  2016-01-15 10:58:45.350297815 +0900
@@ -10,6 +10,7 @@
 # paste application pipelines (for example, in keystone-paste.ini). (string
 # value)
 #admin_token = ADMIN
+admin_token = b5fca4a6d7e3ba1d69ac

 # The base public endpoint URL for Keystone that is advertised to clients
 # (NOTE: this does NOT affect how Keystone listens for connections). Defaults
@@ -141,6 +142,7 @@
 # is ignored if log_config_append is set. (string value)
 # Deprecated group/name - [DEFAULT]/logdir
 #log_dir = <None>
+log_dir = /var/log/keystone

 # (Optional) Uses logging handler designed to watch file system. When log file
 # is moved or removed this handler will open a new log file with specified path
@@ -560,6 +562,7 @@
 # Deprecated group/name - [DATABASE]/sql_connection
 # Deprecated group/name - [sql]/connection
 #connection = <None>
+connection = mysql://keystone:keystone@127.0.0.1/keystone

 # The SQLAlchemy connection string to use to connect to the slave database.
 # (string value)
ログディレクトリ作成
# mkdir /var/log/keystone
# chown keystone:keystone /var/log/keystone
テーブル作成
# keystone-manage db_sync
起動
# service keystone restart
keystone stop/waiting
keystone start/running, process 7461

エンドポイントにアクセスできていれば、正しく起動している。

$ curl -s http://127.0.0.1:5000/v2.0
{"version": {"status": "stable", "updated": "2014-04-17T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}, {"base": "application/xml", "type": "application/vnd.openstack.identity-v2.0+xml"}], "id": "v2.0", "links": [{"href": "http://127.0.0.1:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/content/", "type": "text/html", "rel": "describedby"}, {"href": "http://docs.openstack.org/api/openstack-identity-service/2.0/identity-dev-guide-2.0.pdf", "type": "application/pdf", "rel": "describedby"}]}}

Keystone へテナント、ユーザ、ロール作成

python-keyclientを使用する。

python-keyclient インストール
# git clone https://github.com/openstack/python-keystoneclient.git
# cd ~/python-keystoneclient
# python install -r requirements.txt
Keystoneにテナントやユーザ、ロールを作成するPython スクリプト

Designateのエンドポイント http://10.200.19.40:9001/v1 に対して、

DNSaasというテナントを作成する。

adminUserというユーザに対して、パスワードは、secretwordでユーザ作成する。

#!/usr/bin/python
# ./keystone_create.py

from keystoneclient.v2_0 import client

component_url = 'http://10.200.19.40:9001/v1'
token = 'b5fca4a6d7e3ba1d69ac'
endpoint = 'http://10.200.19.40:35357/v2.0'
tenant_name = 'DNSaas'
description = 'test'
username = 'adminUser'
password = 'secretword'
role = 'admin'
service_name='designate'
service_type='dnsaas'

keystone = client.Client(token=token, endpoint=endpoint)
print keystone

print keystone.tenants.create(
        tenant_name=tenant_name, 
        description=description, 
        enabled=True)

tenants = keystone.tenants.list()
my_tenant = [x for x in tenants if x.name == tenant_name][0]
my_user = keystone.users.create(
        name=username, 
        password=password, 
        tenant_id=my_tenant.id)

role = keystone.roles.create(role)

keystone.roles.add_user_role(my_user, role, my_tenant)
service = keystone.services.create(
        name=service_name, 
        service_type=service_type, 
        description=description)
keystone.endpoints.create(
        region='RegionOne', 
        service_id = service.id,
        publicurl=component_url,
        adminurl=component_url,
        internalurl=component_url)

管理用トークンをヘッダーに追加して、登録されたテナントを確認する。

$ curl -H 'X-Auth-Token: b5fca4a6d7e3ba1d69ac' http://10.200.19.40:35357/v2.0/tenants
{"tenants_links": [], "tenants": [{"description": "hoge", "enabled": true, "id": "beac3004ba344ddc8d4e9be13e77ce0e", "name": "DNSaas"}]}

Designateで、Keystone認証

designate.confに、以下を追加、変更する。

認証方法に関して、

auth_strategy = keystone

認証トークンに関して、

[keystone_authtoken]
auth_host = 127.0.0.1
auth_port = 35357
auth_protocol = http
admin_tenant_name = DNSaas
admin_user = adminUser
admin_password = secretword

Designateを再起動する。

# cd /etc/init.d
# ls designate-* | xargs -I@ service @ restart

通常アクセスした時に、認証エラーになることを確認する。

# curl http://127.0.0.1:9001/v1
Authentication required
Keystone 認証
  1. Keystoneに、ユーザとパスワード情報を渡す。テナントへのアクセストークンを発行する。
  2. テナントへのアクセストークンとテナント名をKeystoneに渡して、Designateへのアクセストークンを発行する。
  3. アクセストークンを用いて、Designateのエンドポイントへアクセスする。
# アクセストークンを取得するPython スクリプト
#!/usr/bin/python

import json
from httplib import HTTPConnection

keystone_unscoped = '127.0.0.1:5000'
username='adminUser'
password='secretword'

conn = HTTPConnection(keystone_unscoped)
header = {'Content-Type':'application/json'}
req = {'auth': {'passwordCredentials': {'username': username, 'password': password }}}
json_req = json.dumps(req)
conn.request('POST','/v2.0/tokens', json_req, header)
json_res = json.loads(conn.getresponse().read())
access_token_id = json_res["access"]["token"]["id"]
conn.close()

conn = HTTPConnection(keystone_unscoped)
header = {'X-Auth-Token': access_token_id, 'Content-Type':'application/json'}
conn.request('GET', '/v2.0/tenants', None, header)
print json.dumps(json.load(conn.getresponse()), indent=2)
conn.close()

tenant = raw_input("\ntenant name: ")
conn = HTTPConnection(keystone_unscoped)
header = {'Content-Type':'application/json'}
req = {'auth': {'tenantName': tenant, 'token': {'id':access_token_id}}}
json_req = json.dumps(req)
conn.request('POST', '/v2.0/tokens', json_req, header)
json_res = json.loads(conn.getresponse().read())
print "===== below is access_token ====="
print json_res["access"]["token"]["id"]
conn.close()

使い方

$ chmod 755 ./get_auth_token.py
$ ./get_auth_token.py
{
  "tenants": [
    {
      "enabled": true,
      "description": "test",
      "name": "DNSaas",
      "id": "5a30147f9c184fc6b618fc16e06c2b66"
    }
  ],
  "tenants_links": []
}

tenant name: DNSaas
===== below is access_token =====
MIIE-QYJKoZIhvcNAQcCoIIE7jCCBOoCAQExDTALBglghkgBZQMEAgEwggNLBgkqhkiG9w0BBwGgggM8BIIDOHsiYWNjZXNzIjogeyJ0b2tlbiI6IHsiaXNzdWVkX2F0IjogIjIwMTYtMDItMDlUMDM6MjE6NTYuMjM5MTU4IiwgImV4cGlyZXMiOiAiMjAxNi0wMi0wOVQwNDoyMTo1MloiLCAiaWQiOiAicGxhY2Vob2xkZXIiLCAidGVuYW50IjogeyJkZXNjcmlwdGlvbiI6ICJ0ZXN0IiwgImVuYWJsZWQiOiB0cnVlLCAiaWQiOiAiNWEzMDE0N2Y5YzE4NGZjNmI2MThmYzE2ZTA2YzJiNjYiLCAibmFtZSI6ICJEZXNpZ25hdGUgRE5TYWFzIn19LCAic2VydmljZUNhdGFsb2ciOiBbeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTAuMjAwLjE5LjQwOjkwMDEvdjEiLCAicmVnaW9uIjogIlJlZ2lvbk9uZSIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTAuMjAwLjE5LjQwOjUwMDAvdjIuMCIsICJpZCI6ICIwYTdkZGNkZDZmODA0NjllYjMzZDJiZGQ5MmI2YzNkNyIsICJwdWJsaWNVUkwiOiAiaHR0cDovL2xvY2FsaG9zdDo5MDAxL3YxLyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJkbnNhYXMiLCAibmFtZSI6ICJkZXNpZ25hdGUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pblVzZXIiLCAicm9sZXNfbGlua3MiOiBbXSwgImlkIjogImNkYTlmYmFhNjZhZTQzNTViZGViOWIwMjJjOTUzMzEzIiwgInJvbGVzIjogW3sibmFtZSI6ICJfbWVtYmVyXyJ9LCB7Im5hbWUiOiAiYWRtaW4ifV0sICJuYW1lIjogImFkbWluVXNlciJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyI5ZmUyZmY5ZWU0Mzg0YjE4OTRhOTA4NzhkM2U5MmJhYiIsICJkNjY2MGVkMzU0NDE0OWU0Yjc4YWQ1NzUxNzI5ZjIzMCJdfX19MYIBhTCCAYECAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAsGCWCGSAFlAwQCATANBgkqhkiG9w0BAQEFAASCAQBWYPlk24npFFVrciVovHYLIUueg5pgV0zRa2cWT8RoWUxXNTcbIbSDCyRh+rbDXx3eCZaafcnddjlYJhGzXp9PD5qgpUhj0tynNN0pZPNklDKAFZvZqtzf8pCGj3RPjmTg-lo2ff5hBpRwsl0TZWnF8S0q-Mx7IemVI48Sairehk0UJ8GkU12cLqeS2K4rRVEYdY81GAuErodlRHvkaRsm5WgjKFjE3TpMNT0xdS+IvKnsE5TRt-6O9pbX+sAp+SGg1fb+XHPIW6L5o6TrFbQtruuoSB7aHLKlY75kYXYaicNyVdsa-gMRuya-93CKdMdwcvDQ0s2IGGVcximTRi+Y

アクセストークンを使って、Designateのエンドポイントにアクセスする。

# ACCESS_TOKEN_ID="<上で出した文字列>"
# curl -H "X-Auth-Token: $ACCESS_TOKEN_ID" http://127.0.0.1:9001/v1/servers
{
  "servers": [
    {
      "created_at": "2016-02-08T06:51:46.000000",
      "id": "06b696c2-b2e0-47ef-b348-de8e221e1b0b",
      "name": "ns1.example.com.",
      "updated_at": "2016-02-08T07:30:26.000000"
    },
    {
      "created_at": "2016-02-08T07:30:26.000000",
      "id": "2c593756-a82c-4372-9587-c4a4489b6724",
      "name": "ns2.example.com.",
      "updated_at": null
    }
  ]
}
参考

KeystoneのUnscoped TokenとScoped Tokenの違い - めもめも Software Defined Boden: OpenStack Keystone Workflow & Token Scoping

Designateの仮想環境作成は、ここを参考にした。

OpenStack Designate を試す : あかぎメモ