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) 전체 흐름 요약(실행 순서)

  1. Route53 Hosted Zone 존재 확인.
  2. terraform apply로 aws_acm_certificate 생성 → aws_route53_record 자동 생성 → aws_acm_certificate_validation 완료 (certificate 발급). registry.terraform.io
  3. EKS 클러스터가 준비되어 있어야 함(또는 Terraform으로 EKS 생성).
  4. OIDC Provider + IAM Role(Controller 전용) 생성 → 필요한 정책 연결. Medium
  5. Helm(또는 kubectl)으로 AWS Load Balancer Controller 설치(위 IAM Role과 연결된 ServiceAccount 사용). registry.terraform.io
  6. 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) 참고(문서)





LIST

Copyright © 2014 visionboy.me All Right Reserved.