ネクストモードブログ

【Okta】入退社手続きをOkta Workflowsでエレガントにしたい! | Nextmode Blog

作成者: kusumin|24/02/02 2:07

はじめに

こんにちは、 ネクストモード株式会社 のSaaSおじさん久住です

ネクストモードではID統合管理(IDaaS)のOktaを利用して各SaaSへのシングル・サインオンやプロビジョニングの一元管理をしています

今回は従業員の入退社に伴う一連の情シス業務をスマートかつエレガントにすべく、Okta Workflowsの活用を考えてみたのでご紹介します

 

弊社のオフボーディング(情シス観点)

ネクストモードではOktaでIDを一元管理し、各SaaSにプロビジョニングしているので、社員の入退社があった際も基本的には(一部のSCIMに対応していない or API開放していないSaaSを除いて)SaaS側のユーザーも自動で作成・削除されます

すごく楽な仕組みになっているんですが、定期的な情シス業務改善ミーティングの中で気になることがありました

プロビジョニング/デプロビジョニングが成功しているかどうかを目視確認(ヨシッ!)している」ということです

エレガントじゃない・・・プロビジョニングの素晴らしさを半減させちゃってる・・・!
そこでこの課題を解決できないか、Okta Workflowsを駆使してみました

やったこと

今回はユーザーが無効(Deactivated)になったことをトリガーに、対象ユーザーのDeprovisioningがSuccessとなったアプリケーション名をOktaのSystem Logsから拾ってきて全部まとめてSlackに通知します

フローは親フローと子フロー(ヘルパーフロー)に分かれていて、親フローで拾ったSystem Logsを子フローに渡して整形しています

親フロー

子フロー

テストしてみるとこんな形でSlackに通知されます

フローの紹介

イベント

Oktaユーザーの無効化をトリガーとしたいため、イベントはDeactivate Userとしました

イベントフックを利用することも可能ですが、Deactivate Userカードの方が楽なのでこちらにしました

アクション

【親】Wait For

Oktaでユーザーを無効化してから各種SaaSのデプロビジョニングが始まり、System Logに吐き出されるのでフローを一時停止するWait For関数をはさみます

ログの傾向から5分あれば十分でしたので5分のWait timeをはさみました(ここはプロビジョニング連携してるSaaS数によるかと思います)

【親】Search System Logs

次にOktaのシステムログから特定のログイベントを検索します

Filterの設定ができるのでEvent TypeTarget IDをフィルター条件とし、SaaSの数は200個以下なのでResult SetFirst 200 Matching Recordsとしました

ちなみに入社(オンボーディング)時のEvent Typeはapplication.provision.user.pushを利用します


【親】Map

Map関数を利用して検索したログイベントをリストのアイテム毎にHelperフローに渡して新しいリストに格納していきます

アイテムの処理の順序性については重要ではないため、数が多い場合はConcurrencyを1より大きくして並列処理するのもいいでしょう

【子】Helper Flow

ここから子フローを作成していきます

まずHelper Flowにより、親フローから渡されたアイテムを受け取ります
わかりやすく、アイテムの中も書いてますがObject型のSystem Logs(名前は任意)だけあれば大丈夫です

【子】Object Get

次にObject型のログイベントのアイテムから成功かどうかの情報を取得します

Objectにはヘルパーフローで受け取ったSystem Logsをドラッグアンドドロップで挿入し、pathはRaw Output.outcome.resultとします

【子】IF/Else

次が少しややこしいかも知れないですが、IF/Else関数を利用して下記の通り実施しています

  • Object Get関数で取得した値がSUCCESSだった場合はdisplaynameを取得し、outputに格納
  • Object Get関数で取得した値がSUCCESSではなかった場合はSlackにエラーメッセージを通知し、Return Error関数でError終了
SUCCESSだった場合にdisplaynameを取得するためのSystem LogsのpathはTarget.2.displayNameです
※pathについては後述に詳細書いてますのでご参照ください

【子】Flow Control Return

最後にSUCCESSだった場合に取得したdisplaynameを返り値として親フローに戻す

【親】Map(戻り)、List to Text

ログイベントの数だけ子フローを呼び出し、取得した値をnew listというlist型に格納します
List型を通知するメッセージで見やすいように / で区切るテキスト型に変換します

【親】Now + Date to Text

Now関数で現在日時を取得し、Date to Text関数で指定フォーマットの日本時間に変換してtext型にします

【親】Compose + Slackメッセージ通知

最後にCompose関数を利用してメッセージを整形してSlack通知します

メッセージ内容は下記の通り設定しました

(例)
オフボーディングが完了しました。
■ 作業日時
2024/02/01 10:00:01
■ ユーザー情報
Yosuke Kusumi

■ SaaS情報
Slack / Notion / Asana 

ユーザー情報は最初のDeactivate User関数のOkta UserのDisplay Nameから引っ張ってきます

詰まったところ

For Each・Map・Reduce

ヘルパーフローの呼び出しを最初For Each関数を使おうとしていたのですが、それだと返り値を設定できず、悪戦苦闘していました
結果的にMap関数でうまくいったのですが、今回For Each関数、Map関数、Reduce関数の違いを正しく知るところから大変でした

 

データの型

以前も大いに詰まって、今回もちょっと躓いたのは型の問題です
Object型なのか、List型なのか、ここを意識して繋げていかないとエラーになります

今回は下記のようなList型のSystem LogsからObject型の下記アイテムを取得していきました

システムログ(List型)
[ログアイテム①(Object型), ログ②(Object型), ・・・]

各ログアイテムについては子フローにて必要な値(今回はターゲットのSaaS名)のみ取り出したのですが、これも癖がありました

ログアイテム(Object型)
各ログアイテムは下記のようにネストされた(=オブジェクトの中にオブジェクトが内包されている)オブジェクトから成り立っており、必要な値を取り出すためにはpathの指定に工夫が必要になります

Targetの3番目のdisplayNameのSlackを取得したい場合は配列Target[2]に格納された情報を取得することになるため、pathにTarget.2.displayNameと指定します

Search System Logsカード使用時の403エラー

出来上がって実際に動かしてみたところ、Search System Logsで403エラーが起こってしまいました

Okta WorkflowsにLogを読み取る権限を付与できていなかったことが原因のようでしたので下記の通り対処しました

Okta管理画面より「アプリケーション」→「Okta Workflows OAuth」→「Okta APIのスコープ」をクリック

okta.logs.readの権限を付与します

以上が躓いたところです、奥が深いですが使えば使うほど慣れてきました!

最後に

今回はOktaでDeactivateしたユーザーがSaaS側で自動削除されていることをWorkflowsを使ってSlack通知する方法をご紹介しました

入社時の通知についても別の親フローを作成し、システムログのフィルター条件を変えるだけで子フローは同じものを活用できます
各SaaSに入ってユーザーが作られている/削除されていることを目視で確認したりログをみたりしていた稼働を減らすことで、エレガントになったのではないでしょうか!

Workflowsは今回のケースのように「自動化したい」「エレガントにしたい」と普段思っているところにハマりやすい機能ですので是非活用してみてはいかがでしょうか