(Esta imagen se creó con la ayuda de Stable Diffusion)
He trabajado con clientes que alojan su base de datos Amazon RDS en una subnet de VPC con una ruta predeterminada hacia internet.
Puede que existan medidas de seguridad, como tener desactivada la opción "publicly accessible" de RDS; reglas de entrada del Security Group restringidas únicamente a las EC2 o Lambda permitidas; y reglas stateful del firewall que detectan amenazas y exploits mediante firmas de SQL. Sin embargo, incidentes como el data breach de Target Corporation en 2013 demuestran que bloquear el tráfico entrante de internet mientras se permite todo el saliente ya no es suficiente para minimizar el riesgo de exfiltración de datos. Un actor malicioso, como un malware de command-and-control (también conocido como C&C o C2), puede aprovechar el tráfico saliente por puertos de uso común como HTTP:80 y HTTPS:443 para hacer beaconing.
Este artículo describe los pasos para mover una instancia de Amazon RDS desde una subnet pública con una tabla de rutas conectada a internet hacia una subnet aislada, sin necesidad de crear una nueva instancia de DB mediante snapshot-restore.
Cualquier VPC puede tener 3 tipos de subnet: una subnet pública, que tiene un internet gateway asociado para permitir tráfico entrante y saliente; una subnet privada, que cuenta con un Network Address Translation (NAT) o un Internet Egress-only gateway para permitir tráfico saliente; y una subnet aislada, que solo permite tráfico dentro de la VPC y no tiene rutas hacia destinos fuera de ella.
Alojar la base de datos en una subnet aislada ayuda a reducir el riesgo de exfiltración de datos, ya que reduce la superficie de ataque y le dificulta a un atacante, como un malware C&C, encontrar la forma de exfiltrar la información.
Eso sí, ten en cuenta que el aislamiento de red es solo una de las medidas de seguridad importantes para reducir el riesgo, pero no es infalible para prevenir la exfiltración de datos. Una cadena es tan fuerte como su eslabón más débil. Cada medida que se sume cuenta.
Configuración del entorno de prueba con Amazon RDS Multi-AZ
Para seguir los pasos de mover la instancia RDS de una subnet pública a una aislada, vas a necesitar un entorno de prueba que conste de un Amazon RDS en las subnets públicas de una VPC. La VPC tendrá subnets públicas y aisladas.
Si ya cuentas con instancias de Amazon RDS en subnets públicas y tu VPC tiene subnets aisladas, puedes saltarte el paso de creación de la VPC.
Vamos a crear los recursos de AWS con CDK. Si CDK es nuevo para ti, puedes comenzar siguiendo https://docs.aws.amazon.com/cdk/v2/guide/hello_world.htm.
Stack de CDK que crea una VPC
El primer paso para configurar el entorno de prueba es crear una VPC con una subnet pública y otra aislada en cada Availability Zone, distribuidas en dos Availability Zones, usando el siguiente stack de CDK.
Vamos a exportar los parámetros necesarios de la VPC, como el VPC ID, para poder importarlos en el stack que crea el RDS en el siguiente paso.
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
const app = new cdk.App();
const vpcStack = new cdk.Stack(app, "vpc-stack");
const vpc = new cdk.aws_ec2.Vpc(vpcStack, `test-vpc`, {
ipAddresses: cdk.aws_ec2.IpAddresses.cidr("10.0.0.0/20"),
vpcName: `test-vpc`,
enableDnsHostnames: true,
enableDnsSupport: true,
maxAzs: 2,
subnetConfiguration: [\
{\
name: "public",\
subnetType: cdk.aws_ec2.SubnetType.PUBLIC,\
cidrMask: 27\
},\
{\
name: "isolated",\
subnetType: cdk.aws_ec2.SubnetType.PRIVATE_ISOLATED,\
cidrMask: 27\
},\
]
});
new cdk.CfnOutput(
vpcStack, 'testVpcVpcID', {
value: vpc.vpcId,
description: 'Test Vpc ID',
exportName: 'test-vpc-VpcID',
});
new cdk.CfnOutput(
vpcStack, 'testVpcAz', {
value: vpc.availabilityZones.join(","),
description: 'Vpc AZs',
exportName: 'test-Vpc-AZs',
});
new cdk.CfnOutput(
vpcStack, 'testVpcPublicSubnets', {
value: vpc.selectSubnets({
subnetType: cdk.aws_ec2.SubnetType.PUBLIC
}).subnetIds.join(","),
description: 'Vpc Public Subnet IDs',
exportName: 'test-Vpc-PublicSubnetIds',
});
new cdk.CfnOutput(
vpcStack, 'testVpcIsolatedSubnets', {
value: vpc.selectSubnets({
subnetType: cdk.aws_ec2.SubnetType.PRIVATE_ISOLATED
}).subnetIds.join(","),
description: 'Vpc Isolated Subnet IDs',
exportName: 'test-Vpc-IsolatedSubnetIds',
});
Si cdk deploy vpc-stack se ejecuta con éxito, deberías ver salidas como las siguientes:
✅ vpc-stack
✨ Deployment time: 76.83s
Outputs:
vpc-stack.testVpcAz = us-east-1a,us-east-1b
vpc-stack.testVpcIsolatedSubnets = subnet-03e58f5428463ad26,subnet-06721c9fdaac5f333
vpc-stack.testVpcVpcID = vpc-090949477d23289ce
vpc-stack.testeVpcPublicSubnets = subnet-0271290b1164913ad,subnet-079b9aaba653c430b
Anota el VPC ID, los IDs de las subnets públicas y los de las subnets aisladas.
En este ejemplo, estos son los parámetros que vamos a usar al crear el Amazon RDS:
- VPC ID:
vpc-090949477d23289ce - IDs de subnets públicas:
subnet-0271290b1164913ad,subnet-079b9aaba653c430b - IDs de subnets aisladas:
subnet-06721c9fdaac5f333,subnet-03e58f5428463ad26
Stack de CDK que crea Amazon RDS
A continuación, vamos a aprovisionar un Amazon Postgres RDS en la subnet pública de la VPC:
Tip rápido sobre CDK:
cdk.Fn.importValue()es un atributo de late-binding. Por eso conviene usar la función de split de strings de CloudFormationcdk.Fn.Split()en lugar del split nativo de TypeScript, comocdk.Fn.importValue(‘test-Vpc-AZs’).split(","), que provocaría errores comoSome input subnets in :[subnet-0271290b1164913ad,subnet-079b9aaba653c430b] are invalid.
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
const app = new cdk.App();
const rdsStack = new cdk.Stack(app, "rds-stack");
const vpcLookup = cdk.aws_ec2.Vpc.fromVpcAttributes(
rdsStack, `${rdsStack.stackName}-vpc-lookup`,
<cdk.aws_ec2.VpcAttributes>{
vpcId: cdk.Fn.importValue('test-vpc-VpcID'),
availabilityZones: cdk.Fn.split(",",cdk.Fn.importValue('test-Vpc-AZs')),
publicSubnetIds: cdk.Fn.split(",",cdk.Fn.importValue('test-Vpc-PublicSubnetIds')),
isolatedSubnetIds: cdk.Fn.split(",",cdk.Fn.importValue('test-Vpc-IsolatedSubnetIds'))
});
const subnetType: cdk.aws_ec2.SubnetSelection = { subnetType: cdk.aws_ec2.SubnetType.PUBLIC };
const subnetGroup = new cdk.aws_rds.SubnetGroup(
rdsStack, `${rdsStack.stackName}-rds-subnetgroup`,
<cdk.aws_rds.SubnetGroupProps>{
subnetGroupName: `${rdsStack.stackName}-rds-subnetgroup`,
vpc: vpcLookup,
vpcSubnets: {
subnets: vpcLookup.selectSubnets(subnetType).subnets
},
description: "RDS subnetgroup"
});
const rdsInstance = new cdk.aws_rds.DatabaseInstance(
rdsStack, `${rdsStack.stackName}-rdsInstance`,
<cdk.aws_rds.DatabaseInstanceProps>{
engine: cdk.aws_rds.DatabaseInstanceEngine.postgres({
version: cdk.aws_rds.PostgresEngineVersion.VER_15_3
}),
vpcLookup,
subnetGroup: subnetGroup,
publiclyAccessible: false,
multiAz: true,
credentials: cdk.aws_rds.Credentials.fromSecret(
new cdk.aws_rds.DatabaseSecret( rdsStack, `${rdsStack.stackName}-database-secret`,
<cdk.aws_rds.DatabaseSecretProps>{
username: "dbMaster",
secretName: `dbMaster-credential`,
}
)
),
instanceIdentifier: `${rdsStack.stackName}-rds`,
instanceType: cdk.aws_ec2.InstanceType.of(cdk.aws_ec2.InstanceClass.BURSTABLE4_GRAVITON, cdk.aws_ec2.InstanceSize.MICRO),
storageType: cdk.aws_rds.StorageType.GP3,
});
new cdk.CfnOutput(
rdsStack, `${rdsStack.stackName}-rds-name`, {
value: rdsInstance.instanceIdentifier,
description: 'RDS instance identifier'
});
new cdk.CfnOutput(
rdsStack, `${rdsStack.stackName}-subnetgroup-name`, {
value: subnetGroup.subnetGroupName,
description: "RDS Subnet Group Name"
});
Si ya tienes una VPC en la que quieras crear el RDS, modifica vpcLookup con los valores correspondientes; por ejemplo:
const vpcLookup = cdk.aws_ec2.Vpc.fromVpcAttributes(rdsStack, `${rdsStack.stackName}-vpc-lookup`, {
vpcId: "vpc-090949477d23289ce",
availabilityZones: ["us-east-1a", "us-east-1b"],
publicSubnetIds: ["subnet-0271290b1164913ad", "subnet-079b9aaba653c430b"],
isolatedSubnetIds: ["subnet-03e58f5428463ad26", "subnet-06721c9fdaac5f333"],
});
Si cdk deploy rds-stack se ejecuta correctamente, deberías ver salidas como las siguientes:
✅ rds-stack
✨ Deployment time: 20.95s
Outputs:
rds-stack.rdsstackrdsname = rds-stack-rds
¿Qué creamos hasta ahora?
Creamos una VPC con dos Availability Zones. Cada zona tiene una subnet pública y una aislada.
También aprovisionamos un Amazon RDS multi-AZ en la subnet pública de ambas Availability Zones.

RDS Multi-AZ en subnets públicas
Mover Amazon RDS de subnet pública a subnets aisladas
Tenemos un RDS Subnet Group compuesto por varias subnets, una por cada Availability Zone; por ejemplo, la instancia primaria en AZ-1 y la instancia standby en AZ-2.
Sin embargo, para cambiar la subnet de cada instancia tenemos que eliminar la instancia que está usando esa subnet. De lo contrario, si intentamos modificar la subnet con una instancia RDS activa en ella, se produce un error:
An error occurred (InvalidParameterValue) when calling the ModifyDBSubnetGroup operation: Some of the subnets to be deleted are currently in use: subnet-0271290b1164913ad
Resumen de los pasos para mover el Amazon RDS de la subnet pública a la subnet aislada:
- Detener la instancia standby para liberar la subnet pública, de modo que el RDS subnet group pueda reemplazar esa subnet pública por la aislada antes de redesplegar la instancia standby en la subnet aislada.
- Promover la standby a primaria y repetir el mismo proceso con la nueva instancia standby (la antigua primaria).
- Actualizar el estado de CDK.
Paso 1: mover la instancia standby
Antes de empezar, hay que capturar algunos parámetros clave:
Anota la subnet de las instancias RDS primaria y standby
Ejecuta este comando de AWS CLI para consultar la Availability Zone primaria y la secundaria:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone}" --output table
------------------------------
| DescribeDBInstances |
+-------------+--------------+
| Primary | Standby |
+-------------+--------------+
| us-east-1a | us-east-1b |
+-------------+--------------+
Mapea la Availability Zone con las subnets del RDS Subnet Group con el siguiente comando del CLI:
% aws rds describe-db-subnet-groups --db-subnet-group rds-stack-rds-subnetgroup --query "DBSubnetGroups[*].Subnets[*].{AvailabilityZone:SubnetAvailabilityZone.Name,SubnetIdentifier:SubnetIdentifier}" --output table
--------------------------------------------------
| DescribeDBSubnetGroups |
+-------------------+----------------------------+
| AvailabilityZone | SubnetIdentifier |
+-------------------+----------------------------+
| us-east-1b | subnet-079b9aaba653c430b |
| us-east-1a | subnet-0271290b1164913ad |
+-------------------+----------------------------+
A partir de estas 2 salidas, podemos concluir que:
- La instancia RDS primaria está en
subnet-0271290b1164913ad. - La instancia RDS standby está en
subnet-079b9aaba653c430b.
Detén la instancia standby y cambia la subnet
Modifica la instancia RDS con el comando del CLI modify-db-instance, como se muestra a continuación:
% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --no-multi-az --apply-immediately --query "DBInstance.MultiAZ"
true
Para confirmar que la instancia RDS quedó como single AZ, vuelve a ejecutar el CLI describe-db-instances:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone}" --output table
---------------------------
| DescribeDBInstances |
+-------------+-----------+
| Primary | Standby |
+-------------+-----------+
| us-east-1a | None |
+-------------+-----------+
Actualiza el RDS Subnet Group para reemplazar la subnet pública de la standby eliminada por una subnet aislada de la misma Availability Zone.
% aws rds modify-db-subnet-group --db-subnet-group-name rds-stack-rds-subnetgroup --subnet-ids "subnet-0271290b1164913ad" "subnet-06721c9fdaac5f333"
{
"DBSubnetGroup": {
"DBSubnetGroupName": "rds-stack-rds-subnetgroup",
"DBSubnetGroupDescription": "RDS subnetgroup",
"VpcId": "vpc-090949477d23289ce",
"SubnetGroupStatus": "Complete",
"Subnets": [\
{\
"SubnetIdentifier": "subnet-0271290b1164913ad",\
"SubnetAvailabilityZone": {\
"Name": "us-east-1a"\
},\
"SubnetOutpost": {},\
"SubnetStatus": "Active"\
},\
{\
"SubnetIdentifier": "subnet-06721c9fdaac5f333",\
"SubnetAvailabilityZone": {\
"Name": "us-east-1b"\
},\
"SubnetOutpost": {},\
"SubnetStatus": "Active"\
}\
],
"DBSubnetGroupArn": "arn:aws:rds:us-east-1:825202810339:subgrp:rds-stack-rds-subnetgroup",
"SupportedNetworkTypes": [\
"IPV4"\
]
}
}
Confirma el RDS Subnet Group con el comando describe-db-subnet-groups:
% aws rds describe-db-subnet-groups --db-subnet-group rds-stack-rds-subnetgroup --query "DBSubnetGroups[*].Subnets[*].{AvailabilityZone:SubnetAvailabilityZone.Name,SubnetIdentifier:SubnetIdentifier}" --output table
--------------------------------------------------
| DescribeDBSubnetGroups |
+-------------------+----------------------------+
| AvailabilityZone | SubnetIdentifier |
+-------------------+----------------------------+
| us-east-1a | subnet-0271290b1164913ad |
| us-east-1b | subnet-06721c9fdaac5f333 |
+-------------------+----------------------------+
Vuelve a habilitar el despliegue Multi-AZ con el comando modify-db-instance:
% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --multi-az --apply-immediately --query "DBInstance.MultiAZ"
false
La modificación puede tardar un poco; puedes monitorearla a través de DBInstanceStatus:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone}" --output table
----------------------------------------
| DescribeDBInstances |
+------------+-----------+-------------+
| Primary | Standby | Status |
+------------+-----------+-------------+
| us-east-1a| None | modifying |
+------------+-----------+-------------+
Confirma que la instancia standby ya se creó con describe-db-instances:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone}" --output table
-------------------------------------------
| DescribeDBInstances |
+------------+--------------+-------------+
| Primary | Standby | Status |
+------------+--------------+-------------+
| us-east-1a| us-east-1b | available |
+------------+--------------+-------------+
¿Qué tenemos ahora?
Movimos la instancia standby de la Availability Zone secundaria desde la subnet pública a la subnet aislada.

RDS Multi-AZ con la primaria en la subnet pública y la standby en la subnet aislada
Paso 2: promover la standby y mover la antigua primaria
Anota el endpoint del RDS para asegurarte de que la dirección no cambie tras el failover y se mantenga la disponibilidad:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone,Endpoint:Endpoint.Address}" --output table
-----------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+---------------------------------------------------------+-------------+-------------+-------------+
| Endpoint | Primary | Standby | Status |
+---------------------------------------------------------+-------------+-------------+-------------+
| rds-stack-rds.cmkhfj0htgnu.us-east-1.rds.amazonaws.com | us-east-1a | us-east-1b | available |
+---------------------------------------------------------+-------------+-------------+-------------+
Nota: reinicia la instancia durante una ventana de mantenimiento o en horarios de baja demanda, ya que las instancias quedarán temporalmente fuera de servicio durante el reinicio.
Reinicia la instancia RDS con el parámetro --force-failover:
aws rds reboot-db-instance --db-instance-identifier rds-stack-rds --force-failover
Confirma el failover con describe-db-instances:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone,Endpoint:Endpoint.Address,MultiAZ:MultiAZ}" --output table
----------------------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
| Endpoint | MultiAZ | Primary | Standby | Status |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
| rds-stack-rds.cmkhfj0htgnu.us-east-1.rds.amazonaws.com | True | us-east-1b | us-east-1a | available |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
Elimina la nueva standby (la antigua primaria) que está en la subnet pública
Con la nueva primaria ya en la subnet aislada, procede a eliminar la nueva instancia standby (la que acaba de ser degradada):
% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --no-multi-az --apply-immediately --query "DBInstance.MultiAZ"
true
La instancia RDS quedará ahora en estado modifying:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone,Endpoint:Endpoint.Address,MultiAZ:MultiAZ}" --output table
----------------------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
| Endpoint | MultiAZ | Primary | Standby | Status |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
| rds-stack-rds.cmkhfj0htgnu.us-east-1.rds.amazonaws.com | True | us-east-1b | us-east-1a | modifying |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
Una vez que la instancia RDS pase a estado available, la subnet de la standby quedará liberada para el siguiente paso:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone,Endpoint:Endpoint.Address,MultiAZ:MultiAZ,Pending:PendingModifiedValues}" --output table
-------------------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+---------------------------------------------------------+----------+-------------+----------+-------------+
| Endpoint | MultiAZ | Primary | Standby | Status |
+---------------------------------------------------------+----------+-------------+----------+-------------+
| rds-stack-rds.cmkhfj0htgnu.us-east-1.rds.amazonaws.com | False | us-east-1b | None | available |
+---------------------------------------------------------+----------+-------------+----------+-------------+
Procede a modificar el RDS subnet group para cambiar la subnet pública por la subnet aislada:
% aws rds modify-db-subnet-group --db-subnet-group-name rds-stack-rds-subnetgroup --subnet-ids "subnet-03e58f5428463ad26" "subnet-06721c9fdaac5f333"
{
"DBSubnetGroup": {
"DBSubnetGroupName": "rds-stack-rds-subnetgroup",
"DBSubnetGroupDescription": "RDS subnetgroup",
"VpcId": "vpc-090949477d23289ce",
"SubnetGroupStatus": "Complete",
"Subnets": [\
{\
"SubnetIdentifier": "subnet-06721c9fdaac5f333",\
"SubnetAvailabilityZone": {\
"Name": "us-east-1b"\
},\
"SubnetOutpost": {},\
"SubnetStatus": "Active"\
},\
{\
"SubnetIdentifier": "subnet-03e58f5428463ad26",\
"SubnetAvailabilityZone": {\
"Name": "us-east-1a"\
},\
"SubnetOutpost": {},\
"SubnetStatus": "Active"\
}\
],
"DBSubnetGroupArn": "arn:aws:rds:us-east-1:825202810339:subgrp:rds-stack-rds-subnetgroup",
"SupportedNetworkTypes": [\
"IPV4"\
]
}
}
Vuelve a desplegar el RDS multi-AZ:
% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --multi-az --apply-immediately
La instancia RDS quedará en estado modifying, con los valores de MultiAZ pendientes de aplicarse:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone,Endpoint:Endpoint.Address,MultiAZ:MultiAZ,NewValue:PendingModifiedValues}" --output table
-------------------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+---------------------------------------------------------+----------+-------------+----------+-------------+
| Endpoint | MultiAZ | Primary | Standby | Status |
+---------------------------------------------------------+----------+-------------+----------+-------------+
| rds-stack-rds.cmkhfj0htgnu.us-east-1.rds.amazonaws.com | False | us-east-1b | None | modifying |
+---------------------------------------------------------+----------+-------------+----------+-------------+
|| NewValue ||
|+------------------------------------------------------------+--------------------------------------------+|
|| MultiAZ | True ||
|+------------------------------------------------------------+--------------------------------------------+|
Cuando la instancia RDS quede en available, la nueva standby se desplegará en la subnet aislada:
% aws rds describe-db-instances --db-instance-identifier rds-stack-rds --query "DBInstances[*].{Status:DBInstanceStatus,Primary:AvailabilityZone,Standby:SecondaryAvailabilityZone,Endpoint:Endpoint.Address,MultiAZ:MultiAZ,NewValue:PendingModifiedValues}" --output table
----------------------------------------------------------------------------------------------------------------
| DescribeDBInstances |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
| Endpoint | MultiAZ | Primary | Standby | Status |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
| rds-stack-rds.cmkhfj0htgnu.us-east-1.rds.amazonaws.com | True | us-east-1b | us-east-1a | available |
+---------------------------------------------------------+----------+-------------+-------------+-------------+
¿Qué tenemos ahora?
Movimos la instancia standby de la Availability Zone secundaria desde la subnet pública a la subnet aislada.

RDS Multi-AZ en las subnets aisladas
Paso 3: actualiza el stack de CDK
Ahora que el cambio de arquitectura ya es real, conviene actualizar tu plantilla de CDK para que refleje los cambios. Modifica el stack de CDK actualizando el subnetType a PRIVATE_ISOLATED:
const subnetType: cdk.aws_ec2.SubnetSelection = { subnetType: cdk.aws_ec2.SubnetType.PRIVATE_ISOLATED };
Si quieres confirmar que la plantilla de CDK y el stack real quedan sincronizados después de la actualización, ejecuta cdk deploy rds-stack tras el cambio. Como el subnet group real ya se actualizó, no se materializa ningún cambio. cdk deploy rds-stack debería terminar correctamente:
rds-stack
rds-stack: deploying... [2/2]
✅ rds-stack (no changes)
✨ Deployment time: 2.25s
Outputs:
rds-stack.rdsstackrdsname = rds-stack-rds
rds-stack.rdsstacksubnetgroupname = rds-stack-rds-subnetgroup
Si tienes dudas sobre la sincronización del estado de CDK, intenta desplegar el stack con
const subnetType: cdk.aws_ec2.SubnetSelection = { subnetType: cdk.aws_ec2.SubnetType.PUBLIC };.
cdk deploy rds-stackdebería arrojar el mismo error de subnet en uso:UPDATE_FAILED | AWS::RDS::DBSubnetGroup | rdsstackrdssubnetgroup Resource handler returned message: "Some of the subnets to be deleted are currently in use: subnet-03e58f5428463ad26, subnet-06721c9fdaac5f333
Alojar Amazon RDS en un entorno aislado, sin enrutamiento de salida a internet, aporta una serie de beneficios fundamentales para la seguridad de los datos, la privacidad y la integridad operativa:
- Protección frente a la exfiltración de datos: al impedir el enrutamiento de salida a internet, el riesgo de exfiltración se reduce de forma significativa. Los datos sensibles se mantienen dentro del entorno controlado, lo que minimiza la posibilidad de fugas accidentales o intencionales. Esto es especialmente relevante para cumplir con las regulaciones de protección de datos y resguardar información propietaria.
- Preservación de la integridad operativa: alojar la base de datos en un entorno aislado garantiza que se mantenga su integridad operativa. Un acceso no intencionado a internet, ya sea por configuraciones erróneas o vulnerabilidades, puede provocar comportamientos inesperados, corrupción de datos o cambios no autorizados.
- Cumplimiento y alineación regulatoria: muchas industrias están sujetas a regulaciones estrictas que exigen controles rigurosos sobre el manejo y almacenamiento de datos. Aislar la base de datos a nivel de red apoya iniciativas de cumplimiento, como la alineación con ISO27001:2013 A.13.1.3.
- Reducción de la superficie de ataque: un entorno aislado disminuye la superficie de ataque de la base de datos y la hace menos susceptible a distintos tipos de ataques. Sin conexión directa a internet, los atacantes tienen menos oportunidades de explotar vulnerabilidades, inyectar código malicioso o realizar reconocimiento.
- Foco en las amenazas internas: si bien las amenazas externas son una preocupación, las internas pueden ser igual de dañinas. Aislar la base de datos limita el acceso únicamente al personal autorizado y reduce el riesgo de amenazas internas, exposición accidental de datos o manipulación indebida.