AWS(Amazon EKS)에서 ALB 완전 자동화(Helm via Terraform)
Posted by Albert 58Day 5Hour 16Min 17Sec ago [2025-12-10]
설계 목표
설계 목표는 다음과 같아:
- Route53 DNS로 도메인 소유 검증을 자동화 → ACM 인증서 발급(DNS 검증). registry.terraform.io
- EKS에 AWS Load Balancer Controller(ALB 컨트롤러)를 Terraform(Helm)로 설치하고 IRSA 권한을 부여. registry.terraform.io
- Kubernetes Ingress(aws-load-balancer-controller)로 ALB 생성, HTTPS termination, 도메인별 라우팅 및 HTTP→HTTPS 리다이렉트 구성. kubernetes-sigs.github.io
1) 전제 / 요구사항
- 이미 AWS 계정과 도메인(예: example.com)이 있고 Route53에 호스트 존이 존재한다고 가정. (존이 다른 계정에 있으면 추가 작업 필요)
- EKS 클러스터는 이미 있거나 Terraform으로 생성 가능(예제는 data/module로 EKS 사용).
- Terraform 1.x, AWS provider 최신(예제는 리소스명 기준) 사용 권장.
2) 파일 구성(예시)
- providers.tf — AWS + kubernetes + helm providers
- route53-acm.tf — ACM 인증서 생성 + Route53 검증 레코드 자동 생성 + validation
- alb-controller-iam.tf — OIDC/IRSA용 IAM Role, Policy 연결
- helm-alb-controller.tf — Helm release로 aws-load-balancer-controller 설치
- k8s-ingress.yaml — Ingress 리소스(HTTPS + redirect)
providers.tf (핵심)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.0"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.0"
}
}
}
provider "aws" {
region = var.aws_region
}
' kubeconfig 얻는 방법: EKS 모듈 outputs를 사용하거나 미리 kubeconfig를 설정
provider "kubernetes" {
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.cluster.token
}
provider "helm" {
kubernetes {
host = data.aws_eks_cluster.cluster.endpoint
cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority[0].data)
token = data.aws_eks_cluster_auth.cluster.token
}
}
(여기서 data.aws_eks_cluster.cluster/data.aws_eks_cluster_auth.cluster는 이미 존재하는 EKS를 가리킴 — 또는 module.eks outputs 사용)
route53-acm.tf — ACM cert + DNS validation
variable "domain" {
type = string
default = "example.com"
}
' Create ACM certificate (region must be the same as ALB region; for global CloudFront it's us-east-1)
resource "aws_acm_certificate" "cert" {
domain_name = var.domain
validation_method = "DNS"
subject_alternative_names = ["*.${var.domain}"] ' 와일드카드 포함 가능
lifecycle {
create_before_destroy = true
}
}
' Get Route53 hosted zone
data "aws_route53_zone" "zone" {
name = "${var.domain}."
private_zone = false
}
' create validation records in Route53
resource "aws_route53_record" "cert_validation" {
for_each = {
for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
type = dvo.resource_record_type
record = dvo.resource_record_value
}
}
zone_id = data.aws_route53_zone.zone.zone_id
name = each.value.name
type = each.value.type
ttl = 60
records = [each.value.record]
}
' Wait for validation (creates aws_acm_certificate_validation that depends on the records)
resource "aws_acm_certificate_validation" "cert_validation" {
certificate_arn = aws_acm_certificate.cert.arn
validation_record_fqdns = [for r in aws_route53_record.cert_validation : r.fqdn]
}
- 이 구성은 ACM에서 요구하는 DNS 레코드들을 자동으로 생성하고 aws_acm_certificate_validation가 완료될 때까지 기다림. (권장 방식). registry.terraform.io
alb-controller-iam.tf — OIDC(IRSA)용 IAM Role 생성 (요약)
AWS Load Balancer Controller는 EKS OIDC + IAM 역할로 권한을 주는 방식(IRSA)을 권장함. Terraform으로 ServiceAccount용 IAM Role 생성 예:
' get cluster OIDC provider
data "aws_eks_cluster" "cluster" {
name = var.eks_cluster_name
}
data "aws_iam_openid_connect_provider" "oidc" {
url = replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")
}
' create IAM policy (use official policy JSON from AWS or use managed policy)
resource "aws_iam_policy" "alb_controller_policy" {
name = "AWSLoadBalancerControllerIAMPolicy-${var.eks_cluster_name}"
description = "Policy for AWS Load Balancer Controller"
policy = file("${path.module}/alb-controller-policy.json") ' download official policy JSON from controller repo
}
resource "aws_iam_role" "alb_controller_role" {
name = "alb-controller-role-${var.eks_cluster_name}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRoleWithWebIdentity"
Effect = "Allow"
Principal = {
Federated = data.aws_iam_openid_connect_provider.oidc.arn
}
Condition = {
StringEquals = {
' issuer + namespace/serviceaccount, example:
"${replace(data.aws_eks_cluster.cluster.identity[0].oidc[0].issuer, "https://", "")}:sub" : "system:serviceaccount:kube-system:aws-load-balancer-controller"
}
}
}]
})
}
resource "aws_iam_role_policy_attachment" "alb_attach" {
role = aws_iam_role.alb_controller_role.name
policy_arn = aws_iam_policy.alb_controller_policy.arn
}
- alb-controller-policy.json는 AWS Load Balancer Controller 공식 정책(보안상 권장)을 사용해야 함 — 공식 GitHub/문서에서 최신 정책을 가져와 파일로 둬라. GitHub
helm-alb-controller.tf — Helm으로 설치 (IRSA 사용)
resource "helm_release" "aws_load_balancer_controller" {
name = "aws-load-balancer-controller"
repository = "https://aws.github.io/eks-charts"
chart = "aws-load-balancer-controller"
version = "1.8.0" ' 예시, 실제로는 최신 확인하세요
namespace = "kube-system"
create_namespace = false
values = [
yamlencode({
clusterName = var.eks_cluster_name
region = var.aws_region
serviceAccount = {
create = false
name = "aws-load-balancer-controller"
}
' if you use node selector / tolerations etc, add here
})
]
depends_on = [
aws_iam_role_policy_attachment.alb_attach,
aws_iam_role.alb_controller_role
]
}
주의: Helm 설치 전에 Kubernetes에 ServiceAccount를 만들어서 eks OIDC와 연결된 aws_iam_role을 사용하는 것이 일반적(혹은 Helm chart가 ServiceAccount를 재사용하게 설정). EKS Blueprints / eksctl 예제가 많음. AWS Integration and Automation
k8s-ingress.yaml — Production-level Ingress (HTTPS Termination + HTTP→HTTPS redirect)
아래 Ingress는 aws-load-balancer-controller가 해석하여 ALB를 만들고 ACM 인증서로 HTTPS 리스너를 구성, 그리고 HTTP 요청을 HTTPS로 리다이렉트 한다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
' HTTPS listener 사용 및 ACM 인증서 지정
alb.ingress.kubernetes.io/certificate-arn: "${ACM_CERT_ARN}"
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]'
' security policy(권장)
alb.ingress.kubernetes.io/ssl-policy: "ELBSecurityPolicy-TLS-1-2-2017-01"
' redirect action 설정 (ALB actions)
alb.ingress.kubernetes.io/actions.ssl-redirect: >
{"Type":"redirect","RedirectConfig":{"Protocol":"HTTPS","Port":"443","StatusCode":"HTTP_301"}}
spec:
ingressClassName: alb
rules:
- host: aaa.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ssl-redirect
port:
name: use-annotation
- host: aaa.example.com
http:
paths:
- path: /app
pathType: Prefix
backend:
service:
name: aaa-service
port:
number: 80
- host: bbb.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ssl-redirect
port:
name: use-annotation
- host: bbb.example.com
http:
paths:
- path: /app
pathType: Prefix
backend:
service:
name: bbb-service
port:
number: 80
설명:
- alb.ingress.kubernetes.io/certificate-arn에 Terraform에서 생성된 aws_acm_certificate.cert.arn 값을 넣으면 ALB가 443 리스너를 ACM 인증서로 구성해줌. kubernetes-sigs.github.io
- alb.ingress.kubernetes.io/actions.ssl-redirect를 사용해 HTTP 요청을 HTTPS로 리다이렉트하도록 ALB에서 직접 처리. 이는 ALB Ingress Controller 공식 가이드의 권장 패턴. kubernetes-sigs.github.io
참고: 위 manifest에서 "${ACM_CERT_ARN}" 부분은 실제로 kubectl apply 전 혹은 CI 파이프라인에서 sed/kustomize/helm 등으로 대체하거나, ExternalDNS/kubectl 템플릿으로 자동화해서 넣으면 편리.
3) 전체 흐름 요약(실행 순서)
- Route53 Hosted Zone 존재 확인.
- terraform apply로 aws_acm_certificate 생성 → aws_route53_record 자동 생성 → aws_acm_certificate_validation 완료 (certificate 발급). registry.terraform.io
- EKS 클러스터가 준비되어 있어야 함(또는 Terraform으로 EKS 생성).
- OIDC Provider + IAM Role(Controller 전용) 생성 → 필요한 정책 연결. Medium
- Helm(또는 kubectl)으로 AWS Load Balancer Controller 설치(위 IAM Role과 연결된 ServiceAccount 사용). registry.terraform.io
- Kubernetes에 Ingress 리소스 배포 → ALB 자동 생성, 80/443 리스너 구성 및 ACM 인증서 적용 → HTTP→HTTPS 리다이렉트 작동 확인. kubernetes-sigs.github.io
4) 운영상 팁 & 권장 설정
- ACM 리전: ALB는 리전 리소스이므로 ACM 인증서는 ALB와 동일 리전에 발급해야 함(CloudFront는 us-east-1). Head for the Cloud
- SSL 정책: ELBSecurityPolicy-TLS-1-2-2017-01 또는 최신 TLS13 정책 사용 권장. GitHub
- WAF 연동: ALB에 AWS WAF 연결 가능(헬스 체크/리소스 태깅 등).
- DNS TTL: validation 레코드 TTL은 짧게(60) 두는 것이 편리.
- 로그/접근제어: ALB access logs(ElasticSearch, S3), AWS ALB target group health checks 확인.
- ACM 자동 갱신: ACM은 DNS 검증이 유지되는 한 자동 갱신됨(레코드 삭제 주의). registry.terraform.io
5) Terraform-aws-alb-acm-eks-repo 쌤플상 팁 & 권장 설정
' Terraform repo: AWS ALB + ACM + EKS (complete example)
This repository contains a working, opinionated Terraform layout to:
- Provision ACM certificate (DNS validation via Route53)
- Create IAM Role & Policy for AWS Load Balancer Controller (IRSA)
- Install AWS Load Balancer Controller via Helm
- Deploy a production-ready Kubernetes Ingress manifest that uses ALB + ACM (HTTPS termination + HTTP->HTTPS redirect)
**Assumptions**
- You already have an EKS cluster (or will provide EKS outputs via data sources). This repo references an existing cluster via `data.aws_eks_cluster` and `data.aws_eks_cluster_auth`.
- The domain is managed in Route53 and a hosted zone exists for it.
- Terraform v1.x and AWS provider v4/5.
---
' File tree
```
.
├── README.md
├── versions.tf
├── providers.tf
├── variables.tf
├── locals.tf
├── route53-acm.tf
├── alb-controller-iam.tf
├── helm-alb-controller.tf
├── k8s-resources
│ ├── serviceaccount-alb-controller.yaml
│ └── ingress-example.yaml
├── alb-controller-policy.json
└── outputs.tf
```
---
' Notes about usage
1. Update `terraform.tfvars` or use CLI `-var` to set `aws_region`, `eks_cluster_name`, `domain`, and `account_id`.
2. Ensure your AWS credentials have permissions to manage Route53, ACM, IAM, and EKS data access.
3. Run:
```bash
terraform init
terraform apply
```
4. After apply completes, deploy any sample workloads referenced by the `ingress-example.yaml` (e.g. `aaa-service`, `bbb-service`).
---
' terraform.tfvars (sample)
aws_region = "ap-northeast-2"
eks_cluster_name = "my-eks-prod"
domain = "example.com"
account_id = "123456789012"
' GitHub Actions CI/CD pipeline
' .github/workflows/deploy.yaml
name: Deploy ALB + Ingress
on:
push:
branches: [ "main" ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubOIDCDelegatedRole
aws-region: ap-northeast-2
- name: Terraform Init
run: terraform init
- name: Terraform Apply
run: terraform apply -auto-approve
- name: Update K8s Ingress
run: |
aws eks update-kubeconfig --region ap-northeast-2 --name my-eks-prod
kubectl apply -f k8s-resources/ingress-example.yaml
' Customized Ingress for production
' k8s-resources/ingress-example.yaml
' Updated with domain-based routing, ACM, and HTTPS redirect.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: prod-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: ${acm_certificate_arn}
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/target-type: ip
spec:
rules:
- host: aaa.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: aaa-service
port:
number: 80
- host: bbb.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bbb-service
port:
number: 80
' End of repo
(Full file contents are included in this textdoc.)
5) 참고(문서)
- AWS Load Balancer Controller 설치 및 Ingress annotations (공식): ALB Ingress Controller 문서. kubernetes-sigs.github.io
- Terraform aws_acm_certificate / aws_acm_certificate_validation 문서. registry.terraform.io
- Terraform 예제 모듈: aws-load-balancer-controller 예제(레지스트리 / GitHub). registry.terraform.io