ブロックと変数

ブロック

ブロック名説明
terraformTerraform のバージョン指定
プロバイダーのバージョン制約
リモートバックエンド(terraform.tfstate)
providerクラウドプロバイダーの設定
 aws / google / azurerm
resourceTerraform が管理するリソースを定義
localsローカル変数(式の再利用・可読性向上)
moduleモジュールの呼び出し
 ルートモジュール ⇒ 子モジュール
variableモジュールの入力変数
 ルートモジュール ⇒ 子モジュール
outputモジュールの出力変数
 子モジュール ⇒ ルートモジュール
importTerraform 管理外の既存リソースを Terraform 管理下に取り込む
dataTerraform管理外のリソース情報を参照する

terraform ブロック

terraform {
  # Terraform バージョン指定
  required_version = ">= 1.5.0"

  # プロバイダーのバージョン制約
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.5"
    }
  }

  # リモートバックエンド(terraform.tfstate の保存先)
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

provider ブロック

# AWS プロバイダー
provider "aws" {
  region = "ap-northeast-1"
  
  default_tags {
    tags = {
      Environment = "production"
      ManagedBy   = "Terraform"
    }
  }
}

# エイリアスを使用した複数リージョン設定
provider "aws" {
  alias  = "tokyo"
  region = "ap-northeast-1"
}

provider "aws" {
  alias  = "osaka"
  region = "ap-northeast-3"
}

resourceブロック

# EC2 インスタンス
resource "aws_instance" "web_server" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"
  
  tags = {
    Name = "web-server-01"
  }
}

# S3 バケット
resource "aws_s3_bucket" "data_bucket" {
  bucket = "my-data-bucket-20241220"
  
  tags = {
    Name        = "DataBucket"
    Environment = "production"
  }
}

# VPC
resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true
  
  tags = {
    Name = "main-vpc"
  }
}

# 他のリソースを参照
resource "aws_subnet" "public" {
  vpc_id            = aws_vpc.main.id  # VPC リソースの参照
  cidr_block        = "10.0.1.0/24"
  availability_zone = "ap-northeast-1a"
  
  tags = {
    Name = "public-subnet-1a"
  }
}

localsブロック

locals {
  # 単純な変数
  environment = "production"
  region      = "ap-northeast-1"
  
  # 複雑な式の再利用
  common_tags = {
    Environment = local.environment
    ManagedBy   = "Terraform"
    Project     = "MyApp"
  }
  
  # 条件式
  instance_type = local.environment == "production" ? "t3.large" : "t3.micro"
  
  # リスト・マップの操作
  availability_zones = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
  
  subnet_cidrs = {
    public_1a  = "10.0.1.0/24"
    public_1c  = "10.0.2.0/24"
    private_1a = "10.0.11.0/24"
    private_1c = "10.0.12.0/24"
  }
  
  # 文字列結合
  bucket_name = "${var.project_name}-${local.environment}-data"
}

# locals を使用したリソース定義
resource "aws_instance" "app" {
  instance_type = local.instance_type
  tags          = local.common_tags
}

module ブロック

# 子モジュールの呼び出し
module "vpc" {
  source = "./modules/vpc"  # ローカルモジュール
  
  # 入力変数
  vpc_cidr           = "10.0.0.0/16"
  environment        = "production"
  availability_zones = ["ap-northeast-1a", "ap-northeast-1c"]
}

# Terraform Registry のモジュール使用
module "s3_bucket" {
  source  = "terraform-aws-modules/s3-bucket/aws"
  version = "3.15.0"
  
  bucket = "my-application-bucket"
  acl    = "private"
  
  versioning = {
    enabled = true
  }
}

# Git リポジトリのモジュール使用
module "network" {
  source = "git::https://github.com/myorg/terraform-modules.git//network?ref=v1.0.0"
  
  vpc_name = "production-vpc"
  cidr     = "10.0.0.0/16"
}

# モジュールの出力を参照
resource "aws_instance" "web" {
  subnet_id = module.vpc.public_subnet_ids[0]  # モジュールの出力を使用
  
  tags = {
    Name = "web-server"
  }
}

variableブロック

# 基本的な変数定義
variable "environment" {
  description = "環境名(dev, stg, prod)"
  type        = string
  default     = "dev"
}

# 型指定付き変数
variable "instance_count" {
  description = "起動する EC2 インスタンス数"
  type        = number
  default     = 1
}

variable "enable_monitoring" {
  description = "CloudWatch 監視の有効化"
  type        = bool
  default     = false
}

# リスト型
variable "availability_zones" {
  description = "使用するアベイラビリティゾーン"
  type        = list(string)
  default     = ["ap-northeast-1a", "ap-northeast-1c"]
}

# マップ型
variable "instance_types" {
  description = "環境別のインスタンスタイプ"
  type        = map(string)
  default = {
    dev  = "t3.micro"
    stg  = "t3.small"
    prod = "t3.large"
  }
}

# オブジェクト型
variable "database_config" {
  description = "データベース設定"
  type = object({
    engine         = string
    engine_version = string
    instance_class = string
    storage_gb     = number
  })
  default = {
    engine         = "postgres"
    engine_version = "15.3"
    instance_class = "db.t3.micro"
    storage_gb     = 20
  }
}

# バリデーション付き変数
variable "region" {
  description = "AWS リージョン"
  type        = string
  
  validation {
    condition     = can(regex("^ap-northeast-[1-3]$", var.region))
    error_message = "リージョンは ap-northeast-1, 2, 3 のいずれかを指定してください"
  }
}

# センシティブ変数
variable "db_password" {
  description = "データベースパスワード"
  type        = string
  sensitive   = true  # ログに出力されない
}

output ブロック

# 基本的な出力
output "vpc_id" {
  description = "VPC の ID"
  value       = aws_vpc.main.id
}

# 複数の値を出力
output "subnet_ids" {
  description = "サブネット ID のリスト"
  value       = aws_subnet.public[*].id
}

# オブジェクトとして出力
output "instance_info" {
  description = "EC2 インスタンス情報"
  value = {
    id         = aws_instance.web.id
    public_ip  = aws_instance.web.public_ip
    private_ip = aws_instance.web.private_ip
  }
}

# センシティブな出力
output "db_password" {
  description = "データベースパスワード"
  value       = aws_db_instance.main.password
  sensitive   = true  # terraform output で表示されない
}

# 条件付き出力
output "load_balancer_dns" {
  description = "ロードバランサーの DNS 名"
  value       = var.create_lb ? aws_lb.main[0].dns_name : null
}

# モジュール内での出力定義(子モジュール)
# modules/vpc/outputs.tf
output "vpc_id" {
  description = "作成された VPC の ID"
  value       = aws_vpc.this.id
}

output "public_subnet_ids" {
  description = "パブリックサブネットの ID リスト"
  value       = aws_subnet.public[*].id
}

importブロック

# 既存の EC2 インスタンスを Terraform 管理下に取り込む
import {
  to = aws_instance.existing_server
  id = "i-1234567890abcdef0"
}

resource "aws_instance" "existing_server" {
  # リソース定義は terraform plan で確認後に記述
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"
  
  tags = {
    Name = "existing-server"
  }
}

# S3 バケットのインポート
import {
  to = aws_s3_bucket.existing_bucket
  id = "my-existing-bucket-name"
}

resource "aws_s3_bucket" "existing_bucket" {
  bucket = "my-existing-bucket-name"
}

# VPC のインポート
import {
  to = aws_vpc.imported_vpc
  id = "vpc-0123456789abcdef0"
}

resource "aws_vpc" "imported_vpc" {
  cidr_block = "10.0.0.0/16"
  
  tags = {
    Name = "imported-vpc"
  }
}

dataブロック

# 最新の Amazon Linux 2 AMI を取得
data "aws_ami" "amazon_linux_2" {
  most_recent = true
  owners      = ["amazon"]
  
  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }
  
  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

# 既存の VPC 情報を取得
data "aws_vpc" "existing" {
  filter {
    name   = "tag:Name"
    values = ["production-vpc"]
  }
}

# アベイラビリティゾーンの一覧を取得
data "aws_availability_zones" "available" {
  state = "available"
}

# 現在の AWS アカウント ID を取得
data "aws_caller_identity" "current" {}

# 現在のリージョンを取得
data "aws_region" "current" {}

# Secrets Manager からシークレット取得
data "aws_secretsmanager_secret" "db_password" {
  name = "production/database/password"
}

data "aws_secretsmanager_secret_version" "db_password" {
  secret_id = data.aws_secretsmanager_secret.db_password.id
}

# data ブロックの値を使用
resource "aws_instance" "web" {
  ami               = data.aws_ami.amazon_linux_2.id
  instance_type     = "t3.micro"
  availability_zone = data.aws_availability_zones.available.names[0]
  
  tags = {
    Name      = "web-server"
    AccountId = data.aws_caller_identity.current.account_id
    Region    = data.aws_region.current.name
  }
}

# 複数のサブネットを取得
data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.existing.id]
  }
  
  filter {
    name   = "tag:Type"
    values = ["private"]
  }
}

output "private_subnet_ids" {
  value = data.aws_subnets.private.ids
}

変数のスコープ

スコープ定義適用範囲
グローバルスコープterraform ブロック内で定義プロジェクト全体
ルートモジュールスコープlocals、variableで定義同一ディレクトリ内
モジュールスコープmodule ブロック内で渡された変数各モジュール内

モジュール(引数と出力の受け渡し)

サンプルコードのディレクトリ構造
project-root/
  |
  +- environments/
  |  |
  |  +- prd/
  |      |
  |      +- main.tf            # ルートモジュール
  |      +- variables.tf       # ルートモジュールの入力変数
  |      +- outputs.tf         # ルートモジュールの出力変数
  |
  +- modules/
      |
      +- s3/
          |
          +- main.tf           # 子モジュールのリソース定義
          +- variables.tf      # 子モジュールの入力変数
          +- outputs.tf        # 子モジュールの出力変数

ルートモジュール

environments/prd/main.tf
# S3 モジュールの呼び出し
module "s3_bucket" {
  source = "../../modules/s3"
  
  # 子モジュールへ引数を渡す
  bucket_name = var.bucket_name
  environment = var.environment
  enable_versioning = var.enable_versioning
}
environments/prd/variables.tf
# ルートモジュール - 入力変数

variable "bucket_name" {
  description = "S3 バケット名"
  type        = string
  default     = "my-app-data-bucket"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "prd"
}

variable "enable_versioning" {
  description = "バージョニングを有効にするか"
  type        = bool
  default     = true
}
environments/prd/outputs.tf
# ルートモジュール - 出力変数
# 子モジュールからの出力を受け取る

output "bucket_id" {
  description = "S3 バケット ID"
  value       = module.s3_bucket.bucket_id
}

output "bucket_arn" {
  description = "S3 バケット ARN"
  value       = module.s3_bucket.bucket_arn
}

output "bucket_domain_name" {
  description = "S3 バケットのドメイン名"
  value       = module.s3_bucket.bucket_domain_name
}

子モジュール

modules/s3/main.tf
# 子モジュール - S3 バケットの作成

resource "aws_s3_bucket" "this" {
  bucket = "${var.bucket_name}-${var.environment}"
  
  tags = {
    Name        = "${var.bucket_name}-${var.environment}"
    Environment = var.environment
  }
}

# バージョニング設定
resource "aws_s3_bucket_versioning" "this" {
  bucket = aws_s3_bucket.this.id
  
  versioning_configuration {
    status = var.enable_versioning ? "Enabled" : "Suspended"
  }
}

# パブリックアクセスブロック
resource "aws_s3_bucket_public_access_block" "this" {
  bucket = aws_s3_bucket.this.id
  
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}
modules/s3/variables.tf
# 子モジュール - 入力変数
# ルートモジュールから値を受け取る

variable "bucket_name" {
  description = "S3 バケットのベース名"
  type        = string
}

variable "environment" {
  description = "環境名(dev, stg, prd)"
  type        = string
}

variable "enable_versioning" {
  description = "バージョニングを有効にするか"
  type        = bool
  default     = false
}
modules/s3/outputs.tf
# 子モジュール - 出力変数
# ルートモジュールに値を返す

output "bucket_id" {
  description = "S3 バケットの ID"
  value       = aws_s3_bucket.this.id
}

output "bucket_arn" {
  description = "S3 バケットの ARN"
  value       = aws_s3_bucket.this.arn
}

output "bucket_domain_name" {
  description = "S3 バケットのドメイン名"
  value       = aws_s3_bucket.this.bucket_domain_name
}