Создание приватного кластера Amazon EKS с помощью Terraform и OpenVPN
Безопасность является ключевым приоритетом при проектировании облачной инфраструктуры. Стандартное развертывание кластера Amazon EKS (Elastic Kubernetes Service — сервис управления контейнерами от AWS) с публичным доступом к API подвергает панель управления внешним угрозам. Для защиты от сетевых атак необходимо разворачивать приватный кластер EKS без публичного API-эндпоинта, доступ к которому осуществляется только через VPN-туннель.
В данном руководстве описан процесс развертывания такой инфраструктуры с использованием Terraform и шлюза OpenVPN на виртуальном сервере EC2.
Архитектура защищенной сети и распределение ресурсов
Вся инфраструктура разворачивается в рамках одного VPC (Virtual Private Cloud — виртуальное облако в AWS) с адресным пространством 10.0.0.0/16, разделенным на публичные и приватные подсети в двух зонах доступности (AZ).
| Ресурс | Сетевой диапазон (CIDR) | Тип подсети | Назначение |
|---|---|---|---|
| VPC | 10.0.0.0/16 | Виртуальное облако | Сеть для всей инфраструктуры |
| Public Subnet 1 | 10.0.1.0/24 | Публичная | OpenVPN инстанс, NAT Gateway |
| Public Subnet 2 | 10.0.2.0/24 | Публичная | Резервная зона |
| Private Subnet 1 | 10.0.10.0/24 | Приватная | Ноды EKS, внутренние балансировщики |
| Private Subnet 2 | 10.0.11.0/24 | Приватная | Ноды EKS, внутренние балансировщики |
| VPN Client Range | 10.8.0.0/24 | VPN-туннель | Адреса для VPN-клиентов |
Ноды EKS в приватных подсетях общаются с интернетом (для скачивания образов) через NAT Gateway в публичной подсети. Это ограничивает только входящие соединения: API-сервер EKS доступен только изнутри VPC, а исходящий трафик идет наружу.
Схема прохождения трафика при администрировании:
[ Ноутбук администратора ] (Внешняя сеть)
| (Secure Tunnel: UDP 1194 / OpenVPN)
v
[ OpenVPN Server EC2 ] (Public Subnet - 10.0.1.x)
| (NAT Masquerade - подмена IP на внутренний IP сервера)
v
[ EKS API Endpoint ] (Private Subnets - HTTPS 443) <--- Управление
|
[ Grafana Internal Load Balancer ] (HTTP 80/443) <--- Мониторинг
Подготовка конфигурации провайдеров Terraform
Поскольку API-сервер EKS приватный, провайдеры Helm и Kubernetes должны взаимодействовать с ним через VPN. Ниже представлен файл providers.tf:
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
tls = { source = "hashicorp/tls", version = "~> 4.0" }
helm = { source = "hashicorp/helm", version = "~> 2.0" }
kubernetes = { source = "hashicorp/kubernetes", version = "~> 2.0" }
}
}
provider "aws" { region = var.aws_region }
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
}
}
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
exec {
api_version = "client.authentication.k8s.io/v1beta1"
command = "aws"
args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
}
}
}
Важное предупреждение при деплое (bootstrap caveat): При запуске terraform apply вне VPC шаги по установке Helm-чартов зависнут, так как Terraform не сможет подключиться к приватному API EKS. Рекомендуется разделить процесс: сначала развернуть VPC, OpenVPN-сервер и кластер EKS, затем подключиться к VPN на локальной машине и повторно запустить terraform apply для деплоя Helm-чартов.
Настройка VPC и EKS в Terraform
Для обнаружения подсетей контроллером AWS Load Balancer Controller необходимо разметить подсети тегами в модуле VPC:
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "eks-secure-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b"]
private_subnets = ["10.0.10.0/24", "10.0.11.0/24"]
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
enable_dns_support = true
public_subnet_tags = { "kubernetes.io/role/elb" = "1" }
private_subnet_tags = { "kubernetes.io/role/internal-elb" = "1" }
}
При настройке модуля EKS (terraform-aws-modules/eks/aws версии ~> 20.0) отключаем публичный доступ к управляющему контуру:
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "secure-prod-cluster"
cluster_version = "1.29"
cluster_endpoint_public_access = false
cluster_endpoint_private_access = true
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
enable_cluster_creator_admin_permissions = true
eks_managed_node_groups = {
default = {
min_size = 2; max_size = 5; desired_size = 2
instance_types = ["t3.medium"]
}
}
}
Параметр enable_cluster_creator_admin_permissions = true автоматически дает права создателю кластера в EKS Access Entries, предотвращая ошибку You must be logged in to the server.
Развертывание и конфигурация OpenVPN-шлюза
Сервер OpenVPN запускается на инстансе EC2 (Ubuntu 22.04 LTS) в публичной подсети с Elastic IP. Группа безопасности разрешает входящий UDP/1194 и ограничивает SSH (TCP/22) вашим IP. На сетевом интерфейсе EC2 необходимо отключить проверку источника и назначения: source_dest_check = false.
Скрипт user-data выполняет следующие шаги:
- Устанавливает
openvpn,easy-rsaиiptables-persistent. - Включает IP Forwarding:
sysctl -w net.ipv4.ip_forward=1(с записью в/etc/sysctl.conf). - Создает локальный CA, генерирует сертификат сервера и общий ключ
ta.key. - Настраивает трансляцию адресов:
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE. - Генерирует клиентский профиль
/home/ubuntu/client-configs/client1.ovpnс правами600.
Ключевые директивы /etc/openvpn/server.conf:
port 1194
proto udp
dev tun
server 10.8.0.0 255.255.255.0
push "route 10.0.0.0 255.255.0.0"
push "dhcp-option DNS 10.0.0.2"
cipher AES-256-GCM
auth SHA256
user nobody
group nogroup
Адрес 10.0.0.2 (AmazonProvidedDNS) передается клиентам для корректного резолва имен приватных DNS-зон в Route 53.
Интеграция DNS и мониторинга
Внутри приватных подсетей разворачивается kube-prometheus-stack (Prometheus, Grafana). Grafana настраивается как внутренний балансировщик (internal Load Balancer) с помощью аннотаций AWS LB Controller. В Route 53 создается Private Hosted Zone devops.private, связанная с VPC, и CNAME-запись grafana.devops.private на внутренний балансировщик Grafana, доступный только внутри VPN.
Пошаговая инструкция по запуску, проверке и подключению
- Развертывание сети: Примените Terraform для создания VPC, OpenVPN-сервера, Route 53 и кластера EKS.
- Получение профиля: Подключитесь по SSH к VPN-серверу и скачайте профиль:
scp -i key.pem ubuntu@<PUBLIC_IP_VPN>:/home/ubuntu/client-configs/client1.ovpn ./client1.ovpn - Подключение к VPN: Запустите OpenVPN-клиент с полученным профилем.
- Конфигурация kubectl: Создайте kubeconfig на локальной машине с помощью AWS CLI (требуются права
eks:DescribeCluster):aws eks update-kubeconfig --region us-east-1 --name secure-prod-cluster - Проверка сетевого пути:
- Без VPN:
curl -k -m 5 https://<EKS_API_ENDPOINT>/readyzзавершается ошибкой. - С VPN: Тот же запрос возвращает код
401илиok. - Проверьте доступ к нодам:
kubectl get nodes.
- Без VPN:
- Проверка мониторинга: Выполните
nslookup grafana.devops.private(должен вернуть IP-адрес10.0.x.x) и откройте интерфейс в браузере.
Безопасность и ограничения
- Конфиденциальность ключей: Утеря
client1.ovpnкомпрометирует доступ в приватную сеть. Храните профили в зашифрованном виде. - Точки отказа: Одиночный инстанс OpenVPN является единой точкой отказа (SPOF). В production замените его на AWS Client VPN или отказоустойчивую группу VPN за балансировщиком.
- Стоимость: NAT Gateway тарифицируется поминутно. Для экономии в dev-средах используется
single_nat_gateway = true. - Права доступа: Используйте именные сертификаты, MFA и настройте регулярное обновление списка отзыва сертификатов (CRL).

