はじめに
※本記事は、社内勉強会用の資料も兼ねています。
「業務をしていて、なんかVPCまわりイマイチわかってないなあ」
「実践的なVPCを構築しながら学びたいけど、適当に触り過ぎてもすごいお金かかりそうで怖いなあ」
そんな折、以下の @c60evaporator(Kenta Nakamura) さんの記事を見つけ、
「こ、これだ!」
というわけで、今回はこれらの記事を熟読して、実際にやってみたところめちゃくちゃ感動したので、躓いたところなどを含め記事にしてみようと思いました。
対象とする読者
- VPCを勉強したいけど何からやればいいかわからない人
- 認定試験に向けて、VPCをとにかく触りながら勉強したい人
私の学習の流れ
まずは、こちらの記事を熟読しました。(2時間くらい)
タイトルに偽りなく、めちゃくちゃわかりやすかったです。
続いて、こちらの記事を見ながら実際に構築しました。(7時間くらい)
出典元:https://qiita.com/c60evaporator/items/b9e645b96afa3a34f41e
どうですか?すごくないですか?
冗長構成なwebアプリのネットワーク(VPC1)を構築するところまでなら見たことありましたが、それを開発・運用するためのアクセスは社内ネットワーク(VPC2)からのみ行えるようにするところまでやるのは、非常に実践的だなと個人的には思いました。
コスト
私は、2日に分けて構築しました。その際、かかった費用はこちらです。
合計、$3.40ですね。
シャン〇ス「安いもんだ 3.4ドルくらい」
冗談抜きで、このネットワークを構築できた達成感を考えると、個人的には全然OKです。
とはいえ、私は ケチ節約家なので使ってないときは以下を行い多少工夫しました(笑)
- スナップショットを取った上でRDSインスタンスの削除
- EC2インスタンス停止
- ALBの削除
- VPNエンドポイントの削除
学習したこと
以下では、上記学習を行う中で自分の中で疑問に思い調べたところなどを、問いかけも交えながら説明します。
ネットワークACLとセキュリティグループ
両者は、以下のように整理できます。
セキュリティグループ | ネットワークACL | |
---|---|---|
フィルタ対象単位 | インスタンスごと(セキュリティグループIDでグルーピング可) | サブネットごと |
フィルタ方式 | ホワイトリスト | ホワイトリスト+ブラックリスト |
戻り値の取り扱い | ステートフル1 | ステートレス2 |
🔍どちらの方がより優先して使うべきでしょうか?理由も考えてみてください。
📝
優先して使った方がよいとされているのは、セキュリティグループです。
理由は、ホワイトリスト&ステートフルにより、設定をシンプルにできるからです。
また、インスタンスごとに設定できるため、より細かい設定ができる点も利点といえます。
参考: ネットワークACLを使用してサブネットへのアクセスを、セキュリティグループを使用してサブネット内のインスタンスへのトラフィックを制御する
ルートテーブル
ルートテーブルは、ロンゲストマッチングアルゴリズムに基づき、宛先ルートを選択する通信振り分けルールです。
AWS VPCの場合、例えば以下のようにルートを設定できます。
送信先 | ターゲット |
---|---|
0.0.0.0/0 | インターネットゲートウェイ |
172.31.0.0/16 | local(自身のネットワーク内) |
172.31.1.0/24 | VPCピアリング接続 |
🔍このとき、172.31.1.1
宛ての通信はどのターゲットに転送されるでしょうか?
📝
転送されるのは、VPCピアリング接続です。
172.31.1.1
は、上記のいずれにもマッチしますが、ロンゲストマッチングアルゴリズムに基づき、VPCピアリングが転送先として選ばれます。
参考記事の通り、AWSのマネジメントコンソールから「VPCなど」を選択して構築すると、VPCだけでなく一緒にサブネットやエンドポイントを作成する事ができます。
参考記事通りに操作すると、VPC1は以下のような画面になります。
この画像に表示されている通り、各サブネットにはルートテーブルが自動作成され関連付けられますが、public1とpublic2は共通のルートテーブルを使用するのに対し、private1とprivate2はそれぞれルートテーブルを作成され関連付けられます。
🔍このような挙動になるのはなぜでしょうか?
📝
NATゲートウェイは各AZに作るのがベストプラクティス3であり、各privateのルートテーブルにはそれぞれ異なるNATゲートウェイへのルートを定義する必要があります。
したがって、それを見込んでprivateのルートテーブルは各AZごとに分けて作成されます。
参考記事通りに構築する中で、一時的に以下のような状態になります。
🔍このとき、Web1からAP2へはSSHできるでしょうか?
📝
Web1からAP2へは、SSHアクセス可能です。
Web1からのAP2宛てのSSHアクセスは、まずPublic subnet route tableに基づきlocalルートに転送され、AP2へ向かいます。ここで、AP2に関連付けられているSecurity group2では、すべてのSSHアクセスを許可しているので問題なくSSHアクセスできます。
localルートは、VPC内での通信を可能にするもので、デフォルトですべてのルートテーブルに追加されます。4
ルートテーブルには、以下のように「伝播済み」という列があります。
🔍この「伝播済み」とはどういう意味でしょうか?
📝
ルート伝播とは、仮想プライベートゲートウェイ(VGW)またはトランジットゲートウェイ(TGW)が動的にルートをルートテーブルに追加する機能のことです。すなわち、対象のVPCの外側にTGWやVGWで接続されているネットワークが増えた際に、自動的にサブネットのルートテーブルを追記してくれます。
したがって、「伝播済み」とは、自動的に追記されたルートかどうかを記載している列になります。
参考: ルート伝播とは
構築する際の躓きポイントや工夫まとめ
私の環境と構築する際に選択したリソースタイプ
私の環境は以下です。
- Windows 11
- OpenVPN 2.6.1201
参考記事が少しだけ古いので、新しい選択肢が増えてたりしていて、若干迷いました。結論、私は以下を選んで構築してみました。後述する躓きポイントはあったものの、問題なく動作しました。
- EC2
- Amazon マシンイメージ: Amazon Linux 2023 AMI
- インスタンスタイプ: t2.micro
- ストレージタイプ:gp2
- RDS
- DBエンジン:MySQL 8.0.39
- インスタンスタイプ: t3.micro
- ストレージタイプ:gp2
ホスト名の変更
参考記事に従い、ネットワーク構築を進めると、疎通確認の手順が大量にあります。
しかし、EC2インスタンスは、デフォルトでホスト名がip-172-16-1-11
のようなプライベートアドレスから自動生成されたものになっているため、SSHログインした際もプロンプトが以下のようになり、自分が今どのサーバーにいるのか、直感的にわかりにくいです。
[ec2-user@ip-172-16-1-11 ~]$
そこで、以下コマンドでホスト名を変更しておくと便利です。
sudo hostnamectl set-hostname --static <設定したいホスト名>
上記コマンド実行後には、以下コマンドでインスタンスを再起動してください。
reboot
これにより、以下のように表示されるようになるので、誤操作を防ぐことができます。
[ec2-user@development-server-1 ~]$
/etc/hostsの追記
参考記事では、疎通確認用のSSHログイン時のコマンドは以下のように説明されています。
ssh ec2-user@<ログインするサーバのプライベートIPアドレス> -i <ローカルのキーペア秘密鍵のパス>
これだと、<ログインするサーバのプライベートIPアドレス>
を毎回AWSのマネジメントコンソールから調べるのが大変です。そこで、SSHコマンドを実行するサーバー上の/etc/hosts
ファイルにホスト名とプライベートIPアドレスの対応を追記します。例えば、以下のようなコマンドを実行して追記します。
echo "<サーバのプライベートアドレス> <サーバー名>" | sudo tee -a /etc/hosts
追記内容は、catコマンドやlessコマンドで確認できます。
これを行うと、以下のコマンドでログインできるので、いちいちIPアドレスを調べる必要がなくなります。これはscpコマンドでも同様です。
ssh ec2-user@<ログインするサーバー名> -i <ローカルのキーペア秘密鍵のパス>
VPN接続用のサーバー証明書とキーの生成コマンド
参考記事では、VPN接続用のサーバー証明書とキーを生成するコマンドは以下のように説明されています。
./easyrsa build-server-full server nopass
このコマンドも実行はできるのですが、これにより生成されたサーバー証明書はACMにアップロードしても正しく認識されません。公式ドキュメントによると、以下が正しいコマンドのようです。
./easyrsa --san=DNS:server build-server-full server nopass
こちらのコマンドを用いて生成したサーバー証明書とキーを使うと、無事VPN接続することができました。
mysqlのインストール
mysqlのインストールですが、参考記事に沿ってインストールを行うと、私のAmazon Linux 2023 AMIで起動したEC2では以下のようにエラーとなりました。
[ec2-user@ip-172-16-1-11 ~]$ sudo yum install mysql
Last metadata expiration check: 2:40:47 ago on Sat Jan 4 02:34:48 2025.
No match for argument: mysql
Error: Unable to find a match: mysql
公式ドキュメントを参照すると、Amazon Linux 2023では、mysqlパッケージではなくmariadb105を使うのが正しいようです。したがって、以下のコマンドを実行すると無事インストールできました。
sudo dnf install mariadb105
参考までに、dnfはyumの後継コマンドであり、sudo yum install mariadb105
でも問題なくインストール可能です。
squidの設定ファイル変更
参考記事に従いプロキシサーバの設定を完了しても、⑬VPNからプロキシサーバ経由でのインターネットへのHTTP疎通確認がうまくいきません。
原因はsquidの設定ファイルでした。以下のコマンドなどでsquidの設定ファイルを開き、
sudo vi /etc/squid/squid.conf
以下の部分に追記を行います。
#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#
http_access allow localnet ← ★追記
この追記を行った上でsystemctl restart squid
を実行しサービス再起動すると、ローカルネットワークからプロキシサーバにアクセスできるようになり、プロキシサーバ経由でインターネットへHTTP通信できるようになりました。
おわりに
今回はVPCのベストプラクティスについて実際に構築しながら学んでみました。
ネットワークは、プロジェクトの初期段階にある程度上級エンジニアが構築済みだったりして、あとからプロジェクトに参画してアプリケーションの開発とかだけに専念しているとあまり意識しないこともあるかと思います。しかし、実際に手を動かしながら構築して、思い通りのアクセス制御を実現できたときの達成感は格別です。ぜひ皆さんも本記事でご紹介している記事を参考に構築してみてください。
最後になりましたが、以下の非常にタメになる記事を書いてくださった@c60evaporator(Kenta Nakamura)さん、本当にありがとうございました!