Accéder à S3 en privé avec un endpoint VPC

AWSBeginner
Pratiquer maintenant

Introduction

Une application privée de livraison lit un manifeste S3 via NAT. Elle a besoin d'un chemin propre au service, utilisable sans accès général à Internet. Vous créerez un endpoint de passerelle S3, comparerez des requêtes réelles, diagnostiquerez une mauvaise association et restaurerez le réseau fourni.

Terminez d'abord Give a Private Subnet Outbound Access. Cet environnement neuf fournit sa propre application, un objet S3, des sous-réseaux public et privé, une passerelle NAT et des règles de sécurité. La CLI est configurée. Conservez ces ressources et le réseau de référence ; créez puis supprimez uniquement votre endpoint et restaurez la route NAT privée temporairement retirée.

Liens avec les certifications

Ce laboratoire propose une pratique fondamentale des thèmes suivants.

Créer un endpoint de passerelle S3 pour l'application privée

Vous inspecterez le chemin NAT initial, identifierez les plages S3 et créerez l'endpoint dans la table privée.

Utilisez Terminal et ouvrez AWS View à côté. L'application conserve 10.20.2.10. Le bucket fourni parcel-delivery-storage contient message.txt, dont le texte est Parcel manifest ready.

cd /home/labex/project

Sélectionnez le VPC par son tag Name. Les filtres sélectionnent les ressources, la requête extrait l'ID et $(...) l'enregistre :

VPC_ID=$(aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=application-network \
  --query 'Vpcs[0].VpcId' \
  --output text)

Enregistrez les IDs des tables privée et publique. Leurs associations aux sous-réseaux sont déjà correctes :

PRIVATE_RT_ID=$(aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=private-routes \
  --query 'RouteTables[0].RouteTableId' \
  --output text)
PUBLIC_RT_ID=$(aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=public-routes \
  --query 'RouteTables[0].RouteTableId' \
  --output text)

Lisez les routes et associations :

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes,Associations:Associations}' \
  --output json

La route privée 0.0.0.0/0 cible NAT ; la publique cible la passerelle Internet. Les deux conservent local. Enregistrez l'ID NAT pour restaurer la route lors du nettoyage :

NAT_ID=$(aws ec2 describe-nat-gateways \
  --filter "Name=vpc-id,Values=$VPC_ID" Name=state,Values=available \
  --query 'NatGateways[0].NatGatewayId' \
  --output text)

Consultez ses adresses pour comparer les requêtes :

aws ec2 describe-nat-gateways \
  --nat-gateway-ids "$NAT_ID" \
  --query 'NatGateways[].{State:State,Addresses:NatGatewayAddresses}' \
  --output json

Dans AWS View, cliquez sur Read storage object : la réponse doit contenir Success et le manifeste. Source address est l'adresse publique NAT. Request outbound service réussit avec cette même adresse. Vous restaurerez cet état initial.

Une liste de préfixes gérée par AWS regroupe les plages d'un service dans une région. Un endpoint de passerelle S3 ajoute une route vers cette liste dans les tables associées, sans attribuer d'adresse publique ni ouvrir l'accès général à Internet. Sélectionnez la liste S3 et consultez les plages IPv4 :

PREFIX_ID=$(aws ec2 describe-prefix-lists \
  --filters Name=prefix-list-name,Values=com.amazonaws.us-east-1.s3 \
  --query 'PrefixLists[0].PrefixListId' \
  --output text)
aws ec2 get-managed-prefix-list-entries \
  --prefix-list-id "$PREFIX_ID" \
  --query 'Entries[].Cidr' \
  --output json

Créez l'endpoint S3 de us-east-1, associé uniquement à la table privée. --vpc-endpoint-type Gateway choisit le type basé sur les routes, --service-name le service régional et --route-table-ids la table de l'application. Les tags identifient votre ressource :

ENDPOINT_ID=$(aws ec2 create-vpc-endpoint \
  --vpc-id "$VPC_ID" \
  --vpc-endpoint-type Gateway \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids "$PRIVATE_RT_ID" \
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=parcel-s3-endpoint},{Key=Project,Value=parcel}]' \
  --query 'VpcEndpoint.VpcEndpointId' \
  --output text)

Consultez son état et son association :

aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids "$ENDPOINT_ID" \
  --query 'VpcEndpoints[].{ID:VpcEndpointId,State:State,Type:VpcEndpointType,Service:ServiceName,Tables:RouteTableIds}' \
  --output json

Attendez que State soit available. Sinon, attendez quelques secondes et répétez la même requête. Le type doit être Gateway, le service S3, avec seulement la table privée. Gardez Terminal ouvert pour conserver les variables.

Cliquez de nouveau sur Read storage object. Le manifeste est identique, mais la source devient 10.20.2.10. La route S3 est plus spécifique que la route NAT par défaut ; S3 utilise l'endpoint, tandis que les autres sorties utilisent NAT.

Conserver S3 sans route NAT par défaut

Vous retirerez la route de sortie générale pour vérifier le chemin propre au service.

Supprimez seulement la route NAT par défaut de la table privée. Conservez la passerelle, son adresse, la route publique et l'endpoint :

aws ec2 delete-route --route-table-id "$PRIVATE_RT_ID" --destination-cidr-block 0.0.0.0/0

Une suppression réussie n'affiche rien. Consultez les routes :

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" \
  --query 'RouteTables[].Routes' \
  --output json

local et la route S3 DestinationPrefixListId restent ; la route par défaut disparaît. Le GatewayId du service est l'endpoint, avec l'état active. Les associations d'endpoint gèrent ces routes ; ne les modifiez pas avec des commandes de route ordinaires.

Read storage object renvoie encore Parcel manifest ready depuis 10.20.2.10. Request outbound service échoue : 198.51.100.20:9000 est hors du préfixe S3 et n'a plus de route par défaut. Request private application from outside échoue aussi. L'endpoint fournit S3 en privé, sans adresse publique ni route vers les autres destinations Internet.

L'application privée lit S3 sans route NAT par défaut

Exemple : la table privée conserve local et le préfixe S3, sans 0.0.0.0/0. La réponse réelle contient le manifeste et la source 10.20.2.10. NAT reste disponible mais n'est pas sur ce chemin S3. Les IDs et adresses générés peuvent varier.

Observer l'association à la mauvaise table

Vous déplacerez l'endpoint hors de la table de l'application afin de comprendre pourquoi un endpoint disponible peut être inaccessible.

Une association endpoint–table est différente d'une association sous-réseau–table. Modifiez seulement la première :

aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id "$ENDPOINT_ID" \
  --add-route-table-ids "$PUBLIC_RT_ID" \
  --remove-route-table-ids "$PRIVATE_RT_ID"

La réponse indique Return: true. Consultez l'endpoint :

aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids "$ENDPOINT_ID" \
  --query 'VpcEndpoints[].{State:State,Tables:RouteTableIds}' \
  --output json

Il reste available, mais seule la table publique apparaît. Consultez les deux tables :

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes,Associations:Associations}' \
  --output json

La route S3 automatique est passée à la table publique. La privée n'a plus que local. Les associations des sous-réseaux restent intactes. Partager un VPC ne rend pas une route d'endpoint utilisable par tous les sous-réseaux.

Quand AWS View affiche le changement, cliquez sur Read storage object. La nouvelle requête retourne Connection failed et Storage unavailable, car la table de l'application n'a aucun chemin S3. Request outbound service échoue aussi. Une ancienne réussite est historique. Conservez cette panne pour la vérification ; l'étape suivante la réparera.

Restaurer la route privée du service

Vous réparerez l'association sans recréer l'endpoint, attribuer d'adresse publique ou restaurer NAT.

Ramenez le même endpoint à la table privée et retirez la publique :

aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id "$ENDPOINT_ID" \
  --add-route-table-ids "$PRIVATE_RT_ID" \
  --remove-route-table-ids "$PUBLIC_RT_ID"

Consultez l'association :

aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids "$ENDPOINT_ID" \
  --query 'VpcEndpoints[].{State:State,Tables:RouteTableIds}' \
  --output json

Seule la privée doit apparaître. Inspectez les routes :

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes}' \
  --output json

La route S3 privée revient automatiquement et disparaît de la table publique. La route publique Internet reste, sans route privée par défaut.

Envoyez une nouvelle Read storage object : le manifeste original revient depuis 10.20.2.10. Request outbound service échoue toujours, car l'endpoint S3 n'offre pas Internet général. Request private application from outside reste bloquée. L'adresse privée et les règles fournies restent inchangées.

Supprimer l'endpoint et restaurer NAT

Vous supprimerez votre endpoint, confirmerez le retrait de ses routes automatiques et restaurerez la route privée vers NAT fourni.

Supprimez uniquement votre endpoint :

aws ec2 delete-vpc-endpoints --vpc-endpoint-ids "$ENDPOINT_ID"

La liste Unsuccessful doit être vide. Consultez tout l'inventaire, sans filtrage par tags supprimables :

aws ec2 describe-vpc-endpoints \
  --query 'VpcEndpoints[].{ID:VpcEndpointId,State:State,Tables:RouteTableIds}' \
  --output json

L'endpoint peut rester affiché comme deleted, mais aucun endpoint de pratique actif ne doit subsister. Ce registre ne route aucun trafic. Si l'état est deleting, attendez quelques secondes et répétez la requête. Consultez les tables :

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes}' \
  --output json

Aucune ne doit conserver le préfixe S3. Cliquez sur Read storage object : la requête échoue avec seulement local dans la table privée, confirmant l'absence de chemin alternatif caché.

Restaurez la route par défaut vers l'ID NAT enregistré. Ne supprimez ni NAT, ni son adresse, ni l'application ou ses données S3 :

aws ec2 create-route \
  --route-table-id "$PRIVATE_RT_ID" \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id "$NAT_ID"

Consultez les routes restaurées :

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" \
  --query 'RouteTables[].Routes' \
  --output json

local et NAT actif correspondent à l'état initial. Une requête d'inventaire en échec ne prouve aucune suppression : la requête authentifiée doit réussir et montrer absence ou deleted, avec routes automatiques retirées.

Read storage object doit de nouveau renvoyer le manifeste via NAT, avec son adresse publique dans Source address. Request outbound service réussit avec la même adresse ; Request private application from outside reste bloquée. Conservez VPC, sous-réseaux, NAT, règles, objet S3 et réseau de référence.

Exécutez la vérification de cette étape.

Résumé

Vous avez créé un endpoint S3 et vérifié des lectures réelles avec une source privée. Sans route NAT par défaut, S3 restait accessible tandis que les autres destinations échouaient. L'association à la table publique a interrompu cet accès ; le retour à la privée l'a réparé sans changer l'application ni ses règles.

Vous avez supprimé l'endpoint, vérifié ses routes et restauré NAT.