Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Proteja seus dados: migre o Amazon RDS de subnet pública para isolada

By Dr. Richard KangNov 1, 202312 min read

Esta página também está disponível em English, Deutsch, Español, Français, Italiano e 日本語.

(Imagem criada com a ajuda do Stable Diffusion)

Tenho atendido clientes que mantêm o banco de dados Amazon RDS em uma subnet de VPC com rota padrão para a internet.

Pode haver medidas de segurança em vigor, como a opção "publicly accessible" do RDS desativada, regras de entrada do Security Group restritas apenas às instâncias EC2 ou Lambda autorizadas e regras stateful de firewall que detectam ameaças e exploits com assinaturas SQL. Mas incidentes como o vazamento de dados da Target Corporation em 2013 mostram que apenas bloquear o tráfego de entrada da internet enquanto se libera todo o tráfego de saída já não basta para minimizar o risco de exfiltração de dados. Um agente malicioso, como um malware de comando e controle (também conhecido como C&C ou C2), pode usar o tráfego de saída em portas comuns como HTTP:80 e HTTPS:443 para fazer beaconing.

Este artigo descreve como mover um Amazon RDS de uma subnet pública com tabela de rotas voltada para a internet para uma subnet isolada, sem precisar criar uma nova instância de banco de dados via snapshot-restore.

Toda VPC pode ter 3 tipos de subnet: uma subnet pública, com um internet gateway anexado para permitir tráfego de internet de entrada e saída; uma subnet privada, que tem um Network Address Translation (NAT) ou um Internet Egress-only gateway para permitir tráfego de saída para a internet; e uma subnet isolada, que permite apenas tráfego dentro da VPC e não possui rotas para destinos externos.

Hospedar o banco de dados em uma subnet isolada ajuda a reduzir o risco de exfiltração de dados ao diminuir a superfície de ataque, tornando menos provável que um invasor, como um malware C&C, encontre uma forma de tirar os dados de lá.

Vale lembrar, porém, que o isolamento de rede é apenas uma das medidas importantes para reduzir o risco — não é uma solução infalível contra a exfiltração de dados. Uma corrente é tão forte quanto seu elo mais fraco, e cada medida que reduz o risco faz diferença.

Configurando o ambiente de teste com Amazon RDS Multi-AZ

Para acompanhar os passos de migração da instância RDS de uma subnet pública para uma isolada, você vai precisar de um ambiente de teste com um Amazon RDS rodando nas subnets públicas de uma VPC. A VPC tem subnets públicas e isoladas.

Se você já tem instâncias do Amazon RDS em subnets públicas e a VPC já conta com subnets isoladas, fique à vontade para pular a etapa de criação da VPC.

Vamos criar os recursos da AWS usando o CDK. Se essa é sua primeira vez com o CDK, comece por https://docs.aws.amazon.com/cdk/v2/guide/hello_world.htm.

Stack do CDK que cria uma VPC

O primeiro passo da configuração do ambiente de teste é criar uma VPC com uma subnet pública e uma isolada em cada Availability Zone, em duas Availability Zones, usando a stack do CDK abaixo.

Vamos exportar os parâmetros necessários da VPC, como o VPC ID, para conseguir importá-los na stack que cria o RDS na próxima etapa.

#!/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',
});

Se o cdk deploy vpc-stack rodar com sucesso, você verá saídas parecidas com estas:

✅  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

Anote o VPC ID, os IDs das subnets públicas e os IDs das subnets isoladas.

Neste exemplo, são esses os parâmetros que vamos usar ao criar o Amazon RDS:

  • VPC ID: vpc-090949477d23289ce
  • IDs das subnets públicas: subnet-0271290b1164913ad, subnet-079b9aaba653c430b
  • IDs das subnets isoladas: subnet-06721c9fdaac5f333, subnet-03e58f5428463ad26

Stack do CDK que cria o Amazon RDS

Em seguida, vamos provisionar um Amazon Postgres RDS na subnet pública da VPC:

Dica rápida sobre CDK: cdk.Fn.importValue() é um atributo de associação tardia (late-bound). Por isso, é preciso usar a função de split de strings do CloudFormation cdk.Fn.Split() em vez do split de strings do TypeScript, como em cdk.Fn.importValue('test-Vpc-AZs').split(","), que geraria erros como Some 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"
});

Se você já tem uma VPC e quer criar o RDS dentro dela, ajuste o vpcLookup com os valores correspondentes, por exemplo:

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"],
});

Se o cdk deploy rds-stack rodar com sucesso, você verá saídas parecidas com estas:

 ✅  rds-stack

✨  Deployment time: 20.95s

Outputs:
rds-stack.rdsstackrdsname = rds-stack-rds

O que criamos até aqui?

Criamos uma VPC com duas Availability Zones. Cada zona tem uma subnet pública e uma isolada.

Também provisionamos um Amazon RDS Multi-AZ na subnet pública de cada uma das Availability Zones.

RDS Multi-AZ em subnets públicas

Mover o Amazon RDS de subnets públicas para subnets isoladas

Temos um RDS Subnet Group composto por várias subnets, uma para cada Availability Zone — por exemplo, a instância primária na AZ-1 e a instância standby na AZ-2.

Para alterar a subnet de cada instância, no entanto, é preciso remover a instância que está usando aquela subnet. Caso contrário, ao tentar modificar a subnet com uma instância RDS ativa, ocorre um erro:

An error occurred (InvalidParameterValue) when calling the ModifyDBSubnetGroup operation: Some of the subnets to be deleted are currently in use: subnet-0271290b1164913ad

Visão geral dos passos para mover o Amazon RDS da subnet pública para a isolada:

  1. Parar a instância standby para liberar a subnet pública, de modo que o RDS subnet group possa trocar essa subnet pública pela isolada antes de reimplantar a standby na subnet isolada.
  2. Promover a standby a primária e repetir o mesmo procedimento na nova standby (antiga primária).
  3. Atualizar o estado do CDK.

Passo 1: mover a instância standby

Antes de começar, precisamos coletar alguns parâmetros importantes:

Anote a subnet das instâncias RDS primária e standby

Execute este comando da AWS CLI para consultar a Availability Zone primária e a secundária:

% 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  |
+-------------+--------------+

Mapeie a Availability Zone para as subnets do RDS Subnet Group com este comando:

% 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  |
+-------------------+----------------------------+

Pelas duas saídas, dá para concluir que:

  • A instância primária do RDS está em subnet-0271290b1164913ad.
  • A instância standby do RDS está em subnet-079b9aaba653c430b.

Pare a instância standby e altere a subnet

Modifique a instância RDS com o comando modify-db-instance da CLI, conforme abaixo:

% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --no-multi-az --apply-immediately --query "DBInstance.MultiAZ"
true

Para confirmar se a instância RDS está em AZ única, rode novamente o 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     |
+-------------+-----------+

Atualize o RDS Subnet Group para substituir a subnet pública da standby encerrada por uma subnet isolada na mesma 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"\
        ]
    }
}

Confirme o RDS Subnet Group com o 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  |
+-------------------+----------------------------+

Reative a implantação Multi-AZ com o comando modify-db-instance:

% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --multi-az --apply-immediately --query "DBInstance.MultiAZ"
false

A modificação pode levar algum tempo e dá para acompanhá-la pelo 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  |
+------------+-----------+-------------+

Confirme que a instância standby foi criada com 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  |
+------------+--------------+-------------+

O que temos agora?

Movemos a instância standby na Availability Zone secundária da subnet pública para a subnet isolada.

RDS Multi-AZ com a primária na subnet pública e a standby na subnet isolada

Passo 2: promover a standby e mover a antiga primária

Anote o endpoint do RDS para garantir que o endereço não mude após o failover, mantendo a disponibilidade:

% 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  |
+---------------------------------------------------------+-------------+-------------+-------------+

Observação: faça o reboot da instância em janelas de manutenção ou horários de baixo pico, já que ela fica indisponível durante esse processo.

Reinicie a instância RDS com o parâmetro --force-failover:

aws rds reboot-db-instance --db-instance-identifier rds-stack-rds --force-failover

Confirme o failover com 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  |
+---------------------------------------------------------+----------+-------------+-------------+-------------+

Remova a nova standby (antiga primária) que está na subnet pública

Com a nova primária na subnet isolada, prossiga para remover a standby recém-rebaixada:

% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --no-multi-az --apply-immediately --query "DBInstance.MultiAZ"
true

A instância RDS vai entrar no status 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  |
+---------------------------------------------------------+----------+-------------+-------------+-------------+

Quando a instância RDS estiver no status available, a subnet da standby deve ficar livre para a próxima etapa:

% 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  |
+---------------------------------------------------------+----------+-------------+----------+-------------+

Modifique o RDS subnet group para trocar a subnet pública pela isolada:

% 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"\
        ]
    }
}

Reimplante o RDS Multi-AZ:

% aws rds modify-db-instance --db-instance-identifier rds-stack-rds --multi-az --apply-immediately

A instância RDS ficará no status modifying, com os valores de MultiAZ pendentes de modificação:

% 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                                      ||
|+------------------------------------------------------------+--------------------------------------------+|

Quando a instância RDS estiver available, a nova standby será implantada na subnet isolada:

% 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  |
+---------------------------------------------------------+----------+-------------+-------------+-------------+

O que temos agora?

Movemos a instância standby na Availability Zone secundária da subnet pública para a subnet isolada.

RDS Multi-AZ nas subnets isoladas

Passo 3: atualizar a stack do CDK

Agora que a mudança de arquitetura está feita, é hora de atualizar o template do CDK para refletir essa mudança. Modifique a stack alterando o subnetType para PRIVATE_ISOLATED:

const subnetType: cdk.aws_ec2.SubnetSelection = { subnetType: cdk.aws_ec2.SubnetType.PRIVATE_ISOLATED };

Para garantir o alinhamento entre o template do CDK e a stack real após a atualização, rode um cdk deploy rds-stack depois da alteração. Como o subnet group já foi atualizado de fato, não há mudanças materializadas. O cdk deploy rds-stack deve concluir com sucesso:

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

Se ainda restar dúvida sobre a sincronização do estado do CDK, tente fazer o deploy da stack com const subnetType: cdk.aws_ec2.SubnetSelection = { subnetType: cdk.aws_ec2.SubnetType.PUBLIC };.

O cdk deploy rds-stack deve cair no mesmo erro de subnet em 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

Hospedar o Amazon RDS em um ambiente isolado, sem roteamento de saída para a internet, traz uma série de benefícios fundamentais para a segurança, a privacidade e a integridade operacional dos dados:

  • Proteção contra exfiltração de dados: ao bloquear o roteamento de saída para a internet, o risco de exfiltração cai consideravelmente. Dados sensíveis ficam dentro do ambiente controlado, reduzindo as chances de vazamentos acidentais ou intencionais. Isso é especialmente importante para conformidade com regulamentações de proteção de dados e para resguardar informações proprietárias.
  • Preservação da integridade operacional: hospedar um banco de dados em um ambiente isolado garante a manutenção da sua integridade operacional. Acessos não intencionais à internet, seja por configurações incorretas ou vulnerabilidades, podem provocar comportamentos inesperados, corrupção de dados ou alterações não autorizadas.
  • Conformidade e alinhamento regulatório: muitos setores estão sujeitos a regulamentações rigorosas que exigem controles estritos sobre o manuseio e o armazenamento de dados. Isolar o banco de dados em rede contribui para os esforços de conformidade, como o atendimento à ISO 27001:2013 A.13.1.3.
  • Redução da superfície de ataque: um ambiente isolado reduz a superfície de ataque do banco de dados, deixando-o menos suscetível a diversos tipos de ofensiva. Sem conexão direta com a internet, os atacantes têm menos brechas para explorar vulnerabilidades, injetar código malicioso ou fazer reconhecimento.
  • Atenção às ameaças internas: por mais que as ameaças externas preocupem, as internas podem ser igualmente prejudiciais. Isolar o banco de dados restringe o acesso a pessoas autorizadas, diminuindo o potencial de ameaças internas, exposição acidental de dados ou adulteração.