Aller au contenu

Step 1-3 : VPC

Vous avez appris à déployer une application conteneurisée dans une instance EC2 qui regroupe votre front, votre api et votre base de donnée.

Jusqu'ici, vous avez tous utilisé le même réseau virtuel, le même VPC (Virtual Private Cloud). Celui automatiquement créé sur chaque compte par AWS. Il est fourni pour aider à faire ses débuts avec son compte AWS ou si l'on ne maîtrise pas encore ses stacks réseau. Un certain nombre de choix par défault y sont faits et l'on préfère souvent maitriser ses paramètres notamment les plages d'IPs et le découpage en sous-réseaux.

Concepts

VPC

Un VPC, ou Virtual Private Cloud, est un réseau virtuel. On peut y faire tourner nos serveurs isolés les uns des autres de façon logique, tout cela géré via API et avec la scalabilité d'infrastructure d'AWS, ce qui fait d'un VPC un SDN, Software-Defined Network. Plus besoin de gérer des datacenters classiques avec leurs gestions de baies, routeurs, câbles, firewalls, etc.

Vous avez un contrôle total sur votre réseau virtuel, y compris la sélection de vos propres plages d'adresses IPs (CIDR), la création de sous-réseaux et la configuration des tables de routage et des passerelles réseaux (gateways). Vous pouvez également connecter via VPN infrastructures ou datacenters existants à votre VPC. Vos serveurs communiquent comme s'ils étaient sur le même réseau.

Info

Un VPC est dans une région.

Chaque subnet est dans une AZ, availability zone. C'est dans ses subnets que l'on met nos machines virtuelles et autres services.

Le VPC par défaut fourni dans chaque région est composé d'un subnet publique fourni dans chaque AZ.

Voici les différentes fonctionnalités et concepts des VPC pour connecter vos applications et serveurs :

Fonctionnalité Description
VPC Un VPC est un réseau virtuel qui ressemble à un réseau traditionnel que vous exploiteriez dans un datacenter classique. Il est composé de sous-réseaux.
Subnet Un subnet est une plage d'adresses IP CIDR placée dans une AZ où l'on déploie nos resources.
Adressage IPs Les ranges IPv4 et IPv6 à vos VPC et sous-réseaux. Il est possible de ce servir de ses propres plages IPs publiques si on en a. (Bring your own IP addresses BYOIP)
Routage Les tables de routage permettent de déterminer vers où le trafic réseau des nos subnets et gateways est dirigé.
Gateways et Endpoints Une gateway connecte votre VPC à un autre réseau. Une gateway Internet peut connecter les VPCs à Internet. Les VPC endpoints eux permettent de se connecter aux services AWS en privé, sans gateway Internet ou NAT.
VPC Peering Permet d'interconnecter 2 VPCs
Traffic monitoring Permet de superviser et analyser en profondeur des flux en les copiant depuis les interfaces réseaux
Transit gateways Utilisez une passerelle de transit, qui fait office de hub central, pour acheminer le trafic entre vos VPC, vos connexions VPN et vos connexions AWS Direct Connect.
VPC flow logs Un journal de flux capture des informations sur le trafic IP entrant et sortant des interfaces réseau de votre VPC.
VPN connections Connectez vos VPC à vos réseaux sur site à l'aide d'AWS Virtual Private Network (AWS VPN).

Les types subnets

Il y a plusieurs types de subnets qui sont déterminés par la manière dont on configure les configure :

  • Subnet public : Il a une route directe vers une gateway Internet. Ses instances peuvent joindre internet.
  • Subnet privé : Il n'a pas de route directe vers une gateway Internet. Ses ressources nécessitent un périphérique NAT pour joindre internet.
  • Subnet VPN uniquement : Il ne dispose que d'une route vers une connexion VPN via une Virtual Private Gateway, VPG, et pas d'accès Internet.
  • Subnet isolé : Il n'a aucune route menant hors du VPC et ses ressources ne peuvent joindre et ne sont accessibles que par d'autres ressources du VPC.

L'Internet Gateway est le composant AWS permettant aux instances/interfaces avec une IP publique dans un subnet de joindre internet. Il faut également avoir une règle sur la table de routage associé à votre subnet pointant sur cette gateway.

Info

C'est le fait d'être associé à une route table avec une règle de routage de sortie pointant vers une Internet Gateway qui fait de votre subnet un subnet public. Plus d'informations ici

Par sécurité, pour éviter que son instance soit joignable depuis internet et aussi éviter de payer trop d'IPs publiques (c'est payant maintenant oui), on préfère ne pas mettre nos instances dans des subnets publiques, des subnets isolés. Il est cependant fréquent d'avoir besoin de joindre internet (update de paquets, installation d'outils etc). Dans ce cas, il faut mettre en place une NAT Gateway publique que l'on place dans un subnet publique puis configurer la table de routage du subnet en question pour faire sortir les flux internet vers la NAT Gateway.

Info

C'est avoir une règle de routage de sortie pointant vers une NAT Gateway qui fait de votre subnet un subnet privé. Plus d'informations ici

Sécurité

Les VPC disposent de plusieurs couches de sécurité, les groupes de sécurité (SG/security group) et des listes de contrôle d'accès (ACL), permettant de contrôler les accès aux instances dans chaque subnet.

Les security group fonctionnent au niveau de l'instance et les networks ACL au niveau du subnet.

Un security group est un firewall virtuel permettant de contrôler le trafic entrant et sortant de vos instances EC2, de leurs cartes réseaux plus précisément. Un security group est dans un seul VPC mais on peut associer plusieurs security groups à une instance.

Pour les deux, on y définit des règles entrantes (Ingress) et sortantes (Egress) où l'on spécifie les protocols et ports des flux que l'on souhaite autoriser. Pour les sources/destinations, on définit des plages CIDR mais les security groups permettent aussi surtout les instances associées aux security groups eux-mêmes, permettant ainsi une meilleure flexibilité et simplifiant la micro-segmentation.

Les security groups sont stateful, ils traquent les connexions autorisées et autorisent le flux retour automatiquement. Ce n'est pas le cas des networks ACL qui sont stateless et pour lesquels on doit penser à déclarer le flux retour. On peut changer les règles à chaud d'un security group, mais les connexions déjà traquées ne sont pas immédiatement intérrompues contrairement aux changements sur les networks ACL.

Les ACL et security groups viennent tous les deux sans surcoûts.

Tip

Pour ce TP et de façon générale nous préférons sécuriser nos instances en utilisant uniquement des security groups. Toutefois, les network ACL proposent pour une couche de défense supplémentaire. Vous trouverez une comparaison plus détaillée entre les security groups et network ACL ici.

Les security groups permettent une approche micro-segmentation dans un esprit Zero Trust.

TP

Step1-3-1 : VPC + subnet public

Pour commencer, vous allez refaire le déploiement de votre ec2 et ses conteneurs, mais cette fois-ci dans votre propre VPC à l'image de celui fourni.

Faites un nouveau dossier nommé Step1-3-1

  • Créez votre VPC : CIDR 10.32.0.0/16 avec support les dns hostnames et support
  • Créez votre subnet public qui dépend de votre VPC avec un CIDR en 10.32.0.0/20 et votre AZ en eu-west-3a
  • Créez une internet gateway pour votre vpc
  • Créez une route table dirigeant le range 0.0.0.0/0 vers de votre internet gateway
  • Associez votre route table et votre subnet
  • Créez votre security group qui va accépter les connection ssh (port 22), sur le port 80 et sur le port 8080 de n'importe où (0.0.0.0/0) et un egress vers n'importe où
  • Mettez votre instance EC2 dans votre nouveau subnet/VPC

Success

Vous devriez avoir de nouvelles resources terraform:

Step1-3-2 : Subnet privé + split

L'idée de cette étape est maintenant de créer notre premier subnet privé afin d'y mettre la base de donnée.

Cela implique déjà de séparer les services. Nous allons désormais faire 3 instances, back, front et DB.

Reprenez l'étape précédente dans un nouveau dossier nommé Step1-3-2 :

  • Créez votre nouveau subnet privé avec un CIDR en 10.32.16.0/20 et votre AZ en eu-west-3a
  • Allouez une Elastic IP nécessaire pour la gateway
  • Créez une NAT Gateway dans le subnet publique
  • Créez une nouvelle route table qui sera pour les subnets privés dirigeant le range 0.0.0.0/0 vers votre NAT gateway
  • Associez votre route table privée et votre subnet privé
  • Dupliquez votre instance en 3, une instance par service ainsi que les security_groups associés. Pensez Least privilege !

Tip

Les security groups permettent d'autoriser d'autres sécurity groups. Ici on peut n'autoriser les flux vers la DB sur le port 5432 que pour les instances ayant le security group de l'api

Template aws-user-data.sh.tftpl

Pour éviter de dupliquer tout le script nous allons en faire un template que l'on va résoudre avec paramètres.

Dans Terraform les templates s'utilisent via la fonction templatefile.

Le template que l'on vous fourni possède plusieurs variables à définir et voici les snippets :

user_data = templatefile("scripts/aws-user-data.sh.tftpl", {
  container_name         = "db"
  image                  = "registry.takima.io/school/proxy/postgres:14"
  port_mapping           = "5432:5432"
  enable_disk_mount      = true
  environments_variables = <<EOF
    POSTGRES_USER=myuser
    POSTGRES_PASSWORD=mypassword
    POSTGRES_DB=mydb
    PGDATA=/var/lib/postgresql/data/pgdata
  EOF
})
user_data = templatefile("scripts/aws-user-data.sh.tftpl", {
  container_name         = "api"
  image                  = "registry.gitlab.com/takima-school/images/cdb/api:latest"
  port_mapping           = "80:8080"
  enable_disk_mount      = false
  environments_variables = <<EOF
    POSTGRES_USER=myuser
    POSTGRES_PASSWORD=mypassword
    POSTGRES_DB=mydb
    DB_ENDPOINT=${aws_instance.db.private_ip}:5432
  EOF
})
user_data = templatefile("scripts/aws-user-data.sh.tftpl", {
  container_name         = "front"
  image                  = "registry.gitlab.com/takima-school/images/cdb/www:latest"
  port_mapping           = "80:8080"
  enable_disk_mount      = false
  environments_variables = <<EOF
    API_URL=http://${aws_instance.api.public_ip}:80
  EOF
})

Voici le template lui-même :

scripts/aws-user-data.sh.tftpl
#! /bin/bash

# Install docker https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository
apt-get update
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io

# Docker post install configuration
groupadd docker
usermod -aG docker ubuntu
newgrp docker

# Start docker service
systemctl start docker.service
systemctl start containerd.service

# Configure Docker to start on boot
systemctl enable docker.service
systemctl enable containerd.service

%{if enable_disk_mount}
# Initialize disk
export DEVICE_NAME="xvdf"
export DEVICE_PATH="/dev/$DEVICE_NAME"
export FSTYPE="ext4"
export MOUNT_FOLDER="/data"

while ! ls $DEVICE_PATH > /dev/null
do
  sleep 5
done

if ! lsblk -o NAME,FSTYPE | grep $DEVICE_NAME | grep $FSTYPE; then
  mkfs -t $FSTYPE $DEVICE_PATH
fi

mkdir $MOUNT_FOLDER
mount $DEVICE_PATH $MOUNT_FOLDER
echo "$DEVICE_PATH $MOUNT_FOLDER $FSTYPE defaults,nofail 0 2" >> /etc/fstab
%{endif}

# Use a private registry (Secret management simplified here, not a best practice)
docker login registry.gitlab.com -p "5t9L4Z9BXvPopSAdysVs" -u "readregcred"

# Setup environment variables
cat >/home/ubuntu/.env <<EOL
${environments_variables}
EOL

# Create and start the containers
docker run -d --name ${container_name} --restart always -p ${port_mapping} --env-file /home/ubuntu/.env %{if enable_disk_mount}-v $MOUNT_FOLDER:/var/lib/postgresql/data %{endif} ${image}

Warning

La DB étant dans un subnet privé on ne peut plus la joindre en SSH directement !

Vous pouvez "Jump" sur une de vos autres instances via cette commande :

ssh -J ec2-user@IP_PUBLIQUE_DU_FRONT ec2-user@IP_PRIVEE_DANS_LE_SUBNET_PRIVE

Success

Vous devriez avoir de nouvelles resources terraform:

  • aws_eip
  • aws_nat_gateway
  • un nouveau subnet privé et la route_table table associée
  • les nouvelles instances ainsi que les security groups adaptés.

Warning

Pensez à détruire votre infra

terraform destroy