【AWS】Lambda用のNAT Gatewayの自動起動・終了

# NAT Gatewayのコスト
東京リージョンの場合は下記の料金が発生します。
`$0.062 per NAT Gateway Hour`

# 自動化したい作業を手動で確認
## NAT Gatewayを削除してみる

### ルートを編集する
VPCのルートテーブルのページに移動し、ルートの編集を指定する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/68bab1b4-3ae8-651c-c5a0-028393eb8caf.png)

下記の設定項目を削除する

```
送信先：0.0.0.0/0
ターゲット：nat-（作成したやつ）
```
### NATゲートウェイの削除
VPCのNATゲートウェイの設定画面に移動し、`NATゲートウェイの削除`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/3b120d72-f6e1-3478-71f3-2b0b0578176d.png)


### Elastic IPの解放
VPCのElasticIPの設定でアドレスの解放を行う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/378cb5d6-968b-31ab-c334-7eeb47610e19.png)



## NATゲートウェイを復元してみる

### NATゲートウェイの作成
VPCのNATゲートウェイの設定画面に移動し、`NATゲートウェイの作成`

作成時にElastic IPを割り当てることができるので、ここで割り当ててしまう。

### ルートテーブルの編集
NATゲートウェイにルーティングしたいルートテーブルを選択し、下記の設定を行います。

```
送信先：0.0.0.0/0
ターゲット：nat-（作成したやつ）
```


### Elastic IP名の修正
NATゲートウェイの作成時に生成されたElastic IPに名前を付けておきます。
※必ず付ける必要はありませんが、多くなると管理できなくなる為、付けておいた方が良いと思います。

# 構成
今回は、決まった時間に自動起動・終了するようにしたいと思います。
以下の図のように、CloudWatch Events をトリガーにし、Lambdaを動作させる構成にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/d899e440-5bee-ea9f-db7e-7341e8877a9c.png)

操作する内容は以下の通りです。

**■ NAT GateWay 起動時**
1. 月曜～金曜 朝9時に実行
2. `Elastic IP`の作成
3. `NAT GateWay`の作成
4. サブネットのルートテーブルに`NAT GateWay`を割り当て

**■ NAT GateWay 終了時**
1. 月曜～金曜 夜7時に実行
2. サブネットのルートテーブルから`NAT GateWay`をデタッチ
3. `NAT GateWay`の削除
4. `Elastic IP`の解放


# 起動処理の自動化

## 実行ロールの作成
IAMのロール作成画面から、ロールを作成します。

必要なポリシーは
- CloudWatchLogsFullAccess
- AmazonVPCFullAccess
- AWSLambdaBasicExecutionRole
の3点です。
ロール名は適当な物を付けてください。

## Lambdaの作成
関数の作成ページから、`設計図の使用`を選択し、キーワードに`lambda-canary`を指定し、`lambda-canary`を選択して、`設定`ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/af115f1d-f739-c1fd-5b1b-42c485b6f0f7.png)

### 基本的な情報

|要素|設定|
|:----:|:----|
|関数名|任意の名前|
|実行ロール|既存のロールを使用する|
|既存のロール|上記の手順で作成したロールを選択してください|

### CloudWatch Events トリガー

|要素|設定|
|:----:|:----|
|ルール|新規ルールの作成|
|ルール名|NAT_Start|
|ルールの説明|Create Elastic IP and NAT gateway.|
|スケジュール式|cron(0 0 ? * MON-FRI *)|
※スケジュール式は、協定世界時（UTC）なので注意してください。
[スケジュール式の時差について](https://qiita.com/niwasawa/items/6e0b191d6aa21213c7ec)

トリガーの有効化については、チェックを外しておいてください。

ソースコードと環境変数は後ほど編集しますので、そのまま`関数の作成`をクリックしてください。

## ソースコード

```py:起動自動化
import os
import boto3
import logging
import json

""" ログ設定 """
logger = logging.getLogger()
logger.setLevel(logging.INFO)

""" 変数設定 """
subnet = os.environ['SUBNET_ID']

client = boto3.client('ec2')

def allocate_Eip():
    """ Elastic IPの取得処理 """
    response = client.allocate_address(Domain='vpc')
    return response.get('AllocationId')

def start_natgw(Eip,Subnet):
    """ NAT GateWayの開始処理 """
    response = client.create_nat_gateway(
        AllocationId=eip,
        SubnetId=Subnet
    )
    natid = response['NatGateway']['NatGatewayId']
    client.get_waiter('nat_gateway_available').wait(NatGatewayIds=[natid])
    return(natid)

def atatch_natgw(natgw, Subnet):
    """ サブネットへの割り当て処理 """
    filters = [ { 'Name': 'association.subnet-id', 'Values': [Subnet] } ]
    response = client.describe_route_tables(Filters = filters)
    rtb = response['RouteTables'][0]['Associations'][0]['RouteTableId']
    response = client.create_route(
        DestinationCidrBlock = '0.0.0.0/0',
        NatGatewayId = natgw,
        RouteTableId = rtb
    )

def lambda_handler(event, context):
    logging.info('■ 開始')
    eip = allocate_Eip()
    natgw = start_natgw(eip, Subnet)
    atatch_natgw(natgw, Subnet)
    logging.info('■ 終了')

```


# 終了処理の自動化

## 実行ロールの作成
起動時用に作成したものを利用します。

## Lambdaの作成
関数の作成ページから、`設計図の使用`を選択し、キーワードに`lambda-canary`を指定し、`lambda-canary`を選択して、`設定`ボタンを押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/401878/af115f1d-f739-c1fd-5b1b-42c485b6f0f7.png)

### 基本的な情報

|要素|設定|
|:----:|:----|
|関数名|任意の名前|
|実行ロール|既存のロールを使用する|
|既存のロール|上記の手順で作成したロールを選択してください|

### CloudWatch Events トリガー

|要素|設定|
|:----:|:----|
|ルール|新規ルールの作成|
|ルール名|NAT_Stop|
|ルールの説明|Delete Elastic IP and NAT gateway.|
|スケジュール式|cron(0 10 ? * MON-FRI *)|
※スケジュール式は、協定世界時（UTC）なので注意してください。
[スケジュール式の時差について](https://qiita.com/niwasawa/items/6e0b191d6aa21213c7ec)

トリガーの有効化については、チェックを外しておいてください。

ソースコードと環境変数は後ほど編集しますので、そのまま`関数の作成`をクリックしてください。

## ソースコード