Documentation

15. トークンベースの認証

Ansible Tower 3.3 以降、OAuth 2 がトークンベースの認証に使用されます。OAuth トークン、アプリケーション、トークン生成に使用する API クライアントのサーバー側の表現を管理できます。HTTP 認証ヘッダーの一部として OAuth トークンを追加して、自身の認証を行い、基本の RBAC パーミッションの他に制限するパーミッション範囲を調節します。OAuth 2 仕様の詳細は、「 RFC 6749 」を参照してください。

15.1. OAuth 2 アプリケーションおよびトークンの管理

アプリケーションとトークンは、トップレベルのリソースとして /api/<version>/applications/api/<version>/tokens で管理できます。これらのリソースは、ユーザーごとに /api/<version>/users/N/<resource> からアクセスできます。アプリケーションは、 POST 要求を api/<version>/applications または /api/<version>/users/N/applications に行うことで作成可能です。

OAuth 2 アプリケーションはそれぞれ、サーバー側で特定の API クライントを表現します。API クライアントがアプリケーショントークン経由で API を使用するには、アプリケーションを先に用意し、アクセストークンを発行する必要があります。個別のアプリケーションは、/api/<version>/applications/<pk>/ の主要キー経由でアクセス可能です。以下は、一般的なアプリケーションです。

    {
    "id": 1,
    "type": "o_auth2_application",
    "url": "/api/v2/applications/2/",
    "related": {
        "tokens": "/api/v2/applications/2/tokens/"
    },
    "summary_fields": {
        "organization": {
            "id": 1,
            "name": "Default",
            "description": ""
        },
        "user_capabilities": {
            "edit": true,
            "delete": true
        },
        "tokens": {
            "count": 0,
            "results": []
        }
    },
    "created": "2018-07-02T21:16:45.824400Z",
    "modified": "2018-07-02T21:16:45.824514Z",
    "name": "My Application",
    "description": "",
    "client_id": "Ecmc6RjjhKUOWJzDYEP8TZ35P3dvsKt0AKdIjgHV",
    "client_secret": "7Ft7ym8MpE54yWGUNvxxg6KqGwPFsyhYn9QQfYHlgBxai74Qp1GE4zsvJduOfSFkTfWFnPzYpxqcRsy1KacD0HH0vOAQUDJDCidByMiUIH4YQKtGFM1zE1dACYbpN44E",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false,
    "organization": 1
}

上記の例で示されるように、name は人間が判読可能なアプリケーションの識別子です。client_idredirect_uris など、残りの他のフィールドは、OAuth2 認可に使用されます。これについては、あとで「 パーソナルアクセストークン (PAT) 向けの OAuth2 トークンシステムの使用 」で説明します。

client_id および client_secret フィールドの値は作成時に生成されるアプリケーション識別子で、編集できません。反対に、organization および authorization_grant_type は作成時に必要で、その後に編集不可になります。

15.1.1. アプリケーションのアクセスルール

アプリケーションのアクセスルールは以下のとおりです。

  • システム管理者は、システム内の全アプリケーションを表示し、操作できます。

  • 組織の管理者は、組織メンバーに属するアプリケーションすべてを表示し、操作できます。

  • 他のユーザーは、自身のアプリケーションの表示、更新、削除が可能ですが、新規アプリケーションは作成できません。

反対に、トークンは受信要求を実際に認証して、基盤のユーザーのパーミッションをマスクするために使用するリソースです。トークンの作成方法には 2 種類あります。

  • application および scope フィールドで、関連のアプリケーションを参照して、トークンの範囲を指定し、/api/v2/tokens/ エンドポイントに POST 要求を送信する

  • scope を指定し、親アプリケーションを自動的にリンクさせて、/api/v2/applications/<pk>/tokens/ に POST 要求を送信する

個別のトークンには /api/<version>/tokens/<pk>/ の主要キー経由でアクセスできます。以下は一般的なトークンの例です。

{
    "id": 4,
    "type": "o_auth2_access_token",
    "url": "/api/v2/tokens/4/",
    "related": {
        "user": "/api/v2/users/1/",
        "application": "/api/v2/applications/1/",
        "activity_stream": "/api/v2/tokens/4/activity_stream/"
},
    "summary_fields": {
        "application": {
            "id": 1,
            "name": "Default application for root",
            "client_id": "mcU5J5uGQcEQMgAZyr5JUnM3BqBJpgbgL9fLOVch"
        },
        "user": {
            "id": 1,
            "username": "root",
            "first_name": "",
            "last_name": ""
        }
    },
    "created": "2018-02-23T14:39:32.618932Z",
    "modified": "2018-02-23T14:39:32.643626Z",
    "description": "App Token Test",
    "user": 1,
    "token": "*************",
    "refresh_token": "*************",
    "application": 1,
    "expires": "2018-02-24T00:39:32.618279Z",
    "scope": "read"
},

OAuth 2 トークンでは、完全に編集可能なフィールドは scopedescription だけです。以下のように、application フィールドは更新時に編集不可で、他のフィールドはすべて編集できず、作成時に自動生成されます。

  • user フィールドは、作成したトークンの対象ユーザーと同じです。今回は、トークンを作成したユーザーもこれになります。

  • expires は、Tower の設定 OAUTH2_PROVIDER に基づいて生成されます。

  • token および refresh_token は、クラッシュなしの乱数文字列として自動生成されます。

アプリケーショントークンとパーソナルアクセストークンは両方、/api/v2/tokens/ エンドポイントに表示されます。パーソナルアクセストークンの application フィールドは常に null です。これは、2 種類のトークンを区別するのに適した方法です。

15.1.2. トークンのアクセスルール

トークンのアクセスルールは以下のとおりです。

  • ユーザーは、関連のアプリケーションを表示できる場合にはトークンを作成でき、自身の個人トークンも作成可能です。

  • システム管理者は、システム内の全トークンを表示し、操作できます。

  • 組織の管理者は、組織メンバーに属する全トークンの表示と操作が可能です。

  • システム監査者は全トークンおよびアプリケーションの表示が可能です。

  • 他の通常ユーザーは自身のトークンのみの表示と操作が可能です。

注釈

ユーザーは、トークンの表示または、作成時にのみトークンの値の更新が可能です。

15.2. パーソナルアクセストークン (PAT) 向けの OAuth2 トークンシステムの使用

OAuth 2 の用途として最も一般的なのは、ユーザーの認証です。トークンの token フィールドは、Authorization: Bearer <token field value> の形式で、HTTP 認証ヘッダーの一部として使用します。 以下の例のように、Bearer トークンは、/api/o/token/ エンドポイント で curl コマンド実行して取得することができます。

curl -ku <user>:<password> -H "Content-Type: application/json" -X POST \
-d '{"description":"Tower CLI", "application":null, "scope":"write"}' \
https://<tower>/api/v2/users/1/personal_tokens/ | python -m json.tool

注釈

特別な OAuth 2 エンドポイントは、x-www-form-urlencoded Content-type の使用のみをサポートするので、api/o/* のエンドポイントで application/json を受け入れるものはありません。

以下は、curl を使用して API エンドポイントにアクセスするためにパーソナルトークンを使用する例です。

curl -k -H "Authorization: Bearer <token>" -H "Content-Type: application/json" -X POST  -d '{}' https://tower/api/v2/job_templates/5/launch/

OAuth 2 仕様に合わせてユーザーはアクセストークンの取得、取り消し、更新ができます。Ansible Tower では、同様に最も効率的にトークンを更新するには、トークンを作成して、そのトークンを削除してからすぐに新しいトークンを作成します。トークンを取り消すには、ユーザーインターフェースのアプリケーション設定で削除するか、API のトークン詳細ページで削除するだけです。

Ansible Tower では、OAuth 2 システムは Django Oauth Toolkit 上にビルドされ、トークンの承認、呼び出し、更新を専用とするエンドポイントを提供します。Tower は、トークンを実装して、関連のエンドポイントを /api/o/ エンドポイントに配置し、これらのエンドポイントの一般的な用途に関する詳細例を提供します。

注釈

/api/o/ エンドポイントは、アプリケーショントークン用としてだけ使用でき、パーソナルアクセストークンには有効ではありません。

15.2.1. RBAC システム全体のトークンスコープのマスク

OAuth 2 トークンのスコープは、有効なスコープキーワード「read」と「write」で構成されるスペース区切りの文字列です。これらのキーワードは、設定可能で、認証済みの API クライアントのパーミッションレベルを指定するのに使用します。Read (読み取り) および Write (書き込み) スコープを設定することで、Ansible Tower のロールベースアクセス制御 (RBAC: Role-Based Access Control) パーミッションシステムにマスク層を提供します。具体的には、「write」スコープでは、RBAC システムが提供する全パーミッションを認証済みのユーザーに付与し、「read」スコープでは RBAC システムが提供する読み取りパーミッションのみを認証済みのユーザーに付与します。「write」パーミッションには、「read」も含まれている点に注意してください。

たとえば、ジョブテンプレートに管理者権限がある場合には、セッションまたは Basic 認証で認証済みであればジョブテンプレートの表示、変更、起動、削除が可能です。反対に、OAuth 2 トークンを使用して認証しており、関連のトークンスコープが 'read' の場合は、管理者であってもジョブテンプレートの表示はできますが、操作や起動はできません。トークンスコープが 'write' または 'read write' の場合は、管理者としてジョブテンプレートをすべて活用できます。

トークンを取得して使用するには、まずアプリケーショントークンを作成します。

  1. authorization_grant_type`password に設定してアプリケーションを作成します。/api/v2/applications/ endpoint に対して、以下の HTTP POST 要求を実行します (独自の組織 ID を指定します)。

{
    "name": "Admin Internal Application",
    "description": "For use by secure services & clients. ",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false,
    "organization": <organization-id>
}
  1. トークンを作成して、POST 要求を /api/v2/tokens/ エンドポイントに実行します。

{
    "description": "My Access Token",
    "application": <application-id>,
    "scope": "write"
}

これで、今後の要求の認証に使用できるように <token-value> を返します (これは今後表示されません)。

  1. このトークンを使用してリソースにアクセスします。以下は、例として curl を使用します。

curl -H "Authorization: Bearer <token-value>" -H "Content-Type: application/json" -X GET https://<tower>/api/v2/users/

CA をまだ設定しておらず、SSL を使用する場合には、-k フラグが必要な場合があります。

トークンを取り消すには、そのトークンに対して、トークンの ID を使用し、詳細ページで DELETE 要求を実行します。以下に例を示します。

curl -ku <user>:<password> -X DELETE https://<tower>/api/v2/tokens/<pk>/

同様に、トークンを使用する場合:

curl -H "Authorization: Bearer <token-value>" -X DELETE https://<tower>/api/v2/tokens/<pk>/ -k

15.3. アプリケーションの機能

このページでは、認可、トークンの更新、取り消しに使用する OAuth 2 ユーティリティーエンドポイントを表示します。/api/o/authorize/ 以外のエンドポイントは、ブラウザーでの使用を目的としておらず、HTTP GET はサポートしていません。ここで説明されているエンドポイントは、OAuth 2 の RFC 仕様に厳密に準拠しているので、詳しい参考資料としてこの RFC 仕様をお使いください。implicit 付与タイプが使用できるのは、セッション認証でログイン済みの場合に、アクセストークンを取得するためだけです。これは、セッション認証でログインしていると、アクセストークンの作成が許可されていることが確認できるためです。以下は、特にさまざまな付与タイプを使用したアプリケーションの作成など、Tower でこれらのエンドポイントを使用する方法例を紹介しています。

  • 認可コード

  • 暗黙的

  • パスワード

15.3.1. authorization code` の付与タイプを使用したアプリケーション

アプリケーションの 付与タイプ は、サーバー上でアプリケーションが実行される場合に使用することを目的としています。付与タイプが authorization-code で名前が AuthCodeApp のアプリケーションを作成する場合には、/api/v2/applications/ エンドポイントに POST 要求を実行します。

{
    "name": "AuthCodeApp",
    "user": 1,
    "client_type": "confidential",
    "redirect_uris": "http://<tower>/api/v2",
    "authorization_grant_type": "authorization-code",
    "skip_authorization": false
}

client_id と URI リンクを Django-oauth-toolkit simple test application にコピーして、新規アプリケーションで認可フローをテストし、送信 をクリックします。

response_typeclient_idredirect_uris および scope で、クライアントアプリケーションから authorize エンドポイントに、GET 要求を実行すると発生するワークフロー

  1. Tower は、アプリケーションに指定されている redirect_uri に対して、認可コードとステータスで応答します。

  2. 次に、クライアントアプリケーションは、codeclient_idclient_secretgrant_type および redirect_uri を指定して、Tower の api/o/token/ エンドポイントに POST 要求を送信します。

  3. Tower は access_tokentoken_typerefresh_token および expires_in で応答します。

このフローのテストについては、「 Django's Test Your Authorization Server ツールキット」を参照してください。

15.3.2. implicit 付与タイプを使用したアプリケーション

単一ページの Web アプリケーションが client_secret をセキュアに保てない場合に、implicit 付与タイプを使用します。この手法ではフローの認可コードの部分を省略し、アクセストークンを返すだけです。以下は、アプリケーションの管理者が、アプリの付与タイプを implicit にしていることが前提です。

{
    "id": 1,
    "type": "application",
    "related": {
    ...
    "name": "admin's app",
    "user": 1,
    "client_id": "L0uQQWW8pKX51hoqIRQGsuqmIdPi2AcXZ9EJRGmj",
    "client_secret": "9Wp4dUrUsigI8J15fQYJ3jn0MJHLkAjyw7ikBsABeWTNJbZwy7eB2Xro9ykYuuygerTPQ2gIF2DCTtN3kurkt0Me3AhanEw6peRNvNLs1NNfI4f53mhX8zo5JQX0BKy5",
    "client_type": "confidential",
    "redirect_uris": "http://<tower>/api/",
    "authorization_grant_type": "implicit",
    "skip_authorization": false
}

API ブラウザーで、まず、セッション認証経由でログインしていることを確認し、指定のパラメーターで、認可エンドポイントに移動します。

http://localhost:8013/api/o/authorize/?response_type=token&client_id=L0uQQWW8pKX51hoqIRQGsuqmIdPi2AcXZ9EJRGmj&scope=read

これは、client_id が、基盤のアプリケーションの client_id フィールドと同じ必要がある場合です。成功すると、認可ページに、プロンプトが表示され、アクセストークンを付与するか拒否するかが尋ねられます。付与 をクリックした後に、API ブラウザーにより、POST 本体のパラメーターに同じパラメーターが指定されている同じエンドポイントに対して POST 要求が実行されます。成功すると、「302 redirect」が返されます。

HTTP/1.1 302 Found
Connection:keep-alive
Content-Language:en
Content-Length:0
Content-Type:text/html; charset=utf-8
Date:Tue, 05 Dec 2017 20:36:19 GMT
Location:http://localhost:8013/api/#access_token=0lVJJkolFTwYawHyGkk7NTmSKdzBen&token_type=Bearer&state=&expires_in=315360000000&scope=read
Server:nginx/1.12.2
Strict-Transport-Security:max-age=15768000
Vary:Accept-Language, Cookie

注釈

暗黙的なアプリケーションで作成したトークンには、更新トークンが含まれません。

15.3.3. password 付与タイプを使用したアプリケーション

このタイプは、resource owner credentials grant とも呼ばれます。これは、Web アプリケーションにネイティブアクセスのあるユーザーに最適で、クライアントがリソースの所有者である場合に使用すると良いでしょう。以下は、付与タイプが password の 'Default Application' のアプリケーションを前提としています。

{
    "id": 6,
    "type": "application",
    ...
    "name": "Default Application",
    "user": 1,
    "client_id": "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l",
    "client_secret": "fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo",
    "client_type": "confidential",
    "redirect_uris": "",
    "authorization_grant_type": "password",
    "skip_authorization": false
}

password の付与タイプにはロギングは必要ないので、curl を使用して /api/o/token/ エンドポイントからパーソナルアクセストークンを取得するだけです。

curl -X POST \
-d "grant_type=password&username=<username>&password=<password>&scope=read" \
-u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569e
IaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
http://<tower>/api/o/token/ -i

上記の POST 要求で、usernamepassword のパラメーターには、基盤となるアプリケーションの Tower ユーザーのユーザー名とパスワードを指定します。また、認証情報は、<client_id>:<client_secret> の形式をとり、client_idclient_secret は基盤アプリケーションの対応フィールドに置き換えます。

注釈

特別な OAuth 2 エンドポイントは、x-www-form-urlencoded Content-type の使用のみをサポートするので、api/o/* のエンドポイントで application/json を受け入れるものはありません。

成功すると、JSON 形式でアクセストークンを含めて応答が表示され、トークンと他の情報が更新されます。

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 05 Dec 2017 16:48:09 GMT
Content-Type: application/json
Content-Length: 163
Connection: keep-alive
Content-Language: en
Vary: Accept-Language, Cookie
Pragma: no-cache
Cache-Control: no-store
Strict-Transport-Security: max-age=15768000

{"access_token": "9epHOqHhnXUcgYK8QanOmUQPSgX92g", "token_type": "Bearer", "expires_in": 315360000000, "refresh_token": "jMRX6QvzOTf046KHee3TU5mT3nyXsz", "scope": "read"}

15.4. アプリケーショントークンの機能

このセクションでは、トークンに関連する更新および取り消し機能について説明します。それ以降はすべて、アプリケーショントークンでしか実行できません (/api/o/ エンドポイントでトークンの更新と取り消し) が、暗黙的なアプリケーションで作成されたトークンでは、トークンは更新されません。

15.4.1. 既存のアクセストークンの更新

以下の例には、提供された更新トークンと既存のアクセストークンが示されています。

{
    "id": 35,
    "type": "access_token",
    ...
    "user": 1,
    "token": "omMFLk7UKpB36WN2Qma9H3gbwEBSOc",
    "refresh_token": "AL0NK9TTpv0qp54dGbC4VUZtsZ9r8z",
    "application": 6,
    "expires": "2017-12-06T03:46:17.087022Z",
    "scope": "read write"
}

/api/o/token/ エンドポイントは、アクセストークンの更新に使用します。

curl -X POST \
    -d "grant_type=refresh_token&refresh_token=AL0NK9TTpv0qp54dGbC4VUZtsZ9r8z" \
    -u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
    http://<tower>/api/o/token/ -i

上記の POST 要求では、refresh_token は、その上にあるアクセストークンの refresh_token フィールドから渡されます。認証情報の形式は <client_id>:<client_secret> で、client_idclient_secret は、配下にあるアクセストークンの関連アプリケーションの対応するフィールドに置き換えます。

注釈

特別な OAuth 2 エンドポイントは、x-www-form-urlencoded Content-type の使用のみをサポートするので、api/o/* のエンドポイントで application/json を受け入れるものはありません。

成功すると、JSON 形式で以前のものと同じスコープ情報を含む、新しい (更新済み) アクセストークンを含めて応答が表示されます。

HTTP/1.1 200 OK
Server: nginx/1.12.2
Date: Tue, 05 Dec 2017 17:54:06 GMT
Content-Type: application/json
Content-Length: 169
Connection: keep-alive
Content-Language: en
Vary: Accept-Language, Cookie
Pragma: no-cache
Cache-Control: no-store
Strict-Transport-Security: max-age=15768000

{"access_token": "NDInWxGJI4iZgqpsreujjbvzCfJqgR", "token_type": "Bearer", "expires_in": 315360000000, "refresh_token": "DqOrmz8bx3srlHkZNKmDpqA86bnQkT", "scope": "read write"}

基本的に、更新の操作では、元のトークンを削除した直後に、元のトークンと同じスコープと関連のアプリケーションを持つ新規トークンを作成することで、既存のトークンを置き換えます。/api/v2/tokens/ エンドポイントに、新しいトークンがあり、以前のトークンが削除されていることを確認してください。

15.4.2. アクセストークンの取り消し

同様に、/api/o/revoke-token/ エンドポイントを使用してアクセストークンを取り消すことができます。

この方法でアクセストークンを取り消すのも、トークンリソースオブジェクトを削除するのも同じですが、トークンの値と関連の client_id (およアプリケーションが``confidential`` の場合には client_secret) を指定してトークンを削除することができます。

curl -X POST -d "token=rQONsve372fQwuc2pn76k3IHDCYpi7" \
-u "gwSPoasWSdNkMDtBN3Hu2WYQpPWCO9SwUEsKK22l:fI6ZpfocHYBGfm1tP92r0yIgCyfRdDQt0Tos9L8a4fNsJjQQMwp9569eIaUBsaVDgt2eiwOGe0bg5m5vCSstClZmtdy359RVx2rQK5YlIWyPlrolpt2LEpVeKXWaiybo" \
http://<tower>/api/o/revoke_token/ -i

注釈

特別な OAuth 2 エンドポイントは、x-www-form-urlencoded Content-type の使用のみをサポートするので、api/o/* のエンドポイントで application/json を受け入れるものはありません。

注釈

外部ユーザーによる OAuth2 トークンの作成を許可 (API では ALLOW_OAUTH2_FOR_EXTERNAL_USERS) の設定はデフォルトでは無効になっています。外部ユーザーは、LDAP やその他の SSO サービスなどのサービスで外部認証されたユーザーを指します。この設定では、外部ユーザーは独自のトークンを*作成*できません。有効にしてから再度無効にした場合には、有効にしていた期間に外部ユーザーが作成したトークンは依然として存在しますが、自動的に呼び出されません。

この設定は、Ansible Tower ユーザーインターフェースからシステムレベルで構成できます。

_images/configure-tower-system-oauth2-tokens-toggle.png

成功すると、200 OK の応答が表示されます。トークンが /api/v2/tokens/ エンドポイントに存在するかどうかをチェックして、削除されていることを確認します。