Appearance
AWS VPC (Virtual Private Cloud)
Si tuvieras tu propia infraestructura, tendrías un centro de datos con toda la arquitectura de una red que debe ser administrada y con ciertos servicios o recursos que se publican a través de Internet. Cuando pensamos en la nube de AWS no disponemos de una red visible en la cual accedemos a nuestros aparatos y servidores sino que se proporciona una red virtual en la nube o VPC (Virtual Private Cloud). De este modo se aislan los recursos disponibles para nuestra red en la nube.

Imagen tomada de
https://docs.aws.amazon.com
Para comprender los elementos claves de una VPC debemos considerar los siguientes conceptos:
- Region: Corresponde a la división y sección definida por AWS para disponer de la infraestructura cercana a nuestra ubicación.
- Zonas de disponibilidad (AZ - Availability Zone): Son zonas que se encuentran dentro de la misma región definida, obteniendo por ejemplo, Zona 1 y Zona 2.
- Subredes: Si comprendemos que una VPC es una red en la nube, AWS nos proporciona también subredes, podemos definir una subred de tipo pública y privada. De este modo, una página web estaría en un recurso que corresponda la subred pública (la cual tiene salida por medio de un Gateway de Internet), mientras en la subred privada podemos colocar nuestra base de datos.
- Instancias de Computo: Correspondería a nuestro mecanismo de computo, semejante a una máquina virtual o VPS (Virtual Private Server), sobre la cual se basan varios servicios de AWS. Las instancias corren en una subred de nuestra VPC.
Una VPC estaría en una sola región y es transversal a las subredes, es decir, mi VPC puede conformarse por 2 zonas de disponibilidad y tener cada una de éstas 2 subredes, en las cuales puede variar el número de instancias de computo. Se puede definir otra VPC para otras regiones.
Otros conceptos claves más avanzados que podemos encontrar cuando definimos instancias de computo en nuestra VPC serían los siguientes:
- Internet Gateway: Se trata del componente que encamina la salida a Internet para exponer componentes que se encuentra en una red privada virtual pública.
- Classless Inter-Domain Routing (CIDR): Se refiere a los rangos asignados para establecer una serie de números de IP (Internet Protocol) a los dispositivos o servicios de nuestra red privada virtual.
- NAT Gateway: Cuando tenemos una subred privada es neceario el redireccionamiento entre subredes mediante un NAT Gateway.
- Network ACLs: Puede verse como un Firewall con reglas a nivel de subred.
- Security Groups: Puede verse como un Firewall con reglas a nivel de instancia de computo. Por ejemplo, para abrir el puerto de un servicio web (80, 443) y exponerlo a Internet.

Imagen tomada de
https://docs.aws.amazon.com
Puedes administrar t VPC desde la consola web de AWS con la opción VPC Dashboard.
Ejemplo de VPC con CloudFormation
El siguiente contenido nos puede servir para preparar la configuración de Networking (red) en la nube de AWS que se organiza a partir de una VPC (Virtual Private Cloud). Esta configuración se puede definr con AWS Cloudformation.
Para ello, abrimos un nuevo archivo, por ejemplo cf-vpc-net.yaml, y copiamos dentro cada trozo o bloque a continuación. Comenzaremos por definir el encabezado con los atributos AWSTemplateFormatVersion y Description, así:
yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Network Stack for AWS Services'A continuación especificamos parámetros usando el atributo Parameters de la siguiente manera:
yaml
Parameters:
EnvironmentName:
Description: An environment name that is used in resource names
Type: String
Default: Lab
VpcCIDR:
Description: The IP range (CIDR notation) for this VPC
Type: String
Default: 10.0.0.0/16
PublicSubnet1CIDR:
Description: The IP range (CIDR notation) for the public subnet in the first Availability Zone
Type: String
Default: 10.0.1.0/24
PublicSubnet2CIDR:
Description: The IP range (CIDR notation) for the public subnet in the second Availability Zone
Type: String
Default: 10.0.2.0/24
PrivateSubnet1CIDR:
Description: The IP range (CIDR notation) for the private subnet in the first Availability Zone
Type: String
Default: 10.0.3.0/24
PrivateSubnet2CIDR:
Description: The IP range (CIDR notation) for the private subnet in the second Availability Zone
Type: String
Default: 10.0.4.0/24Nótese que cada parámetro se define bajo su propio nombre con propiedades como
DescriptionyType(ejemplo:String).
Es conveniente un valor por defecto (usandoDefault) de ser posible.
Iniciamos el bloque Resources definiendo el recurso para la VPC (de tipo AWS::EC2::VPC), es decir, asignamos un nombre lógico o etiqueta para una nube privada virtual (que comprenderá componentes de red en AWS)...
yaml
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCIDR
EnableDnsHostnames: true
EnableDnsSupport: true
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub VPC-${EnvironmentName}Semejante a
Parameters, cada recurso se define bajo su propio nombre y tendrá unas propiedades dependiendo delType.
La propiedadCidrBlocktendrá el valor referido en el parámetroVpcCIDRy por defecto sería10.0.0.0/16.
Nótese que encontramos la función intrínseca !Ref que se usa para referenciar recursos o parámetros a partir del nombre especificado. También encontramos la función !Sub que se usa para sustituir expresiones que incluyen variables reflejando su valor, por ejemplo el uso de ${EnvironmentName}
Continuamos con el recurso para Internet Gateway (puerta de enlace a internet), el cual da paso a la comunicación de la VPC hacia Internet...
yaml
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub IGW-${EnvironmentName}
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPCNo solo se crea el recurso de tipo
AWS::EC2::InternetGatewaysino que también es necesario asociarlo a la VPC (asignando enVpcIdel valor obtenido en el recursoVPC)
Podemos definir inicialmente una tabla de enrutamiento con una ruta por defecto para establecer conectividad de red en la VPC. Esto permitirá que instancias en una subred pública puedan tener acceso a Internet a través de la puerta de enlace a internet (Internet Gateway). Veamos:
yaml
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Routes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGatewayNótese que
PublicRouteTablees de tipoAWS::EC2::RouteTabley se estable como rutaDefaultPublicRoutede tipoAWS::EC2::RoutecuyoDestinationCidrBlocksería0.0.0.0/0DependsOnse usa para indicar una dependencia, en este caso conInternetGatewayAttachment
En una VPC es común tener al menos dos subredes de tipo público y dos subredes de tipo privado, dado que cada una se ubicaría en un AZ (Zona de disponibilidad) de la Region (una región puede brindar dos zonas de disponibilidad). Ilustraremos esto en Cloudformation con el siguiente bloque...
yaml
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet1CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ1)
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs '' ]
CidrBlock: !Ref PublicSubnet2CIDR
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Public Subnet (AZ2)
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 0, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet1CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ1)
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [ 1, !GetAZs '' ]
CidrBlock: !Ref PrivateSubnet2CIDR
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Subnet (AZ2)Además de asignar
VpcIdes clave el atributoAvailabilityZone(que se resuelve obteniendo AZs) yCidrBlock, cuyos valores pueden ser por defecto10.0.1.0/24,10.0.2.0/24,10.0.3.0/24y10.0.4.0/24repectivamente.
Será necesario incorporar algún NAT (Network Address Translation), el cual actua como traductor entre redes privadas (sin acceso al público) y publicas (con acceso a Internet) tomando la IP privada de una red para trasladarla en una IP pública cuando se tiene una comunicación hacia el mundo (sin exponer la IP privada al público). Se pueden crear 2 NATs para cada subred pública y por tanto 2 IP públicas fijas (EIP) así:
yaml
NatGateway1EIP:
Type: AWS::EC2::EIP
DependsOn: InternetGatewayAttachment
Properties:
Domain: vpc
NatGateway2EIP:
Type: AWS::EC2::EIP
DependsOn: InternetGatewayAttachment
Properties:
Domain: vpc
NatGateway1:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGateway1EIP.AllocationId
SubnetId: !Ref PublicSubnet1
NatGateway2:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGateway2EIP.AllocationId
SubnetId: !Ref PublicSubnet2
!GetAttpermite recuperar el valor de la propiedad de un recurso, en este casoNatGateway1EIP.AllocationIdyNatGateway2EIP.AllocationIdpara asignarlo a la propieadadAllocationId.NatGateway1EIPyNatGateway2EIPson de tipoAWS::EC2::EIPy se refieren al servicio EIP (IP v4 fijas). Podría simplificarse a un EIP y NAT si hablamos de entornos No productivos.
Para dirigir el tráfico dentro de una VPC se crean tablas de enrrutamiento que habilitan destinos externos. Es necesario además asociar estas a las subredes a la ruta por defecto, que involucra el Internet Gateway (o un NAT en el caso de subredes privadas).
Veamos el escenario para asociar las dos subredes públicas involucrando la tabla de enrutamiento del Internet Gateway...
yaml
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2Este bloque de código se asocia con uno anterior en el que definimos previamente el
PublicRouteTableparaInternetGateway(podríamos organizar este código dejando estas definiciones conjuntamente con la asociada anteriormente)
Ahora veamos el escenario para las subredes privadas involucrando un NAT...
yaml
PrivateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ1)
DefaultPrivateRoute1:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable1
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway1
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable1
SubnetId: !Ref PrivateSubnet1
PrivateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ2)
DefaultPrivateRoute2:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable2
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway2
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PrivateRouteTable2
SubnetId: !Ref PrivateSubnet2En este caso,
PrivateRouteTable1yPrivateRouteTable2tendrían unDefaultPrivateRoute1yDefaultPrivateRoute2(respectivamente) en donde se referencia un NAT enNatGatewayIdy cuyoDestinationCidrBlocksería0.0.0.0/0
Para retornar ciertos valores de recursos que intervienen en el Stack (Pila), en el bloque final del archivo usaremos bajo el atributo Outputs un contenido como el siguiente...
yaml
Outputs:
VPC:
Description: A reference to the created VPC
Value: !Ref VPC
Export:
Name: !Sub VPCID-${EnvironmentName}
PublicSubnets:
Description: A list of the public subnets
Value: !Join [ ",", [ !Ref PublicSubnet1, !Ref PublicSubnet2 ]]
Export:
Name: !Sub PUBLIC-SUBNETS-${EnvironmentName}
PrivateSubnets:
Description: A list of the private subnets
Value: !Join [ ",", [ !Ref PrivateSubnet1, !Ref PrivateSubnet2 ]]
Export:
Name: !Sub PRIVATE-SUBNETS-${EnvironmentName}
PublicSubnet1:
Description: A reference to the public subnet in the 1st Availability Zone
Value: !Ref PublicSubnet1
Export:
Name: !Sub PUBLIC-SUBNET-AZ1-${EnvironmentName}
PublicSubnet2:
Description: A reference to the public subnet in the 2nd Availability Zone
Value: !Ref PublicSubnet2
Export:
Name: !Sub PUBLIC-SUBNET-AZ2-${EnvironmentName}
PrivateSubnet1:
Description: A reference to the private subnet in the 1st Availability Zone
Value: !Ref PrivateSubnet1
Export:
Name: !Sub PRIVATE-SUBNET-AZ1-${EnvironmentName}
PrivateSubnet2:
Description: A reference to the private subnet in the 2nd Availability Zone
Value: !Ref PrivateSubnet2
Export:
Name: !Sub PRIVATE-SUBNET-AZ2-${EnvironmentName}
!Joines usado para unir valores de una lista y expresarlos en una cadena usando un separador (,)
Finalmente, podemos crear un Stack (Pila) ejecutando un comando como el siguiente:
bash
aws cloudformation create-stack \
--stack-name my-vpc-net \
--template-body file://cf-vpc-net.yaml \
--region us-east-1
my-vpc-netse refiere al nombre asignado al Stack (Pila) ycf-vpc-net.yamlse refire el archivo elaborado.us-east-1sería la región respectiva.
Se podrían incorporar parámetros indicando por ejemplo:--parameters ParameterKey=EnvironmentName,ParameterValue=Test
Si se requiere deshacer el Stack (Pila), se puede ejecutar lo siguiente:
bash
aws cloudformation delete-stack --stack-name my-vpc-net --region us-east-1Ejemplo ajustado para VPC de pruebas
Para reducir costos, por usar doble EIP y NAT, cuando se trata de un entorno transitorio o de prueba se puede considerar la siguiente configuración (reemplazando los atributos respectivos)...
yaml
NatGatewayEIP:
Type: AWS::EC2::EIP
DependsOn: InternetGatewayAttachment
Properties:
Domain: vpc
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt NatGatewayEIP.AllocationId
SubnetId: !Ref PublicSubnet1
PrivateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ1)
PrivateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ2)
DefaultPrivateRoute1:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable1
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
DefaultPrivateRoute2:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable2
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGatewayTanto EIP como NatGateway aún pueden generar algún costo. Para evitar costos en un entorno de pruebas o laboratorio, se puede evitar el uso de EIP y remover el NatGateway siempre y cuando No se necesiten que en las redes privadas se tenga acceso a Internet. Y es que lo común es que se tenga acceso a Internet en los recursos de una subred pública y No en una subred privada (salvo excepciones como bases de datos). Siendo así el bloque de configuración anterior quedaría simplificado de la siguiente manera:
yaml
PrivateRouteTable1:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ1)
PrivateRouteTable2:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} Private Routes (AZ2)En este último escenario las subredes privadas No tendrían acceso a Internet por lo que no aplican los recursos:
NatGatewayEIP,NatGateway,DefaultPrivateRoute1,DefaultPrivateRoute1