【2020/05/14 Update】Oracle Identity Cloud Service(IDCS)のRest APIを使って監査とユーザー情報を取得してみた

皆さんこんにちは。id:k-furusawa--g です。いかがお過ごしでしょうか? 私は左肩の凝り具合が尋常ではありません。聞いたところによれば眼精疲労は肩こりにもつながるそうです。人体の不思議ですね。

今回はOracle Cloud(以下OCI)から半歩ほど離れて、Identity Cloud Service(以下IDCS)を触っていこうかと思います。IDCSとはなにか?という方は、以下の記事がとてもよくまとまっていてわかりやすいので、参考にしてください。

blogs.techvan.co.jp

では本記事の目次です。

はじめに

ほとんどOCI利用ユーザーは、IDCSからのフェデレーションをおこなっているのではないでしょうか?

IDCSからのフェデレーションを利用すると、以下のような問題に直面します。

  • フェデレーションユーザーの場合、OCIの監査にサインオンの記録が残らない
  • フェデレーションユーザーの場合、OCIの監査にユーザー名が記載されないパターンが多い
  • IDCS側のユーザーロックの状態などがOCIからは分からない

他にもありそうですが、遭遇して大きな問題になりそうなものを並べると以上だと思います。主にガバナンスの充実さを気にする企業さんにとっては大きな障害とも呼べるかもしれませんね。

これらの問題はIDCS側の監査情報やユーザー情報を確認することで解消されます。IDCSのユーザーIDと、OCIの監査情報に含まれているプリンシパルIDが紐づく仕様となっており、双方の情報を得ることで、より正確な監査情報にすることができます。

IDCSの情報をAPIを利用して取得したい

弊社ではOCIの情報をRest APIで取得して独自のGUIで提供するアプリケーションの開発を行っています。

同じように、IDCS側の情報をAPIを利用して手軽に取得したい! できます。

REST APIを直接呼び出す

IDCSにも公開されたRest APIがあり、ドキュメントもあります。

docs.oracle.com

とても具体的で、アプリケーション開発時のセキュリティチェックリストまであります。OCIにもこれくらいの情報が欲しいですね。

というわけで、具体的なリクエスト方法が明記されているREST APIをアプリケーション側から呼び出すことで、情報取得を実現したいと思います。

ちなみにSDKは……

こぼれ話ですが、SDKもあります。

以下のリンクから、SDKの利用方法を知ることができます。

www.oracle.com

ただこのSDK、サンプルが認証までしかしておらず具体的な使い方がほぼ示されていないのと、SDKそのもののドキュメントが見当たらないため、どう扱うのかほとんど情報がなく、ぶっちゃけお手上げになりました

今回はIDCSへのリクエストを具体的に知りたいという側面もあったため、利用は見送らせていただきました。

2020/05/14 Update

サポートでSDKについて質問をしてみました。

結果、このSDKは認証部分しか提供しておらず、それ以外のAPI類を扱いたい場合は自分で実装する必要があるようです。

SDK フレームワークへ IDCS への Rest API のコールを実施頂く部分を
組み込んで頂くことにより、ご提示の操作が可能な可能性がございます。

なので公式SDKというよりも、SDK開発用のサンプル程度に思ったほうがいいようです。

個人的には、ほとんど利用する価値はないと思います

まずはIDCSへアプリケーション登録をしよう

前準備として、IDCSにアプリケーション登録を行いましょう。登録方法は、ドキュメント通りに行えば概ね問題ありません。

docs.oracle.com

重要なのは、クライアント構成の項目でアプリケーションロールの追加を行う際に、以下のロールを付与することです。

  • Authenticator Client

    アクセストークン発行の認証を行うのに必要

  • Me

    OAuthを行う場合に必要

  • Audit Administrator

    今回は監査とユーザー情報が欲しいので付与。 User Administrator でも同レベルの権限になるのでどちらでも可

作成が終わると、クライアントIDとクライアント・シークレットが発行されます。どこかにメモしておきましょう。ちなみに、この値はいつでも確認できるのでメモし忘れても大丈夫です。

アプリケーションを作っていこう

ここまでできれば、あとは実装だけです。ちゃっちゃと作っていきましょう。

アクセストークンを発行しよう

トークン発行のAPIは以下です。

Oracle Identity Cloud Service REST API - リソースにアクセスするためのアクセス・トークンおよびその他のOAuthランタイム・トークンの生成

これだけだとなかなか難しいので、コードで示します。例外処理などは省略します。

var endpoint= "https://" + idcsServiceId + ".identity.oraclecloud.com";
var uri = new Uri($"{endpoint}/oauth2/v1/token");
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = HttpMethod.Post.Method;
request.ContentType = "application/x-www-form-urlencoded";
request.Headers["Cache-Control"] = "no-store";
request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(clientId + ":" + clientSecret));

// BODY必須
var body = "grant_type=client_credentials&scope=urn%3Aopc%3Aidm%3A__myscopes__";
var bytes = Encoding.UTF8.GetBytes(body);
request.ContentLength = bytes.Length;
using (var stream = request.GetRequestStream())
{
    stream.Write(bytes, 0, bytes.Length);
}

using (var webResponse = (HttpWebResponse)request.GetResponse())
using (var s = webResponse.GetResponseStream())
using (var sr = new StreamReader(s))
{
    var content = sr.ReadToEnd();

    // contentをJSONパースしてTokenを取得
}

idcsServiceIdIdentity Service Idで、 clientIdsecretClient がアプリケーション登録時に発行されたクライアントIDとクライアント・シークレットです。Authorization ヘッダにBasicでこの二つを組み合わせるのがコツです。Cache-Control ヘッダの設定は推奨なのでつけるようにしましょう。

パースまで書くと長くなるので省略します。

IDCSから情報を取得しよう

アクセストークンが得られれば、ほぼすべてのIDCS REST APIが利用できます。

監査を取得してみましょう。ドキュメントは以下です。

Oracle Identity Cloud Service REST API - 監査イベントの検索

今回は普通にGetで取得します。IDをつかった検索をしたときに、ログやファイアウォールにIDを載せたリクエストが残るなどが気になる場合は、Postによる検索もサポートされているので、そちらを使うといいと思います。

var endpoint= "https://" + idcsServiceId + ".identity.oraclecloud.com";
var uri = new Uri($"{endpoint}/admin/v1/AuditEvents?startIndex={index}&count={Limit}&sortBy=timestamp&sortOrder=descending");
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = HttpMethod.Get.Method;
request.ContentType = "application/x-www-form-urlencoded";
request.Headers["Cache-Control"] = "no-store";
request.Headers["Authorization"] = "Bearer " + accessToken;

using (var webResponse = (HttpWebResponse)request.GetResponse())
using (var s = webResponse.GetResponseStream())
using (var sr = new StreamReader(s))
{
    var content = sr.ReadToEnd();
        
    // contentをJSONパースする
}

今度は Authorization ヘッダに Bearer で発行したアクセストークンを記載します。あとは特に説明するまでもないですね。オプションの件数制御が Offset Limit じゃなくて startIndex count なのが変な感じですが……。

というわけでテストアプリケーションを作りました

上記してきた感じでリクエストをしていけば、簡単にIDCSから情報が取得できます。

というわけで、ざっくりとテストアプリケーションを作成してみました。

f:id:k-furusawa--g:20200423165717j:plain
IDCSテストアプリ1

こんな感じで、必要情報を入力して、トークンを発行ボタンを押す。

f:id:k-furusawa--g:20200423180138j:plain
IDCSテストアプリ2

トークンが発行される。今思えばトークン野ざらしとか凄いですね。直しておきます。

f:id:k-furusawa--g:20200423170332j:plain
IDCSテストアプリ3

監査を取得すると、こんな感じでツリー構造で表示されます。これが一番早いと思います。

f:id:k-furusawa--g:20200423170356j:plain
IDCSテストアプリ4

ユーザー情報も取得できますね。問題ありません。

??となっているユーザーですが、これはOCI側からフェデレーションサービス経由でユーザーを作成する際に、日本語を入れるとIDCSユーザー側が文字化けする現象です。社内でも一度注意したのですが、誰かが作っちゃったようですね。みなさん気を付けましょう。

おしまいに

いかがだったでしょうか?

OCI側は何かと触る機会が多いのですが、IDCS側はほぼ触っていなくて新鮮でした。訳あって触り始めましたが、意外とすんなり情報が取得できたと思います。

ただ、IDCSはサインオンを扱うサービスで、セキュリティの観点から見てもかなり重要な部分です。今回サンプルで作成したアプリケーションのように、直接ドメインやクライアントID、クライアント・シークレットを入力するタイプのアプリケーションは割と危ないので、ある程度隠ぺいできる仕組みを整えてから開発に取り組むようにしてください。実験で遊ぶ程度ならいいと思います。

それではまたの機会に。