Как стать автором
Обновить

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

Время на прочтение7 мин
Количество просмотров4.9K
Автор оригинала: Amet Umerov

В этом туториале я опишу простую и безопасную настройку мультиаккаунтной инфраструктуры, основанной на 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-коде.

Полезные ссылки

Теги:
Хабы:
Всего голосов 4: ↑4 и ↓0+4
Комментарии4

Публикации

Истории

Работа

Ближайшие события