Skip to content
All posts

AWS Istanbul Local Zone ile KVKK Uyumlu Cloud Mimarisi - Bölüm 2: Temel Altyapı

 

Bu blog, AWS Istanbul Local Zone ile KVKK Uyumlu Cloud Mimarisi - Bölüm 1: Mimari ve Karar'ın devamıdır.

 

Istanbul Local Zone için Terragrunt proje yapısını, VPC subnet stratejisini ve EKS cluster kurulumunu gerçek kod örnekleriyle anlatıyorum.

 

 

2. Gereksinimler ve Hazırlık

Local Zone Opt-in

Istanbul Local Zone varsayılan olarak kapalı gelir, hesabınızda aktif etmeniz gerekir. İki yöntem var:

Seçenek 1 — Terragrunt (önerilen):

Opt-in işlemini altyapı koduna dahil etmek için Terraform'ın aws_ec2_availability_zone_group resource'unu kullanabilirsiniz. Böylece bu adım da versiyon kontrolünde olur ve VPC'den önce otomatik uygulanır.

# modules/local-zone-optin/main.tf
resource "aws_ec2_availability_zone_group" "istanbul" {
  group_name    = "eu-central-1-ist-1a"
  opt_in_status = "opted-in"
}
# env/hepapi/eu-central-1/prod/local-zone-optin/terragrunt.hcl
terraform {
  source = "../../../../modules/local-zone-optin"
}
include "root" {
  path = find_in_parent_folders()
}

 

VPC modülünün dependency bloğuna bu modülü ekleyerek sıralamayı garantileyin. Aktifleştirme birkaç dakika sürebilir; Terraform bunu otomatik bekler.


Seçenek 2 - AWS CLI / Console:

AWS Console:

EC2 → Sol menü → "Zone Groups" → eu-central-1-ist-1a → Actions → Enable

AWS CLI:

aws ec2 modify-availability-zone-group \
  --group-name eu-central-1-ist-1a \
  --opt-in-status opted-in \
  --region eu-central-1 \
  --profile hepapi-sso

Aktifleştirme birkaç dakika alabilir. Kontrol edin:

aws ec2 describe-availability-zones \
  --all-availability-zones \
  --region eu-central-1 \
  --query 'AvailabilityZones[?ZoneName==`eu-central-1-ist-1a`]' \
  --profile hepapi-sso

 

Araçlar

# macOS
brew install terraform terragrunt awscli kubectl helm

# Versiyon kontrol
terraform --version   # >= 1.5.0
terragrunt --version  # >= 0.55.0
aws --version         # >= 2.0.0

 

S3 Backend ve DynamoDB

Terragrunt remote state için S3 bucket ve DynamoDB tablosu gerekir. İki yöntem var:

Seçenek 1 - Terragrunt (önerilen):

terragrunt.hcl dosyasındaki remote_state bloğuna bucket ve dynamodb_table tanımlandığında Terragrunt, ilk terragrunt apply sırasında bu kaynakları otomatik olarak oluşturur - ayrıca bir şey yapmanıza gerek yoktur.

 

# terragrunt.hcl (root)
remote_state {
  backend = "s3"
  config = {
    encrypt        = true
    bucket         = "hepapi-local-zone-terragrunt-states"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "eu-central-1"
    dynamodb_table = "hepapi-local-zone-terragrunt-lock-tables"
    profile        = local.profile
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

Bucket versioning ve server-side encryption da otomatik aktif edilir.

 

Seçenek 2 - AWS CLI (manuel):

# S3 bucket
aws s3api create-bucket \
  --bucket hepapi-local-zone-terragrunt-states \
  --region eu-central-1 \
  --create-bucket-configuration LocationConstraint=eu-central-1 \
  --profile hepapi-sso

# Versioning aktif et
aws s3api put-bucket-versioning \
  --bucket hepapi-local-zone-terragrunt-states \
  --versioning-configuration Status=Enabled \
  --profile hepapi-sso

# DynamoDB lock table
aws dynamodb create-table \
  --table-name hepapi-local-zone-terragrunt-lock-tables \
  --attribute-definitions AttributeName=LockID,AttributeType=S \
  --key-schema AttributeName=LockID,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST \
  --region eu-central-1 \
  --profile hepapi-sso

 

SSO ile Kimlik Doğrulama

AWS SSO kullanıyorsanız kritik bir sorunla karşılaşırsınız: Terraform S3 backend sso_session formatını desteklemez. Her terminal oturumunda şunu çalıştırın:

aws sso login --profile hepapi-sso
eval "$(aws configure export-credentials --profile hepapi-sso --format env)"

Bu komut AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY ve AWS_SESSION_TOKEN ortam değişkenlerini set eder. Terraform bu değişkenleri otomatik okur.

 

3. Proje Yapısı

.
├── terragrunt.hcl                    # Root config (provider, backend)
├── account.hcl                       # Account ID
└── env/
    └── hepapi/
        └── eu-central-1/
            └── prod/
                ├── env.hcl           # Tüm versiyon ve config değerleri
                ├── vpc/
                │   └── terragrunt.hcl
                └── eks/
                    ├── eks/
                    │   └── terragrunt.hcl
                    ├── node-group/
                    │   └── terragrunt.hcl
                    ├── karpenter/
                    │   ├── karpenter-module/
                    │   ├── karpenter-controller-helm/
                    │   └── karpenter-configs/
                    ├── ebs-csi/
                    ├── alb-controller/
                    │   ├── aws-alb-controller-role/
                    │   └── aws-alb-controller/
                    └── common-security-group/

 

4. Terragrunt Root Yapılandırması

Kök terragrunt.hcl dosyası tüm alt modüller için provider ve backend ayarlarını otomatik üretir. Her modülde tekrar tekrar yazmaya gerek kalmaz.

# terragrunt.hcl (root)
locals {
  account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl"))
  env_vars     = read_terragrunt_config(find_in_parent_folders("env.hcl"))
  region       = local.env_vars.locals.region
  profile      = "hepapi-sso"
}

generate "provider" {
  path      = "providers.tf"
  if_exists = "overwrite"
  contents  = <<EOF
provider "aws" {
  region  = "${local.region}"
  profile = "${local.profile}"
}
EOF
}

generate "provider_version" {
  path      = "provider_version_override.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.83.0"
    }
    helm = {
      source  = "hashicorp/helm"
      version = "~> 3.1.1"
    }
    kubectl = {
      source  = "gavinbunney/kubectl"
      version = ">= 1.19.0"
    }
  }
}
EOF
}

remote_state {
  backend = "s3"
  config = {
    encrypt        = true
    bucket         = "hepapi-local-zone-terragrunt-states"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "eu-central-1"
    dynamodb_table = "hepapi-local-zone-terragrunt-lock-tables"
    profile        = local.profile
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

Versiyon Uyumluluğu - En Kritik Konu

Bu kurulumda en çok zaman harcadığımız konu provider ve module versiyon uyumluluğuydu. Kısaca:

  • EKS module 20.x → AWS Provider v5 gerektirir (v6 ile çalışmaz)
  • VPC module 6.x → AWS Provider v6 gerektirir
  • Sonuç: VPC module'ü 5.19.0'a düşürdük, AWS Provider ~> 5.83.0 sabitledik

Tüm versiyon değerleri tek yerden yönetilir:

# env/hepapi/eu-central-1/prod/env.hcl
locals {
  module_versions = {
    vpc        = "5.19.0"   # v6 AWS Provider v6 gerektirir, uyumsuz
    eks        = "20.33.1"  # AWS Provider ~> 5.83.0 gerektirir
    node-group = "20.33.1"
  }
  helm_versions = {
    karpenter-chart              = "1.1.2"
    ebs-csi-chart                = "2.40.3"
    efs-csi-chart                = "3.1.5"
    aws-load-balancer-controller = "1.11.0"
  }
}

 

5. VPC Kurulumu

Subnet İndeksleme Stratejisi

Local Zone kurulumunun temel tasarım kararı budur. VPC module subnet'leri azs listesinin sırasına göre oluşturur ve bu sıra garanti edilmiştir.

azs = ["eu-central-1a", "eu-central-1b", "eu-central-1-ist-1a"]

private_subnets[0] → 10.20.0.0/19   → eu-central-1a       → EKS control plane
private_subnets[1] → 10.20.64.0/19  → eu-central-1b       → EKS control plane
private_subnets[2] → 10.20.32.0/19  → eu-central-1-ist-1a → Istanbul workers

Bu indeks stratejisi sayesinde: 

  • slice(subnets, 0, 2) → Control plane subnets
  • slice(subnets, 2, 3) → Istanbul worker subnets


# env.hcl — VPC konfigürasyonu
vpc = {
  vpc_name        = "hepapi-local-zone"
  cidr            = "10.20.0.0/16"
  azs             = ["eu-central-1a", "eu-central-1b", "eu-central-1-ist-1a"]
  private_subnets = ["10.20.0.0/19", "10.20.64.0/19", "10.20.32.0/19"]
  public_subnets  = ["10.20.100.0/24", "10.20.102.0/24", "10.20.101.0/24"]
  enable_nat_gateway     = true
  single_nat_gateway     = true   # Istanbul trafiği Frankfurt NAT üzerinden
  one_nat_gateway_per_az = false
}
# env/hepapi/eu-central-1/prod/vpc/terragrunt.hcl
terraform {
  source = "tfr:///terraform-aws-modules/vpc/aws//?version=${local.env_vars.locals.module_versions.vpc}"
}

inputs = {
  name            = "${local.env_vars.locals.vpc.vpc_name}-vpc"
  cidr            = local.env_vars.locals.vpc.cidr
  azs             = local.env_vars.locals.vpc.azs
  private_subnets = local.env_vars.locals.vpc.private_subnets
  public_subnets  = local.env_vars.locals.vpc.public_subnets

  # Local Zone'da database subnet group desteklenmiyor
  create_database_subnet_group       = false
  create_database_subnet_route_table = false

  enable_nat_gateway     = local.env_vars.locals.vpc.enable_nat_gateway
  single_nat_gateway     = local.env_vars.locals.vpc.single_nat_gateway
  one_nat_gateway_per_az = local.env_vars.locals.vpc.one_nat_gateway_per_az

  enable_dns_hostnames = true
  enable_dns_support   = true

  # ALB discovery için public subnet tag'i
  public_subnet_tags = {
    "kubernetes.io/role/elb"                                           = 1
    "kubernetes.io/cluster/${local.env_vars.locals.eks.cluster_name}" = "shared"
  }

  # Karpenter subnet discovery için private subnet tag'leri
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb"                                  = 1
    "kubernetes.io/cluster/${local.env_vars.locals.eks.cluster_name}"  = "shared"
    "karpenter.sh/discovery/${local.env_vars.locals.eks.cluster_name}" = "${local.env_vars.locals.eks.cluster_name}"
  }
}

 

 

NAT Gateway Notu: single_nat_gateway = true ile NAT Gateway yalnızca eu-central-1a'da oluşturulur. Istanbul pod'larının internet trafiği Frankfurt NAT üzerinden geçer. Bu cross-zone data transfer ücreti doğurur (~$0.02/GB). Yüksek egress trafiğiniz varsa bunu maliyet planlamasına ekleyin.

Sıradaki bölümler için takipte kalın:

  • Bölüm 3: Node'lar ve Servisler - EKS, Karpenter, EBS CSI, ALB Controller
  • Bölüm 4: Production'a Taşımak - Sorunlar, maliyet analizi, best practices