はじめに
この記事では
AWS のサービスと LINE Messaging API 連携させて
AWS の請求情報を返してくれる LINE bot を作成するハンズオンです。
ベストプラクティスや間違いがあれば書き直していく予定です。
※実演動画がくろかわこうへいさんのチャンネルで公開されました。
https://youtu.be/w8o5uI2ONGw
LINE Developers Communityの紹介もされていますので
もしご興味のある方はぜひ!!
そもそもなんで bot なんか作ろうと思ったんすか?
大人の事情があるんですけど
それはタテマエでホンネを言うと
多額の請求でクラウド破産する人が
いらっしゃるので手軽に請求情報にアクセスできる仕組みが欲しい。
あと、コンソールにログインするのが面倒
という事情があったりします。
開発環境
-
Surface Book(初代)
- 実装 RAM 8GB
-
エディション Windows 10 Pro
-
バージョン 20H2
-
OS ビルド 19042.867
-
Chrome
- 89.0.4389.90(Official Build) (64 ビット)
-
Python 3
- Version 3.95
今回は Web ベースで行うので利用する PC は Mac でも問題ありません。
が、途中で Python のソースコード編集したり、pip でパッケージをダウンロードするので
- Python3 がインストールされていること
が最低条件になります。あとは
ご自身が使いやすい環境に合わせていただけると幸いです。
今回扱うサービス
AWS 側
AWS Lambda
AWS API Gateway
AWS IAM
AWS Cost Explorer
AWS CloudWatch
AWS S3
LINE 側
LINE Developers Console
LINE Messaging API
おことわり
今回は外部に漏らしてはいけない重要な情報を扱います。
LINE Developers Console で言うと
-
Channel ID
-
チャネルアクセストークン
-
User ID
AWS 側では
-
API Gateway で作成した API の URL
-
アカウント ID および IAM ユーザ名
また、これらに加えて IAM ユーザおよび IAM ロールは
最小権限の原則を守ってアカウントを運用しましょう。
他、注意事項ですが
Cost Explorer を有効化後、AWSリソースを利用して24時間が経過しないと
Cost Explorer にコストが反映されません。
コストが反映されていない為
LINE botをテストしたときに以下のようなエラーが出る可能性があります。
[Error]
specify up to the past 12 months.
User not enabled for cost explorer access
LINE botの作り方に問題が見られない場合は24時間おいて
メッセージをLine botに送ると良いでしょう。
今回利用するサービスの説明
Lambda
AWS の中ではコンピューティングリソースを提供してくれるサーバレスサービスの代表例
後述の API Gateway と組み合わせることで Web API として利用できるサービス
API Gateway
API を構築、公開できるフルマネージド型のサービス
フルマネージドというのはざっくりいうと、運用管理などを気にせず、裏側で良しなにやってくれる形態のこと
今回は Lambda と LINE bot の中間に出入口を作ってくれる役割を果たす。
IAM
AWS Identity and Access Management の略
AWS サービスのアクセス管理に利用するサービス
今回は Lambda が Cost Explorer にアクセスするときのアクセス権と
CloudWatch にアクセスするときのアクセス権を管理します。
Cost Explorer
AWS のコストと使用量の経時的変化を可視化するサービス
今回はこちらのサービスで算出される利用料を取得します。
Cloud Watch
AWS のサービスおよびリソースを監視するサービス
監視した内容は S3 に保存される。
今回は Lamda がうまく動かない時などの切り分けに利用
S3
AWS のオブジェクトストレージサービス
ここでは具体的に述べませんが過去に記事を作成していますので
わからない方はこちらをご覧ください。
【AWS】用語を整理しながら学ぶ AWS - part7 Simple Storage Service
今回は bot の動作に直接関係はないですが、Cloud Watch のログを保存する先に指定されています。
(※エラー発生時には参照することになるので解説)
LINE Developers
LINE Developers とは
ざっくり言うと
LINE の開発者向けサービス
自身の開発したアプリケーションに LINE を組み込む際に
必要な開発者向けの情報や API が提供されています。
事前準備
LINE Developers Console にログインする
「Messaging API」をクリックします。
「今すぐ始めよう」をクリック
LINE アカウントにログイン
ご自身の LINE アカウントで認証をしていただければと思います。
プロバイダの作成
チャネルを作成するには
まず、プロバイダを作成しなければいけません。
「Create a new provider」をクリック
作成するプロバイダ名を聞かれるので「AWS 請求表示」と入力して
「Create」をクリック
続いて、Messaging API をクリック
チャネルを作成
今回はこのように設定しました。
項目 | 入力内容 |
---|---|
チャネルの種類 | LINE Messaging API |
プロバイダー | AWS 請求表示 |
チャネル名 | AWS 請求確認 |
チャネル説明 | AWS の請求情報を返信してくれる bot です。 |
大業種 | ウェブサービス |
小業種 | ウェブサービス(その他) |
一応、各項目について説明すると
チャネルの種類:LINE Messaging API
プロバイダー:「新規プロバイダーの作成」を選択
プロバイダー名:管理コンソール上で表示される名前を入力
チャネル名:実際に LINE で表示される名前を入力
チャネル説明:チャネルの説明を書く
大業種:該当の業種を選択
小業種:大業種に合わせた該当の業種を選択
最後に規約を読んでチェック、作成をクリック
重要な情報をコピー
先ほど作成した チャネル を開く
Messaging API 設定にあるチャネルアクセストークンをメモしておく。
※チャネルアクセストークンは新規で bot を作成したとき
アクセストークンが発行されていない。
表示するには発行ボタンをクリックする必要がある。
LINE のデフォルト応答メッセージを消す
デフォルト設定では以下のように LINE のデフォルト応答メッセージが表示される為
デフォルトの応答メッセージを表示しないように
「Messaging API 設定」の 「応答メッセージ」を無効にする。
「Messaging API 設定」の 「応答メッセージ」を無効にする為には
LINE Official Account Manager から詳細設定を変更する。
LINE Official Account Manager を開く場合は
「Messaging API 設定」のにある以下の応答メッセージの項目にある編集をクリックする。
詳細設定の応答メッセージをオン → オフ
設定切替後は LINE Official Account Manager のウィンドウを閉じる。
LINE Developers Console にある「Messaging API 設定」から
「応答メッセージ」の項目がオフになっていることを確認する。
今回のインフラ構成図
AWS で利用するサービスと LINE とのつながりを明確に構成図に起こすとこんな感じになります。
IAM ポリシーを作成する
今回は請求情報にアクセスする為の IAM ロールを 作成する為に IAM ポリシーを作成する必要があります。
まずは AWS マネジメントコンソールから IAM のダッシュボードを開きます。
IAM のダッシュボードにある「ポリシー」をクリックして
IAM ロールにアタッチする IAM ポリシーを作成します。
json でポリシーを作成する。このとき権限は最小限にとどめる。
「ポリシーの作成」画面から JSON タブをクリックして
以下のポリシーにある「XXXXXXXXXXXX」をご自身のアカウント ID に置き換えてコピペ
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ce:GetCostAndUsage",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:ap-northeast-1:XXXXXXXXXXXX:*"
},
{
"Effect": "Allow",
"Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
"Resource": [
"arn:aws:logs:ap-northeast-1:XXXXXXXXXXXX:log-group:/aws/lambda/aws_cost_bot:*"
]
}
]
}
タグは以下のように設定
キー | 値 |
---|---|
CostExplorer | aws_cost |
ポリシー名および説明は以下のように設定後、「ポリシーの作成」をクリック
ポリシー名 | 説明 |
---|---|
MyCostExplorerRead | Amazon Web Services Cost Explorer Read Only |
IAM ロールの作成
ポリシー作成後はロールを作成します。
IAM のダッシュボードにある「ロール」をクリックして IAM ロールにポリシーをアタッチします。
「ロールの作成」をクリック
一般的なユースケースから Lambda を選択
先ほど作成したポリシー名を検索する。
ポリシー名は以下のように設定しました。(IAM ポリシーの作成時に入力したポリシー名)
ポリシー名 |
---|
MyCostExplorerRead |
こちらもポリシー名と同じく key Value を設定しておきましょう。
キー | 値 |
---|---|
CostExplorer | aws_cost |
次のステップへ
ロール名を設定します。今回はポリシー名と同じ名前を設定します。
ロール名 |
---|
MyCostExplorerRead |
ロールの作成をクリック
bot 用スクリプトの作成
Pyhton を利用します。
ソースコードは雲のメモ帳さんにある
ソースコードを引用してチョットだけアレンジしてみました。
※今回は LINE Developers Community の方に
ソースコードのレビューをしていただきました。ありがとうございました。
ソースコードは GitHub にアップロードしています。(クリックすると別タブで GitHub を開きます。)
LINE SDK をダウンロード
LINE bot 作成に必要なパッケージをインストールする為
pip install を利用します。
lambda_function.py を保存したディレクトリで以下のコマンドを実行
python -m pip install LINE-bot-sdk -t .
なお、MacBook環境の場合は
Python2とPython3の両方がインストールされている可能性があるのでpip3で
SDKをダウンロードするようにしてください。
pip3 install LINE-bot-sdk -t .
lambda_function.py と一緒に圧縮して保存します。ファイル名は「aws_cost_bot.zip」とします。
インストールが終わったら圧縮をして zip にしておきます。
うまく圧縮できると 2.2MB 弱になるかと思います。
※今後、LINE の SDK に変化があれば、サイズも変わるかと思います。
Lambda を利用
Lambda 関数を作成
LINE bot から利用する API を作成する為に
AWS マネジメントコンソールから Lambda のダッシュボードを開きます。
※Lambda のリージョンは東京リージョン(ap-northeast-1)を利用
Lambda のダッシュボードから関数をクリック
関数の作成をクリック
「一から作成(シンプルな Hello World の例で開始します。)」を選択
基本的な情報は以下の表のとおりに設定
項目 | 値 |
---|---|
関数名 | aws_cost_bot |
ランタイム | Python3.8 |
デフォルトの実行ロールの変更 | 基本的な Lambda アクセス権限で新しいロールを作成 |
詳細設定は以下の表のとおりに設定
項目 | 設定内容 |
---|---|
コードの署名 | 空白 |
ネットワーク | 空白 |
Lambda のコードソース画面から 「aws_cost_bot.zip」 をアップロード
環境変数を設定
「設定」項目をクリック後、環境変数をクリック
今回は以下の2点を環境変数に設定します。
環境変数名 | 設定する内容 |
---|---|
LINE_CHANNEL_ACCESS_TOKEN | チャネルアクセストークン |
この環境変数を間違えていると Lambda から LINE bot を操作できません。
IAM ロールを 設定
同じく「設定」項目から実行ロールを設定する。
「アクセス権限」をクリック
実行ロールの編集をクリックすると以下のような画面が表示される。
実行ロールの「既存ロール」に先ほど作成した IAM ロールをアタッチして「保存」をクリック
※今回作成したロール名:「MyCostExplorerRead」
Lambda 関数をデプロイ
「コード」の「コードソース」画面に戻ってデプロイをクリック
※デプロイボタンが無効になっている場合はすでにデプロイが完了しているので次の「API Gateway を設定」に移ってください。
しばらくすると、デプロイが完了します。
API Gateway を設定
ざっくり手順
- API の作成
- リソースの作成
- メソッドの作成
- デプロイ
今回はプライベートではないほうの REST API を利用します。
AWS マネジメントコンソールから API Gateway のダッシュボードを開きます。
API の名前を決める
API 名に任意の名前を入れます。(例 line_api)
入れたら「API の作成」をクリック
リソースの作成
アクションからリソースの作成を選択
リソース名を決めます。
この名前は API の名前になります。わかりやすい名前をつけましょう。
例:aws-ce
メソッドの作成
アクションからメソッドの作成を選択
メソッドタイプを POST にしましょう。
メソッド作成がうまくいくと設定画面が右のフレームに表示されます。
項目 | 設定内容 |
---|---|
統合タイプ | Lambda 関数 |
Lambda プロキシ統合の使用 | オン |
Lambda リージョン | ap-northeast-1 |
Lambda 関数 | aws_cost_bot |
※Lambda 関数の設定内容は
各自、作成した Lambda 関数名に合わせていただければと思います。
デプロイ
アクションから「API のデプロイ」を選択
設定画面が表示される。
ステージ名とステージの説明を入力(入力例:line)
入力が終わったらデプロイ
API の URL をコピー
先ほどのデプロイボタンをクリックすると
api ステージエディターに画面が遷移
ステージ名、/(スラッシュ)、API 名、POST の順にクリックすると
URL の呼び出しに API の URL が表示される。
(URL の例)
https://XXXXXXXXXX-api.ap-northeast-1.amazonaws.com/line/aws-ce
LINE Developpers Console を設定
Webhook URL に APIGateway で取得した URL を登録
LINE Developers Console から Messaging API のプロバイダを開きます。
LINE チャネル名が保存されているプロバイダ名をクリック
チャネル名をクリック
チャネルの「チャネル基本設定」の右側にある Messaging API をクリック
「Webhook 設定」から Webhook URL を編集します。
Webhook URL は API Gateway でコピーした API の URL を貼り付けて「更新」をクリック
Webhook 更新後は「検証」をクリックする。
上記のように検証に成功したら
「Webhook の利用」の利用にチェックが入っていない場合はオンにしてください。
実際に bot を使ってみる
今回の返信パターンは 2 パターン
- 「料金」または適当な文字列を送信すると現時点における今月の料金を返信
- 「YYYY MM」と送信すると指定された日付の月初から月末までの利用料金を返信
パターン 1 現時点における今月の料金を聞く
Success! うまくいった。
パターン 2 指定された月の料金を聞く
Success! うまくいった。
こんな感じでうまくいったのですが実際は結構苦労した話があったりします。
「開発の過程で困ったこととその解決方法」に記載
お片付け
API Gateway の API URL を削除
API Gateway のダッシュボードを開く。
API 名、「aws_cost」を選択してアクションから「削除」または「Delete」をクリック
ダイアログが表示されるので「削除」をクリック
Lambda 関数の削除
Lambda のダッシュボードを開く。
関数名、「aws_cost_bot」を選択してアクションから「削除」または「Delete」をクリック
ダイアログが表示されるので「削除」をクリック
IAM ロールの削除
IAM のダッシュボードを開く。ロールをクリック
ロール名、「MyCostExplorerRead」選択して「削除」または「Delete」をクリック
また、Lambda 関数作成時にデフォルトロールも作成されている為
それも削除します。
ロール名、「aws_cost_bot-role-XXXXXXX」選択して「削除」または「Delete」をクリック
※XXXXXXX には任意の Lambda 関数の ID が入ります。
IAM ポリシーの削除
IAM のダッシュボードを開く。ポリシーをクリック
ポリシー名、「MyCostExplorerRead」選択してアクションから「削除」または「Delete」をクリック
LINE BOT の削除
Developers Console から「AWS 請求確認」の LINE bot を削除する。
Providers から
プロバイダ名「AWS 請求表示」をクリック
「AWS 請求確認」をクリック
「基本設定」(英語名だと Basic settings)を選択して一番下までスクロールし、
「チャネルを削除」(英語名だと Delete this channel)をクリック
削除するか聞かれるので右側の赤いボタンをクリック
アカウント削除の画面に遷移後、規約に同意するにチェックを入れて
「アカウント削除」をクリック
本当に削除するか聞かれるので削除をクリック(赤いボタン)
削除に成功するとアカウントリストに遷移する。
LINE Provider の削除
次に LINE bot で利用したプロバイダを削除する。
Developers Console を一から開き、Providers から 「AWS 請求表示」をクリック
「設定」(英語名だと Settings)をクリックして
「Delete this provider」の「Delete」をクリックする。
削除するか聞かれるので OK をクリック
はじめてプロバイダを作成したときと同じ画面が表示されれば、削除に成功しています。
片付けはこれでおわり。
開発の過程で困ったこととその解決方法
IAM 周りの認証エラー
「IAM ポリシーで Billing 系のアクセスを有効にしたが、認証エラーになったこと」
ポリシーがわからずとにかく
Cost Explorer の IAM ユーザアクセスをオンにしたり
他の Billing 関連のポリシーをオンにしたりと無意味なことをした。
AWS が用意する IAM ポリシー「Billing」には今回のポリシーが含まれていないので
ロールとして利用しても意味がない。
ちなみに Billing を適用した場合は以下のようなポリシーを利用する。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"aws-portal:*Billing",
"aws-portal:*Usage",
"aws-portal:*PaymentMethods",
"budgets:ViewBudget",
"budgets:ModifyBudget",
"ce:UpdatePreferences",
"ce:CreateReport",
"ce:UpdateReport",
"ce:DeleteReport",
"ce:CreateNotificationSubscription",
"ce:UpdateNotificationSubscription",
"ce:DeleteNotificationSubscription",
"cur:DescribeReportDefinitions",
"cur:PutReportDefinition",
"cur:ModifyReportDefinition",
"cur:DeleteReportDefinition",
"purchase-orders:*PurchaseOrders"
],
"Resource": "*"
}
]
}
確かに Cost Explorer (ce)のポリシーは存在するが
とりわけ、AWS の利用料を取得するポリシーが存在しない。
じゃあ、CostExplorer の設定を全部オンにすれば解決するんじゃない。
確かに解決はしますが、利用予定のないポリシーは付与すべきではないです。
以下はダメな例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ce:*"],
"Resource": ["*"]
}
]
}
※参考資料の StackOverFlow にはアスタリスクで全許可になっていますが
最小権限の原則を守る前提で考えるとキレイなポリシーではないです。
どう解決したか
try-except をしているところで
エラーオブジェクトの Class Name や詳細を閲覧した。
具体的には以下のエラー内容を bot につぶやかせることで解消
User: arn:aws:sts::000000000000:assumed-role/BillingFullAccess/aws_cost_bot is not authorized to
perform: ce:GetCostAndUsage on resource: arn:aws:ce:us-east-1:000000000000:/GetCostAndUsage
※000000000000 にはアカウント ID が入ります。
調査過程
1 回目
過去 12 ヵ月の請求情報を指定するようにエラーが出る。
※get_aws_cost の try except にある文章を返している。
bot に入力した日付が取れているかを確認する為に入力内容をオウム返ししてくれるか検証するも
うまいこと返してくれる。
2 回目
1 回目の内容から bot => API Gateway => Lambda => LINE bot の経路が確立できていることが確認できた。請求情報を閲覧できるかトライしてみるも Client エラーが出る。
そういえば、Lambda の IAM ロールってこれでいいんだっけと思い
boto3 のエラーと Billing 系の IAM ポリシーを調べると IAM ロールがダメっぽいことに気づく。
いろいろ調べると Stack Overflow に辿り着き
Cost Explorer 関連のポリシーを全部オンにするような内容で質問回答がなされていた。
ひょっとしてポリシー足りないんじゃないと思い、Client Error から IAM のエラーを拾えるか試してみる。
結果:拾えた。
どうやら、ce:GetCostAndUsage というポリシーがねぇよってことらしい。知らんがな。。。
ちなみに
ローカルで作成したスクリプトをチェックすると
boto3 のパッケージが入っていないように見えますが
boto3 は AWS SDK に含まれるパッケージなので Lambda で利用する分にはインストール不要
※つまり、pip install 不要
さいごに
すぐにできそうな改修
-
AWS の利用料金に応じて bot が返信してくれる
例えば
10 ドル以上なら「めっちゃつかっとるやんけ」
5 ドル以下ならば「そこそこつかっとるやんけ」
0 ドルなら「AWS 使ってあげて」といった感じで請求内容に合わせて改修するとおもしろさが増すかも。
現状の課題
-
作成した bot で閲覧できる請求情報は作成時に利用したアカウントだけ
1 個人につき一つの bot ととなるうえに AWS の知識ないと構築が難しい。
bot は 1 つでみんなが扱えるものとなるといろいろ問題にぶつかる。
bot 用のスクリプトは? Lambda 関数の作成は?エンドポイントどう作る?
請求情報を参照するユーザはどう認証する?。。。etc -
返してくれる利用料金はドル表記で日本円ではない
チョット前に流行った Google さんとこの為替レートって提供やめたんですね。
forex とかはたまた円表記をやめて BitCoin の価格表示にでもしてしまおうか。 -
Lambda が二重で叩かれる現象が起きている
以前、雑食サロンのもくもく会で聞いたことのあるエラー
確か、SQS を入れることで解決するんだっけ。2021.06.30 追記
自分ではない他人が bot に対してメッセージを送ると
自身の LINE アカウントに通知が届くことに気づいた。
Lambda のせいではない可能性が濃厚2021.07.03 補足
Webhook URL を登録して Webhook をオンにしたにも関わらず Webhook が反応しない。
=>チャネルを削除して新しくチャネルを作成2021.07.10 追記
1 回のメッセージで 2 回リプライが返ってきている理由が判明
やはり、自分以外に Bot に対してメッセージを送信した可能性が濃厚
その理由に 1 通目のリプライと 2 通目のリプライで時間差がある。
また、Lambda が二回実行される現象は非同期で関数を実行する場合に起きる。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-services.html
非同期で関数を実行する場合はいわゆる 2 重起動になるが今回使用している API Gateway は
同期呼び出しで Lambda を動かすので 2 重起動はありえない。
また、他人にメッセージを送信されても自身の LINE に通知が来ないようにするため
push_message ではなく、reply_message を利用するように変更しました。push_message と reply_message の違いについて
https://developers.line.biz/ja/docs/messaging-api/sending-messages/#methods-of-sending-message
参考資料
boto3 のドキュメント