工事中

AWS予算オーバー時にSlack, LINEに通知する方法
2021年1月10日
目次
Open TOC
link

対象

    Email通知以外の方法で利用料確認をしたい人
    利用料が一定額を超えたときに、LINEやSlackに通知したい人
link

Slack 通知

一定額超えたら、Slack に通知するように設定します。

マイ請求ダッシュボードの AWS Budgets から『予算を作成』をクリックします。

billing/home#budgets

Budgets top

『予算タイプの選択』を『コスト予算』にします。

Budgets type

AWS チャットボットのアラートというのを設定しないと、Slack 通知ができないので、次はそちらを設定します。

link

AWS Chatbot の設定

AWS Chatbot にアクセスします。

chatbot/home#/home

Chatbot

チャットクライアントを Slack に設定し、自身の作成した Slack のワークスペースと連携します。

連携が終わると、以下の画面に遷移します。

slack

新しいチャンネルを設定するためには既に作成されたSNSが必要なので、次はSNSを設定します。

link

SNS の設定

Amazon Simple Notification Service にアクセスします。

sns/v3/home?region=ap-northeast-1#/homepage

sns

トピック名を適当に作成し、次のステップに移ります。

SNS は AWS Budgets から実行したいので、アクセスポリシーを修正します。

デフォルトでは以下のようになってます (メソッドを『高度な』に変えると JSON エディタが開きます)。

1
{
2
"Version": "2008-10-17",
3
"Id": "__default_policy_ID",
4
"Statement":
5
[
6
{
7
"Sid": "__default_statement_ID",
8
"Effect": "Allow",
9
"Principal": { "AWS": "*" },
10
"Action":
11
[
12
"SNS:Publish",
13
"SNS:RemovePermission",
14
"SNS:SetTopicAttributes",
15
"SNS:DeleteTopic",
16
"SNS:ListSubscriptionsByTopic",
17
"SNS:GetTopicAttributes",
18
"SNS:Receive",
19
"SNS:AddPermission",
20
"SNS:Subscribe",
21
],
22
"Resource": "arn:aws:sns:ap-northeast-1:<マイアカウントの番号>:<トピック名>",
23
"Condition":
24
{ "StringEquals": { "AWS:SourceOwner": "<マイアカウントの番号>" } },
25
},
26
],
27
}

AWS Budgets から SNS を push するように、これを Statement に追加します。

1
{
2
"Sid": "AWSBudgets-notification-1",
3
"Effect": "Allow",
4
"Principal": { "Service": "budgets.amazonaws.com" },
5
"Action": "SNS:Publish",
6
"Resource": "arn:aws:sns:ap-northeast-1:<マイアカウントの番号>:<トピック名>",
7
}

最終的にこうなります。

1
{
2
"Version": "2008-10-17",
3
"Id": "__default_policy_ID",
4
"Statement":
5
[
6
{
7
"Sid": "AWSBudgets-notification-1",
8
"Effect": "Allow",
9
"Principal": { "Service": "budgets.amazonaws.com" },
10
"Action": "SNS:Publish",
11
"Resource": "arn:aws:sns:ap-northeast-1:<マイアカウントの番号>:<トピック名>",
12
},
13
{
14
"Sid": "__default_statement_ID",
15
"Effect": "Allow",
16
"Principal": { "AWS": "*" },
17
"Action":
18
[
19
"SNS:Publish",
20
"SNS:RemovePermission",
21
"SNS:SetTopicAttributes",
22
"SNS:DeleteTopic",
23
"SNS:ListSubscriptionsByTopic",
24
"SNS:GetTopicAttributes",
25
"SNS:Receive",
26
"SNS:AddPermission",
27
"SNS:Subscribe",
28
],
29
"Resource": "arn:aws:sns:ap-northeast-1:<マイアカウントの番号>:<トピック名>",
30
"Condition":
31
{ "StringEquals": { "AWS:SourceOwner": "<マイアカウントの番号>" } },
32
},
33
],
34
}

トピックを作成したら、ARN をコピーしておきます。

1
arn:aws:sns:ap-northeast-1:<アカウント番号>:<SNSトピック名>
link

AWS Chatbot のチャンネル設定に戻る

CloudWatch のログを有効化しておきます。

CloudWatch

Slack チャンネルはパブリックにしておきます。

アクセス権限も適当に選択しておきます。

IAM Role

通知オプションは SNS で作成したものを使います。

notification option
link

AWS Budgets から『予算を作成』に戻る

SNS の設定で、作成した ARN を貼り付けます。

SNS ARN

予算を 1$にし、アラート通知を 1%にすれば、通知のテストができます。

こんな感じで Slack に通知がきます (AWS は自動でメンバーに追加されます)。

Slack Notification

これで、AWS Chatbot が SNS の push を検知して、Slack に通知を送るようになります。

link

LINE Bot の設定

先に Lambda を作ります。

link

Lambda の設定

Node.jsで作成します。

lambda

SNS でトリガーして、Lambda が動くようにします。

lambda

Lambda に何が来るかわからないので、console.log で確認してみます。

index.js
1
exports.handler = async event => {
2
console.log("AWS Budgets Test")
3
console.log(event)
4
console.log(JSON.stringify(event))
5
// TODO implement
6
const response = {
7
statusCode: 200,
8
body: JSON.stringify("Hello from Lambda!"),
9
}
10
return response
11
}

CloudWatch では以下が返ってきました。

大雑把な値を知りたい場合は、AWS Budgets で設定する予算名に値段を入れておくと良さそうです (Sns の Subject で取れます)。

詳細を取り出したい場合は、Message を使います。/n とか入ってますが、LINE がいい感じに整形するので、そのまま投げても大丈夫です。

1
{
2
"Records":
3
[
4
{
5
"EventSource": "aws:sns",
6
"EventVersion": "1.0",
7
"EventSubscriptionArn": "xxx",
8
"Sns":
9
{
10
"Type": "Notification",
11
"MessageId": "xxx",
12
"TopicArn": "xxxx",
13
"Subject": "AWS Budgets: <AWS Budgetsで設定した予算名> has exceeded your alert threshold",
14
"Message": "xxxxxxxx",
15
"Timestamp": "2020-11-02T15:43:38.009Z",
16
"SignatureVersion": "1",
17
"Signature": "xxxxx",
18
"SigningCertUrl": "xxxx",
19
"UnsubscribeUrl": "xxxx",
20
"MessageAttributes": {},
21
},
22
},
23
],
24
}

どちらにせよ、以下で Subject と Message が取れることがわかります。

index.js
1
exports.handler = async event => {
2
console.log("AWS Budgets Subject")
3
console.log(event.Records[0].Sns.Subject)
4
console.log("AWS Budgets Contents")
5
console.log(event.Records[0].Sns.Message)
6
// TODO implement
7
const response = {
8
statusCode: 200,
9
body: JSON.stringify("Hello from Lambda!"),
10
}
11
return response
12
}

上記の CloudWatch の結果をコピーし、テストをクリックします (SNS のテンプレートを選んで使っても大丈夫です!)。

Lambda Test

新しいテストイベントを作成し、先ほどの CloudWatch の結果を貼り付けます。

Lambda Test Event

再度テストをクリックすると、テストが実行され、結果が見れます。

Lambda Test Result
CloudWatch Log
link

LINE Bot の設定

developer コンソールにログインします。

https://developers.line.biz/console/

ログインして、Provider を作成します。

provider

LINE Bot に予算アラートを喋らせるので、Messaging API を選びます。

LINE

カテゴリなどを適当に設定しておきます。

設定が終わると、この画面になります。

Basic Setting の一番下にシークレットアクセスキーとユーザー ID、Messaging API にアクセスキーがあるので、控えておきます。

LINEの設定
link

Lambda に反映

ローカルの適当なディレクトリで、以下のコマンドを実行します。

1
$ touch index.js
2
$ yarn init
3
$ yarn add @line/bot-sdk

ディレクトリ構成はこんな感じです。

1
lambda_test
2
├── apis
3
| └── line.js
4
├── index.js
5
├── package.json
6
├── node_modules/
7
└── yarn.lock

line.js は次のようにします。

apis/line.js
1
"use strict"
2
3
const line = require("@line/bot-sdk")
4
const configs = {}
5
6
if (process.env.LINE_CHANNEL_TOKEN && process.env.LINE_CHANNEL_SECRET) {
7
configs.channelAccessToken = process.env.LINE_CHANNEL_TOKEN
8
configs.channelSecret = process.env.LINE_CHANNEL_SECRET
9
} else {
10
console.warn("LINE Channel Token or Secret Token is missing...")
11
}
12
13
module.exports = new line.Client(configs)

index.js はこうします。

index.js
1
"use strict"
2
3
exports.handler = async event => {
4
const lineClient = require("../images/apis/line")
5
console.log("AWS Budgets Subject")
6
await lineClient.pushMessage(process.env.USER_ID, {
7
type: "text",
8
text: event.Records[0].Sns.Subject,
9
})
10
console.log("AWS Budgets Contents")
11
await lineClient.pushMessage(process.env.USER_ID, {
12
type: "text",
13
text: event.Records[0].Sns.Message,
14
})
15
16
const response = {
17
statusCode: 200,
18
body: JSON.stringify("Hello from Lambda!"),
19
}
20
return response
21
}

作成した以下のファイルを zip 化し、Lambda にデプロイします。

1
lambda_test
2
├── apis
3
| └── line.js
4
├── index.js
5
├── package.json
6
├── node_modules/
7
└── yarn.lock

先ほどのように Lambda でテストをしたり、適当な予算を作ってみたりすると、LINE にもアラートが飛ぶようになります。

line alert
link

総括

これで、設定した予算よりも利用料が超えそうになると、Slack と LINE にメッセージが飛ぶようになりました。

自己紹介
はじめまして Pilefortです。
東京でエソジニアをしてます。
興味のあるスタックは、JavaScript (React, Vue), TypeScript, Rust, WebAssembly, AWS, Pulumi, Serverless Frameworkです。
このブログでは、普段の業務や趣味で気になったことをまとめたり、フロントやAWS, GitHubやTwitterで見かけた面白い記事やニュースをまとめるためのものです。少しでも何かの役に立てば幸いです。
最近の活動
技術書典12 (2022.1.22 - 2022.1.30) で本を出しました。
2021年に登場したり、大幅なアップデートがあったWebサービスや開発ツール、ライブラリ、フレームワークを紹介した本です。
TailwindCSSv3やRailway, Partytown, Nextjs12なんかの紹介やChrome DevToolsやChrome Extensions Manifest V3などの話を書いてます。
うぇぶちぇんじろぐ2022
サイトマップ
Notes
業務や趣味での気づき・メモ
Scraps
雑記。ネットで見つけた面白い記事やニュース
Snippets
記事にするまでもないけど、便利なコマンドや豆知識