CloudFormation Modulesの真髄:社内標準インフラを「強制」し、開発スピードを極限まで高めるガバナンス設計
こんにちは。大規模クラウドインフラの設計・運用に日々向き合っているテックリードの皆さん。
「また別のチームが、暗号化されていないS3バケットを作ってセキュリティアラートを鳴らした」
「インフラのベストプラクティスをまとめたはずの社内Wikiは誰にも読まれず、コピペされた古いCloudFormationテンプレートが蔓延している」
――こんな悪夢にうなされていませんか?
コードによるインフラ管理(IaC)が当たり前になった現在、最大の課題は「コードを書くこと」ではなく「組織全体で安全で一貫したパターンをどう強制し、再利用するか」にシフトしています。
これまで、ネストされたスタック(Nested Stacks)や、CI/CDパイプラインでのスニペット流用、あるいはCDKのConstructといったアプローチが取られてきました。しかし、それぞれに「デプロイの複雑化」「言語依存による学習コストの壁」といったトレードオフが存在しました。
ここで、AWSが提供するネイティブ機能「CloudFormation Modules(CFN Modules)」の出番です。
これは、単なるテンプレートの切り貼りではなく、CloudFormationのプライマリ・リソースと同等レベルの抽象化とガバナンスをネイティブに実現する、究極の再利用メカニズムです。
今回は、このCloudFormation Modulesを使いこなし、開発チームのスピードを落とさずにセキュリティとコンプライアンスを完全に担保する実践的アプローチを、プロの知見を交えて徹底解説します。
—
1. なぜ「ネストされたスタック」や「CDK」ではなく「CFN Modules」なのか?
まず、アーキテクチャの選定における思想をクリアにしておきましょう。既存の手法と何が決定的に違うのか。
| アプローチ | デプロイ時の挙動 | ガバナンスの強制力 | 依存関係・言語エコシステム |
| :— | :— | :— | :— |
| ネストされたスタック | 親から子へS3経由でテンプレート参照。変更管理が煩雑 | テンプレートを書き換えられたらすり抜け可能 | 純粋なCFn (YAML/JSON) |
| AWS CDK (Construct) | 合成(Synthesis)されて通常のCFnテンプレートに変換 | 開発者がConstructを使わない選択(L1への逃げ)が可能 | TypeScript, Python, Java等のランタイムが必要 |
| CloudFormation Modules | AWSプライベートレジストリに登録され、ネイティブのリソースとして振る舞う | モジュール内のパラメータは上書き不可(強制的) | 純粋なCFn (JSON/スキーマ定義) |
CFN Modulesの本質は、「AWSが提供する標準リソース(`AWS::S3::Bucket`など)と同じ感覚で、自社専用のカスタムリソース(例:`MyCompany::Storage::SecureBucket`)をCloudFormationの型システムに組み込める点」にあります。
開発者は、モジュールがラップしている内部の複雑なIAMポリシーや暗号化設定を意識する必要すらありません。ただモジュールを呼び出すだけで、「社内セキュリティ基準を満たしたインフラ」が強制的に生成されるのです。
—
2. 実践:セキュアなストレージモジュールの設計と構築
では、実際に組織標準となる「完全暗号化・パブリックアクセス完全ブロック型S3バケット」のモジュールを作成してみましょう。
CFN Modulesの開発には、通常のテンプレートに加え、リソースのインターフェースを定義するモジュールスキーマ(JSON)が必要です。
ディレクトリ構造
cfn-modules/
└── storage-secure-bucket/
├── module.json # モジュールのメタデータとパラメータスキーマ
├── template.json # モジュール内部のCloudFormationテンプレート
└── README.md # 使い方ドキュメント
① モジュールスキーマ (`module.json`)
このファイルで、利用者が外部からどのプロパティを変更できるかを厳格に制限します。
{
“AWSTemplateFormatVersion”: “2010-09-09”,
“Description”: “社内標準:完全暗号化&パブリックアクセスブロック済みのS3バケットモジュール”,
“ResourceType”: “RPMS::Storage::SecureBucket”,
“Properties”: {
“BucketNamePrefix”: {
“Type”: “String”,
“Description”: “バケット名のプレフィックス(一意のサフィックスが自動付与されます)”,
“MaxLength”: 50
},
“Environment”: {
“Type”: “String”,
“Description”: “デプロイ環境 (dev, stg, prd)”,
“AllowedValues”: [“dev”, “stg”, “prd”]
}
},
“Required”: [
“BucketNamePrefix”,
“Environment”
]
}
② 内部テンプレート (`template.json`)
※CFN Modulesの本体テンプレートは現在JSON形式のみサポートされています。
ここに、S3バケット本体、パブリックアクセスブロック、KMS暗号化、バケットポリシーの「絶対に外してはいけない安全装置」をハードコーディングします。開発者はこの中身をいじることはできません。
{
“AWSTemplateFormatVersion”: “2010-09-09”,
“Description”: “Secure Bucket Inner Template”,
“Parameters”: {
“BucketNamePrefix”: { “Type”: “String” },
“Environment”: { “Type”: “String” }
},
“Resources”: {
“EncryptionKey”: {
“Type”: “AWS::KMS::Key”,
“Properties”: {
“Description”: “KMS Key for SecureBucket encryption”,
“EnableKeyRotation”: true,
“KeyPolicy”: {
“Version”: “2012-10-17”,
“Statement”: [
{
“Sid”: “Enable IAM User Permissions”,
“Effect”: “Allow”,
“Principal”: { “AWS”: { “Fn::Sub”: “arn:aws:iam::${AWS::AccountId}:root” } },
“Action”: “kms:”,
“Resource”: “”
}
]
}
}
},
“SecureBucket”: {
“Type”: “AWS::S3::Bucket”,
“Properties”: {
“BucketName”: { “Fn::Sub”: “${BucketNamePrefix}-${Environment}-${AWS::AccountId}” },
“BucketEncryption”: {
“ServerSideEncryptionConfiguration”: [
{
“ServerSideEncryptionByDefault”: {
“SSEAlgorithm”: “aws:kms”,
“KMSMasterKeyID”: { “Ref”: “EncryptionKey” }
}
}
]
},
“VersioningConfiguration”: {
“Status”: “Enabled”
},
“LoggingConfiguration”: {
“DestinationBucketName”: “mycompany-central-access-logs-bucket”,
“LogFilePrefix”: { “Fn::Sub”: “${BucketNamePrefix}/” }
}
}
},
“BucketPublicAccessBlock”: {
“Type”: “AWS::S3::BucketPublicAccessBlock”,
“Properties”: {
“Bucket”: { “Ref”: “SecureBucket” },
“BlockPublicAcls”: true,
“BlockPublicPolicy”: true,
“IgnorePublicAcls”: true,
“RestrictPublicBuckets”: true
}
}
},
“Outputs”: {
“BucketArn”: {
“Description”: “作成されたセキュアバケットのARN”,
“Value”: { “Fn::GetAttr”: [“SecureBucket”, “Arn”] }
},
“BucketName”: {
“Description”: “作成されたセキュアバケット名”,
“Value”: { “Ref”: “SecureBucket” }
}
}
}
—
3. プライベートレジストリへの登録とバージョン管理
作成したモジュールは、組織のAWSアカウント内(マルチアカウント環境であれば管理アカウント、または専用のツールチェーンアカウント)のCloudFormationプライベートレジストリにパブリッシュします。
登録のコマンドライン手順 (AWS CLI)
1. モジュールパッケージの検証 (AWS CLI v2が必要)
aws cloudformation validate-template-object –template-body file://template.json
2. レジストリへのモジュール登録(初回)
※あらかじめzip等に固めてアップロードするか、S3経由で指定します
aws cloudformation register-type \
–type MODULE \
–schema-handler-package s3://mycompany-cfn-modules-bucket/storage-secure-bucket-v1.0.0.zip \
–logging-config RoleArn=arn:aws:iam::123456789012:role/CloudFormationRegistryLogsRole,LogGroupName=CFNRegistryLogs
出力される RegistrationToken を元にステータスを確認
aws cloudformation describe-registration –registration-token
3. デフォルトバージョンへの設定
aws cloudformation set-type-default-version \
–type MODULE \
–type-name “RPMS::Storage::SecureBucket” \
–version-id 00000001
組織内でControl TowerやAWS Organizationsを利用している場合、このプライベートレジストリを「AWS CloudFormation Extensions (Publisher)」機能を使って組織全体(Organization単位)に自動共有することが可能です。これにより、子アカウントの開発チームはレジストリから直接モジュールを呼び出せるようになります。
—
4. 開発チームがモジュールを利用する(実用YAMLテンプレート)
レジストリに登録されたモジュールは、開発者が書くCloudFormationテンプレート内で、以下のように通常のリソースと同じ構文で呼び出せます。
AWSTemplateFormatVersion: ‘2010-09-09’
Description: 開発チームAのアプリケーションスタック
Resources:
# 自社標準のモジュールを呼び出す
AppStorage:
Type: RPMS::Storage::SecureBucket
Properties:
BucketNamePrefix: “app-team-a-data”
Environment: “prd”
# モジュールの出力値(Outputs)を他のリソース(例:Lambda)から参照する
AppLambda:
Type: AWS::Lambda::Function
Properties:
FunctionName: “DataProcessor”
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Runtime: python3.11
Environment:
Variables:
TARGET_BUCKET: !GetAtt AppStorage.BucketName
開発者は、KMSキーポリシーの設定や、パブリックアクセスのブロック設定を一切記述していません。しかし、デプロイされる実体は10 ಸಂಸ್ಥ(社)のセキュリティ基準を100%満たした堅牢なバケットになります。
—
5. プロの現場で役立つ!開発スピードを爆上げする実践Tips
ここからは、日々の開発現場でCFN Modulesを運用するうえで知っておくべき、現場の知見を共有します。
1. VS Code / IDEでの入力補完(IntelliSense)を効かせる裏技
CFN Modulesをプライベートレジストリに登録すると、AWS Toolkit for VS CodeなどのIDE拡張機能が自動的にスキーマを認識し、プロパティの補完(IntelliSense)やバリデーションを行ってくれます。
開発チームには必ず AWS Toolkit の導入を義務付けましょう。型定義がエディタ上でリアルタイムにチェックされるため、ドキュメントを見に行かなくても安全なコードが書けます。
2. バージョンアップ戦略:セマンティックバージョニングの徹底
モジュールを修正・改修する際は、必ずバージョンをインクリメント(v1.0.0 -> v1.1.0)してレジストリに登録してください。
既存のスタックで使用されているモジュールは、デフォルトでは自動アップデートされません(安定性の担保)。新バージョンへの追従は、開発チームが明示的にテンプレート側のバージョン指定(あるいはデフォルトバージョンの昇格)を行うことで、意図しないインフラ破壊(破壊的変更によるダウンタイムなど)を防ぎます。
3. GitOps / CI/CDパイプラインでの静的解析 (cfn-lint)
モジュール自体のソースコード管理にはGitHubやCodeCommitを用い、PR(Pull Request)の段階で `cfn-lint` や `Checkov` などの静的解析ツールを走らせます。
特にモジュールの `module.json` や `template.json` にセキュリティホールがないかを自動テストするパイプラインを組むことで、ガバナンスの品質を維持します。
—
まとめ:規律とスピードの両立こそがSREの真骨頂
「ガバナンスを厳しくすると開発スピードが落ちる」
これは古い時代のジレンマです。
CloudFormation Modulesを正しく導入すれば、「安全で正しいやり方が、一番簡単な(コード量が少ない)やり方」に変わります。開発者は面倒なセキュリティ要件のボイラープレートを書く必要がなくなり、ビジネスロジックの実装に集中できます。一方で、経営層やSREチームは、組織全体のインフラが強固なガードレールに守られているという絶対的な安心感を得られます。
社内のインフラ標準化に悩んでいるテックリードの皆さん、ぜひ今週のスプリントで、自社初のCFN Moduleを作成し、プライベートレジストリへのパブリッシュを試してみてください。
あなたの組織のインフラ開発生産性は、次のステージへと進化するはずです。