42
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

【とりあえずハンズオン】AWS×LINEで実践!AWS利用料返信Botをつくろう

はじめに

この記事では
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 にログインする

LINE Developers Console を開く

「Messaging API」をクリックします。

Messaging_API.JPG

「今すぐ始めよう」をクリック

Messaging_API_now.JPG

LINE アカウントにログイン
ご自身の LINE アカウントで認証をしていただければと思います。

line_login.JPG

プロバイダの作成

チャネルを作成するには
まず、プロバイダを作成しなければいけません。

「Create a new provider」をクリック

provider.JPG

作成するプロバイダ名を聞かれるので「AWS 請求表示」と入力して
「Create」をクリック

create_provider.JPG

続いて、Messaging API をクリック

messaging_api_click.JPG

チャネルを作成

今回はこのように設定しました。

項目 入力内容
チャネルの種類 LINE Messaging API
プロバイダー AWS 請求表示
チャネル名 AWS 請求確認
チャネル説明 AWS の請求情報を返信してくれる bot です。
大業種 ウェブサービス
小業種 ウェブサービス(その他)

一応、各項目について説明すると

チャネルの種類:LINE Messaging API
プロバイダー:「新規プロバイダーの作成」を選択
プロバイダー名:管理コンソール上で表示される名前を入力
チャネル名:実際に LINE で表示される名前を入力
チャネル説明:チャネルの説明を書く
大業種:該当の業種を選択
小業種:大業種に合わせた該当の業種を選択

最後に規約を読んでチェック、作成をクリック

重要な情報をコピー

先ほど作成した チャネル を開く
Messaging API 設定にあるチャネルアクセストークンをメモしておく。

※チャネルアクセストークンは新規で bot を作成したとき
アクセストークンが発行されていない。
表示するには発行ボタンをクリックする必要がある。

image.png

LINE のデフォルト応答メッセージを消す

デフォルト設定では以下のように LINE のデフォルト応答メッセージが表示される為
デフォルトの応答メッセージを表示しないように
「Messaging API 設定」の 「応答メッセージ」を無効にする。

trouble_shoot_1.JPG

「Messaging API 設定」の 「応答メッセージ」を無効にする為には
LINE Official Account Manager から詳細設定を変更する。

LINE Official Account Manager を開く場合は
「Messaging API 設定」のにある以下の応答メッセージの項目にある編集をクリックする。

image.png

詳細設定の応答メッセージをオン → オフ

response_off.JPG

設定切替後は LINE Official Account Manager のウィンドウを閉じる。

LINE Developers Console にある「Messaging API 設定」から
「応答メッセージ」の項目がオフになっていることを確認する。

response_off_for.JPG

今回のインフラ構成図

AWS で利用するサービスと LINE とのつながりを明確に構成図に起こすとこんな感じになります。

line_bot.png

IAM ポリシーを作成する

今回は請求情報にアクセスする為の IAM ロールを 作成する為に IAM ポリシーを作成する必要があります。
まずは AWS マネジメントコンソールから IAM のダッシュボードを開きます。
IAM のダッシュボードにある「ポリシー」をクリックして
IAM ロールにアタッチする IAM ポリシーを作成します。

iam_role.JPG

「ポリシーの作成」をクリック
cretae_policy.JPG

json でポリシーを作成する。このとき権限は最小限にとどめる。

click_json.JPG

「ポリシーの作成」画面から 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

tag.JPG

ポリシー名および説明は以下のように設定後、「ポリシーの作成」をクリック

ポリシー名 説明
MyCostExplorerRead Amazon Web Services Cost Explorer Read Only

policy_name.JPG

IAM ロールの作成

ポリシー作成後はロールを作成します。
IAM のダッシュボードにある「ロール」をクリックして IAM ロールにポリシーをアタッチします。

iam_role.JPG

「ロールの作成」をクリック

cretae_role.JPG

一般的なユースケースから Lambda を選択

use_case.JPG

先ほど作成したポリシー名を検索する。
ポリシー名は以下のように設定しました。(IAM ポリシーの作成時に入力したポリシー名)

ポリシー名
MyCostExplorerRead

search_policy.JPG

こちらもポリシー名と同じく key Value を設定しておきましょう。

キー
CostExplorer aws_cost

role_key_value.JPG

次のステップへ

ロール名を設定します。今回はポリシー名と同じ名前を設定します。

ロール名
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 のダッシュボードから関数をクリック

lambda_dashbord.JPG

関数の作成をクリック

function.jpg

「一から作成(シンプルな Hello World の例で開始します。)」を選択

基本的な情報は以下の表のとおりに設定

項目
関数名 aws_cost_bot
ランタイム Python3.8
デフォルトの実行ロールの変更 基本的な Lambda アクセス権限で新しいロールを作成

詳細設定は以下の表のとおりに設定

項目 設定内容
コードの署名 空白
ネットワーク 空白

Lambda のコードソース画面から 「aws_cost_bot.zip」 をアップロード

zip_upload.jpg

環境変数を設定

「設定」項目をクリック後、環境変数をクリック

env_var.JPG

今回は以下の2点を環境変数に設定します。

環境変数名 設定する内容
LINE_CHANNEL_ACCESS_TOKEN チャネルアクセストークン

この環境変数を間違えていると Lambda から LINE bot を操作できません。

IAM ロールを 設定

同じく「設定」項目から実行ロールを設定する。
「アクセス権限」をクリック

access_role.JPG

実行ロールの編集をクリックすると以下のような画面が表示される。
実行ロールの「既存ロール」に先ほど作成した IAM ロールをアタッチして「保存」をクリック

※今回作成したロール名:「MyCostExplorerRead」

execute_role.JPG

Lambda 関数をデプロイ

「コード」の「コードソース」画面に戻ってデプロイをクリック

※デプロイボタンが無効になっている場合はすでにデプロイが完了しているので次の「API Gateway を設定」に移ってください。

lambda_not_deploy.kpg.JPG

しばらくすると、デプロイが完了します。

lambda_deploy.kpg.JPG

API Gateway を設定

ざっくり手順

  1. API の作成
  2. リソースの作成
  3. メソッドの作成
  4. デプロイ

今回はプライベートではないほうの REST API を利用します。

image.png

AWS マネジメントコンソールから API Gateway のダッシュボードを開きます。

API の名前を決める

api_name_lambda.JPG

API 名に任意の名前を入れます。(例 line_api)
入れたら「API の作成」をクリック

リソースの作成

アクションからリソースの作成を選択

resource_create.JPG

リソース名を決めます。
この名前は API の名前になります。わかりやすい名前をつけましょう。
例:aws-ce

メソッドの作成

アクションからメソッドの作成を選択

method_create.jpg

メソッドタイプを POST にしましょう。
メソッド作成がうまくいくと設定画面が右のフレームに表示されます。

api_post_method.JPG

項目 設定内容
統合タイプ Lambda 関数
Lambda プロキシ統合の使用 オン
Lambda リージョン ap-northeast-1
Lambda 関数 aws_cost_bot

※Lambda 関数の設定内容は
各自、作成した Lambda 関数名に合わせていただければと思います。

デプロイ

アクションから「API のデプロイ」を選択

api_deploy.JPG

設定画面が表示される。
ステージ名とステージの説明を入力(入力例:line)

api_deploy_stage.JPG

入力が終わったらデプロイ

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 をクリック

Messaging_API_config.JPG

「Webhook 設定」から Webhook URL を編集します。
Webhook URL は API Gateway でコピーした API の URL を貼り付けて「更新」をクリック

Webhook 更新後は「検証」をクリックする。

image.png

image.png

上記のように検証に成功したら
「Webhook の利用」の利用にチェックが入っていない場合はオンにしてください。

Webhook_on.JPG

実際に bot を使ってみる

今回の返信パターンは 2 パターン

  • 「料金」または適当な文字列を送信すると現時点における今月の料金を返信
  • 「YYYY MM」と送信すると指定された日付の月初から月末までの利用料金を返信

パターン 1 現時点における今月の料金を聞く

complete_now.JPG

Success! うまくいった。

パターン 2 指定された月の料金を聞く

complete.JPG

Success! うまくいった。

こんな感じでうまくいったのですが実際は結構苦労した話があったりします。
「開発の過程で困ったこととその解決方法」に記載

お片付け

API Gateway の API URL を削除

API Gateway のダッシュボードを開く。
API 名、「aws_cost」を選択してアクションから「削除」または「Delete」をクリック
ダイアログが表示されるので「削除」をクリック

clear_api.JPG

Lambda 関数の削除

Lambda のダッシュボードを開く。
関数名、「aws_cost_bot」を選択してアクションから「削除」または「Delete」をクリック

delete_function.JPG

ダイアログが表示されるので「削除」をクリック

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 請求表示」をクリック

image.png

「AWS 請求確認」をクリック

image.png

「基本設定」(英語名だと Basic settings)を選択して一番下までスクロールし、
「チャネルを削除」(英語名だと Delete this channel)をクリック

image.png

削除するか聞かれるので右側の赤いボタンをクリック

image.png

アカウント削除の画面に遷移後、規約に同意するにチェックを入れて
「アカウント削除」をクリック

image.png

本当に削除するか聞かれるので削除をクリック(赤いボタン)

削除に成功するとアカウントリストに遷移する。

LINE Provider の削除

次に LINE bot で利用したプロバイダを削除する。
Developers Console を一から開き、Providers から 「AWS 請求表示」をクリック

「設定」(英語名だと Settings)をクリックして
「Delete this provider」の「Delete」をクリックする。

image.png

削除するか聞かれるので OK をクリック

image.png

はじめてプロバイダを作成したときと同じ画面が表示されれば、削除に成功しています。
片付けはこれでおわり。

開発の過程で困ったこととその解決方法

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 にある文章を返している。

iam_error_1.JPG

bot に入力した日付が取れているかを確認する為に入力内容をオウム返ししてくれるか検証するも
うまいこと返してくれる。

oumu_return.JPG

2 回目

1 回目の内容から bot => API Gateway => Lambda => LINE bot の経路が確立できていることが確認できた。請求情報を閲覧できるかトライしてみるも Client エラーが出る。

iam_clinet_error.JPG

そういえば、Lambda の IAM ロールってこれでいいんだっけと思い
boto3 のエラーと Billing 系の IAM ポリシーを調べると IAM ロールがダメっぽいことに気づく。

いろいろ調べると Stack Overflow に辿り着き
Cost Explorer 関連のポリシーを全部オンにするような内容で質問回答がなされていた。

ひょっとしてポリシー足りないんじゃないと思い、Client Error から IAM のエラーを拾えるか試してみる。
結果:拾えた。

iam_error.JPG

どうやら、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 のドキュメント

Cost Explorer boto3 Docs

Stack OverFlow

AWS Lambda のエラーを確認するには

おわり

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
42
Help us understand the problem. What are the problem?