こんにちは!インフラを担当しております上平と申します。 このエントリーでは弊社が運営するサービスB/43のインフラをどのように構築してきたかを紹介します! スタートアップ企業でイチから構築する大変さや面白さをお伝えできればと思います!
今回は前回の選定編の後の構築編となります。 長くなりそうなので、2部構成に分けて選定後に構築してきた内容をご紹介します。
構築 と言ってもサービスインフラ構築だけではなく、オフィスインフラ構築も実施しており、 両方に関して紹介予定です。 今回は サービスインフラ構築 に関して紹介していきます。
サービスインフラ構築
AWSアカウント
選定編でも書きましたが、開発スピードの低下を回避するため、PCI DSS非準拠アカウントと準拠アカウントの2アカウントに分離しました。 セキュリティレベルは2アカウントとも同様の基準で構築しております。
環境
弊社ではDevelopment環境・Staging環境・Production環境と3つの環境でサービス開発を行なっています。 それぞれの環境はVPC単位で分かれています。
IAM
ユーザー
弊社では2アカウント存在しますが、IAMユーザー管理は1アカウントで実施しております。 Development環境で使用するssh鍵などもIAMにて管理し、PCI DSS非準拠アカウントに集約しています。 PCI DSSでは無効なセッションを15分で切断する必要があり、AWSコンソールはその条件をデフォルトで満たしません。 弊社ではPCI DSS準拠環境へのログインはswitchロールで制御し、MFA必須で有効時間を15分としています。(MultiFactorAuthAge) そのため、PCI DSS準拠アカウントではユーザーは存在しておらず全てロールで動作するように構築しています。
しかし、この運用方法には課題があり、PCI DSSの要件はクリアしたものの短時間でログアウト状態になってしまうので、改善策を模索中です。
ネットワーク
VPC
VPCのネットワークアドレスは、ネットワークアドレス帯に注意しました。 理由は2アカウントある点と環境による区別が必要となるからです。 弊社では 10.x.x.x/16 をPCI DSS準拠アカウント、172.x.x.x/16をPCI DSS非準拠アカウントで構築し、第3オクテットを環境によって合わせるように構築しています。 また、subnetは定番の3階層で実施しています。 それぞれのsubnetに対して個別に、NACL、RouteTableを設定し、柔軟なネットワーク制御を実現しています。
環境 | アカウントA | アカウントB |
---|---|---|
Development環境 | 10.16.x.x/16 | 172.16.x.x/16 |
Staging環境 | 10.17.x.x/16 | 172.17.x.x/16 |
Production環境 | 10.18.x.x/16 | 172.18.x.x/16 |
outbound
PCI DSSでは要件1.2.1にてアウトバウンドに対するパケットを制御する必要があり、 NACLで制御するのが通説なのですが、通信先のIPアドレスが必ず固定というわけではないため苦労しました。
接続先の環境が、ALBなどのようにIPアドレスが変化するサービスを使っていた場合、アウトバウンドのIPアドレスをNACLにて制御できません。 そのため、環境内にアウトバウンドトラフィックを制御するproxyをNLB+nginxを構築し、アウトバウンドを ドメイン レベルで制御するようにしました。
しかし、それでは OS が起動するまでproxyができないという問題がありました。具体的にはECS(Fargate)起動時のimageのダウンロードができなかっため、それはVPC-endpointを使うことで解決しています。
コンテナ
Development環境
Development環境のコンテナは、ログインしてデバッグするシーンが多かったのでECS on EC2で実施しています。
Staging・Production環境
Staging・Production環境ではFargateを使用しています。 構成の違いによる挙動の差異をなくすため、Staging環境とProduction環境ではスペックの差のみにし、構成を合わせています。
PCI DSSではIDS/IPS(不正侵入検知/不正侵入防御)が必要となります。 弊社ではStaging・Production環境のコンテナに対するsshでのログインを不可能にし、ファイルシステムも全てReadOnlyにして構築しています。 それにより、IDS/IPSの要件をクリアしつつ運用コストを削減できたのは大きかったと思います。
秘匿情報
秘匿情報は全てSecretsManagerに投入して管理しています。 しかし、最近秘匿情報が多くなりすぎて登録上限に達してしまったので、情報を精査し秘匿する必要のなかったものを切り出し、一部をリポジトリで管理するようにしています。 全ての秘匿情報はコンテナ起動時にentrypoint.shにて取得後、メモリ上に設定(環境変数)し起動するため、秘匿情報の非保存状態を実現しております。
ログ基盤
構成
前回の 選定編 でも書きましたが、CloudWatch+Kinesis+Athena(S3)という構成を選択しています。
ログはCloudWatchLogsに蓄積し、そこからKinesis Firehoseを使って転送し、S3に保存するようになっています。 当初はfluentdを使って転送する方法も検討しましたが、障害ポイントが増える事と、障害によってログがロストする事を懸念し、fluentdは断念しました。
工夫した点
蓄積されたS3のログはGlue Tableに格納し、Athenaで検索可能ですが、1つ問題がありました。 CloudWatchLogsからKinesis Firehoseへ転送されるログデータはJson形式で送信され、改行無しの1行で送られてきます。 しかし、Athenaは改行を1レコードと判定しているため、ログの総数が合わない形となりました。 そこでKinesis FirehoseのLambdaを使ったData Transferで改行を入れることにしました。
苦労した点
CloudWatchLogsからKinesis Firehoseへ転送されるログは以下の条件を満たす必要があり、それらを実現するlambdaを作成し、構築しています。
- Json形式で送信される
- messageTypeが
CONTROL_MESSAGE
とDATA_MESSAGE
がありCONTROL_MESSAGE
は不要
- messageTypeが
- Base64エンコードされている
- gzip圧縮されている
しかしながら、parquet形式に変換してS3保存してないため、まだまだ課題はあります。
まとめ
B/43のインフラ構築編1部をご紹介しました。 PCI DSSに準拠することを念頭においてインフラ構築することは割と大変でした。
特にネットワークの基礎を理解していないと行えないNACLの設定、アウトバウンドのトラフィック制御に苦労しました。 また、ログ集約に関してもAWSのマネジメントサービスを通してしかわからない部分もあったのも難しかった点の一つです。
今後も改善したいポイントがまだまだあり、オフィス移転なども控えているため、またオフィスインフラを構築するのが楽しみです。
スマートバンクでは一緒に B/43 を作り上げていくメンバーを募集しています! カジュアル面談も受け付けていますので、お気軽にご応募ください 🙌