1. 概要
depends_onが必要な場面(暗黙的な依存が検出できないケース)depends_onの基本構文dataブロックへのdepends_on- モジュールへの
depends_on - 使いすぎによる弊害
Terraformは通常、リソース間の暗黙的な依存関係を自動検出します。しかし、コードからは依存が見えない場合(例: IAMロールのポリシー反映待ち、S3バケットポリシーの反映)は、depends_onで明示的に依存関係を設定する必要があります。
2. 暗黙的な依存 vs 明示的な依存
暗黙的な依存(depends_onは不要)
# aws_iam_role.lambda.arnを参照しているので、TerraformはLambdaがIAMロールの
# 作成後に作られることを自動的に理解する
resource "aws_iam_role" "lambda" {
name = "lambda-role"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
resource "aws_lambda_function" "main" {
role = aws_iam_role.lambda.arn # ← この参照が依存関係を示す
# ...
}
明示的な依存が必要なケース
# IAMポリシーをアタッチしても、コード上はLambdaが参照していないため
# Terraformが依存関係を検出できない
resource "aws_iam_role_policy_attachment" "lambda" {
role = aws_iam_role.lambda.name
policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
resource "aws_lambda_function" "main" {
# iam_role_policy_attachmentを参照していないため、
# ポリシーアタッチ前にLambdaが作成される可能性がある
role = aws_iam_role.lambda.arn
# ✅ depends_onで明示する
depends_on = [aws_iam_role_policy_attachment.lambda]
}
3. 基本構文
resource "<TYPE>" "<NAME>" {
# ...
depends_on = [
<resource_or_module_reference>,
<resource_or_module_reference>,
]
}
4. 実用パターン
IAMロール + ポリシーアタッチメント + EC2
terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
data "aws_iam_policy_document" "ec2_assume_role" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "app" {
name = "app-ec2-role"
assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
tags = {
Name = "app-ec2-role"
ManagedBy = "terraform"
}
}
resource "aws_iam_role_policy_attachment" "ssm" {
role = aws_iam_role.app.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
resource "aws_iam_instance_profile" "app" {
name = "app-instance-profile"
role = aws_iam_role.app.name
}
data "aws_ami" "amazon_linux_2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "app" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = "t3.micro"
iam_instance_profile = aws_iam_instance_profile.app.name
root_block_device {
volume_size = 20
volume_type = "gp3"
encrypted = true
}
# ポリシーアタッチが完了してからインスタンスを作成する
depends_on = [aws_iam_role_policy_attachment.ssm]
tags = {
Name = "app"
Environment = "dev"
ManagedBy = "terraform"
}
}
S3バケットポリシー + Lambda
resource "aws_s3_bucket" "data" {
bucket = "myapp-data-bucket"
tags = {
Name = "myapp-data-bucket"
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_policy" "data" {
bucket = aws_s3_bucket.data.id
policy = data.aws_iam_policy_document.s3_policy.json
}
resource "aws_lambda_function" "processor" {
filename = "lambda.zip"
function_name = "data-processor"
role = aws_iam_role.lambda.arn
handler = "index.handler"
runtime = "nodejs20.x"
environment {
variables = {
BUCKET_NAME = aws_s3_bucket.data.bucket
}
}
# バケットポリシーが反映されてからLambdaを作成する
depends_on = [aws_s3_bucket_policy.data]
}
5. dataブロックへのdepends_on
dataブロックが同じapplyで作成するリソースに依存する場合は、depends_onが必要です。
resource "aws_iam_role" "lambda" {
name = "lambda-role"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
# ❌ このdataブロックはplanフェーズで評価されるが、
# lambda-roleはplanフェーズでまだ存在しない
data "aws_iam_role" "lambda" {
name = "lambda-role"
}
# ✅ depends_onでリソース作成後に評価させる
data "aws_iam_role" "lambda" {
name = "lambda-role"
depends_on = [aws_iam_role.lambda]
}
💡 そもそもdataが不要: 同じapplyで作成したリソースは、
dataブロックを使わずに直接aws_iam_role.lambda.arnで参照するのがベストです。dataブロック +depends_onよりも、直接参照の方がシンプルです。
6. モジュールへのdepends_on
モジュール全体に依存する場合は、モジュールブロックにdepends_onを設定します。
module "networking" {
source = "./modules/networking"
environment = var.environment
}
module "compute" {
source = "./modules/compute"
environment = var.environment
subnet_ids = module.networking.private_subnet_ids
# ネットワークモジュール全体の完了を待つ
depends_on = [module.networking]
}
7. depends_onの使いすぎに注意
depends_onを多用すると、Terraformが並列実行できるリソースが減り、apply時間が長くなります。
# ❌ 不要なdepends_onを付けすぎると遅くなる
resource "aws_instance" "web" {
depends_on = [
aws_security_group.web, # すでにsecurity_group_idで参照している
aws_subnet.main, # すでにsubnet_idで参照している
aws_vpc.main, # 間接参照で自動検出される
]
}
# ✅ 明示的な参照があればdepends_onは不要
resource "aws_instance" "web" {
subnet_id = aws_subnet.main.id # 依存を自動検出
vpc_security_group_ids = [aws_security_group.web.id] # 依存を自動検出
}
8. 関連記事
- resourceブロックの使い方 — lifecycleなど他のメタ引数
- dataブロック(データソース)の使い方 — dataへのdepends_on
- moduleブロックの使い方 — モジュールへのdepends_on
- lifecycleメタ引数の使い方 — 他のメタ引数との比較
- 「Cycle detected」循環依存エラーの解消方法
- terraform graph — 依存関係を可視化
9. まとめ
- Terraformは参照(
resource.type.name.attr)から暗黙的な依存を自動検出する - コードから見えない依存がある場合(IAMポリシー反映、バケットポリシー)は
depends_onを使う dataブロックが同じapplyで作成するリソースに依存する場合はdepends_onが必要(または直接参照に変更する)depends_onの多用は並列実行を阻害するため、本当に必要な場合だけ使う
動作確認バージョン: Terraform >= 1.9 / AWS Provider ~> 5.0 公式ドキュメント: https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on