Terraform Import란?
Terraform Import는 이미 존재하는 인프라 리소스를 Terraform State에 등록하여 코드로 관리할 수 있게 만드는 기능입니다. 콘솔에서 수동 생성한 리소스, 다른 도구로 프로비저닝한 리소스를 IaC(Infrastructure as Code)로 전환할 때 필수적입니다.
Terraform State 관리 심화에서 다룬 것처럼 State는 실제 인프라와 코드의 매핑 테이블입니다. Import는 이 테이블에 기존 리소스를 수동으로 추가하는 작업입니다.
CLI Import vs Import Block
Terraform 1.5부터 import 블록이 도입되어 두 가지 방식이 공존합니다.
CLI 방식 (terraform import)
# 1. 먼저 빈 리소스 블록 작성
resource "aws_s3_bucket" "legacy_data" {}
# 2. CLI로 import 실행
terraform import aws_s3_bucket.legacy_data my-legacy-bucket-2024
CLI 방식은 한 번에 하나의 리소스만 처리하며, 실행 즉시 State에 반영됩니다.
Import Block 방식 (Terraform 1.5+)
# import.tf
import {
to = aws_s3_bucket.legacy_data
id = "my-legacy-bucket-2024"
}
import {
to = aws_iam_role.app_role
id = "my-app-role"
}
import {
to = aws_security_group.web_sg
id = "sg-0a1b2c3d4e5f"
}
# plan으로 미리 확인 후 apply
terraform plan
terraform apply
| 기준 | CLI Import | Import Block |
|---|---|---|
| 다중 리소스 | 하나씩 실행 | 여러 개 한 번에 |
| Plan 미리보기 | ❌ 바로 적용 | ✅ plan 가능 |
| 코드 리뷰 | ❌ | ✅ PR로 리뷰 가능 |
| 자동 코드 생성 | ❌ | ✅ (1.5+) |
| CI/CD 호환 | 스크립트 필요 | 기존 워크플로 그대로 |
코드 자동 생성: terraform plan -generate-config-out
Import Block과 함께 사용하면 Terraform이 리소스 코드를 자동 생성합니다.
# import 블록만 작성 (resource 블록 없이)
import {
to = aws_vpc.imported
id = "vpc-0abc123def456"
}
# 코드 자동 생성
terraform plan -generate-config-out=generated.tf
생성된 generated.tf:
resource "aws_vpc" "imported" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
instance_tenancy = "default"
tags = {
Name = "production-vpc"
}
}
자동 생성된 코드는 반드시 검토해야 합니다. 불필요한 기본값이 포함되거나, 민감한 값이 하드코딩될 수 있기 때문입니다.
실전 워크플로: 대규모 마이그레이션
수십 개의 리소스를 한 번에 Import하는 실전 워크플로입니다.
1단계: 리소스 목록 수집
# AWS CLI로 기존 리소스 ID 수집
aws ec2 describe-instances --query 'Reservations[].Instances[].InstanceId' --output text
aws s3api list-buckets --query 'Buckets[].Name' --output text
aws rds describe-db-instances --query 'DBInstances[].DBInstanceIdentifier' --output text
2단계: Import Block 일괄 생성
#!/bin/bash
# generate-imports.sh
for bucket in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
safe_name=$(echo "$bucket" | tr '-.' '_')
echo "import {"
echo " to = aws_s3_bucket.${safe_name}"
echo " id = "${bucket}""
echo "}"
echo ""
done > imports.tf
3단계: 코드 생성 및 검증
# 코드 자동 생성
terraform plan -generate-config-out=generated.tf
# diff 확인 — 변경사항이 없어야 정상
terraform plan
# "No changes. Your infrastructure matches the configuration."
4단계: 정리
# import 블록 제거 (apply 후에는 불필요)
rm imports.tf
# 생성된 코드를 모듈별로 정리
# generated.tf → modules/s3/main.tf, modules/ec2/main.tf 등
for_each와 Import Block 조합
동일 타입의 리소스가 여러 개일 때 for_each와 함께 Import합니다.
locals {
existing_buckets = {
"logs" = "company-logs-prod"
"assets" = "company-assets-prod"
"backups" = "company-backups-prod"
}
}
import {
for_each = local.existing_buckets
to = aws_s3_bucket.managed[each.key]
id = each.value
}
resource "aws_s3_bucket" "managed" {
for_each = local.existing_buckets
bucket = each.value
}
주의사항과 트러블슈팅
| 문제 | 원인 | 해결 |
|---|---|---|
| Plan에서 destroy+create | 코드와 실제 설정 불일치 | 코드를 실제 값에 맞게 수정 |
| Import 후 drift 발생 | 리소스 외부에서 변경됨 | terraform refresh 후 코드 동기화 |
| ID를 모르는 경우 | Provider마다 ID 형식 다름 | Provider 문서의 Import 섹션 확인 |
| 민감한 값 노출 | State에 평문 저장 | S3 backend 암호화 + sensitive 변수 |
| 모듈 내부 리소스 Import | 주소 형식이 다름 | module.name.resource 형식 사용 |
# 모듈 내부 리소스 Import 예시
import {
to = module.networking.aws_vpc.main
id = "vpc-0abc123"
}
# 인덱스가 있는 리소스
import {
to = aws_subnet.private["ap-northeast-2a"]
id = "subnet-0abc123"
}
moved 블록과의 차이
import는 외부 리소스를 State에 추가하고, moved는 이미 State에 있는 리소스의 주소를 변경합니다. Terraform lifecycle에서 다룬 것처럼, 리팩토링 시 moved를 활용하면 리소스 재생성 없이 코드 구조를 변경할 수 있습니다.
# 리소스 이름 변경
moved {
from = aws_s3_bucket.old_name
to = aws_s3_bucket.new_name
}
# 모듈로 이동
moved {
from = aws_s3_bucket.data
to = module.storage.aws_s3_bucket.data
}
정리
Terraform Import는 기존 인프라를 IaC로 전환하는 핵심 기능입니다. Terraform 1.5+의 Import Block을 사용하면 Plan 미리보기, 코드 자동 생성, PR 기반 리뷰가 가능해져 안전한 마이그레이션이 가능합니다. 대규모 전환 시에는 스크립트로 Import Block을 일괄 생성하고, -generate-config-out으로 코드를 자동 생성한 뒤 검증하는 워크플로를 추천합니다.