Настройка AWS SSO с AWS Client VPN

от автора

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

Введение

Я разбил статью на несколько основных частей:

  • Во-первых, я покажу как создать инфраструктуру в AWS с нуля, с безопасной структурой аккаунтов, сетей, пирингов

  • Вторая часть этой статьи посвящена AWS SSO: пользователям, группам, MFA, и т.д.

  • Третья часть описывает процесс развертывания сервиса AWS VPN с помощью terraform и его настройки для ранее созданных сетей

Начнем!

Структура AWS-аккаунтов

Мультиаккаунтная структура для AWS имеет ряд преимуществ. Я не буду на них останавливаться, только покажу пример:

Структура аккаунтов
Структура аккаунтов

Аккаунт root является главным в организации (на него привязывается биллинг), все остальные аккаунты добавляются под руководство этого аккаунта.

Каждый аккаунт привязан к разному почтовому адресу, но обычно можно использовать почтовые алиасы для удобства управления с одного почтового ящика.

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

https://console.aws.amazon.com/organizations/v2/home/accounts
https://console.aws.amazon.com/organizations/v2/home/accounts

Этого достаточно на текущий момент, можем идти дальше.

Сетевая структура

В моем примере аккаунты 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.

Не забываем включать MFA для пользователя
Не забываем включать MFA для пользователя

Итак, мы подготовили группы и пользователя, самое время создать новое 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-devvpn-stagevpn-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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *