はじめに
IT業界に入り4年、AWSを触り始めて1年が経ちました。
前職からAWSをやりたいと言い続け資格を取得し続けたところ「2025 Japan All AWS Certifications Engineers」に選出いただけました。
12冠するのとほぼ同時期からやっとチャンスを頂きAWSを触り始めた者の拙い振り返りになります。
~セキュリティ編~
サブネット
VPCを作成後、まず作成するのがサブネットかと思います。これがそもそも正しくなかった...
app-public-subnet/app-private-subnetと名前が付いていますが、プライベートサブネットと名前が付いていてもパブリックのものが入り乱れていました。
パブリックサブネットとプライベートサブネットの違いについては以前執筆した記事を参照してください。
[初心者向け]パブリックサブネットとプライベートサブネットの違いについて
アプリは本番受け入れテストを実施している最中で安易にネットワークを触ることが出来ませんでした。
状況として開発/検証/本番のワークロードが1つのアカウントにまとまっている。また、すべて構成が異なるという状況でした。特に開発環境はElastic Beanstalk、検証/本番はECSを使用してアプリケーションを稼働しているという点がありました。なので開発環境を新規で構築しなおし、それに倣い検証/本番を構築するという方針で作成しました。
ALBはパブリックサブネット、ECSはプライベートサブネットかつNAT Gatewayからの外部通信を許可、RDSは外部への接続を許可しないものとして3層のサブネット構成にするよう整理しました。
※利用者が少なく多少の停止も許容されていて、コスト削減のため一旦シングルAZ構成になっております。
後々スケールする可能性も考慮してサブネットのみ2AZで準備してあります。

ACM
上記の構成ではACMが使用されていませんでした。通信は今までHTTPで行われていたようです。
なんと恐ろしいことを...
通信傍受されていたらデータが漏洩していてもおかしくありませんね。
なぜかRoute 53にホストゾーンは存在していたのでACMから証明書を発行、ALBに関連付けを行いました。
これでHTTPS通信を実現しました。

ACMを発行したCNAMEレコードは残しておくと自動更新してくれるので削除しておりません。
IAM
これには驚いた...
プロジェクトで1つのユーザーを使用しみんなで使い回していた。
案の定Admin権限...
プロジェクトの利用者を整理してもらい1人ずつにユーザーを発行しました。
これでチームごとに権限を制御しCloudTrailで証跡が残ります。
操作ログも残るので各自に責任もって作業をしていただきましょう。
ついでにMFAの導入も実施。
今まで乗っ取られていなかったのが奇跡としか言いようがない杜撰さです...
CloudTrail
続いてこちらCloudTrail。
有効化はされていましたがデフォルトのまま。
ログが3か月で消えていきます...
監査とかないのか...
専用のS3バケットを作成しログを保持するようにしました。
とりあえずここからの操作ログは残ります。
これまでのは時効で消えてしまいましたが仕方ありません。
GuardDuty
これも有効化しました。
怪しい操作を検知し何度か通知を確認しています。
確認したところ自社の人間の操作なので大丈夫そうではあります。
ハンズオンとかでも最初に有効化するべきリソースとしてよく挙げられているものなので、こういうのは積極的に利用していきたいですね。
Config
これも有効化だけしました。
本当はルールの作成と自動修復までしたいところですが、手が回っていません。
どこまで実現するか悩ましいところです...
Security Hub
これは正直自分もあまりわかっておらず有効化を見送っていましたが、入れたほうが良いと助言をいただき導入することとなりました。
どのセキュリティ基準に対してどこまで対応していくか、プロジェクトごとに考える必要がありますが詰め切れていないです。こういうのも基準を設けてクリアしていきたい課題になります。
セキュリティグループ
慣れないなか試行錯誤した痕跡がたくさん残っていました。
さまざまなIPやポートが空いたセキュリティグループを各インスタンスに複数アタッチしていました。
俗にいうカオス状態です。
挙句、全トラフィックを解放したものが付与されているものもあり「それは通信通るよな...」という状態でした。
環境ごとに設定値も異なりますので、これは地道に対応していくしかありません。
とは言っても全ルール1つ1つ確認して環境差分を見ながら絞り込むのはあまりに大変です。
その時ちょうど知ったAWS Config「高度なクエリ」という機能を使用しました。

生成AIを使用してクエリを記述し、全てのセキュリティグループを取得。
CSV出力し各環境ごとに整理することで値を効率的に進めることが出来ました。
インバウンドルールは他のサービスに関連付けられているセキュリティグループからのみ許可することで統一し、整理しました。
※ALBは全HTTPS通信を受け入れる必要があったのでこれは除く
開発環境から順に整理したものを実装していき、問題なく整理が完了しました。
S3
パブリックアクセスを許可しているものが大半を占めていたので、これを無効化しました。
アプリがS3からデータを取得しているものがありましたが、VPCエンドポイントは作成されていたのでルートテーブルを見直しアプリに影響が出ないように経路を確保しました。
EC2
今回のアプリはローコードを使用していて、ビルドやデプロイにWindowsサーバーが必要だったためEC2でWindowsサーバーを構築されていました。
ただRDPするのにEC2がパブリックに置かれていました。
これはあまり望ましい状況ではありません。これもパブリックに下記の記事を参考に再構築しました。
プライベートなEC2(Windows)に対してRDP接続する方法
結果このような構成になっています。
これで外部からのアクセスの心配もなくなりセキュアな構成にすることが出来ました。

~CI/CD編~
自動デプロイ構成見直し
旧CI/CD構成

①S3イベント導入
ローコードで生成されたwarファイルとbuildspec.yml、DockerfileをZip化する。
これをS3にアップロードすることでCodeBuildが起動するようになっていました。
S3にアップロードした際、CloudTrailイベントを検知してEventBridgeが起動。
CodeBuildが走る仕様でややこしい構成だったので、これをS3イベントに作り直しました。
対象のバケットに名前が一致するファイルだけ上がった際のみ起動するようになっています。
これでシンプルな構成になり保守性も上がります。
②CodePipeline除外
検証環境と本番環境で設定の異なるCodePipelineが配備されていました。
そもそも現状としてCodeBuildしか使用していないので、Piplineがなくても動くしコストは上がり保守性が下がるものだったのでCodePipeline事態を排除しました。
見直し後のCI/CD環境

不要な構成をなくし、スッキリしたので保守性も上げることが出来ました。
buildspec.yml
そもそもbuildspec.ymlとは:
CodeBuildがビルド処理をどう実行するかを定義する設定ファイルです。
今回はECSを使用しているのでwarファイルとDockerfileを使用してECRにイメージをpushするのが役割となります。
元の状態としては2つのECRにイメージをpushしていました。
色々試したのでしょうが、上手く行かなかった残骸が残っていて処理もわかりづらかったのでこれらは削除し、全体のフローがわかりやすい状態にしました。
~コスト削減編~
不要リソース削除
Cost Exploreを使用してリージョンでグループ化することによって使用していないリージョンで操作されたリソースを洗い出しました。これで1つ1つ確認しながら使用されていないリソースを削除し、検証で使用した残骸の整理をしました。
また、全体を見て自身が操作や設定を行っていないリソースについても関係者に確認を取りながら1年以上使用されていないリソースを順に消していきました。
まだ確認途中の物もありますが、だいぶ余計なコストを削減できました。
リソース時間停止
ECSが時間によって起動停止の設定が入れられておらず、常時起動になっていたためEventBridgeを使用して開発/検証環境の起動停止の自動化を実施しました。
これに伴い、RDSも同様の設定を入れています。
また、資産をビルドするためのサーバの停止忘れが多く、余分なコストが掛かっていたためこれも定時から1時間後に自動停止する設定を入れました。
EBS変更
EC2、RDSにおいてストレージでgp2が多く使用されていました。
当時はこれしかなかったのかも知れませんが、gp3の方が性能は良くコストも低いので変更していきました。
パブリックIP解放
EC2やRDS、ECSなどのリソースがパブリックに置かれてパブリックIPアドレスを保持していました。
これらをプライベートに置いたことでEIPを保持する必要がなくなり、およそ20弱のElastic IPアドレスの解放をしました。
細かいことが多いですが、「ちりつも」でコストは上がっていくので注意したいですね。
最大コストの頃からだとおよそ2/3まで下げて運用することが出来ています。
~運用改善編~
IAM棚卸
プロジェクトに参画した際は1つのユーザーを全員で使い回してAWSを利用する運用となっていました。
これだとCloudTrailでも誰の操作で変更されたか追えないし、権限の制御も出来ないです。
全員のユーザーを発行し、チームごとに必要な権限を聞き取りIAMグループに権限を付与することで制御しました。
また、月1でユーザーの棚卸を実施してプロジェクトから抜けた方のユーザーを削除する運用も取り入れました。
本当はIAM Identity Centerを入れたいところですが、企業としての導入となると大規模な話になるので今回はプロジェクトで収まるような施策を取っています。
ログ出力
ECS、RDS、ALB、WAFなどのログが正しく出力されていなかったのでそれぞれ設定しました。
ECSに関してはアプリのログ自体が出ていなかったので、アプリチームと連携して想定しているものが出るかまで確認して無事に出力することが出来ました。
これらをS3に吐き出し1年、CloudWatchでは保持期間を1か月とすることでコストを抑えながら必要な期間ログを保持することに成功しました。
アプリ性能改善
アプリの性能が悪くインフラ側の設定値の問題ではないかと言われ調査を実施しました。
結論としてはDBの設定値はデフォルトから変えてないものがほとんどで、大半が推奨値でした。
ほぼ変更の必要がないのという答えでしたが、それだとアプリの性能は改善されないので調査は続きます。
特定のクエリを実行するとDBのCPUがおよそ100%で張り付き、その他の処理にも影響を与えるものでした。
メンバーが実行計画を取得し内容を見てみるとメモリ不足の状態が続いていました。
クエリの処理が重いせいでメモリが足りなかったと推測されます。
そこで「work_mem」の値をデフォルト4GBから64GBまで上げました。
これで一時的に処理の向上に成功しました。
ただこれもすぐに元に戻ってしまいました。
原因は恐らくtタイプのバーストが尽きてしまったせいかと推測されます。
根本クエリを改善してほしい気持ちはありつつ、ローコードの制約で開発者たちが手を出せない部分もあったので作業は難航します。
結果としてアプリチームがデータ処理を分割することで性能は改善されましたが、原因が不明だったのでそこの調査も実施しました。
100%の確信があるわけではないですが、処理を実施する際に使用するShared Bufferの容量に対してデータ量が多すぎたという結論になりました。
インフラが性能問題をここまで調査を実施したり、クエリで使用するメモリを考慮したりという場面はそうそうないと思うので普段では身に付かないような知見が得られました。
とはいえ、DBの知識がないと初期の設定値考慮が出来ないのでまだまだ勉強不足を痛感しました。
csv出力に元が20分かかっていたものが1分程度で出力されるような大幅改善が出来ました。
さらに改善はするべきですが、根本原因はDBの構成やクエリの問題になるかと思うのでアプリチームにお任せしたいと思います。笑
まとめ
AWSに初めて業務で携わり、基本的な知見はあるものの実務でやっていくにはやはりまだまだ足りないことを痛感した1年目でした。
対応したものも基礎的なものが多く、有識者が初めから対応していればこうはなっていなかったというものが多かった印象です。
ただこのカオスな状況において自身で課題を見つけて課題を見つけて対応して行けたのは大きな力になったと思います。
2年目はさらに知見を深めて新しいことにも挑戦しながら力を伸ばしていきたいです。
本来実施していて当たり前なことが多いですが、これらが漏れている環境も多々あると聞きます。
もし読んでくださった方に1つでも有益な情報となっていたら幸いです。
最後まで読んでいただきありがとうございました。