Oktaのアプリケーションの割り当て処理が失敗したときにSlack通知を行い気付きやすくしました。 Okta logをAmazon EventBridgeにストリーミングし、EventBridgeから直接Slackにメッセージを送ります。
課題
Oktaでアプリケーションをアサインした後、OktaからSaaSに対してライセンス割り当ての処理が行われますが、SaaS側の問題で失敗している時があります。 アサインして即時エラーが出るわけではないのですぐに気づけないことがあります。 タスクには一覧表示されるけど常に見ているわけもなく。
失敗する理由としては、SaaS側でライセンスが不足している場合だったり、Microsoftの仕様でTeamsの試用版をセルフで開始している場合などがあります。
割り当て失敗のログ
失敗した時には、イベントログに記録されます。以下の条件で検索できます。
eventType eq "application.provision.user.push_profile" and outcome.result eq "FAILURE"
イベントログをトリガーに処理を行いたい
できれば、ノーコードで処理したいですよね。
Okta Workflowでトリガーあるかなと思ったけど無く、イベントフックという、イベントが発生した時に外部のURLに通知する機能もあるのですが、これも割り当て失敗イベントに対応していません。(Event Typesのうち event-hook-eligible
と書いてあるものが対象)
ということで、イベントログを外部に連携するログストリーミングを利用します。
ログストリーミング
ログストリーミングは外部にログを連携する仕組みですが、対応しているサービスが少なく、現状以下の2つのみです。
- Amazon EventBridge
- Splunk Cloud
Splunk Cloudは使っていなかったのでのEventBridgeを選択します。
Amazon EventBridgeへの接続
Amazon EventBridgeは、イベントを使用してアプリケーションコンポーネントを接続できるサーバーレスサービスです。これにより、スケーラブルなイベント駆動型アプリケーションを簡単に構築できます。イベント駆動型アーキテクチャとは、イベントの発信と応答によって連携する、ゆるやかに結合されたソフトウェアシステムを構築するスタイルです。イベント駆動型アーキテクチャは、俊敏性を高め、信頼性が高くスケーラブルなアプリケーションを構築するのに役立ちます。
→ 要するに、イベントのストリームを受け取って、それをフィルタして必要なイベントを抽出して、何か処理をしたりすることができるサービス。
AWS自体のイベント (例えばインスタンスの起動停止とか) は当然ながら、パートナーイベントソースというのがあって、他のSaaSのイベントを受け取って処理をすることができる。
他SaaSのイベントをトリガにAWSで何か処理をするとか、単にログを保存するといったことに便利。
Okta側で送信先のAWSアカウントの設定をして、EventBridge側で受け取りの処理をすると接続完了
イベントの受け取り
連携したデータはイベントバスというものに流れてきて、ここに対してルールを設定して、欲しいイベントを受け取ることができる。
流れてくるデータはこんな感じで
{ "version": "0", "id": "...", "detail-type": "SystemLog", "source": "aws.partner/okta.com/tenant/okta", "account": "...", "time": "2024-12-16T03:38:37Z", "region": "ap-northeast-1", "resources": [], "detail": { "actor": { "id": "...", "type": "User", "alternateId": "actor@example.jp", "displayName": "Actor", "detailEntry": null }, ... "displayMessage": "Push user's profile to external application", "eventType": "application.provision.user.push_profile", "outcome": { "result": "FAILURE", "reason": null }, "published": "2024-12-16T03:38:37.672Z", "securityContext": { "asNumber": null, "asOrg": null, "isp": null, "domain": null, "isProxy": null }, "severity": "ERROR", "legacyEventType": "app.user_management.push_profile_failure", ... "uuid": "...", "version": "0", "request": { "ipChain": [] }, "target": [ { "id": "...", "type": "AppUser", "alternateId": "mail@example.jp", "displayName": "Name", "detailEntry": null }, { "id": "...", "type": "User", "alternateId": "mail@example.jp", "displayName": "Name", "detailEntry": null }, { "id": "...", "type": "AppInstance", "alternateId": "Microsoft", "displayName": "Microsoft Office 365", "detailEntry": null } ] } }
イベントパターンというもので対象を抽出する
{ "source": [{ "prefix": "aws.partner/okta.com" }], "detail": { "eventType": ["application.provision.user.push_profile"], "outcome": { "result": ["FAILURE"] } } }
Slackへの送信
EventBridgeはAWSサービスの呼び出しの他、外部APIを呼び出すことができるので、直接Slack APIを呼び出すことにします。 API接続でパートナーテンプレートというのがありSlackもパートナーとして存在するのですが、ドキュメントがまともになくどう接続するかさっぱりわからなかったので、使うのは諦めました。
APIを呼び出すときのpayloadを作るのに入力トランスフォーマーというものを使って加工します。
変数を入力パスというので定義する。JSONから欲しいデータをとってくる
{ "actor": "$.detail.actor.alternateId", "app": "$.detail.target[2].displayName", "app_id": "$.detail.target[2].id", "app_user": "$.detail.target[0].alternateId", "user": "$.detail.target[1].displayName", "user_id": "$.detail.target[1].id" }
入力テンプレートをこんな感じで定義しました。Slackに送るのでチャンネル指定して、雑にblockを定義する感じです。
{ "channel": "[channel id]", "blocks": [{ "type": "section", "text": { "type": "mrkdwn", "text": "<!subteam^[group_id]> <actor> が実施したアプリケーションの割り当てが失敗しました。 <https://tenant-admin.okta.com/admin/tasks|Task> を確認して解消してください。\n\n- User: <https://tenant.okta.com/admin/user/profile/view/<user_id>|<user>>\n- App: <https://tenant-admin.okta.com/admin/app/app_name/instance/<app_id>|<app>>" } }] }
送信先を作成して、エンドポイントをSlackの chat.postMessage
に、メソッドをPOST、認証としてAuthorizationヘッダにSlackアプリを作成して、トークンを取得して Bearer <bot token>
と指定する
できた
こんな感じで通知されます Actor (アプリケーション割り当てを実施した人) をメンションしています。