こんにちは!たつみんです。
先日ブログ記事『弊社Okta環境をOkta Identity Engineにお引越ししました』の中で以下のように触れていた箇所があったかと思います。
Okta管理画面で各ユーザーの画面を開いて紐づく端末がManagedであるかを確認することは手間がかかるためAPIによる情報取得を検討しましたが、APIではDevice単体がManagedかどうかという点は取得できましたが、そのDeviceがどのユーザーに紐づくかは取得できませんでした。そこでOkta WorkflowsでOktaのログからeventTypeを指定し複数のイベントの結果から端末とユーザーを紐付けを行いManagedであることを通知する実装を行いました。
今回はこの部分について解説を記事にしていきます。
課題の詳細
macOSおよびWindowsについて端末がManagedと判定された際にはOktaのログではeventTypepki.cert.bind
が記録されます。しかしこのイベントログの実行者(Actor)はOkta Systemとして記録されるため端末名はわかりますが誰の端末かという情報がありません。
そのため、eventTypepki.cert.bind
より前に記録されるeventTypedevice.user.add
を取得しデバイスに誰が紐づけられたかをあらかじめテーブルに記録しておきます。これら二つのログをDevice IDをキーにしてユーザーと紐付けを行うことで誰のどの端末がDevice Trust状態となったかを明らかにします。
必要な処理
今回の実現したいことのためには以下の1つのテーブルと2つのFlowを作成する必要があります。
- Device IDなどのデータ蓄積用テーブル
- 10分毎にOktaのログを検索するFlow
- 検索結果があった場合にeventType毎に処理を行うFlow
Flowの中に登場する各カードの詳細については『Okta Workflowsのはじめかたとよく使うカードの解説』も参照ください。解説パートでも利用するカードの見出しへのリンクも付けていますのでご確認ください。
テーブル作成
Oktaに登録されたDeviceデータをテーブルに格納します。
今回はOktaに登録されたDeviceデータをテーブルに格納するためにOkta Deviceという名前でテーブルを作成し、下図のようなカラムを作成しておきました。
10分毎にOktaのログを検索するFlow
全体図は以下のとおりです。
- トリガーにはScheduledカードを選択し10分毎に起動するように設定をします。(カード解説)
- Text to DateカードでScheduled Flowの実行時の時間であるCurrent Timeを
YYYY-MM-DD HH:mm
形式に変換しています。これによりFlow実行時の秒部分を切り落として00秒とし、実行時に発生する秒単位の誤差をなくすことができます。(カード解説) - Subtractカードで2.の出力結果から10分を引いた数値を算出しています。(カード解説)
- ConstructカードでAcceptとContent-Typeを作成し、それぞれ
application/json
を指定してHeadersを作成します。(カード解説) - Constructカードでfilterを作成し、以下の指定します。
eventType eq "device.user.add" and outcome.result eq "SUCCESS" or eventType eq "pki.cert.bind" and outcome.result eq "SUCCESS"
さらにSinceとUntilを作成し、3.の出力と2.の出力を指定します。 - Wait Forカードで処理を10秒待機します。
これはシステムログが生成されるのに数秒ラグがあるのではないかと考えて入れています。 - OktaアプリケーションのCustom API Actionカードでエンドポイント
/api/v1/logs
に対して、Queryに5.の出力を、Headersに4.の出力を指定します。またOptionsではGETを指定しています。(カード解説) - For Eachカードでlistには7.を実行した時のレスポンスのBodyを指定します。Helper Flowで次に紹介するFlowを指定し、Helper Flowで指定したフィールドSyslogにはItemを指定します。(カード解説)
検索結果があった場合にeventType毎に処理を行うFlow
- トリガーはHelper Flowカードを選択し、呼び出し元で渡された値を受け取れるようにフィールド
Syslog
を定義しておきます。(カード解説) - Parseカードで1.のSyslogをJSONからオブジェクトに変換します。
- Get Multipleカードで2.で変換したオブジェクトからeventTypeを取り出します。(カード解説)
- If/ElseIfカードでevetTypeが
device.user.add
の場合とpki.cert.bind
の場合をそれぞれ指定します。(カード解説) - evetTypeが
device.user.add
の場合の処理を+から追加します。
以下の6.から9.が該当の処理です。 - Get Multipleカードで2.で変換したオブジェクトから以下を指定しデータを取り出します。
published
,actor.displayName
,actor.alternateId
,target.0.displayName
,target.0.detailEntry.oktaDeviceId
,target.0.detailEntry.osPlatform
,target.0.detailEntry.serialNumber
,target.0.detailEntry.udid
- Date to Textカードで6.で取り出したpublishedをJSTに変換にするために、formatを
YYYY-MM-DD HH:mm:ss.S z
、ZoneをAsia/Tokyo
を指定します。(カード解説) - Search Rowsカードであらかじめ作成しておいたOkta DeviceテーブルのOkta Device IDのカラムを6.で取り出した
target.0.detailEntry.oktaDeviceId
で検索します。(カード解説) - If/Elseカードで8.で検索した結果のRowIDが空でないことを条件とします。
以下の10.がTrueの処理、11.がFalseの処理です。 - 9.の結果が空でない場合はUpdate Rowカードによって既存のレコードを最新のデータで上書きします。これは端末を回収し別の利用者に割り当てた時を想定しています。(カード解説)
- 9.の結果が空である場合はOkta上にデバイス情報がないためCreate Rowカードで新しいレコードを作成しデータを格納します。(カード解説)
- evetTypeが
pki.cert.bind
の場合の処理を+から追加します。
以下の13.から18.が該当の処理です。 - Get Multipleカードで2.で変換したオブジェクトから以下を指定しデータを取り出します。
published
,outcome.result
,target.0.displayName
,target.0.detailEntry.oktaDeviceId
,target.0.detailEntry.serialNumber
- Date to Textカードで13.で取り出したpublishedをJSTに変換にするために、formatを
YYYY-MM-DD HH:mm:ss.S z
、ZoneをAsia/Tokyo
を指定します。 - Search Rowsカードであらかじめ作成しておいたOkta Deviceテーブル内を13.で取り出した
target.0.detailEntry.oktaDeviceId
で検索します。 - Update Rowカードを実行し既存のレコードの各カラムを
published
,target.0.displayName
,outcome.result
で上書きします。 - Composeカードで13.14.15.で取り出した値を組み合わせてSlackに投稿するためのメッセージを作成します。(カード解説)
- 4.のIf/ElseIfカードのOutputsを表示し、17.のアウトプットをドラッグ&ドロップします。
- Continue Ifカードで18.で指定したメッセージが空でない場合は20.の処理を実行します。(カード解説)
- SlackアプリケーションのSend Message to Channelカードでチャンネルを指定し、17.で指定したメッセージを送信します。この時オプションでSlack botとして送信することを指定しているためBotの名前やアイコンを指定しておきます。(カード解説)
実行結果としてSlackに以下のようなメッセージが投稿されます。
最後に
今回はdevice.user.add
とpki.cert.bind
に絞った内容をご紹介しましたが、弊社では他にもユーザー作成user.lifecycle.create
やユーザー削除user.lifecycle.delete.completed
や、アプリケーションに対するグループのアサインgroup.application_assignment.add
など合計13のイベントログを取得し通知処理を行っています。
以下はOIE環境へのSP移行時の作業としてOktaにユーザーを作成したり、アプリケーションにグループをアサインを行った時のログの通知です。
今回ご紹介した方法でeventTypeを増やすとその分、If/ElseIfで記述する処理が多くなりFlowの視認性が悪くなってしまうというデメリットがありますがログが通知されることで意図しない操作に気づきやすくなるというメリットの方が大きいのではないかと思います。
指定可能なeventTypeの詳細については以下のドキュメントをご参照ください。
APIの実行やオブジェクトから値を取り出す操作には少し慣れが必要ですが、その部分をクリアできるといろいろな応用ができるかと思います。
今回ご紹介したFlowはOIE環境でDevice Trustを行う際はあらかじめ設定をしておくとよいのではないかと思います。
それではまた別の記事でお会いしましょう!