Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Sécuriser vos données : migrer Amazon RDS d'un sous-réseau public vers un sous-réseau isolé

By Dr. Richard KangNov 1, 202312 min read

Cette page est également disponible en English, Deutsch, Español, Italiano, 日本語 et Português.

(Cette image a été créée avec l'aide de Stable Diffusion)

J'accompagne régulièrement des clients qui hébergent leur base de données Amazon RDS dans un sous-réseau VPC dont la table de routage par défaut pointe vers Internet.

Plusieurs mesures de sécurité peuvent être en place : option publiquement accessible de RDS désactivée, règles entrantes du Security Group restreintes aux seules instances EC2 ou Lambda autorisées, ou encore règles stateful de pare-feu détectant les menaces et exploits via des signatures SQL. Pourtant, des incidents comme la fuite de données de Target Corporation en 2013 montrent que se contenter de bloquer le trafic Internet entrant tout en laissant passer l'intégralité du trafic sortant ne suffit plus à limiter le risque d'exfiltration. Un acteur malveillant — par exemple un malware de type command-and-control (aussi appelé C&C ou C2) — peut exploiter le trafic sortant sur des ports courants comme HTTP:80 et HTTPS:443 pour effectuer du beaconing.

Cet article décrit la procédure pour déplacer une instance Amazon RDS d'un sous-réseau public, dont la table de routage est ouverte sur Internet, vers un sous-réseau isolé, sans recréer une nouvelle instance par snapshot-restore.

Tout VPC peut comporter trois types de sous-réseaux : un sous-réseau public auquel est rattachée une passerelle Internet pour autoriser le trafic entrant et sortant ; un sous-réseau privé doté d'une passerelle NAT (Network Address Translation) ou d'une passerelle Egress-only pour n'autoriser que le trafic Internet sortant ; et un sous-réseau isolé qui n'autorise que le trafic interne au VPC, sans aucune route vers une destination extérieure.

Héberger la base de données dans un sous-réseau isolé contribue à réduire le risque d'exfiltration en diminuant la surface d'attaque, ce qui complique la tâche d'un attaquant — par exemple un malware C&C — pour trouver une voie de sortie des données.

Notez toutefois que l'isolement réseau n'est qu'une mesure parmi d'autres : il réduit le risque sans pour autant offrir une protection infaillible contre l'exfiltration. Une chaîne ne vaut que par son maillon le plus faible, et chaque mesure prise pour réduire le risque compte.

Mettre en place l'environnement de test avec un Amazon RDS Multi-AZ

Pour suivre les étapes de migration de l'instance RDS d'un sous-réseau public vers un sous-réseau isolé, vous devrez préparer un environnement de test composé d'une instance Amazon RDS dans les sous-réseaux publics d'un VPC. Le VPC contient à la fois des sous-réseaux publics et isolés.

Vous pouvez ignorer l'étape de création du VPC si vous disposez déjà d'instances Amazon RDS dans des sous-réseaux publics et que votre VPC dispose de sous-réseaux isolés.

Nous allons créer les ressources AWS via CDK. Si vous débutez avec CDK, consultez https://docs.aws.amazon.com/cdk/v2/guide/hello_world.htm pour démarrer.

Stack CDK pour créer un VPC

La première étape consiste à créer un VPC comportant un sous-réseau public et un sous-réseau isolé dans chacune des deux Availability Zones, à l'aide de la stack CDK ci-dessous.

Nous exporterons les paramètres VPC nécessaires (notamment l'ID du VPC) afin de pouvoir les importer dans la stack qui créera l'instance RDS à l'étape suivante.

#!/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 aboutit, vous devriez obtenir des sorties similaires à celles-ci :

✅  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

Notez l'ID du VPC, les ID des sous-réseaux publics et ceux des sous-réseaux isolés.

Dans cet exemple, voici les paramètres que nous utiliserons pour créer l'instance Amazon RDS :

  • ID du VPC : vpc-090949477d23289ce
  • ID des sous-réseaux publics : subnet-0271290b1164913ad, subnet-079b9aaba653c430b
  • ID des sous-réseaux isolés : subnet-06721c9fdaac5f333, subnet-03e58f5428463ad26

Stack CDK pour créer Amazon RDS

Provisionnons maintenant une instance Amazon RDS Postgres dans le sous-réseau public du VPC :

Astuce CDK :cdk.Fn.importValue() est un attribut résolu tardivement. Il faut donc utiliser la fonction CloudFormationcdk.Fn.Split() plutôt que la méthode TypeScript de découpage de chaînes : par exemple,cdk.Fn.importValue('test-Vpc-AZs').split(",") provoquerait une erreur du typeSome 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 vous souhaitez créer l'instance RDS dans un VPC existant, modifiez vpcLookup avec les valeurs appropriées, par exemple :

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 aboutit, vous devriez obtenir des sorties similaires à celles-ci :

 ✅  rds-stack

✨  Deployment time: 20.95s

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

Qu'avons-nous créé ?

Nous avons créé un VPC réparti sur deux Availability Zones, chacune disposant d'un sous-réseau public et d'un sous-réseau isolé.

Nous avons également provisionné une instance Amazon RDS Multi-AZ dans les sous-réseaux publics des deux Availability Zones.

RDS Multi-AZ dans des sous-réseaux publics

Migrer Amazon RDS du sous-réseau public vers les sous-réseaux isolés

Notre RDS Subnet Group regroupe plusieurs sous-réseaux, un par Availability Zone : par exemple l'instance primaire dans l'AZ-1 et l'instance de standby dans l'AZ-2.

Pour modifier le sous-réseau de chaque instance, il faut au préalable retirer l'instance qui l'utilise. Sinon, toute tentative de modification d'un sous-réseau encore occupé par une instance RDS générera une erreur :

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

Vue d'ensemble des étapes pour migrer Amazon RDS du sous-réseau public vers le sous-réseau isolé :

  1. Arrêter l'instance de standby afin de libérer le sous-réseau public, ce qui permet au RDS subnet group de remplacer ce sous-réseau public par un sous-réseau isolé avant de redéployer le standby dans le sous-réseau isolé.
  2. Promouvoir le standby en primaire, puis répéter l'opération sur la nouvelle instance rétrogradée en standby.
  3. Mettre à jour l'état de la stack CDK.

Étape 1 : déplacer l'instance de standby

Avant de commencer, recueillons quelques paramètres clés.

Identifier le sous-réseau des instances primaire et de standby

Exécutez cette commande AWS CLI pour interroger les Availability Zones primaire et secondaire :

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

Faites correspondre les Availability Zones aux sous-réseaux du RDS Subnet Group avec la commande suivante :

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

Sur la base de ces deux sorties, nous pouvons en déduire que :

  • L'instance RDS primaire se trouve dans subnet-0271290b1164913ad.
  • L'instance RDS de standby se trouve dans subnet-079b9aaba653c430b.

Arrêter le standby et changer de sous-réseau

Modifiez l'instance RDS avec la commande CLI modify-db-instance ci-dessous :

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

Pour vérifier que l'instance RDS est bien en single-AZ, relancez la commande 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     |
+-------------+-----------+

Mettez à jour le RDS Subnet Group pour remplacer le sous-réseau public du standby supprimé par un sous-réseau isolé situé dans la même 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"\
        ]
    }
}

Vérifiez le RDS Subnet Group avec la commande 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  |
+-------------------+----------------------------+

Réactivez le déploiement Multi-AZ avec la commande modify-db-instance :

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

La modification peut prendre un certain temps ; suivez son avancement via 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  |
+------------+-----------+-------------+

Confirmez la création du standby avec 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ù en sommes-nous ?

Nous avons déplacé l'instance de standby de la Secondary Availability Zone du sous-réseau public vers le sous-réseau isolé.

RDS Multi-AZ avec l'instance primaire dans le sous-réseau public et le standby dans le sous-réseau isolé

Étape 2 : promouvoir le standby et déplacer l'ancienne instance primaire

Notez le endpoint RDS pour vérifier que son adresse reste inchangée après le failover, gage de continuité de service :

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

Remarque : effectuez le redémarrage de l'instance pendant une fenêtre de maintenance ou en heures creuses, car les instances seront indisponibles le temps de l'opération.

Redémarrez l'instance RDS avec le paramètre --force-failover :

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

Confirmez le failover avec 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  |
+---------------------------------------------------------+----------+-------------+-------------+-------------+

Retirer le nouveau standby (ancienne instance primaire) qui se trouve dans le sous-réseau public

La nouvelle instance primaire étant désormais dans le sous-réseau isolé, retirez l'instance fraîchement rétrogradée en standby :

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

L'instance RDS passe alors en statut 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  |
+---------------------------------------------------------+----------+-------------+-------------+-------------+

Une fois l'instance RDS revenue au statut available, le sous-réseau du standby est libéré pour l'étape suivante :

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

Modifiez ensuite le RDS subnet group pour remplacer le sous-réseau public par le sous-réseau isolé :

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

Redéployez l'instance RDS Multi-AZ :

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

L'instance RDS passe en statut modifying avec une modification de la valeur MultiAZ en attente :

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

Une fois l'instance RDS de retour au statut available, le nouveau standby sera déployé dans le sous-réseau isolé :

% 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ù en sommes-nous ?

Nous avons migré l'instance de standby de la Secondary Availability Zone du sous-réseau public vers le sous-réseau isolé.

RDS Multi-AZ dans les sous-réseaux isolés

Étape 3 : mettre à jour la stack CDK

Maintenant que l'architecture a effectivement évolué, mettez à jour votre template CDK pour refléter ces changements. Modifiez la stack en remplaçant subnetType par PRIVATE_ISOLATED :

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

Pour vous assurer que votre template CDK reste cohérent avec la stack réelle après cette mise à jour, lancez un cdk deploy rds-stack à la suite du changement. Le subnet group ayant déjà été mis à jour côté infrastructure, aucune modification effective ne sera appliquée. cdk deploy rds-stack devrait se terminer avec succès :

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 vous doutez de la synchronisation de l'état CDK, essayez de déployer la stack avec const subnetType: cdk.aws_ec2.SubnetSelection = { subnetType: cdk.aws_ec2.SubnetType.PUBLIC };.

cdk deploy rds-stack doit alors rencontrer la même erreur de sous-réseau utilisé : 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

Héberger Amazon RDS dans un environnement isolé, sans routage Internet sortant, offre des bénéfices essentiels en matière de sécurité des données, de confidentialité et d'intégrité opérationnelle :

  • Protection contre l'exfiltration de données : en supprimant le routage Internet sortant, le risque d'exfiltration est considérablement réduit. Les données sensibles restent dans un environnement maîtrisé, ce qui limite les fuites accidentelles ou intentionnelles. C'est un atout majeur pour la conformité aux réglementations sur la protection des données et la préservation des informations propriétaires.
  • Préservation de l'intégrité opérationnelle : héberger une base dans un environnement isolé garantit le maintien de son intégrité. Un accès Internet involontaire — qu'il résulte d'une mauvaise configuration ou d'une vulnérabilité — peut entraîner des comportements inattendus, une corruption des données ou des modifications non autorisées.
  • Conformité et alignement réglementaire : de nombreux secteurs sont soumis à des réglementations strictes qui imposent un contrôle rigoureux du traitement et du stockage des données. Isoler la base au niveau du réseau soutient les démarches de conformité, notamment vers la norme ISO27001:2013 A.13.1.3.
  • Réduction de la surface d'attaque : un environnement isolé réduit la surface d'attaque de la base de données et la rend moins vulnérable à divers types d'attaques. Sans connexion Internet directe, les attaquants disposent de moins d'opportunités pour exploiter des failles, injecter du code malveillant ou mener des actions de reconnaissance.
  • Focalisation sur les menaces internes : si les menaces externes restent une préoccupation, les menaces internes peuvent être tout aussi dommageables. Isoler la base limite l'accès aux seules personnes autorisées et réduit le risque d'attaques internes, d'exposition accidentelle ou d'altération des données.