GitHub Actions で Azure コストを毎朝 Teams に自動通知してみたー手順と解説ー


はじめに

こんにちは!最近 Azure のコスト管理を自動化するのにはまっている横浜情報機器株式会社インターン生のロホマン シャヒンです。

RS

ロホマン シャヒン

  • Microsoft Student Ambassador
  • GitHub Copilot User Group Japan 運営
  • Azure Solutions Architect Expert 取得

「Azure のコスト、今月いくらかかってるんだっけ?」と毎朝ポータルを開いて確認するのが地味に面倒で、何とかしたいと思っていました。Azure Cost Management の REST API と GitHub Actions を組み合わせたら、毎朝 Teams に Adaptive Card で届くようになったので、その手順をまとめます。

コードはほぼゼロから書いて、外部ライブラリも不要な構成にしました。Python 標準ライブラリだけで動きます。


1. 全体構成と仕組み

正直、最初は「GitHub Actions でコスト取得なんてできるの?」と思っていました。やってみたら思ったよりシンプルで、構成はこんな感じです。

  • Azure Cost Management REST API — サブスクリプションの月累計コストとサービス別 Top 7 を取得
  • GitHub Actions — 毎朝 9:00 JST(UTC 00:00)にスケジュール実行
  • Python スクリプト — 標準ライブラリだけで API 呼び出しと Adaptive Card の組み立て
  • Teams Incoming Webhook — Power Automate 経由で Adaptive Card を Teams チャンネルに投稿
  • API(任意)— コストデータを AI 分析して推奨事項を付記

GitHub Secrets に Azure の認証情報と Teams の Webhook URL を登録しあわせておくだけで動きます。CI/CD パイプラインと同じリポジトリで管理できるのが地味に便利で、「どこで動いてるんだっけ」問題が起きません。

GitHub Actions → Azure Cost Management → Teams の全体フロー図

2. リポジトリの構成を確認する

今回作成したリポジトリ azure-cost-daily-report は以下の構成です。

azure-cost-daily-report/
├── .github/
│   └── workflows/
│       └── daily-cost-report.yml    # GitHub Actions ワークフロー
├── scripts/
│   └── daily_cost_report.py         # メインスクリプト
└── README.md

ワークフローファイル(.github/workflows/daily-cost-report.yml):

name: Daily Azure Cost Report → Teams

on:
  schedule:
    # 毎朝 9:00 JST (= UTC 00:00) に実行
    - cron: "0 0 * * *"
  workflow_dispatch: # 手動実行も可能

jobs:
  cost-report:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Send daily cost report to Teams
        env:
          AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
          AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
          AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
          AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }}
          GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
        run: python scripts/daily_cost_report.py

cron: "0 0 * * *" が UTC の 0 時、つまり JST の朝 9 時に実行されます。workflow_dispatch を入れておくと GitHub の Actions タブから手動実行もできて、テスト時に便利でした。

GitHub リポジトリ概要と README に表示されるサンプル通知

3. サービスプリンシパルを作成する(Entra ID App Registration)

GitHub Actions から Azure API を叩くには、サービスプリンシパル(アプリ登録)が必要です。

  1. Azure Portal を開き、「Microsoft Entra ID」「アプリの登録」「新規登録」 をクリック
  2. 名前を入力(例:azure-cost-daily-reports)して登録
Azure Portal で「Microsoft Entra ID」を検索
Entra ID の概要画面で「アプリの登録」をクリック
アプリの登録一覧で「新規登録」をクリック
Entra ID でのアプリ登録画面

登録が完了すると、アプリケーション (クライアント) IDディレクトリ (テナント) ID が表示されます。この 2 つは後で GitHub Secrets に使うので、画面を閉じる前に必ずコピーしておいてください。ちなみに「テナント ID ってどこだっけ」と迷ったら、ここの概要ページに両方あります。

アプリ登録完了後の概要画面(クライアント ID 確認)

4. クライアントシークレットを取得する

アプリ登録の左メニューから 「証明書とシークレット」 を開き、「新しいクライアント シークレット」 を作成します。

アプリ概要の「クライアントの資格情報」から証明書とシークレット画面へ
証明書とシークレットページ

説明と有効期限を入力して「追加」をクリック。

新しいクライアントシークレット作成フォーム

作成直後だけシークレットの 「値」 が表示されます。この画面を離れると二度と確認できないので、必ずここでコピーしてください。

クライアントシークレット値(作成直後のみ表示)

⚠️ 注意:シークレット値はこの画面を閉じると見えなくなります。コピー漏れに注意。


5. Teams Incoming Webhook を設定する

Teams でコストレポートを受け取るチャンネルに Incoming Webhook を追加します。

  1. Teams のチャンネル右上「…」→ 「コネクタ」 または 「ワークフロー」 を開く
  2. 「Incoming Webhook」を選択して設定を進める
  3. Webhook の名前(例:Azure Cost Report)を入力
  4. 生成された Webhook URL をコピー
Teams に「Azure コストレポート」チャネルを作成
チャネルの「…」オプションメニューを開く
メニューから「ワークフロー」を選択
Teams「ワークフロー」で Webhook テンプレートを検索・選択
Webhook 送信先のチームとチャネルを選択して「保存」
Webhook 設定完了 ─「Webhook リンクをコピー」で URL を取得

メモ:Teams の「ワークフロー」で作成した場合、Power Automate 経由の Webhook になります。このスクリプトでは Power Automate 形式(attachments でラップする形式)に対応済みです。


6. GitHub Secrets を登録する

リポジトリの 「Settings」→「Secrets and variables」→「Actions」 を開き、以下の 5 つのシークレットを追加します。

GitHub Settings サイドバーの「Secrets and variables」を展開
GitHub リポジトリ Settings からシークレット設定画面へ
Actions シークレット管理画面(未登録状態)
シークレット名
AZURE_TENANT_ID Entra ID のテナント ID
AZURE_CLIENT_ID アプリ登録のクライアント ID
AZURE_CLIENT_SECRET 作成したクライアントシークレットの値
AZURE_SUBSCRIPTION_ID 対象サブスクリプションの ID
TEAMS_WEBHOOK_URL Teams の Webhook URL

設定完了後、5 つ全部が並んでいれば OK です。

GitHub Actions シークレット 5 件が登録された状態

7. Azure IAM でロールを割り当てる

サービスプリンシパルにコスト情報を読む権限を付与します。コストの参照だけなので、「コスト管理の閲覧者」 ロールで十分です。

  1. Azure Portal → 「サブスクリプション」 を開く
  2. 対象サブスクリプションを選択 → 「アクセス制御 (IAM)」
  3. 「追加」→ 「ロールの割り当ての追加」
Azure Portal ダッシュボードで「サブスクリプション」を選択
サブスクリプション一覧でサブスクリプション ID を確認
対象サブスクリプション(Microsoft Azure)を選択
サブスクリプションの IAM メニューからロール割り当て画面へ

ロールの検索欄に「コスト」と入力すると 「コスト管理の閲覧者」 が出てきます。これを選択して「次へ」。

アクセス制御(IAM)で「+追加」ボタンをクリック
「ロールの割り当ての追加」を選択
「コスト管理の閲覧者」ロールを検索して選択

「メンバー」タブで「+メンバーを選択する」→ アプリ名(azure-cost-daily-reports)で検索して選択します。

メンバー種別で「ユーザー・グループ・サービスプリンシパル」を選択して「+メンバーを選択する」
IAM メンバー選択でサービスプリンシパルを指定

「レビューと割り当て」で内容を確認して完了。

メンバーに azure-cost-daily-reports を追加して「レビューと割り当て」へ
IAM ロール割り当てのレビュー確認画面

8. GitHub Actions ワークフローを実行する

設定が揃ったら、スケジュール実行(翌朝 9 時)を待たずに手動で動作確認するのがおすすめです。私は最初に手動実行したとき、Teams に通知が届くまで 10 秒もかかりませんでした。

  1. リポジトリの 「Actions」 タブを開く
  2. 「Daily Azure Cost Report → Teams」 ワークフローを選択
  3. 「Run workflow」 をクリック
GitHub リポジトリの「Actions」タブを開く
GitHub Actions のワークフロー一覧
「Run workflow」ボタンで手動実行

9. Teams に届いた通知を確認する

ワークフローが成功すると、数秒〜十数秒で Teams に Adaptive Card が届きます。

Teams に届いた Azure 日次コストレポートの Adaptive Card

カードには以下の情報が含まれています:

  • 集計期間:当月 1 日〜今日の日付
  • 月累計コスト:サブスクリプション合計
  • サービス別 Top 7:コストの高いサービス順にリスト表示
  • AI 分析(Gemini API キーを設定した場合):コスト傾向・注意点・最適化推奨事項

実際に届いたカードを見て「あ、Microsoft Fabric がけっこうかかってるな」と気づけたのは嬉しい発見でした。毎朝確認するだけで、コスト異常に早く気づける体制ができました。


まとめ

  • GitHub Actions + Azure Cost Management REST API で、毎朝のコスト確認を完全自動化できる
  • サービスプリンシパルへの権限は 「コスト管理の閲覧者」 だけでよく、最小権限で動く
  • Python 標準ライブラリだけで完結するので、GitHub Actions 環境でそのまま動く
  • API を組み合わせると AI 分析付きのレポートに昇格する
  • 複数サブスクリプションにも対応済み(AZURE_SUBSCRIPTION_ID2 を追加するだけ)

「毎朝ポータルを開いて確認する」から「Teams に自動で届く」に変わっただけなのに、コスト超過への気づきが明らかに早くなりました。地味な自動化ですが、こういうのが積み重なると運用がかなり楽になります。

この記事が少しでも参考になったら、ぜひシェアしていただけると嬉しいです!

Azure のコスト管理・自動化の導入や、GitHub Actions を活用したクラウド運用の効率化について、Microsoftパートナー企業の YJK にお気軽にご相談ください。

Azure コスト管理・自動化を相談する

出典

技術ブログ一覧に戻る