サンドボックス環境のためのNATインスタンスを、AWS CloudFormationで作る

記事タイトルとURLをコピーする

こんにちは。AS部の兼安です。

私のサンドボックス環境で、今月のコストが思ったより高くなりました。NAT Gatewayのコストが思ったよりかかったのが原因です。NAT Gatewayについてはこれまでもうっかりしていてコストがかかったことが何度があるので、節約のために、NAT GatewayだけでなくNATインスタンスをサッと使えるようにしておきたいと思いました。

本記事の概要

NATインスタンスを作り、パブリックサブネットに配置する。
ここまでをCloudFormationテンプレートにまとめて、NATインスタンスを作って設定する手順を少し手軽にしてみました。

思ったよりコストがかかった原因をNAT Gatewayだと特定するまで

最初に思ったよりコストがかかった原因がNAT Gatewayだと特定するまでの経緯を書いておきます。 まず、AWS Cost Explorerを見てみました。 ディメンションサービスにしたところ、EC2 その他の割合が妙に高いことがわかりました。

AWS Cost Explorer - ディメンション:サービス

EC2 その他のままでは、対策のしようがないので、これが何なのか?をこちらの記事を参考に、ディメンション使用タイプにしたところ、大半はNAT Gatewayであることがわかりました。

blog.serverworks.co.jp

AWS Cost Explorer - ディメンション:使用タイプ

余談ですが、この使用タイプを選ぶという操作がなかなか憶えられません。どうもピンとこず、すぐに忘れてしまいます(汗)

Nat GatewayとNATインスタンスの違い

Nat GatewayとNATインスタンスは、どちらもNATの機能を提供するものです。

Nat Gatewayは、サイズの変更や開始・停止ができません。しかし、多くの機能を自動で処理してくれるため、管理が容易です。本番環境での利用を考えると、Nat Gatewayを選択するのが推奨されます。

NATインスタンスは、NAT Gatewayと同様に、プライベートサブネットからインターネットにアクセスするためのものです。EC2を基にしたインスタンスなので、サイズの指定や開始・停止が可能です。ただし、構築や性能不足の際の対処など、管理の面での負担が比較的高くなっています。開発用の限定的な環境におけるコスト観点だと、NATインスタンスの方が有効である場合もあります。

NATインスタンスの作成手順については、以下のページが参考になります。本記事のCloudFormationテンプレートも、これらのページの手順をまとめたものです。

docs.aws.amazon.com

blog.serverworks.co.jp

NATインスタンスを作るCloudFormationテンプレート

このCloudFormationテンプレートは、以下のようにパブリックサブネットとプライベートサブネットがあるVPCを想定しており、実行すると、赤字の部分のように、NATインスタンスがパブリックサブネットに配置されます。

VPC

CloudFormationテンプレートのポイント

NATインスタンス用のセキュリティグループのポイント

  NatInstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: !Sub ${Suffix}-sg-nat-instance
      GroupDescription: Security group for NAT instance
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${Suffix}-sg-nat-instance
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 443
          ToPort: 443
          CidrIp: 0.0.0.0/0

NATインスタンス用のセキュリティグループは以下のページを参考にしています。

NAT インスタンス - セキュリティグループの作成

インバウンドルールは省略し、アウトバウンドルールだけを設定しています。インバウンドルールは後で手動で設定した方が柔軟性があってよいだろうと思い、設定していません。

NATインスタンス用のIAMロールのポイント

  NatInstanceRole: 
    Type: AWS::IAM::Role
    Properties: 
      RoleName: !Sub ${Suffix}-role-nat-instance
      AssumeRolePolicyDocument: 
        Version: '2012-10-17'
        Statement: 
          - Effect: Allow
            Principal: 
              Service: 
                - ec2.amazonaws.com
            Action: 
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns: 
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

NATインスンス用のIAMロールは、セッションマネージャーを使用するためのマネージドポリシーをアタッチしています。

NATインスタンスにするEC2のポイント

  NatInstanceEC2:
    Type: AWS::EC2::Instance
    Properties:
      # (中略)
      # 送信元/送信先チェックを無効にする
      SourceDestCheck: false

NATインスタンスそのものになるEC2は、まずこちらを参考に送信元/送信先チェックを無効にしています。

NAT インスタンス - 送信元/送信先チェックを無効にする

[送信元/宛先を確認] には、[停止] を選択します。

      # (中略)
      UserData:
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            # パッケージの更新
            yum -y upgrade

            yum -y install iptables-services
            sysctl -w net.ipv4.ip_forward=1

            # 主要なネットワークインターフェースを動的に取得
            PRIMARY_INTERFACE=$(ip -o -4 route show to default | awk '{print $5}')
            
            /sbin/iptables -t nat -A POSTROUTING -o $PRIMARY_INTERFACE -j MASQUERADE
            service iptables save

次に、こちらを参考に、NATインスタンスの起動時に、iptablesを設定しています。

NAT インスタンス - NAT AMI を作成する

参考元ページとの違いは、以下の通りです。

  • AMIを作っておくのではなく、起動時にUserDataでipatablesを設定する
  • UserDataはルートで実行されるので、sudoは不要なので削除
  • yumパッケージの更新をしている(念の為追加しましたが、これはやってもやらなくてもどちらでもよいと思います。)
  • iptablesに設定するネットワークインターフェースを動的に取得している

CloudFormationテンプレートの実行方法

  1. CloudFormationの画面で、スタックの作成からテンプレートの指定で実行します。
  2. スタックの詳細を指定でパラメータ名を入力します。
    • Suffix:各種リソース名のサフィックス
    • VPC:NATインスタンスを配置するVPCのID
    • PublicSubnet:NATインスタンスを配置するパブリックサブネットのID
    • KeyPairName:NATインスタンスにログインするためのキーペア名
    • NatInstanceAMIID: NATインスタンスのAMI ID(初期値はARM64用のAmazon Linux 2023)
  3. 次のオプションのタグは何も変更せずそのまま進めて問題ありません。
  4. 最後のレビューでは、このCloudFormationテンプレートがIAMロールを作るため、確認をしてきます。
    チェックを入れて実行してください。

IAMリソースを作る確認

CloudFormationテンプレートの作成後の作業

セキュリティグループの更新

NAT インスタンス - セキュリティグループの作成

上記ページを参考に、NATインスタンス用のセキュリティグループのインバウンドルールに、HTTPとHTTPSを追加します。ソースはプライベートサブネットのCIDRを指定します。プライベートサブネットは2つあるとしたら、以下のように4つのルールを追加します。
アウトバウンドルールは、CloudFormationテンプレートで設定しているので、そのままで大丈夫です。

セキュリティグループの更新

プライベートサブネットから、HTTP・HTTPS以外のリクエストが発生する場合、インバウンドルールを追加してください。
なお、本記事では参考ページとは異なり、インバウンドルールにSSHを設定しませんでした。NATインスタンスに対してセッションマネージャーを利用可能にしているので、不要だと思ったからです。

ルートテーブルの更新

NAT インスタンス - ルートテーブルを更新する

プライベートサブネットに紐づくルートテーブルの、0.0.0.0/0のルートを、NATインスタンスに向けます。

送信先に「0.0.0.0/0」、ターゲットインスタンスを選択してから、インスタンスのドロップダウンリストから、NATインスタンスを選択します。

送信先のターゲットにインスタンスを選択

これで準備完了です。プライベートサブネットに配置したEC2に入れるなら、yum installなどを実行して、インターネットにアクセスできることを確認してください。HTTP・HTTPSを通信許可していないと、yum installは通りません。

Cloud AutomatorでNATインスタンスの自動起動・停止を設定する

NATインスタンスはEC2なので、Cloud AutomatorでNATインスタンスを自動停止させることができます。これで使わない時間は止めておくことができます。

blog.serverworks.co.jp

こちらの記事では、タグを使ってEC2を特定して停止させています。NATインスタンスのEC2に任意のタグを付けて、それを条件にすればOKです。もしくは、インスタンスIDを条件にして自動停止させることもできます。

最後に

本記事が皆様の開発ライフに少しでも役立てば嬉しいです。

兼安 聡(執筆記事の一覧)

アプリケーションサービス部 DS1課所属
AWS12冠。
広島在住です。
最近認定スクラムマスターになりました。今日も明日も修行中です。