メインコンテンツまでスキップ

Infrastructure as Code(IaC)

クラウドインフラの構築・管理を手動操作ではなくコードで定義・自動化するアプローチを学びます。AWS CloudFormation、CDK、SAMを中心に、再現可能で安全なインフラ管理手法を解説します。


所要時間​

約45分

学べること​

  • IaCの概念と手動運用との違い
  • CloudFormationテンプレートの構造と組み込み関数
  • スタック間参照とNested Stacks
  • AWS CDKによるプログラマティックなインフラ定義
  • CDKコンストラクトレベル(L1/L2/L3)の使い分け
  • SAMによるサーバーレスインフラ定義
  • CloudFormation/CDK/Terraformの比較と選定基準

前提知識​

  • AWSの基本サービス(VPC、EC2、RDS等)の理解
  • YAML/JSONの基本構文
  • プログラミングの基本知識(CDKセクション向け)

目次​

  1. IaCの概要と必要性
  2. AWS CloudFormation概要
  3. CloudFormationテンプレートの構造
  4. CloudFormation組み込み関数
  5. スタック間の参照
  6. AWS CDK(Cloud Development Kit)
  7. CDKのコンストラクトレベル
  8. CDKコード例
  9. SAM(Serverless Application Model)
  10. IaCツール比較
  11. IDサービスでの活用
  12. まとめ

IaCの概要と必要性​

Infrastructure as Code(IaC)は、サーバー、ネットワーク、データベースなどのインフラをコード(テンプレートファイル)として定義し、バージョン管理・自動デプロイする手法です。

手動運用の課題​

手動運用の世界:

開発者A ──→ AWSコンソール ──→ 本番環境
│ (手動クリック) │
│ ├─ VPC作成(設定忘れ?)
│ ├─ SG設定(ポート開けすぎ?)
│ └─ RDS作成(パラメータ違う?)
│
開発者B ──→ AWSコンソール ──→ ステージング環境
(手動クリック) │
├─ VPC作成(本番と設定が違う)
├─ SG設定(本番と不整合)
└─ RDS作成(バージョン違い)

→ 環境差異、再現不可能、監査困難

手動運用 vs IaC 比較​

観点手動運用IaC
再現性手順書依存、人的ミスが発生コードで完全再現可能
バージョン管理スクリーンショットや手順書Gitで変更履歴を管理
レビュー作業後の目視確認Pull Requestで事前レビュー
環境差異環境ごとに微妙な違いが蓄積同一テンプレートで統一
監査操作ログの後追い確認コード差分で変更内容を把握
スケール環境数に比例して工数増大パラメータ変更で複数環境に展開
障害復旧手順を再実行(時間がかかる)テンプレートから即座に再構築
ドリフト検知気づきにくい自動検知可能

AWS CloudFormation概要​

CloudFormationはAWSネイティブのIaCサービスです。テンプレートファイルからAWSリソースを自動的にプロビジョニングします。

主要概念​

+------------------+
| テンプレート | ← YAML/JSONファイル(インフラの設計図)
+--------+---------+
|
v
+------------------+
| スタック | ← テンプレートから生成されるリソース群
| +-------------+ |
| | VPC | |
| | Subnet | |
| | EC2 | |
| | RDS | |
| +-------------+ |
+--------+---------+
|
v
+------------------+
| 変更セット | ← スタック更新前の差分プレビュー
| - Subnet追加 |
| - EC2タイプ変更 |
| - RDS変更なし |
+------------------+
  • テンプレート: インフラの宣言的定義(YAML/JSON形式)
  • スタック: テンプレートからデプロイされたリソースの集合。スタック単位で作成・更新・削除を管理
  • 変更セット(Change Set): スタック更新前に変更内容をプレビューする仕組み。意図しない変更を防止

CloudFormationテンプレートの構造​

CloudFormationテンプレートは複数のセクションで構成されます。

AWSTemplateFormatVersion: "2010-09-09"
Description: IDサービス基盤ネットワーク

# --- パラメータ: デプロイ時に値を指定 ---
Parameters:
EnvironmentName:
Type: String
Default: dev
AllowedValues:
- dev
- staging
- prod
Description: デプロイ環境名

VpcCidr:
Type: String
Default: "10.0.0.0/16"
Description: VPCのCIDRブロック

# --- マッピング: 環境ごとの設定値 ---
Mappings:
EnvironmentConfig:
dev:
InstanceType: t3.small
staging:
InstanceType: t3.medium
prod:
InstanceType: t3.large

# --- 条件: 条件付きリソース作成 ---
Conditions:
IsProduction: !Equals [!Ref EnvironmentName, prod]

# --- リソース: 作成するAWSリソース(必須セクション) ---
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub "${EnvironmentName}-vpc"

PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.1.0/24"
AvailabilityZone: !Select [0, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${EnvironmentName}-public-subnet-1"

PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.2.0/24"
AvailabilityZone: !Select [1, !GetAZs ""]
MapPublicIpOnLaunch: true

PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.10.0/24"
AvailabilityZone: !Select [0, !GetAZs ""]

PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: "10.0.11.0/24"
AvailabilityZone: !Select [1, !GetAZs ""]

# --- 出力: スタック外から参照可能な値 ---
Outputs:
VpcId:
Description: VPC ID
Value: !Ref VPC
Export:
Name: !Sub "${EnvironmentName}-VpcId"

PublicSubnetIds:
Description: パブリックサブネットID
Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]]
Export:
Name: !Sub "${EnvironmentName}-PublicSubnetIds"

セクション一覧​

セクション必須説明
AWSTemplateFormatVersion-テンプレートバージョン(現在は2010-09-09のみ)
Description-テンプレートの説明
Parameters-デプロイ時に指定する入力値
Mappings-キーと値の静的マッピング
Conditions-リソース作成の条件
Resources必須作成するAWSリソースの定義
Outputs-スタック外へ公開する値

CloudFormation組み込み関数​

テンプレート内で動的な値を扱うための組み込み関数を利用できます。

関数用途例
Refパラメータ値またはリソースIDの参照!Ref VPC → VPCのID
Fn::Sub文字列内の変数置換!Sub "${Env}-vpc"
Fn::GetAttリソースの属性値を取得!GetAtt ALB.DNSName
Fn::Join文字列の結合!Join [",", [a, b]] → "a,b"
Fn::Selectリスト要素の選択!Select [0, !GetAZs ""]
Fn::Split文字列の分割!Split [",", "a,b,c"]
Fn::ImportValue他スタックのExport値を参照!ImportValue prod-VpcId
Fn::If条件分岐!If [IsProduction, t3.large, t3.small]
Fn::FindInMapMappingsから値を取得!FindInMap [Config, prod, Type]
# 組み込み関数の使用例
Resources:
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Name: idp-server
# Fn::Sub でアカウントIDとリージョンを動的に埋め込み
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/idp-server:latest"
# Fn::If で環境に応じたCPU割り当て
Cpu: !If [IsProduction, 1024, 256]
# Fn::FindInMap でメモリ設定を取得
Memory: !FindInMap [EnvironmentConfig, !Ref EnvironmentName, Memory]

スタック間の参照​

大規模なインフラでは、1つの巨大なテンプレートではなく、役割ごとにスタックを分割して管理します。

クロススタック参照​

+------------------+     Export/Import     +------------------+
| ネットワーク | ──────────────────→ | アプリケーション |
| スタック | | スタック |
| | | |
| Outputs: | | Resources: |
| VpcId (Export)| | ECS Service |
| SubnetIds | | (ImportValue) |
+------------------+ +------------------+

エクスポート側(ネットワークスタック):

Outputs:
VpcId:
Value: !Ref VPC
Export:
Name: !Sub "${EnvironmentName}-VpcId"

インポート側(アプリケーションスタック):

Resources:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterSettings:
- Name: containerInsights
Value: enabled

ECSService:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref ECSCluster
NetworkConfiguration:
AwsvpcConfiguration:
Subnets:
- !ImportValue prod-PrivateSubnet1Id
- !ImportValue prod-PrivateSubnet2Id

Nested Stacks​

親テンプレートから子テンプレートを呼び出す構成です。

+---------------------------+
| 親スタック (root.yaml) |
| |
| +---------+ +---------+ |
| | network | | compute | |
| | .yaml | | .yaml | |
| +---------+ +---------+ |
| | |
| +---------+ |
| | database| |
| | .yaml | |
| +---------+ |
+---------------------------+
# 親テンプレート
Resources:
NetworkStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/mybucket/network.yaml
Parameters:
EnvironmentName: !Ref EnvironmentName

ComputeStack:
Type: AWS::CloudFormation::Stack
DependsOn: NetworkStack
Properties:
TemplateURL: https://s3.amazonaws.com/mybucket/compute.yaml
Parameters:
VpcId: !GetAtt NetworkStack.Outputs.VpcId

AWS CDK(Cloud Development Kit)​

AWS CDKは、TypeScript、Python、Javaなどのプログラミング言語でCloudFormationテンプレートを生成するフレームワークです。

CDKの仕組み​

TypeScript/Python   CDK Synth    CloudFormation     AWS API
コード ──────────→ テンプレート ──────────→ リソース
(app.ts) (生成) (template.json) (デプロイ)

CDKの利点​

観点CloudFormation YAMLCDK
言語YAML/JSONTypeScript, Python, Java等
抽象度低レベル(リソース単位)高レベル(パターン単位)
IDE支援限定的補完、型チェック、リファクタリング
ループ・条件制限あり言語の全機能を利用可能
テスト難しいユニットテスト・スナップショットテスト可能
再利用テンプレートコピーライブラリとして公開・共有

CDKのコンストラクトレベル​

CDKのコンストラクト(リソース定義の構成要素)は3つのレベルに分かれています。

レベル名称説明例
L1CFn ResourcesCloudFormationリソースの1対1マッピング。CfnプレフィックスCfnBucket, CfnVPC
L2CuratedAWSベストプラクティスを含む高レベル抽象化。デフォルト設定付きBucket, Vpc
L3Patterns複数リソースを組み合わせたアーキテクチャパターンApplicationLoadBalancedFargateService
L3: ApplicationLoadBalancedFargateService
(ALB + ECS Fargate + ターゲットグループ + リスナー)
|
+-- L2: ApplicationLoadBalancer (セキュリティグループ自動設定)
+-- L2: FargateService (タスク定義、サービス)
+-- L2: Vpc (サブネット、ルートテーブル自動構成)
|
+-- L1: CfnVPC, CfnSubnet, CfnRouteTable ...

使い分けの指針​

  • L3: 標準的なアーキテクチャパターンに合致する場合に最適。最も少ないコードで構築可能
  • L2: カスタマイズが必要な場合。ベストプラクティスのデフォルト設定を活用しつつ調整
  • L1: CloudFormationの全プロパティへのアクセスが必要な場合。L2未対応の新サービスにも使用

CDKコード例​

VPC + ECS Fargate でIDサービスを構成する例です。

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as rds from 'aws-cdk-lib/aws-rds';
import { Construct } from 'constructs';

export class IdpServerStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

// --- VPC(L2コンストラクト) ---
const vpc = new ec2.Vpc(this, 'IdpVpc', {
maxAzs: 2,
natGateways: 1,
subnetConfiguration: [
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
{
cidrMask: 24,
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
{
cidrMask: 24,
name: 'Isolated',
subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
},
],
});

// --- RDS(L2コンストラクト) ---
const database = new rds.DatabaseCluster(this, 'IdpDatabase', {
engine: rds.DatabaseClusterEngine.auroraPostgres({
version: rds.AuroraPostgresEngineVersion.VER_15_4,
}),
writer: rds.ClusterInstance.provisioned('Writer', {
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE
),
}),
readers: [
rds.ClusterInstance.provisioned('Reader', {
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE
),
}),
],
vpc,
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
defaultDatabaseName: 'idp',
});

// --- ECS Fargate + ALB(L3コンストラクト) ---
const fargateService =
new ecs_patterns.ApplicationLoadBalancedFargateService(
this, 'IdpService', {
vpc,
cpu: 1024,
memoryLimitMiB: 2048,
desiredCount: 2,
taskImageOptions: {
image: ecs.ContainerImage.fromAsset('../'),
containerPort: 8080,
environment: {
SPRING_PROFILES_ACTIVE: 'prod',
DB_HOST: database.clusterEndpoint.hostname,
DB_PORT: database.clusterEndpoint.port.toString(),
DB_NAME: 'idp',
},
},
publicLoadBalancer: true,
},
);

// --- ヘルスチェック設定 ---
fargateService.targetGroup.configureHealthCheck({
path: '/actuator/health',
healthyHttpCodes: '200',
});

// --- RDSへの接続許可 ---
database.connections.allowDefaultPortFrom(
fargateService.service,
'Allow ECS to RDS'
);

// --- Auto Scaling ---
const scaling = fargateService.service.autoScaleTaskCount({
minCapacity: 2,
maxCapacity: 10,
});
scaling.scaleOnCpuUtilization('CpuScaling', {
targetUtilizationPercent: 70,
});
}
}

SAM(Serverless Application Model)​

AWS SAMはCloudFormationの拡張で、Lambda、API Gateway、DynamoDB等のサーバーレスリソースを簡潔に定義できます。

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: IDサービス - カスタム認証Lambda

Globals:
Function:
Timeout: 30
Runtime: nodejs20.x
MemorySize: 256

Resources:
# Lambda Authorizer
TokenAuthorizerFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/authorizer/
Handler: index.handler
Environment:
Variables:
JWKS_URI: https://idp.example.com/.well-known/jwks.json
ISSUER: https://idp.example.com

# Webhook通知用Lambda
SecurityEventFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/security-event/
Handler: index.handler
Events:
SecurityEventQueue:
Type: SQS
Properties:
Queue: !GetAtt SecurityEventQueue.Arn
BatchSize: 10

SecurityEventQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 180
MessageRetentionPeriod: 1209600
RedrivePolicy:
deadLetterTargetArn: !GetAtt SecurityEventDLQ.Arn
maxReceiveCount: 3

SecurityEventDLQ:
Type: AWS::SQS::Queue

SAM CLI コマンド​

# ローカルでLambda関数をテスト
sam local invoke TokenAuthorizerFunction -e event.json

# ローカルでAPIを起動
sam local start-api

# ビルドとデプロイ
sam build
sam deploy --guided

IaCツール比較​

観点CloudFormationCDKTerraform
提供元AWSAWSHashiCorp
定義言語YAML/JSONTypeScript, Python等HCL
対応クラウドAWSのみAWSのみマルチクラウド
状態管理AWSが自動管理AWSが自動管理tfstateファイル
学習コスト中中〜高(言語知識必要)中
プレビューChange Setcdk diffterraform plan
ドリフト検知ありあり(CFn経由)あり
エコシステムAWS公式Construct HubTerraform Registry
適性AWS限定・小〜中規模AWS限定・大規模・チーム開発マルチクラウド・大規模

選定の指針​

AWSのみ利用?
├─ Yes ──→ チーム規模・複雑さは?
│ ├─ 小規模・シンプル ──→ CloudFormation
│ └─ 大規模・複雑 ──→ CDK
└─ No ───→ マルチクラウド?
├─ Yes ──→ Terraform
└─ No ───→ プロジェクトに応じて選択

IDサービスでの活用​

idp-serverのインフラをCDKでコード化する場合の構成例を示します。

idp-server-infra/
├── bin/
│ └── app.ts # エントリポイント
├── lib/
│ ├── network-stack.ts # VPC、サブネット、NAT Gateway
│ ├── database-stack.ts # Aurora PostgreSQL(マルチAZ)
│ ├── compute-stack.ts # ECS Fargate、ALB、Auto Scaling
│ ├── security-stack.ts # WAF、ACM証明書、セキュリティグループ
│ └── monitoring-stack.ts # CloudWatch、アラーム
├── config/
│ ├── dev.ts # 開発環境パラメータ
│ ├── staging.ts # ステージング環境パラメータ
│ └── prod.ts # 本番環境パラメータ
├── test/
│ └── idp-server.test.ts # インフラテスト
├── cdk.json
└── package.json

スタック分割の設計​

+------------------+
| NetworkStack | VPC, Subnets, NAT GW, VPN
+--------+---------+
|
+----+----+
| |
+---v---+ +---v------+
|Database| |Security | Aurora PostgreSQL, WAF, ACM
|Stack | |Stack |
+---+---+ +---+------+
| |
+----+----+
|
+--------v---------+
| ComputeStack | ECS Fargate, ALB, Auto Scaling
+--------+---------+
|
+--------v---------+
| MonitoringStack | CloudWatch Dashboards, Alarms
+------------------+

IDサービス固有の考慮点​

要素IaCでの管理ポイント
マルチテナントテナントごとのリソース分離をコードで定義
秘密鍵管理Secrets ManagerをIaCで構成、鍵ローテーションを自動化
FAPI準拠ALBのTLS設定、WAFルールをコードで厳密に管理
高可用性マルチAZ構成をテンプレートで標準化
環境分離同一テンプレート + パラメータで環境ごとにデプロイ

まとめ​

  • IaCはインフラの再現性、バージョン管理、自動化を実現する手法
  • CloudFormationはAWSネイティブのIaCサービスで、YAMLテンプレートでリソースを宣言的に定義
  • CDKはプログラミング言語でCloudFormationテンプレートを生成し、型安全性やテスタビリティを向上
  • コンストラクトレベル(L1/L2/L3)により、必要な抽象度でインフラを定義可能
  • SAMはサーバーレスに特化した簡潔なIaC記法を提供
  • ツール選定はクラウド戦略、チーム規模、複雑さに基づいて判断

次のステップ​

参考リソース​