EIPの料金改定に向けてお知らせbotを作る

# はじめに
本記事は[アイレット株式会社 新卒 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/iret) の17日目の記事です！

2024年2月1日より、AWSにおけるパブリックIPv4アドレスの料金が改定されることをご存じでしょうか。

https://aws.amazon.com/jp/blogs/aws/new-aws-public-ipv4-address-charge-public-ip-insights/

上記ブログ内の表によると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/8b524c2c-7b73-6500-c598-e2d80c0339fe.png)

今まではリソースに対してパブリックIPv4アドレスが割り当てられていれば料金はかかりませんでしたが、2月1日以降は未割当アドレスと同じ料金がかかるように改定されます。

つまり1つのIPアドレスを利用しているだけで
0.005 × 24 × 31 = 3.72(USD)
1か月で**3.72USD/IP**もかかってしまいます。

これが複数と考えると、個人アカウントではなかなかつらいところがありますね・・・・・・

ということで今回は、2月の料金改定に向けてEIPの利用状況をお知らせしてくれるボットを作成していきます!


# 準備① Slackアプリの準備
今回はSlackチャンネルに対して利用状況を送るためSlackアプリを利用します。

Slackアプリの設定をしてトークンを用意する必要があるのですが、記事内に手順を書くと記事が長くなってしまうため参考にさせていただいたサイトを張っておきます。

https://note.com/npaka/n/n4bcb38a1ea74#b5acdf57-260d-451e-9843-88b2ef0255df

# 準備② Lambda関数の準備

### Lambda関数作成
ローカルで都度実行でも良いのですが、せっかくなら自分で何もせずともメッセージを送ってくれたほうが良いのでEventBridge + Lambdaで定期的にメッセージを送らせてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/cdf1c8b3-11c3-b4a2-994d-530094fc8876.png)
ランタイムは利用したいLayerの兼ね合いでPython 3.11

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/27ce6ad3-3ee1-f919-4d9a-bbe1e610e230.png)
タイムアウトは30秒くらいにしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/77710bf7-9c06-dcdf-b51d-388017f3cc0f.png)
また、設定してあるロールに対してEC2のReadOnlyの許可を与えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/7358cdc2-974f-9a6e-dc0d-d528aa034231.png)
準備①で取得しておいたトークンとメッセージを投稿したいチャンネルを環境変数に設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/3a50e1b5-2b6f-1906-9651-5ae6a518bdf7.png)
requestsを利用するのでそれ用のレイヤーを外部から借りてきます。
```
arn:aws:lambda:ap-northeast-1:770693421928:layer:Klayers-p311-requests:4
```

Lambdaの設定としては以上になります。

### EventBridge作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/bcf976d8-9d89-3c76-0140-83c03716db0f.png)
今回は毎週水曜日の19:00にお知らせしてくれるように設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/7a6fce5e-1ab4-8daa-a362-2077fd986686.png)
ターゲットは先ほど作成したLambda関数を選択します。

その他設定は基本デフォルトでスケジュールを作成します。

これでAWSサービス周りの設定は完了です。

# コード
では実際にLambda関数にコードを乗せていきます。

```python
import boto3
import requests
import os

def get_eips(ec2_client):

    # Elastic IPアドレスの情報を取得
    response = ec2_client.describe_addresses()

    # 取得した情報を表示
    eips = response['Addresses']
    return eips

def generate_associated_resource_message(ec2_client, eips):
    message = "現在利用しているEIPはこちら! 使ってないIPは整理しよう!!\n\n"
    for eip in eips:
        message += f"Public IP: {eip['PublicIp']}, Allocation ID: {eip['AllocationId']}, Domain: {eip['Domain']}\n"
        
        # EIPに関連するリソースが存在するか確認
        if 'AssociationId' in eip:
            association_id = eip['AssociationId']
            instance_id = eip.get('InstanceId', 'N/A')
            message += f"Associated Resource - Association ID: {association_id}, Instance ID: {instance_id} \n"

            # EC2インスタンスの詳細情報を取得
            if instance_id != 'N/A':
                instance_info = ec2_client.describe_instances(InstanceIds=[instance_id])
                instance_state = instance_info['Reservations'][0]['Instances'][0]['State']['Name']
                message += f"Instance State: {instance_state}\n\n\n"
            # NatGatewayの詳細情報を取得
            else:
                nat_gateway_response = ec2_client.describe_nat_gateways()

                nat_gateways = nat_gateway_response['NatGateways']

                for nat_gateway in nat_gateways:
                    for address in nat_gateway['NatGatewayAddresses']:
                        if 'AssociationId' in address and address['AssociationId'] == association_id:
                            message += f"Nat Gateway ID: {nat_gateway['NatGatewayId']}\n"
                            message += f"State: {nat_gateway['State']}\n\n\n"
                            break
        else:
            message += "State: 未割当\n\n\n"
        
    return message
     
def send_message(message):
    TOKEN = os.environ["TOKEN"]
    CHANNEL = os.environ["CHANNEL"]

    url = "https://slack.com/api/chat.postMessage"
    headers = {"Authorization": "Bearer "+TOKEN}
    data  = {
    'channel': CHANNEL,
    'text': message
    }
    r = requests.post(url, headers=headers, data=data)
    print("return ", r.json())


def lambda_handler(event, context):
    # boto3クライアントを作成
    ec2_client = boto3.client('ec2')

    #eip一覧取得
    eips = get_eips(ec2_client)

    #関連付けられたリソースを検索しメッセージを生成
    message = generate_associated_resource_message(ec2_client, eips)

    #メッセージ送信
    send_message(message)
```

<dl>
  <dt>get_eips</dt>
  <dd>アカウント内のEIPを全件取得する。</dd>
  <dt>generate_associated_resource_message</dt>
  <dd>どのIPがどのリソースに紐づけられているか確認し、メッセージを生成する。</dd>
  <dt>send_message</dt>
  <dd>メッセージをSlackに送信する。</dd>
</dl>

# 結果
![スクリーンショット 2023-12-17 082028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269896/a232d9dd-1f6c-99c2-56f9-77ac39e4cce8.png)
映せないものが多すぎたので内容は隠してあるが、画像のような感じでSlackに現在利用しているEIPの情報をお知らせすることができました！

# さいごに
この記事で皆さんの大切なお金が守られることを祈っています。


[アイレット株式会社 新卒 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/iret) はまだまだ続くので明日以降の記事もお楽しみに！