Application Load Balancer を使ってみる : プライベートなAPIをパスでアクセス制限したい

はじめに

仕事でAWS使うことがあって色々覚えたいのと、アカウント作って一年は無料期間なので使わないともったいない気がするので 色々試してみてブログにまとめてみようと思います。 今回はAWSで提供されているロードバランサーの一つであるApplication Load Balancerを使った構成を試してみました。

やりたかったこと

なんらかのWebサービスアプリケーションサーバーがあるとします。 このサーバーは一般ユーザーからアクセスされるパブリックなWeb APIを処理しています。 さらにサービスの色々なデータの計測、解析、管理などのためプライベートなWeb APIも処理させたいということがあると思います。

このプライベートなWeb APIをアクセス制限して内部からのみ呼び出せるようにするというのが目標になります。

今回試した構成

色々な方法が考えられると思います。 まずアプリケーション側で制限するか、ミドルウェアやインフラ側で制限するかという選択肢があると思います。 今回はなるべくAWSの機能で実現するという方針ですがAWSのサービスは非常に多く存在するため他にも色々な方法があると思います。 こういう方法の方がいいよというのがあれば教えてもらえるとありがたいです。

f:id:tkaaad97:20180128181437p:plain

図のような構成にしてみました。 パブリックなAPI用とプライベートなAPI用で二つのアプリケーションロードバランサーを使っています。 これはセキュリティグループをパブリックAPIとプライベートAPIで分けるため、 またプライベートAPIでは内部ロードバランサーを使いたかったので別々のロードバランサーにしました。 (RDBドメインなどは用意してないので試した構成は図と少し違っています。)

AWSコンソールでの構築

今回はAWSコンソールで手動で構築しました。 この他にもCloudFormationなどを利用する方法もあります。 手動での構築はミスも起きやすいので自動化された方法も今後覚えたいです。

VPC

概要 - Amazon Virtual Private Cloud

こちらを参考にVPCを構築しました。 ロードバランサー作成時に二つ以上のアベイラビリティゾーンを選択する必要があるので アベイラビリティゾーンを別にしてサブネットを二つ作成しました。

EC2

EC2インスタンス構築には以下のドキュメントを参考にしました。

チュートリアル: Amazon Linux AMI を使用して LAMP ウェブサーバーをインストールする - Amazon Elastic Compute Cloud

EC2は先に作ったVPCのサブネットに作成し、パブリックIPを自動で割り当てました。 EC2インスタンス作成後、sshできるようにセキュリティグループを設定しyumhttpdをインストールしました。

sudo yum update -y
sudo yum install -y httpd

チュートリアルに沿って/var/wwwのディレクトリの権限を変更し パブリックAPIとプライベートAPIとして使うファイルを設置しました。

echo "Public API" > /var/www/html/public
echo "Private API" > /var/www/html/private

ロードバランサーを構築した後に設定することになりますが EC2のセキュリティグループはロードバランサーからのHTTPアクセスだけを許可し 直接インスタンスへのアクセスはできないようにします。

ロードバランサーの下に置くのにインスタンス1台だけというのもおかしな気がしますが 今回は実験したいだけなのでこれでいいことにします。 通常はオートスケーリンググループを作成して、オートスケーリンググループにインスタンス起動設定を指定します。

インターネット向けアプリケーションロードバランサー

ロードバランサーもEC2のページから作成します。 アプリケーションロードバランサー、ネットワークロードバランサー、クラッシックロードバランサーの3種類があります。 今回はアプリケーションロードバランサーを選択しました。

ロードバランサーの名前はalb-experiment-public-lbとし、スキーマをインターネット向け、IPアドレスタイプをipv4に設定しました。 ロードバランサーも先に作成したVPCに置きます。

セキュリティグループはインターネットからパブリックAPIを呼び出せるようにHTTPアクセスを全て許可します。 セキュリティグループ名はalb-experiment-public-lb-sgとしました。

f:id:tkaaad97:20180128180341p:plain

ルーティングのルールとターゲットグループを設定します。 パブリックAPI用のパスは/public*としました。 ターゲットグループをalb-experiment-public-tgという名前で新規作成し、 先に作成したEC2インスタンスを登録しました。

デフォルトのルーティングルールは削除できないので今回は alb-experiment-public-error-tgという名前で空のターゲットグループを作成して設定しました。

空のターゲットグループにアクセスした場合はステータスコード503が返ってしまうので エラーページを返すインスタンスを別に用意するなどしたほうがいいかもしれません。

内部アプリケーションロードバランサー

ロードバランサーの名前はalb-experiment-private-lbとし、スキーマを内部、IPアドレスタイプをipv4に設定しました。 ロードバランサーも先に作成したVPCに置きます。

セキュリティグループはVPC内部からプライベートAPIを呼び出せるようにHTTPアクセスをVPCのCIDRに対して許可します。 セキュリティグループ名はalb-experiment-private-lb-sgとしました。

f:id:tkaaad97:20180128180349p:plain

プライベートAPI用のパスは/private*としました。 ターゲットグループをalb-experiment-private-tgという名前で新規作成し、 先に作成したEC2インスタンスを登録しました。

デフォルトのルーティングルールは同様に alb-experiment-private-error-tgという名前で空のターゲットグループを作成して設定しました。

セキュリティグループ

f:id:tkaaad97:20180128183352p:plain

ロードバランサーからEC2にHTTPアクセス許可するようにセキュリティグループを設定します。 セキュリティグループのソース (アクセス元) にはCIDRでのIPアドレスや別のセキュリティグループが指定できます。 AWSコンソールでソースの入力欄にsgと入れるとセキュリティグループの候補が表示されます。 ロードバランサーのセキュリティグループalb-experiment-public-lb-sgalb-experiment-private-lb-sgからのHTTPアクセス許可をインバウンドルールに追加します。

アクセス制限できているかテスト

curlAPIを呼び出してみるという方法でテストしてみました。 ドメインは取得していないのでロードバランサーDNS名を使いました。

下のことを確認しました。

  • インターネットからパブリックAPIが呼び出せること
  • インターネットからプライベートAPIが呼び出せずエラーとなること
  • VPC内部からパブリックAPIが呼び出せること
  • VPC内部からプライベートAPIが呼び出せること

参考

Application Load Balancer とは - Elastic Load Balancing

チュートリアル: Application Load Balancer でパスベースのルーティングを使用する - Elastic Load Balancing

Application Load Balancer のセキュリティグループ - Elastic Load Balancing

まとめ

VPC, EC2, アプリケーションロードバランサーの構築方法を学びました。 アプリケーションロードバランサーでのパスベースルーティングについて学びました。 アプリケーションロードバランサーでプライベートAPIのアクセス制限をすることができました。