スタメン エンジニアの松谷(@uuushiro)です。
スタメンは、2020年3月より エンゲージメント診断サービス TERAS(テラス) の提供を開始します。創業プロダクトである TUNAG(ツナグ) に続いて2つ目のプロダクトになります!
TERASは、エンゲージメント経営を実行できるサービス TUNAG のノウハウを元にした、組織のエンゲージメントを可視化する組織診断サービスです。サービスの概要は以下リンクからご覧ください!
この記事では、エンゲージメント診断サービス TERAS の技術アーキテクチャの紹介をします。
TERAS は SPA(React)とAPIサーバ(Ruby on Rails)で作られたWebアプリケーションです。アーキテクチャの構想・実装にあたって、重要視した点は3つです。
- 実装・保守・運用コストをなるべく削減し、機能開発に集中できる基盤にしたい
- セキュリティ・スケーラビリティなどの非機能要件は初期からなるべく妥協したくない
- インフラをコード化して管理し、インフラ知識の冗長化のハードルを下げたい。また、再利用性をあげたい。
特に複雑なことはしておらず、結果としてシンプルな構成になりました。 以下でアーキテクチャの全体図と個別詳細を紹介していきます。
TERAS アーキテクチャ全体図
TERAS アーキテクチャの全体図は以下になります。
ざっくり以下の項目に分けて紹介していきます。
- ネットワーク
- CDN
- WEBサーバー
- デプロイ
- 秘匿情報管理
- インフラのコード化
ネットワーク
ネットワーク以下3つのサブネットに分けています。
- グローバルIPを持てば、外部ネットワークと通信ができるサブネット(Public Subnet)
- NATを介してのみ外部ネットワークと通信ができるサブネット(Protected Subnet)
- 外部ネットワークと通信はできないサブネット(Private Subnet)
TERAS では、Application Load Balancer を Public Subnet に配置し、ECS/Fargateタスクを Protected Subnet に配置することで、Application Load Balancer からのみアクセスを受け付けるようにしています。また、WEBサーバーとしてFargateタスクを利用していますが、Fargateタスクに対して直接Elastic IPを割り当てることができないので、外部へのアウトバウンド通信(メール配信サービスへのAPIアクセスなど)を許可するために、NATを Public Subnet に配置しています。RDSは、外部通信の必要性がないので、Private Subnetに配置しています。このように、ネットワークの役割毎に作成することで、階層化したアクセス制御を行いセキュリティを向上させています。
CDN
TERAS では、CDNとして Amazon CloudFront を利用しています。導入理由は3点です。
パフォーマンス向上
- エッジサーバーからコンテンツが送信される分、レスポンスが速い
- ただ、オリジンが東京リージョンなので実際にはそこまで差がでないかもしれない。
コスト削減
- Amazon CloudFront からデータを送信するコストは Amazon S3 から送信するコストよりも安い
セキュリティ
- AWS WAF の統合が可能で、XSSやSQLインジェクションなどの一般的なWEBアプリケーションの攻撃を防ぐことができる。(2019年11月に新しくリリースされた AWS WAF V2 の Managed Rule を利用し、WAF V1に比べ、ルールの設定が大幅に楽になった。)
- Amazon CloudFrontは、世界中にノードがあるため大量の帯域幅があり、多くのDDOS攻撃を軽減できる
また、Amazon CloudFront に関して、SPAにおける要件や、セキュリティの観点で対応した事項があるので以下で紹介します。
キャッシュコントロール
Amazon CloudFront のキャッシュコントロール機能(Behaviors)を活用し、Amazon S3(SPAサーバー)と Application Load Balancer (APIサーバー)のマルチオリジン構成にしています。クライアントからのリクエストパターンを元に、キャッシュポリシーやオリジンへのアクセスルールを個別設定しています。TERAS では、/api
というリクエストパターンの場合は、Application Load Balancerへ、その他のリクエストパターンは Amazon S3へ振り分けられるように設定しています。
また、/api
のような動的コンテンツに関しては、キャッシュされないようにTTLを0に設定しています。
カスタムエラーページ
React RouterなどSPA側でルーティングをしている場合、サブディレクトリ含むURLでブラウザをリロードをすると、S3のエラーページが表示されてしまいます。これは対象のディレクトリがS3バケットに存在しないことが原因です。Amazon CloudFrontの Error Pages に403または404エラーの場合には /index.html
へ転送し、SPA側でルーティングの制御が行えるようにしています。
オリジンサーバーの保護
セキュリティ・パフォーマンスの観点において、外部から直接オリジンへアクセスされることを防ぎたいです。
Amazon S3 には、ブロックパブリックアクセスという、あらゆるルールより優先されるアクセス制御ポリシーがデフォルトで有効化されています。設定ミスなどデータが意図せず公開されることを防ぐために、基本ブロックパブリックアクセスは有効化のままで運用できるようにしたいです。Amazon CloudFront の Origin Access Identity を使うことで、 ブロックパブリックアクセスを有効化したまま、Amazon S3 へのアクセスを Amazon CloudFront からのリクエストに限定することができます。
また、Application Load Balancer についても、Amazon CloudFront でカスタムヘッダを追加し、Application Load Balancer側で値が一致すれば、CloudFrontから転送されてきたリクエストとみなし、リクエストを許可することができます。これによって、Application Load Balancer についても Amazon CloudFront からのリクエストに限定することができます。
クロスドメイン通信が不要
SPAとAPIサーバが連携するアプリケーションをホスティングする場合、SPAサーバーとAPIサーバーが別ドメインでホスティングされることがあると思いますが、Amazon CloudFront でマルチオリジン対応することで、同一ドメインで扱うことができ、APIサーバー側におけるCORS対応が不要になります。実装・検証工数を抑える1つの要因となりました。
WEBサーバー
AWS Fargateを以下の理由で導入しました。
- ホストインスタンスの管理から解放
- オートスケールの設定が不要
つまり、自分でサーバーを管理することなくコンテナを実行できます。EC2に比べて、コストは割高ですが人的工数の削減を考えると元が取れるのではないかと思います。
AWS Fargate については、以下の AWS Startup ブログ が大変分かりやすかったので興味のある方はそちらをご覧ください。 スタートアップのためのコンテナ入門 – AWS Fargate 編
デプロイ
APIサーバー(Amazon ECS)
AWS CodePipeline で AWS CodeBuild と AWS CodeDeploy を連携しデプロイをしています。以下の理由で導入しました。
- デプロイサーバーの構築・運用コスト削減
- オートスケールとの相性が良い
- ECSとの統合機能が充実している
- Blue Green Deployment
- Canary Deployment
- Linear Deployment
- AWS内でデプロイフローが完結することで、AWSの認証情報などを外部に公開する必要がなくセキュアに
まだ、AWS CodePipeline関連のサービスの利用経験が浅いので課題が見つかるかもしれませんが、セキュリティ・スケーラビリティの観点や他AWSサービスとの親和性においても良い選択なのではないかと思っています。
SPA(Amazon S3)
AWS CodeBuild でビルドし、その生成物を S3 sync して、Amazon CloudFrontの invalidate を実行しキャッシュをクリアするだけです。
秘匿情報管理
System Manager の Parameter Store 秘匿情報を登録することで、AWS CodeBuild、Amazon ECS で環境変数に機密情報を渡せます。Railsのcredentials機構を使うよりも楽で、ビルドやデプロイ時など必要な秘匿情報も合わせて一元管理できるのでとても便利でセキュアだと感じています。
インフラのコード化
これらの構成を AWS CloudFormation で作成しています。AWS CodeDeploy のECS Blue Green Deployment については、未だ AWS CloudFormation 対応していないため、マネジメントコンソールから手動で登録しています。 このアーキテクチャは、プロダクト固有の特殊な構成ではないので、今後 WEBアプリケーションの基盤構築の際に、再利用しやすくなっています。そして、今後新しく TERAS へ参加するメンバーもこの記事とインフラコードを見れば、全体像を把握することがでるので、システム知識のキャッチアップが速くなるのではないかと期待しています。
まとめ
TERASの全体像と各項目について紹介させていただきました。インフラ構築・運用コストを抑え、かつセキュアでスケールするシステムを作る際の参考になれば幸いです。この構成はシンプルで、汎用性も高く、かつコード化をしているので、今後プロダクトが増えた際にも、割と簡単に再利用ができるのではないかと期待しています。
3月にリリースされ運用が始まりますが、まだまだ課題はたくさんあります。また、プロダクトが複数になったことで、セキュリティ・IAM管理・監視体制など、プロダクトごとにポリシーが乱立しないように、戦略立てて決めていく必要があるなと感じています。
最後に
TUNAG、TERAS、新規プロダクトを横断的に設計・改善してくれるSREを募集しています! プロダクトが複数になり、TUNAG の大規模化に向けて一層インフラ面の強化を進めていくタイミングなので、とてもやりがいのある面白い仕事になると思います。興味を持ってくれた方は是非、下記のエンジニア採用サイトを見てください!