はじめに
Azureコンテナソリューショングループの髙井です。
私の部署ではAzureのクラウドネイティブ内製化支援サービスを提供しています。そして、その一環として、私はAKSを中心としたAppアーキテクトを担当しています。
ところでみなさんは、Azureの料金をSlackに通知させたくなったことがありませんか?
ありますよね。あると思います。
ということで今日はその方法をざっくり紹介しましょう。
全体の流れ
お仕事的にはAzure推しなのでLogic Apps
やFunctions
を使っていただきたいところですが、単なるREST APIのためGAS1等を使って無料で組むことも可能です。
ざっくりの内容としては以下となります。
- 認証用のサービスプリンシパルを作る
- サービスプリンシパルを使ってAPI用のtokenを取得する
- Cost Management APIを叩いて課金データのJSONを取得する
- JSONをエエ感じに加工してSlackに投げるためのFunctionsなりGASなりのコードを書く
今回は前編として「サービスプリンシパルを使ってAPI用のtokenを取得する」までを説明していきます!
1. 認証用のサービスプリンシパルを作る
では、さっそくやっていくわけですが、サービスプリンシパルとは何ぞや、と。
Azureを触り始めたばかりだとこれがわからずにいきなり面食らうと思います。
大丈夫です。Azure Solutions Architect Expertの私が説明いたしましょう。
いや、偉そうにしてすみません。先着で会社から報奨金が出ると聞いて取っただけなんです許してください現金は正義ですお金のためならなんだってやります
1-1. サービスプリンシパルとは何か
気を取り直して、まず分かりやすいところからいきましょうか。
たとえば人間が課金情報を見る場合、ブラウザでAzure Portalにログインして、サブスクリプションのコスト分析で課金情報を見ます。
これはその人が、サブスクリプションに紐づいたAADテナントに存在するアカウントを使ってログインしているので、Azureが「お前さんは見てもオッケー」と許してくれているわけです。
新しい言葉が出てきましたね。これも説明しておかねばならないでしょう。
Azureサブスクリプション
まず、サブスクリプションは、ざっくりAzureに登録するクレジットカードごとの区分だと思ってください。
Azureを使ったらお金がかかる→お金は登録したクレカで払う→クレカを登録するときにサブスクリプションというグループが作られていて、普段はその中でAzureを使っている(別のサブスクリプションを作ってその中でAzureを使うとその分は別の支払い方法になる)くらいの認識でOKです。
AAD(Azure Active Directory)
そして、AADテナントというのは、同じAzureを使う人たちを管理するグループです。たとえば、あなたがABC株式会社にいるとして、ABC株式会社の社員が共同で利用するAzureがあったとしたら、すべての社員は同じAADテナントに属します。つまりAADテナント=会社や組織ごとのグループと思えばOKです。厳密にはいくつかの会社で共同で使うなどのパターンも存在するのでその限りではありませんが、今は「AADテナント=同じAzureを使う人がみんなそこに入っている」くらいの認識でOKでしょう。
人ではなく「アプリ」に権限を与える
話を戻しましょう。あなたはブラウザでAzure Portalを開けば課金情報を見ることができます。これと同じことを今から作るアプリでも実現したいです。つまり、人ではなくアプリに対して課金情報を見る権限を付与してやらねばなりません。
察しの良い読者の方であればもう気付いたと思います。そうです、そのためのエンティティがサービスプリンシパルです。
1-2. サービスプリンシパルの作り方
サービスプリンシパル(SP)は、人ではなくアプリに権限を付与するための仕組みでした。次はSPを実際に作っていきましょう。
これはGUIでやるならAzure PortalのAzure Active Directory
からアプリの登録
で行えます。
が。
わりとポチポチ回数が多くて面倒なので、ここはローカルのAzure CLI
あるいはAzure Cloud Shell
で以下のコマンドを叩いて一発で終わりにしましょう。
az ad sp create-for-rbac --name slack-cost --role "Billing Reader"
上記のコマンドを叩くと以下のような結果が返ってきます。
{ "appId": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", "displayName": "slack-cost", "name": "http://slack-cost", "password": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "tenant": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" }
これで対象のサブスクリプションについてのBilling Reader
=課金データ閲覧者
のロールを持つSPを作成できました!
長々と説明したわりにやることはたったの一行でした……(笑)
が、ワケも分からずコマンドを打っても一生理解した気持ちになれないと思いますので、けっして無駄な説明ではなかったと思い込むことにします。
コマンドを打って返ってきたJSON形式の情報はあとで使いますので画面は消さないようにしてください。ちなみに、コマンドに含まれるslack-cot
は作成するSPの名前です。これは任意の名前に変えてしまってもかまいません。
2. API用のtokenを取得する
課金データを取得するには、Azureが用意しているREST APIであるCost Mangement API
を叩いてあげればOKです。
そのためにはまず、Cost Management API
に対する認証・認可プロセスに使用するtokenを取得する必要があります。
curlで叩くならこうです。3箇所ある${}
には、さきほどSPを作った際に出てきた情報を入れてください。(ローカルにcurlとjqがインストールされている前提です)
curl -X POST \ https://login.microsoftonline.com/${tenant}/oauth2/token \ -F grant_type=client_credentials \ -F resource=https://management.core.windows.net/ \ -F client_id=${appId} \ -F client_secret=${password} \ | jq -r .access_token
このcurl
コマンドを実行するとメチャクチャ長い文字列が返ってきます。
そう、これこそが我々が求めしtokenです!
ちなみにcurlではなくGASだとこんなイメージでしょうか(これはclaspでトランスパイルされたものです)。
function fetchToken() { var payload = 'client_id=' + CLIENT_ID + '&client_secret=' + CLIENT_SECRET + '&grant_type=client_credentials' + '&resource=https%3A%2F%2Fmanagement.core.windows.net%2F'; var options = { headers: { contentType: 'application/x-www-form-urlencoded' }, method: 'post', payload: payload }; var url = 'https://login.microsoftonline.com/' + TENANT_ID + '/oauth2/token'; var res = UrlFetchApp.fetch(url, options); var token = JSON.parse(res.getContentText()).access_token; return token; }
詳細は省きますが、GASでは認証情報のハードコーディングを避けるため、組み込みのキーバリューストアPropertiesServie
を利用するのがよいでしょう。
var TENANT_ID = PropertiesService.getScriptProperties().getProperty('TENANT_ID');
次回につづく
今回はtokenの取得方法までを解説しました。これで、ようやくAPIを利用する準備が整ったことになります。
次回は、満を持してCost Management API
を呼び出しましょう!
-
Google Apps Scriptの略。無料で利用でき、ブラウザ上で動くJavaScriptベースの言語です。↩