AWS EKS 클러스터와 주변 인프라를 프로비저닝하는 Terraform 프로젝트입니다.
VPC(사설 서브넷), IAM Role, Security Group, EKS Cluster/Managed NodeGroup, IRSA(IAM Roles for Service Accounts),
(선택) AWS IoT Things/Certificate/Policy 구성을 포함합니다.
Root Module
│
├── module.iam → EKS 클러스터·노드용 IAM 역할 생성
├── module.vpc → 멀티-AZ 사설 서브넷, NAT 게이트웨이, 라우트 테이블 생성
├── module.security → EKS용 보안 그룹 생성
├── module.eks → EKS 클러스터 및 관리형 노드 그룹 생성
├── module.irsa → OIDC 공급자, ALB Controller·ESO Kafka용 IRSA 역할 생성
└── module.iot (주석) → AWS IoT Things·인증서·정책 생성 (선택)
의존성 흐름:
iam ─┐
vpc ─┼─► eks ─► irsa
sec ─┘
| 도구 | 최소 버전 | 비고 |
|---|---|---|
| Terraform | >= 1.5.0 | |
| AWS CLI | >= 2.x | aws eks update-kubeconfig 사용 |
| kubectl | 클러스터 버전과 일치 | |
| jq | - | apply.sh 사용 시 필요 |
AWS 자격증명이 설정되어 있어야 합니다:
aws configure
# 또는
export AWS_PROFILE=<profile-name># 1) terraform.tfvars 파일 생성
cp terraform.tfvars.example terraform.tfvars
# 2) 초기화
terraform init
# 3) 플랜 확인
terraform plan
# 4) 적용
terraform apply
# 또는 apply.sh 스크립트 사용 (검증·플랜·적용·kubeconfig 업데이트 자동화)
bash apply.shterraform.tfvars 파일에 아래 변수를 설정합니다. (.gitignore에 포함되어 커밋되지 않습니다)
권장: 변수는 "필수/기본값/민감정보 여부"를 팀 표준으로 통일해서 관리하세요.
| 변수명 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
aws_region |
string |
✅ | - | AWS 리전 (예: ap-northeast-2) |
vpc_id |
string |
✅ | - | 기존 VPC ID |
rtb_id |
string |
✅ | - | 기존 라우트 테이블 ID |
cluster_name |
string |
✅ | - | EKS 클러스터 이름 |
nodegroup_name |
string |
✅ | - | EKS 관리형 노드 그룹 이름 |
desired_capacity |
number |
✅ | - | 원하는 노드 수 |
min_capacity |
number |
✅ | - | 최소 노드 수 |
max_capacity |
number |
✅ | - | 최대 노드 수 |
instance_types |
list(string) |
✅ | - | EC2 인스턴스 타입 목록 |
azs |
list(string) |
✅ | - | 가용 영역 목록 |
public_subnet_ids |
list(string) |
✅ | - | 공용 서브넷 ID 목록 (NAT 게이트웨이 배치용) |
private_subnet_cidrs |
list(string) |
✅ | - | 생성할 사설 서브넷 CIDR 목록 (azs와 순서 일치) |
server_tls_secret_prefix |
string |
✅ | - | Kafka 브로커 서버 TLS 시크릿의 Secrets Manager 이름 접두사 |
client_tls_secret_prefix |
string |
✅ | - | Kafka 퍼블리셔 클라이언트 TLS 시크릿의 Secrets Manager 이름 접두사 |
factory_id |
string |
IoT 사용 시 | - | IoT 팩토리 ID |
line_id |
string |
IoT 사용 시 | - | IoT 라인 ID |
equipment_thing_names |
set(string) |
IoT 사용 시 | - | IoT 장비 Thing 이름 목록 |
terraform.tfvars 예시:
aws_region = "ap-northeast-2"
vpc_id = "vpc-0123456789abcdef0"
rtb_id = "rtb-0123456789abcdef0"
cluster_name = "my-eks-cluster"
nodegroup_name = "my-node-group"
desired_capacity = 2
min_capacity = 1
max_capacity = 4
instance_types = ["t3.medium"]
azs = ["ap-northeast-2a", "ap-northeast-2c"]
public_subnet_ids = ["subnet-aaa111", "subnet-bbb222"]
private_subnet_cidrs = ["10.0.10.0/24", "10.0.11.0/24"]
server_tls_secret_prefix = "kafka/broker/tls"
client_tls_secret_prefix = "kafka/client/tls"Module: iam — modules/iam/
EKS 클러스터 제어 플레인과 워커 노드에 필요한 IAM 역할을 생성합니다.
| 변수명 | 타입 | 필수 | 설명 |
|---|---|---|---|
cluster_name |
string |
✅ | IAM 역할 이름에 사용되는 EKS 클러스터 이름 |
| 출력명 | 설명 |
|---|---|
eks_cluster_role_arn |
클러스터 제어 플레인 IAM 역할 ARN |
eks_cluster_role_name |
클러스터 제어 플레인 IAM 역할 이름 |
eks_node_role_arn |
워커 노드 IAM 역할 ARN |
eks_node_role_name |
워커 노드 IAM 역할 이름 |
연결되는 관리형 정책:
- 클러스터:
AmazonEKSClusterPolicy - 노드:
AmazonEKSWorkerNodePolicy,AmazonEKS_CNI_Policy,AmazonEC2ContainerRegistryReadOnly,CloudWatchAgentServerPolicy
Module: vpc — modules/vpc/
기존 VPC 내에 멀티-AZ 사설 서브넷, NAT 게이트웨이, 라우트 테이블을 생성합니다.
| 변수명 | 타입 | 필수 | 설명 |
|---|---|---|---|
vpc_id |
string |
✅ | 기존 VPC ID |
azs |
list(string) |
✅ | 가용 영역 목록 |
public_subnet_ids |
list(string) |
✅ | 기존 공용 서브넷 ID 목록 (NAT 게이트웨이 배치용, azs와 순서 일치) |
private_subnet_cidrs |
list(string) |
✅ | 사설 서브넷 CIDR 목록 (azs와 순서 일치) |
| 출력명 | 설명 |
|---|---|
vpc_id |
VPC ID |
private_subnet_ids |
생성된 사설 서브넷 ID 목록 |
nat_gateway_ids |
생성된 NAT 게이트웨이 ID 목록 |
private_route_table_ids |
생성된 사설 라우트 테이블 ID 목록 |
Module: security — modules/security/
EKS 클러스터용 보안 그룹을 생성합니다. 내부 통신(self) 허용, 전체 아웃바운드 허용.
| 변수명 | 타입 | 필수 | 설명 |
|---|---|---|---|
cluster_name |
string |
✅ | 보안 그룹 이름에 사용되는 클러스터 이름 |
vpc_id |
string |
✅ | 보안 그룹을 생성할 VPC ID |
| 출력명 | 설명 |
|---|---|
eks_security_group_id |
생성된 EKS 보안 그룹 ID |
Module: eks — modules/eks/
EKS 클러스터 제어 플레인과 관리형 노드 그룹을 생성합니다.
| 변수명 | 타입 | 기본값 | 설명 |
|---|---|---|---|
cluster_name |
string |
- | EKS 클러스터 이름 |
cluster_version |
string |
null |
Kubernetes 버전 (null이면 최신) |
cluster_role_arn |
string |
- | 클러스터 제어 플레인 IAM 역할 ARN |
node_role_arn |
string |
- | 워커 노드 IAM 역할 ARN |
private_subnet_ids |
list(string) |
- | 클러스터 및 노드 배치용 사설 서브넷 ID 목록 |
eks_security_group_id |
string |
- | EKS 보안 그룹 ID |
endpoint_private_access |
bool |
true |
클러스터 프라이빗 엔드포인트 활성화 여부 |
endpoint_public_access |
bool |
true |
클러스터 퍼블릭 엔드포인트 활성화 여부 |
public_access_cidrs |
list(string) |
["0.0.0.0/0"] |
퍼블릭 엔드포인트 접근 허용 CIDR 목록 |
nodegroup_name |
string |
- | 노드 그룹 이름 |
desired_capacity |
number |
- | 원하는 노드 수 |
min_capacity |
number |
- | 최소 노드 수 |
max_capacity |
number |
- | 최대 노드 수 |
instance_types |
list(string) |
- | EC2 인스턴스 타입 목록 |
capacity_type |
string |
ON_DEMAND |
ON_DEMAND 또는 SPOT |
| 출력명 | 설명 |
|---|---|
cluster_name |
클러스터 이름 |
cluster_arn |
클러스터 ARN |
cluster_endpoint |
클러스터 API 서버 엔드포인트 |
cluster_certificate_authority_data |
클러스터 CA 인증서 (Base64) |
cluster_oidc_issuer_url |
OIDC 발급자 URL (IRSA 구성에 사용) |
node_group_name |
노드 그룹 이름 |
node_group_arn |
노드 그룹 ARN |
Module: irsa — modules/irsa/
EKS OIDC 공급자를 생성하고, ALB Controller와 External Secrets Operator(Kafka)를 위한 IRSA 역할 및 정책을 설정합니다.
| 변수명 | 타입 | 기본값 | 설명 |
|---|---|---|---|
cluster_name |
string |
- | EKS 클러스터 이름 |
oidc_issuer_url |
string |
- | EKS OIDC 발급자 URL (module.eks.cluster_oidc_issuer_url) |
aws_region |
string |
- | AWS 리전 |
aws_account_id |
string |
- | AWS 계정 ID |
server_tls_secret_prefix |
string |
- | Kafka 브로커 TLS 시크릿 접두사 |
client_tls_secret_prefix |
string |
- | Kafka 클라이언트 TLS 시크릿 접두사 |
alb_controller_namespace |
string |
kube-system |
ALB Controller가 배포될 K8s 네임스페이스 |
alb_controller_service_account_name |
string |
aws-load-balancer-controller |
ALB Controller 서비스 어카운트 이름 |
eso_namespace |
string |
external-secrets |
ESO가 배포될 K8s 네임스페이스 |
eso_kafka_service_account_name |
string |
eso-kafka-sa |
ESO Kafka 서비스 어카운트 이름 |
| 출력명 | 설명 |
|---|---|
oidc_provider_arn |
OIDC 공급자 ARN |
oidc_provider_url |
OIDC 공급자 URL |
alb_controller_role_arn |
ALB Controller IAM 역할 ARN |
alb_controller_role_name |
ALB Controller IAM 역할 이름 |
eso_kafka_secrets_role_arn |
ESO Kafka IAM 역할 ARN |
eso_kafka_secrets_role_name |
ESO Kafka IAM 역할 이름 |
Module: iot (선택) — modules/iot/
AWS IoT Things, 인증서, 정책을 생성하고 인증서 파일을 로컬에 저장합니다.
기본적으로 main.tf에서 주석 처리되어 있습니다. 활성화하려면 주석을 해제하세요.
| 변수명 | 타입 | 필수 | 설명 |
|---|---|---|---|
aws_region |
string |
✅ | AWS 리전 |
aws_account_id |
string |
✅ | AWS 계정 ID |
factory_id |
string |
✅ | 팩토리 ID (MQTT 토픽 경로 및 정책에 사용) |
line_id |
string |
✅ | 라인 ID (MQTT 토픽 경로 및 정책에 사용) |
equipment_thing_names |
set(string) |
✅ | 등록할 장비 Thing 이름 목록 |
| 출력명 | 설명 |
|---|---|
iot_endpoint |
AWS IoT ATS 엔드포인트 주소 |
equipment_thing_names |
등록된 Thing 이름 목록 (정렬) |
equipment_topic_filter |
MQTT 토픽 필터 패턴 |
cert_files_created |
생성된 인증서 파일 경로 목록 |
주의: 이 모듈은 개인 키(
.key) 파일을../certs/디렉토리에 로컬로 생성합니다. 해당 파일은 반드시 안전하게 관리하고 절대 커밋하지 마십시오.
terraform init
terraform validate
terraform plan -out=tfplan
terraform apply tfplanapply.sh는 다음을 자동으로 수행합니다:
- 도구 사전 조건 확인 (terraform, aws, jq)
terraform init및validateterraform plan(변경 사항 있을 때만 apply)- EKS 클러스터 활성화 대기
kubeconfig자동 업데이트
bash apply.shaws eks update-kubeconfig \
--region <aws_region> \
--name <cluster_name>1. plan/apply가 권한(AccessDenied)으로 실패할 때
AWS_PROFILE/ AssumeRole 설정 확인- Terraform 실행 계정에 필요한 IAM 권한 확인
2. aws eks update-kubeconfig는 성공했는데 kubectl이 401/403
- EKS 인증은 kubeconfig만으로 끝나지 않고, 클러스터 RBAC(
aws-authConfigMap 등) 매핑이 필요할 수 있습니다.
3. VPC/서브넷/NAT 관련 네트워크 이슈
- private subnet에서 외부 통신이 필요하면 NAT 및 라우팅 설정 확인
- 노드가 ECR pull을 못하면 NAT 게이트웨이 또는 VPC Endpoint 구성이 필요할 수 있습니다.
terraform.tfvars파일은.gitignore에 포함되어 있습니다. 민감한 값이 포함될 수 있으므로 절대 커밋하지 마십시오.- Terraform 상태 파일(
.tfstate) 은 팀 협업 시 원격 백엔드(S3 + DynamoDB) 사용을 권장합니다. 로컬 state는 충돌 및 유실 위험이 있습니다. - IoT 인증서 파일(
../certs/*.key,../certs/*.pem)은 개인 키를 포함합니다. 생성 후 안전한 저장소로 이전하십시오. public_access_cidrs의 기본값은["0.0.0.0/0"]입니다. 프로덕션 환경에서는 접근 허용 CIDR을 제한하는 것을 권장합니다.- EKS 클러스터 삭제 전 LoadBalancer 타입 Service 등 Kubernetes 리소스를 먼저 정리해야 VPC 삭제 실패를 피할 수 있습니다.