※この記事は2025/12時点の情報です。
✅はじめに
AWS設計では、ちょっとした判断ミスが後々大きなコスト増につながることがあります。本記事では、「よくある失敗パターン(あるある)を深掘りし、なぜ起きるのか、実務への影響、そして防ぐためのベストプラクティスをまとめます。Qiita読者が「今すぐ改善できる」状態を目指します。
本記事のゴール
- AWS設計でよくあるコスト爆発の原因を理解する
- 実務で使える解決策・自動化・監査方法を知る
- 設計時に意識すべきポイントを整理する
目次
- VPC CIDR設計が後から足りない
- S3バケットが誰でも読める
- CloudWatch Logsが無限に増える
- EC2インスタンスが停止忘れで課金継続
- Provisioned IOPSのEBSを過剰スペックで作成
- 共通ガイド:運用に落とし込むためのチェックリスト
- まとめ
1. VPC CIDR設計が後から足りない
背景
VPCのCIDRブロックはシステムの土台。**初期に狭いCIDR(例:/24)**で作ると、後でPrivate/Public Subnetやエンドポイント、EKSノード、将来のAZ追加に対応できず、VPC再構築(新VPC→移行)が必要になることがあります。
なぜ起きるのか(パターン)
- "とりあえず小さく" で開始。将来のAZ増設/サービス追加(EKS、RDS、PrivateLink、TGW)を見積らない。
- サブネット分割戦略がない(AZごとの/24確保、用途別に/26などの方針が未定)。
- Pod/IP消費量の想定漏れ(EKSのCNIやENI上限、Pod密度の影響)。
実務での影響(コスト)
- VPC再構築の工数コスト(新VPC作成、ルーティング、セキュリティグループ、エンドポイント再作成、テスト)。
- サービス停止リスクや移行の段取りコスト(社内調整、検証期間)。
- 隠れコスト:監査・申請、権限付与や運用ドキュメントの差し替え。
解決策(設計指針)
- 初期は十分に広いCIDR(例:/16〜/20)。RFC1918の範囲で他ネットワークと重複回避。
-
サブネット分割戦略を明文化:
- AZ×用途(Public/Private/DB)で固定サイズを確保。
- 例:AZごとに
/24を3本(Public/Private/DB)=1AZで/22程度。
- VPC Secondary CIDRを理解:後からCIDRを追加して拡張可能(ただし既存と重複不可)。
- VPC IPAMで組織横断のIP計画を管理(将来のアカウント/リージョン拡張に備える)。
自動化&監査(すぐ使える)
- Terraform/CloudFormationにCIDRとサブネットサイズの変数を用意して再現可能性を担保。
- **Config(カスタムルール)**で"小さすぎるCIDR"を検出し、申請・承認フローへ。
-
タグ基準の静的解析(例:
Purpose=PublicSize=/24など)をCIでチェック。
実務Tips
- エンドポイント(Interface/ Gateway)やNATの台数もIP設計に影響。将来のプライベートアクセスを見込む。
- EKSはPod/ノードのIP消費が多くなりがち。Pod密度前提を置いた余裕設計。
IaCスニペット(Terraform例)
variable "vpc_cidr" { default = "10.0.0.0/16" }
variable "public_subnet_cidrs" { default = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"] }
variable "private_subnet_cidrs" { default = ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"] }
落とし穴(Avoid)
- 既存オンプレとCIDR重複。後でDirect Connect/Site-to-Site VPNで衝突。
- Secondary CIDR追加後のルートテーブル整備漏れ。
2. S3バケットが誰でも読める
背景
S3は柔軟ゆえに公開ミスが起こりやすい。ACL/バケットポリシー/パブリックアクセスブロックの理解不足で全世界公開になると、情報漏洩・信用失墜へ直結します。
なぜ起きるのか(パターン)
- 検証で一時的に公開→本番へ設定移植。
- CloudFront配信の誤設定(オリジンをPublicにする必要がないのに公開)。
- IAMロールが広すぎて、ポリシーが意図せず緩む。
実務での影響(コスト)
- 漏洩対応・外部通報・法的手続き・再発防止の多額のコスト。
- メディア対応やブランド毀損の長期的損失。
解決策(設定の原則)
- Block Public Access(BPA)を常時ON(アカウント単位&バケット単位)。
- S3バケットポリシーのデフォルト拒否+条件付き許可にする。
- aws:SecureTransportでTLS必須、aws:PrincipalOrgIDで組織外を拒否。
- AWS Configルールで公開検知→自動修正(Lambda/SSM)。
- Macieで機密データ検出(検出後の自動隔離フローを用意)。
すぐ効くCLI
# アカウント単位のBPA
aws s3control put-public-access-block \
--account-id <ACCOUNT_ID> \
--public-access-block-configuration 'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'
# バケット単位のBPA
aws s3api put-public-access-block \
--bucket <BUCKET> \
--public-access-block-configuration 'BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true'
バケットポリシー例(TLS必須&組織限定)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonTLS",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::example-bucket", "arn:aws:s3:::example-bucket/*"],
"Condition": { "Bool": { "aws:SecureTransport": "false" } }
},
{
"Sid": "AllowOnlyOrg",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": ["arn:aws:s3:::example-bucket", "arn:aws:s3:::example-bucket/*"],
"Condition": { "StringNotEquals": { "aws:PrincipalOrgID": "o-abcdef1234" } }
}
]
}
監査&自動修正
-
Configルール(例):
s3-bucket-public-read-prohibited、s3-bucket-public-write-prohibited、s3-bucket-level-public-access-blocks。 - ルール違反→EventBridge→LambdaでBPAを強制ON/公開ポリシー削除。
実務Tips
- CloudFront経由でもオリジンは非公開が原則(Origin Access Control/OAI)。
- 共有バケットはプリンシパル限定(組織ID/特定ロール)で運用。
落とし穴(Avoid)
- 静的サイト公開のつもりで業務データを混在。
- ACLを使った権限付与(推奨はポリシー)。
3. CloudWatch Logsが無限に増える
背景
CloudWatch Logsは保持期間がデフォルト無期限。サービスが増えるほどロググループが増殖し、ストレージコストが膨らみます。早期に設計・運用ルールを整えるのが鍵。
なぜ起きるのか(パターン)
- Retention未設定(デフォルトのまま)。
- 監査要件が曖昧で、全部長期保管という安易な選択。
- ロググループ命名がバラバラ→棚卸し不能。
実務での影響(コスト&運用)
- 毎月の固定費増(無駄な保持)。
- 後からアーカイブ/削除の大工事(影響調査・可用性検討)。
解決策(運用設計)
- 保持期間の標準を決める(例:本番30〜90日、開発7〜14日)。
- S3アーカイブ+Athena/Glueで長期分析(コスト低減)。
- Logs Insightsで必要なときだけ深掘り(常時保持を避ける)。
-
命名規約:
/env/service/componentで整理。
すぐ効くCLI
# Retention設定(例:30日)
aws logs put-retention-policy \
--log-group-name /prod/app/web \
--retention-in-days 30
# 既存ロググループの棚卸し
aws logs describe-log-groups --query 'logGroups[].{name:logGroupName,retention:retentionInDays}'
Logs Insightsクエリ例(重いログの特定)
fields @logGroup, @message, @timestamp, @ptr
| stats sum(bytes) as total_bytes by @logGroup
| sort total_bytes desc
| limit 20
※ 実際はBytes計測には@messageサイズからの近似やS3側の集計を組み合わせます。
自動化&監査
-
タグ
RetentionDaysを付け、EventBridge + Lambdaで強制適用。 - **Config(カスタム)**でRetention未設定のロググループ検出。
- FirehoseでS3へ転送し、ライフサイクルでアーカイブ→削除。
実務Tips
- 監査要件は用途別に差をつける(認証ログは長め、アクセスログは短め)。
- 重複ログ(ALBアクセスログとアプリアクセスログの二重記録)を整理。
落とし穴(Avoid)
- 重要イベントをS3へ移したのに削除ポリシー未設定で結局増える。
- 解析のために無期限保持を選びがち。アーカイブ+オンデマンド分析に切替。
4. EC2インスタンスが停止忘れで課金継続
背景
検証・一時利用のEC2が停止漏れで月末にコスト爆発。とくにGPU/メモリ最適化などの高額クラスは短期間でも痛い。
なぜ起きるのか(パターン)
- 手動運用に依存(誰が止めるか曖昧)。
- 夜間・週末の自動停止が未整備。
- "あとで使うかも"で惰性稼働。
実務での影響
- 余分なオンデマンド課金。
- コスト可視化不十分で、どのチームの負担か不明確。
解決策(仕組み化)
-
EventBridgeスケジュール+Lambdaでタグベース停止(例:
AutoStop=true)。 -
SSM Automation(
AWS-StopEC2Instance)で停止・起動の定期運用。 - Budgets Actionsでしきい値超過時に通知&自動停止フローへ。
- Trusted Advisor/Compute Optimizerで低利用インスタンスを洗い出し。
すぐ効くCLI
# 起動中インスタンスの一覧(タグ付与確認)
aws ec2 describe-instances --filters Name=instance-state-name,Values=running \
--query 'Reservations[].Instances[].{Id:InstanceId,Tags:Tags}'
# 停止(例)
aws ec2 stop-instances --instance-ids i-0123456789abcdef0
監視ロジック例(アイドル検知)
- CPUUtilization < 5% が7日継続、NetworkIn/Outが低水準、ディスクIO低水準。
- Composite Alarmで複合条件を満たしたらタグ付与→自動停止フロー。
実務Tips
- 検証環境は平日日中のみ起動が基本。夜間・週末は自動停止。
- チームごとにコストタグ(
CostCenter,Owner,Schedule)を必須化。
落とし穴(Avoid)
- 停止すると消えるインスタンスストアに重要データを置く。
- AutoStop対象に本番や常時稼働が必要な監視サーバを含める。
5. Provisioned IOPSのEBSを過剰スペックで作成
背景
EBSはタイプ選択とIOPS/スループットの設計がコストに直結。io1/io2のProvisioned IOPSは高性能だが高額。実測無しで過大スペックにしがち。
なぜ起きるのか(パターン)
- SLAへの過剰反応で最上位を選ぶ。
- 開発環境まで本番並みに設定。
- 性能課題の原因が**EBS以外(DB設定、アプリ設計)**なのに、ストレージに寄せる。
実務での影響
- 月次の固定費増(容量+IOPS+スループットの課金)。
- 性能課題の解決遅延(本質的改善が遅れる)。
解決策(選定・可視化・調整)
-
CloudWatchメトリクス:
VolumeReadOps/WriteOps/QueueLength/IdleTimeでp95/p99を観測。 - gp3の活用:容量とIOPS/スループットを独立調整可能。多くのワークロードで十分。
-
段階的チューニング:
- 2週間の観測→ボトルネック特定。
- gp3に切替(
modify-volume)し、IOPS/スループットを漸増。 - 変化を負荷試験で検証。
- io2は一貫した IOPS が必須なクリティカルDBに限定。
すぐ効くCLI
# 既存ボリュームのタイプ変更(例:gp3へ)
aws ec2 modify-volume --volume-id vol-0123456789abcdef0 --volume-type gp3 --iops 6000 --throughput 250
# メトリクス参照のためのタグ取得
aws ec2 describe-volumes --query 'Volumes[].{Id:VolumeId,Tags:Tags,Type:VolumeType,Size:Size}'
監査&自動化
-
Config(カスタム)で
io1/io2を使用する際の事前承認を要求。 - Compute Optimizerの推奨を定期レビューしてRightsizing。
- バックアップ設計(Snapshot/DLM)と併せて容量の無駄を削減。
実務Tips
- DBはキャッシュ設計(バッファプール、クエリ最適化)が効果大。EBSだけで解決しない。
- 高IOPSが必要でも、短期ピークならアプリ側のバッチ分散やキュー化で吸収。
落とし穴(Avoid)
- IOPSとスループットの単位誤解(IOPS=小さなIO、MB/s=帯域)。
- 価格の固定観念(時期やリージョンで変動。最新の料金表を確認)。
✅共通ガイド:運用に落とし込むためのチェックリスト
-
タグ戦略:
OwnerCostCenterEnvironmentScheduleRetentionDaysを必須。 - イベント駆動の自動化:EventBridge→Lambda/SSMで停止・修正・通知をワンストップ。
- 監査の定期化:Config、Budgets、Trusted Advisor、Compute Optimizerの月次レビュー。
- IaCの標準化:VPC/S3/Logs/EC2/EBSをモジュール化し、逸脱を検知。
✅まとめ
本記事のポイント
- 設計時に将来予測を考慮する
- 自動化でヒューマンエラーを防ぐ
- 監視とライフサイクル管理を徹底する
付録:Runbook(運用手順サンプル)
A. S3公開検知→即遮断
- Config違反検知→EventBridgeルールでLambda起動。
- LambdaでBPA強制ON、公開ポリシー削除、所有者にSNS通知。
- Macieで機密データスキャン→検出時はアクセスキーをローテーション。
B. Logs保持の一括是正
-
describe-log-groupsで棚卸し→RetentionDaysタグ付与。 - Lambdaで
put-retention-policyを一括適用。 - 重いログはFirehoseでS3に転送→Glueカタログ→Athenaのビュー作成。
C. EC2停止スケジュール
- タグ
AutoStop=trueを必須。 - EventBridgeで夜間停止/朝再起動のスケジュール。
- 低利用検知のComposite Alarm→タグ付与→次回サイクルで停止。
D. EBSのRightsizing
- 2週間のメトリクス取得。
-
modify-volumeでgp3へ切替、IOPS/帯域を段階増減。 - 負荷試験でSLA満たすことを確認→設定固定。
参考(価格や仕様は常に最新を確認)
- 料金はリージョンや時期で変動します。月額 ≈ 容量単価×GB + IOPS単価×IOPS + 帯域単価×MB/s のように把握し、Cost Explorer/Budgetsで常時可視化。
- セキュリティ設定は**Well-Architected(セキュリティ&コスト最適化の柱)**のチェックリストに沿って運用標準化。
参考リンク: