EC2インスタンスの消し忘れをLINE Messaging APIで通知する

#はじめに
テストなどでEC2インスタンスを作成していろいろと検証をした後に、ついうっかり停止し忘れて余計な料金がかかってしまうことはよくあることです。
本記事では毎朝決まった時間に、起動中のEC2インスタンス情報をLINE Messaging APIを使ってLINEに通知するための仕組みを作っていきたいと思います。

#構成図
構成図は以下の通り。
![EC2_Notification.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/d5053642-d06a-a1c3-4217-2ee652a58bde.png)
今回はAWS Lambdaを使用して実装していきます。
LambdaにてAmazon EC2インスタンスの起動情報を取得するコードを作成し、Amazon EventBridgeで毎日9:00にLine Messaging APIへ連携する構成となっています。

#実装
ここからは構成図の通りに実装していきます。
###①Line Messaging APIの作成
まずはLINE Developersへログインを行います。
https://developers.line.biz/ja/
※アカウントを持っていない場合は、作成から行いましょう
ログイン後は左ペインからプロバイダーを選択し、新規チャネル作成の画面へ遷移します。
※プロバイダーを作成していない場合は、ホーム画面からプロバイダーの作成を行いましょう

次にチャネルの設定タブを選択し、[新規チャネルの作成]をクリックします。
![WS000003.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/96b3c9f2-7d84-650b-6e53-75a16ccedf75.jpeg)

チャネルの種類が表示されるので、[Messaging API]をクリックします。
<img width="550" alt="WS000004.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/9eafadd6-c56b-bb6e-638a-8c273734444d.jpeg">
Messaging APIの作成画面に遷移するので、スクロールしながら必須項目の[チャネル名]、[チャネル説明]、[大業種]、[小業種]を入力します。（今回はそれぞれ、「ec2-notification」、「ec2-notification」、「個人」、「個人(IT・コンピュータ)」を入力しています）
<img width="500" alt="WS000005.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/d87f91f5-5bc9-9ef0-166d-1e07231f4d79.jpeg">

さらに画面をスクロールし、利用規約にチェック後、[作成]ボタンをクリックします。
<img width="500" alt="WS000006.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/bf3c3329-033b-8716-02dc-79b8312686f5.jpeg">

以上で[ec2-notification-to-LINEAPI]のチャネル作成が完了します。
あとは[Messaging API設定]タブから、本チャネルのQRコードを読み込んでLINE登録を行いましょう。
<img width="500" alt="WS000011.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/7c5da708-e8d0-4b41-0271-aeab0710dbe4.jpeg">

また本実装では、後続のLambda関数作成で以下2つの情報が必要となります。
###### ・ユーザーID
[チャネルの基本設定]タブを選択し、下部へスクロールすると[あなたのユーザーID]という項目があるので、この文字列をメモしておきます。
<img width="450" alt="WS000009.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/49eac738-4ddc-1acc-a524-3c106b3a6ac3.jpeg">
###### ・チャネルアクセストークン
[Messaging API設定]タブを選択し、下部へスクロールすると[チャネルアクセストークン]という項目があるので、[発行]をクリックします。
するとトークンが発行されるので、この文字列をメモしておきます。
<img width="450" alt="WS0010.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/ed3e69fb-3637-477b-9343-f399f0ff563b.jpeg">

###②EC2インスタンスの情報を取得するLambdaコードの作成
次にLambdaコードの作成を行います。
まずはAWS Lambdaのコンソールを開き、[関数を作成]をクリックします。
![WS000000.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/2fea1714-209b-267e-2209-7ee6c136e29b.jpeg)

次に基本的な情報を入力していきます。
今回は関数名を「ec2-notification-to-LINEAPI」とし、ランタイムは「Python 3.9」を選択して[関数の作成]をクリックします。
![WS000015.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/d8d10cba-f0ba-32bd-cace-e98c97f2f908.jpeg)
以上でLambda関数が作成されます。
ここからは、「lambda_function.py」をにコードを記述していきます。

######・LINE Messaging APIへのメッセージ送信方法
今回はLINE APIで時間にメッセージを送信するので、LINE Messaging APIの[プッシュメッセージの送信](https://developers.line.biz/ja/docs/messaging-api/sending-messages/#methods-of-sending-message)を利用します。
「https://api.line.me/v2/bot/message/push 」に対してjson形式で以下の情報をPOSTすることによって、APIにプッシュメッセージを送信することが出来ます。

```python:
'Content-Type: application/json'
'Authorization: Bearer {channel access token}'
'{
    "to": ["U4af4980629...","U0c229f96c4..."],
    "messages":[
        {
            "type":"text",
            "text":"Hello, world1"
        }
    ]
}'
```

######・EC2インスタンス起動情報の取得
EC2インスタンスの起動情報については、Boto3ライブラリをインポートし、describe_instances()で出力することによって取得が行えます。
詳細については「[boto3でec2をdescribeして値を取り出す](https://qiita.com/t_wkm2/items/bdb6890e23a6d0bc9ce7)」の記事に詳しく載っていますので、こちらをご参照ください。

以上を参考にし、「lambda_function.py」のコードを記述します。
「チャネルアクセストークン」と「ユーザーID」には、「①Line Messaging APIの作成」で控えておいたLINE Messaging APIチャネル情報を入力します。

```python:lambda_function.py
import boto3;
import json
import urllib.request

def lambda_handler(event, context):
    #EC2インスタンス情報を取得
    ec2 = boto3.client('ec2')
    reservation = ec2.describe_instances()['Reservations']
    
    #起動状態のインスタンスがあればインスタンスidを配列に格納
    running_ec2_list = []
    for instance in reservation:
        state = instance['Instances'][0]['State']['Name']
        if state.__eq__('running'):
            running_ec2_list.append(instance['Instances'][0]['InstanceId'])
    
    #配列が空でなければLINE Botで通知
    if len(running_ec2_list) != 0:
        text = ""
        for run_ec2 in running_ec2_list:
            text = text + (run_ec2 + "のEC2インスタンスが起動中です。\n")
        text = text.rstrip("\n")
        url = 'https://api.line.me/v2/bot/message/push'
        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + 'チャネルアクセストークン'
        }
        body = {
            'to': "ユーザーID",
            'messages': [
                {
                    "type": "text",
                    "text": text,
                }
            ]
        }
    
    req = urllib.request.Request(url, data=json.dumps(body).encode(), method='POST', headers=headers)
    urllib.request.urlopen(req)
    
    return {
        'statusCode': 200,
    }
```
これでLambda関数は完成です。

###③IAMロールをLambdaに付与
次にLambdaがEC2インスタンス情報を取得できるようにするため、LambdaにIAMロールを設定します。
Lambda関数の画面から、[設定] > [アクセス権限]をクリックするとデフォルトの実行ロールがあるので、こちらをクリックします。
![WS000022.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/739d0ae1-dbfc-06c8-118b-dfeccb652fb6.jpeg)
ロールの設定画面に遷移するので、[ポリシーをアタッチします]のボタンをクリックします。
![WS000023.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/7220ba56-77fd-1e2d-9fad-a9dd91483d0f.jpeg)
ポリシーの一覧から[AmazonEC2ReadOnlyAccess]を探してチェックを入れ、[ポリシーのアタッチ]ボタンをクリックします。
![WS000024.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/54ae8d98-acf2-3761-0196-571308921c14.jpeg)
ロールに[AmazonEC2ReadOnlyAccess]が追加されていれば設定は完了です。
![WS000025.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/00855634-5fda-c867-3839-52d894baa9cd.jpeg)

###④Amazon EventBridgeでスケジュール設定
最後に作成したLambda関数をスケジュール実行するための設定を行います。
「ec2-notification-to-LINEAPI」関数の画面から、[トリガーを追加]をクリックします。
![WS000016.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/11714061-b036-7b57-a4e1-5079c3cf60f4.jpeg)
トリガーの設定画面に遷移するので、リストから[EventBridge(CloudWatch Events)]を選択して[新規ルールの作成]のラジオボタンにチェックを入れます。
![WS000017.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/f070b00f-23a1-4ac0-cadc-63a35264cc4e.jpeg)

ルール名に任意の名前を入力します。（今回は「ec2-instances-check」としています）
また、スケジュール式の欄には、cronの起動設定を入力します。今回はUTCで毎日0:00（ローカルタイムで毎日9:00）に起動するよう設定を行い、[追加]ボタンをクリックします。
![WS000019.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/54a6596e-d3bd-f04d-b350-0a0b1ad44640.jpeg)

作成したスケジュールがトリガーに追加されれば、設定は完了です。
![WS000020.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/b91b7b22-885a-9da3-8359-7aae7a8d6c61.jpeg)

#動作確認
試しにC2インスタンスを起動した状態で翌朝9:00を迎えてみます。
するとLINEにて、以下のメッセージを受信することができました。
![unnamed.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689573/07bd5c95-2856-15db-92ce-613ad6aca00e.jpeg)

#最後に
今回はLambdaとEventBridge、LINE Messgging APIを使用してシンプルな通知の仕組みを作成してみました。
他にも工夫することで、別のAWSリソース情報の取得や別サービスへの連携を行うことが出来そうです。