SlackへのAWS料金通知を(ほぼ)Step Functionsの機能だけで作ってみた
大阪オフィスの小倉です。
プライベートのAWSアカウントをAWS Organizationsで管理するようになったのですが、
それに伴って従来使っていたSlack料金通知が活用しづらくなってしまいました。
長年お世話になってきたのは以下のブログです。
ということで、以下の要件に従い、Step Functionsで作り直してみました。
- 基本の仕様は上記ブログを踏襲
- マルチアカウント環境で、アカウント別と合計の料金を通知したい
- Lambdaを使わずに実装したい
できたもの


実装はマネジメントコンソールで行った後、以下の機能でCloudFormationテンプレートにExportしています。
以降、Step Functionsの実装部分を紹介していきます。
日付の編集
EventBridge Schedulerから送られる日付を利用して、集計日付のFrom-Toを作ります。
- 基本は当月の月初日〜本日
- ただし、本日が月初日の場合、前月の月初日〜前月末日
編集処理は、先日対応が発表されたJSONataを使いました。
入力のtimeの値を使って、
{
  "version": "0",
  "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "detail-type": "Scheduled Event",
  "source": "aws.scheduler",
  "account": "xxxxxxxxxxxxx",
  "time": "2024-12-10T00:00:00Z",
  "region": "ap-northeast-1",
  (省略)
}
From-Toを作ります。
{
  "start_date": "2024-12-01",
  "end_date": "2024-12-10"
}
JSONataはプログラミング言語としての機能を備えているので、変数、条件分岐、ループなどが使えます。
うるう年の判定とかあるので、だいぶ力技です。。。
サービス料金をアカウント毎に集計
組織の管理アカウント上でGetCostAndUsage APIを実行すると、
配下のアカウントの料金情報もまとめて取得できますが、ResultsByTime.Groupsという配列の中に全アカウント分入ってしまうので、 こちらもJSONataで編集・集計します。
APIの出力は以下イメージですが、
{
	"DimensionValueAttributes": [
		{
			"Attributes": {
				"description": "account-1"
			},
			"Value": "111111111111"
		},
		{
			"Attributes": {
				"description": "account-2"
			},
			"Value": "222222222222"
		},
        (略)
	],
	"GroupDefinitions": [
		{
			"Key": "LINKED_ACCOUNT",
			"Type": "DIMENSION"
		},
		{
			"Key": "SERVICE",
			"Type": "DIMENSION"
		}
	],
	"ResultsByTime": [
		{
			"Estimated": true,
			"Groups": [
				{
					"Keys": [
						"111111111111",
						"AWS Cost Explorer"
					],
					"Metrics": {
						"AmortizedCost": {
							"Amount": "0.58",
							"Unit": "USD"
						}
					}
				},
				{
					"Keys": [
						"111111111111",
						"AWS Lambda"
					],
					"Metrics": {
						"AmortizedCost": {
							"Amount": "0.0000123252",
							"Unit": "USD"
						}
					}
				},
    (略)
}
このように、アカウント毎にまとめてみました。
{
  "accounts": [
    {
      "accountId": "111111111111",
      "description": "account-1",
      "totalCost": "2.13 USD",
      "services": {
        "AWS Cost Explorer": "0.18 USD",
        "AWS Secrets Manager": "0.11 USD",
        "EC2 - Other": "0.09 USD",
        "Amazon Route 53": "0.5 USD",
        "Amazon Simple Storage Service": "1.04 USD",
        "Tax": "0.2 USD"
      }
    },
    {
      "accountId": "222222222222",
      "description": "account-2",
      "totalCost": "0.32 USD",
      "services": {
        "AWS Cost Explorer": "0.18 USD",
        "AWS Secrets Manager": "0.11 USD",
        "Tax": "0.03 USD"
      }
    },
    {
      "accountId": "333333333333",
      "description": "account-3",
      "totalCost": "0.41 USD",
      "services": {
        "AWS Cost Explorer": "0.37 USD",
        "Tax": "0.04 USD"
      }
    }
  ],
  "total": "2.86 USD"
}
あとは、アカウント毎にMapステートで処理してあげます。
まとめ
JSONataがサポートされたことで、従来Lambdaで行っていた編集処理をStep Functions内で完結させることができました。
JSONataは今回利用した書き方だけでなく、クエリによる配列やオブジェクトの操作、ソートや集計、各種関数を利用することが出来るので、
ステート入出力の編集処理は恐らくJSONataでほぼ対応できるのではないでしょうか。
Web上にPlaygroundも多数あり、ブラウザからすぐ試すことも出来ますので、
少しでも気になる方は是非JSONataのドキュメントを確認してみてください。










