В этом туториале я опишу простую и безопасную настройку мультиаккаунтной инфраструктуры, основанной на AWS, включая SSO и решение для VPN от Amazon.

Введение
Я разбил статью на несколько основных частей:
-
Во-первых, я покажу как создать инфраструктуру в AWS с нуля, с безопасной структурой аккаунтов, сетей, пирингов
-
Вторая часть этой статьи посвящена AWS SSO: пользователям, группам, MFA, и т.д.
-
Третья часть описывает процесс развертывания сервиса AWS VPN с помощью terraform и его настройки для ранее созданных сетей
Начнем!
Структура AWS-аккаунтов
Мультиаккаунтная структура для AWS имеет ряд преимуществ. Я не буду на них останавливаться, только покажу пример:

Аккаунт root является главным в организации (на него привязывается биллинг), все остальные аккаунты добавляются под руководство этого аккаунта.
Каждый аккаунт привязан к разному почтовому адресу, но обычно можно использовать почтовые алиасы для удобства управления с одного почтового ящика.
Давайте создадим аккаунт с именем root и добавим новые аккаунты в организацию. Логинимся в аккаунты, включаем MFA для пользователей и удостоверяемся, что наша структура аккаунтов верна и мы находимся в одной организации.

Этого достаточно на текущий момент, можем идти дальше.
Сетевая структура
В моем примере аккаунты dev, stage и prod изолированы друг от друга.
Аккаунт common используется для общих сервисов, таких как система CI/CD, хранилища данных (S3-бакеты), и т.д. Поэтому, в моем случае, для того чтобы разрешить сетевое соединение между common и dev/stage/prod аккаунтам, нам нужно создать VPC-пиринг (соединение между виртуальными сетями).
Давайте сделаем это с помощью terraform для аккаунтов common и dev.
Для начала создадим VPC:
data "aws_availability_zones" "available" {} module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.7.0" name = "${var.env}-vpc" cidr = var.vpc_cidr azs = data.aws_availability_zones.available.names private_subnets = var.vpc_private_subnets public_subnets = var.vpc_public_subnets enable_nat_gateway = true single_nat_gateway = true enable_dns_hostnames = true }
А также файл с входными параметрами terraform.tfvars:
region = "eu-central-1" env = "common" # https://www.davidc.net/sites/default/subnets/subnets.html # каждая подсеть ~8190 хостов # 10.0.192.0/19 зарезервирована под VPN-клиентов vpc_cidr = "10.0.0.0/16" vpc_private_subnets = ["10.0.0.0/19", "10.0.32.0/19", "10.0.64.0/19"] vpc_public_subnets = ["10.0.96.0/19", "10.0.128.0/19", "10.0.160.0/19"]
Если вы хотите применить то же самое для аккаунта dev, просто скопируйте и вставьте файл и измените значения сетей и подсетей, к примеру на 10.1.0.0/16 и т.д. Помните, что подсети должны быть разными, чтобы избежать их пересечения после пиринга.
После этого мы имеем новые виртуальные сети:
-
common-vpcв аккаунтеcommonс CIDR:10.0.0.0/16, тремя публичными и тремя частными подсетями -
dev-vpcв аккаунтеdevс CIDR:10.1.0.0/16, тремя публичными и тремя частными подсетями
Давайте соединим их с помощью пиринга:
module "common_dev_peering" { source = "grem11n/vpc-peering/aws" version = "4.0.1" providers = { aws.this = aws aws.peer = aws.dev } this_vpc_id = module.vpc.vpc_id peer_vpc_id = var.vpc_dev_accepter_id auto_accept_peering = true }
Не забываем указать vpc_dev_accepter_id в файле terraform.tfvars:
... vpc_dev_accepter_id = "vpc-12345678"
Ту же самую процедуру можно проделать, к примеру, для аккаунтов stage и prod.

Для тестирования сетевого соединения, достаточно в обоих сетях создать виртуалку и попробовать проверить каким-нибудь инструментом типа ping или traceroute.
Настраиваем SSO
Заходим в AWS в аккаунт root, находим сервис AWS SSO и создаем три группы:
-
vpn-dev -
vpn-stage -
vpn-prod
Идея состоит в том, чтобы разделять доступ к различным сетям для разных групп (RBAC) с VPN.

Также создадим пользователя, пусть будет amet-umerov, после добавления его во все ранее созданные группы, мы хотим чтобы пользователь получил доступ во все сети с помощью VPN.

Итак, мы подготовили группы и пользователя, самое время создать новое SSO-приложение под названием VPN:
-
Add a custom SAML 2.0 application
-
Загружаем
AWS SSO SAML metadata file, он нам пригодится позже -
Set session duration:
12 hours -
Application ACS URL:
http://127.0.0.1:35001 -
Application SAML audience:
urn:amazon:webservices:clientvpn
Также создадим еще одно SSO-приложение с именем VPN Self-Service с такими же настройками, кроме:
-
Application ACS URL:
https://self-service.clientvpn.amazonaws.com/api/auth/sso/saml
Добавим маппинг атрибутов для этих приложений:
-
Subject—user:subject—emailAddress -
NameID—${user:email}—unspecified -
FirstName—${user:name}—unspecified -
LastName—${user:familyName}—unspecified -
memberOf—${user:groups}—unspecified
И привяжем к ним все три группы (vpn-dev, vpn-stage, vpn-prod).

Вот как оно работает:

Настраиваем VPN
Нашим последним шагом является создание клиентской точки доступа для VPN в аккаунте common. Но перед этим необходимо подготовить некоторые сертификаты и ключи.
Генерируем сертификаты для сервера и клиента:
$ git clone https://github.com/OpenVPN/easy-rsa.git $ cd easy-rsa/easyrsa3 $ ./easyrsa init-pki $ ./easyrsa build-ca nopass ... Common Name (eg: your user, host, or server name) [Easy-RSA CA]:vpn.domain.org $ ./easyrsa build-server-full vpn-aws-server nopass $ ./easyrsa build-client-full vpn-aws-client nopass
Копируем сгенерированные сертификаты в безопасное место и импортируем сертификат для сервера в AWS ACM:
$ mkdir ~/.vpn-assets/ $ cp pki/ca.crt ~/.vpn-assets/ $ cp pki/private/ca.key ~/.vpn-assets/ $ cp pki/issued/vpn-aws-*.crt ~/.vpn-assets/ $ cp pki/private/vpn-aws-*.key ~/.vpn-assets/ $ aws --profile common \ --region eu-central-1 \ acm import-certificate \ --certificate fileb://$HOME/.vpn-assets/vpn-aws-server.crt \ --private-key fileb://$HOME/.vpn-assets/vpn-aws-server.key \ --certificate-chain fileb://$HOME/.vpn-assets/ca.crt # На всякий случай скопируем это все в S3-бакет $ aws --profile=common s3 cp --recursive ~/.vpn-assets/ s3://my-bucket/vpn/
Создаем новое VPN-соединение с помощью terraform:
# SAML провайдеры из метадата-файлов, загруженных нами ранее resource "aws_iam_saml_provider" "vpn" { name = "vpn" saml_metadata_document = file("${path.module}/files/VPN_ins-mymetadata-file.xml") } resource "aws_iam_saml_provider" "vpn_self_service" { name = "vpn-self-service" saml_metadata_document = file("${path.module}/files/VPN Self-Service_ins-mymetadata-file.xml") } # Получаем импортированный нами сертификат и subnet_id data "aws_acm_certificate" "vpn_aws_server_cert" { domain = "vpn-aws-server" statuses = ["ISSUED"] } data "aws_subnet" "vpn_subnet_id" { filter { name = "tag:Name" values = ["${var.env}-vpc-private"] } availability_zone_id = "euc1-az1" } # Подготовка CloudWatch для логирования VPN resource "aws_cloudwatch_log_group" "client_vpn" { name = "vpn_endpoint_cloudwatch_log_group" } resource "aws_cloudwatch_log_stream" "client_vpn" { name = "vpn_endpoint_cloudwatch_log_stream" log_group_name = aws_cloudwatch_log_group.client_vpn.name } # Точка доступа VPN resource "aws_ec2_client_vpn_endpoint" "vpn" { description = "VPN client for AWS" server_certificate_arn = data.aws_acm_certificate.vpn_aws_server_cert.arn client_cidr_block = var.vpn_client_cidr_block dns_servers = var.vpn_dns_servers split_tunnel = "true" self_service_portal = "enabled" transport_protocol = "udp" authentication_options { type = "federated-authentication" saml_provider_arn = aws_iam_saml_provider.vpn.arn self_service_saml_provider_arn = aws_iam_saml_provider.vpn_self_service.arn } connection_log_options { enabled = true cloudwatch_log_group = aws_cloudwatch_log_group.client_vpn.name cloudwatch_log_stream = aws_cloudwatch_log_stream.client_vpn.name } } # Фаерволы для VPN resource "aws_security_group" "vpn_main" { name = "vpn_main" description = "Allow VPN all traffic" vpc_id = module.vpc.vpc_id egress { description = "Allow all traffic for VPN" cidr_blocks = ["0.0.0.0/0"] from_port = "0" protocol = "-1" self = "false" to_port = "0" } ingress { description = "Allow all traffic for VPN" cidr_blocks = ["0.0.0.0/0"] from_port = "0" protocol = "-1" self = "false" to_port = "0" } } # Ассоциируем VPN-точку с подсетью resource "aws_ec2_client_vpn_network_association" "vpn" { client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id subnet_id = data.aws_subnet.vpn_subnet_id.id security_groups = [aws_security_group.vpn_main.id] } # Идентификаторы (access_group_id) можно найти тут (в аккаунте root): # https://eu-central-1.console.aws.amazon.com/singlesignon/home?region=eu-central-1#/groups resource "aws_ec2_client_vpn_authorization_rule" "vpn_dev" { client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id target_network_cidr = "10.10.0.0/16" access_group_id = "1234-5678-..." description = "vpn-dev" } # Разрешаем доступ в сеть common для группы vpn-dev resource "aws_ec2_client_vpn_authorization_rule" "vpn_common" { client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id target_network_cidr = "10.0.0.0/16" access_group_id = "1234-5678-..." description = "vpn-common" } # Маршруты resource "aws_ec2_client_vpn_route" "vpn_to_dev" { client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id destination_cidr_block = "10.10.0.0/16" target_vpc_subnet_id = aws_ec2_client_vpn_network_association.vpn.subnet_id }
И модифицируем файл terraform.tfvars:
... vpn_client_cidr_block = "10.0.192.0/19" vpn_dns_servers = ["1.1.1.1", "8.8.8.8"]
После применения данной конфигурации мы получаем клиентскую точку доступа к VPN с контролем доступа на уровне ролей (групп).
Тестируем.
-
Заходим на портал самообслуживания, выглядит ссылка примерно так:
https://self-service.clientvpn.amazonaws.com/endpoints/cvpn-endpoint-1234567890 -
Загружаем VPN-клиент для своей ОС, а также конфигурацию (файл в формате
.ovpn)

-
Запускаем VPN-клиент, создаем новый профиль и импортируем конфигурацию VPN
-
Удостоверяемся, что мы подключены к VPN
-
Проверяем соединение с помощью
traceroute/pingи все тех же виртуальных машин
После всех проделанных ранее манипуляций у нас есть доступ к сетям аккаунтов common и dev с помощью VPN .
Данная конфигурация может быть масштабирована для других аккаунтов с иными правилами доступа и маршрутами в нашем terraform-коде.
Полезные ссылки
ссылка на оригинал статьи https://habr.com/ru/articles/585648/
Добавить комментарий