Amazon S3
Le service de stockage d'objets d'AWS offrant une durabilité de 99,999999999% et une disponibilité inégalée, parfait pour stocker et récupérer n'importe quelle quantité de données, n'importe quand et n'importe où.
Qu'est-ce qu'Amazon S3 ?
Imaginez un immense entrepôt ultra-sécurisé avec une capacité pratiquement illimitée, capable de stocker tous vos objets précieux. Dans cet entrepôt, chaque objet est soigneusement étiqueté, peut être rapidement retrouvé, et est protégé contre pratiquement toute perte ou dommage. De plus, vous pouvez accéder instantanément à n'importe quel objet à tout moment, depuis n'importe où dans le monde.
Amazon S3 (Simple Storage Service) est l'équivalent numérique de cet entrepôt. C'est un service de stockage d'objets dans le cloud qui offre une durabilité, une disponibilité et une performance exceptionnelles pour stocker et protéger vos données.
Comment fonctionne S3 ?
Buckets et Objets
S3 organise les données en "buckets" (conteneurs) qui stockent les "objets" (fichiers). Pensez aux buckets comme des entrepôts et aux objets comme les articles à l'intérieur.
Fiabilité exceptionnelle
S3 est conçu pour offrir une durabilité de 99,999999999% (11 neuf), ce qui signifie que si vous stockez 10 000 objets, vous pourriez théoriquement en perdre un tous les 10 millions d'années.
S3 est utilisé pour de nombreuses applications, de la sauvegarde et l'archivage de données à l'hébergement de sites web, en passant par le stockage d'applications mobiles et les lacs de données pour l'analyse. Sa flexibilité, sa sécurité et sa scalabilité en font un choix privilégié pour les entreprises de toutes tailles.
Fonctionnement technique
Amazon S3 est un service de stockage d'objets qui stocke les données sous forme d'objets dans des buckets. Son architecture est conçue pour offrir une durabilité et une disponibilité exceptionnelles tout en permettant un accès rapide et une sécurité robuste.
Concepts clés
Buckets et objets
Buckets : Conteneurs de niveau supérieur pour les objets. Ils ont un nom unique globalement et sont associés à une région AWS spécifique.
Objets : Entités de base stockées dans S3, composées de :
- Données : Le contenu réel de l'objet (fichier)
- Clé : Identifiant unique de l'objet dans le bucket, formant une structure de pseudo-dossiers avec les "/"
- Métadonnées : Ensemble de paires nom-valeur (type de contenu, date de dernière modification, etc.)
- Identifiant de version : Si le versionnement est activé pour le bucket
- Sous-ressources : ACL, torrent, politique de cycle de vie, etc.
Opérations de base avec AWS SDK
Voici comment utiliser le SDK AWS pour JavaScript avec S3 :
// Exemples d'utilisation du SDK AWS pour Node.js avec S3
const { S3Client, PutObjectCommand, GetObjectCommand, ListObjectsV2Command, DeleteObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
const fs = require('fs');
// Initialisation du client S3
const s3Client = new S3Client({ region: 'eu-west-3' });
// 1. Téléversement d'un fichier dans un bucket
async function uploadFile(bucketName, key, filePath) {
try {
const fileContent = fs.readFileSync(filePath);
const command = new PutObjectCommand({
Bucket: bucketName,
Key: key,
Body: fileContent,
ContentType: 'application/pdf', // Ajustez selon le type de fichier
Metadata: {
'x-amz-meta-title': 'Mon document important',
'x-amz-meta-owner': 'user123'
},
// Chiffrement côté serveur avec clés gérées par AWS
ServerSideEncryption: 'AES256'
});
const result = await s3Client.send(command);
console.log('Fichier téléversé avec succès', result);
return true;
} catch (err) {
console.error('Erreur lors du téléversement:', err);
return false;
}
}
// 2. Récupération d'un fichier depuis un bucket
async function downloadFile(bucketName, key, outputPath) {
try {
const command = new GetObjectCommand({
Bucket: bucketName,
Key: key
});
const response = await s3Client.send(command);
// Création d'un stream d'écriture vers le fichier local
const writeStream = fs.createWriteStream(outputPath);
// Pipe du corps de la réponse vers le fichier
response.Body.pipe(writeStream);
return new Promise((resolve, reject) => {
writeStream.on('finish', () => {
console.log('Fichier téléchargé avec succès');
resolve(true);
});
writeStream.on('error', (err) => {
console.error('Erreur d'écriture du fichier:', err);
reject(err);
});
});
} catch (err) {
console.error('Erreur lors du téléchargement:', err);
return false;
}
}
// 3. Génération d'une URL présignée pour un accès temporaire
async function generatePresignedUrl(bucketName, key, expirationSeconds = 3600) {
try {
const command = new GetObjectCommand({
Bucket: bucketName,
Key: key
});
const url = await getSignedUrl(s3Client, command, { expiresIn: expirationSeconds });
console.log('URL présignée:', url);
return url;
} catch (err) {
console.error('Erreur lors de la génération de l'URL:', err);
return null;
}
}
// 4. Liste des objets dans un bucket
async function listBucketObjects(bucketName, prefix = '') {
try {
const command = new ListObjectsV2Command({
Bucket: bucketName,
Prefix: prefix,
MaxKeys: 1000
});
const response = await s3Client.send(command);
console.log(`${response.KeyCount} objets trouvés dans le bucket`);
response.Contents.forEach(item => {
console.log(`- ${item.Key} (${item.Size} octets, modifié le ${item.LastModified})`);
});
// Gérer la pagination si nécessaire
if (response.IsTruncated) {
console.log('Résultats tronqués, ContinuationToken pour la page suivante:', response.NextContinuationToken);
}
return response.Contents;
} catch (err) {
console.error('Erreur lors de la liste des objets:', err);
return [];
}
}
// 5. Suppression d'un objet
async function deleteObject(bucketName, key) {
try {
const command = new DeleteObjectCommand({
Bucket: bucketName,
Key: key
});
const response = await s3Client.send(command);
console.log('Objet supprimé avec succès', response);
return true;
} catch (err) {
console.error('Erreur lors de la suppression:', err);
return false;
}
}
Hébergement de sites web statiques
S3 peut héberger des sites web statiques complets avec HTML, CSS, JavaScript, images et autres fichiers :
# 1. Configuration d'un bucket S3 pour l'hébergement de site statique via Terraform
resource "aws_s3_bucket" "website" {
bucket = "example-static-website"
// Les ACLs sont dépréciées dans les nouvelles versions de Terraform AWS Provider
}
resource "aws_s3_bucket_website_configuration" "website" {
bucket = aws_s3_bucket.website.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
routing_rule {
condition {
key_prefix_equals = "docs/"
}
redirect {
replace_key_prefix_with = "documents/"
}
}
}
resource "aws_s3_bucket_ownership_controls" "website" {
bucket = aws_s3_bucket.website.id
rule {
object_ownership = "BucketOwnerPreferred"
}
}
resource "aws_s3_bucket_public_access_block" "website" {
bucket = aws_s3_bucket.website.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_acl" "website" {
depends_on = [
aws_s3_bucket_ownership_controls.website,
aws_s3_bucket_public_access_block.website,
]
bucket = aws_s3_bucket.website.id
acl = "public-read"
}
# Politique de bucket pour permettre l'accès public en lecture
resource "aws_s3_bucket_policy" "website" {
bucket = aws_s3_bucket.website.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Principal = "*"
Action = [
"s3:GetObject"
]
Effect = "Allow"
Resource = [
"${aws_s3_bucket.website.arn}/*"
]
},
]
})
}
# 2. Configuration d'un CloudFront avec S3 comme origine pour un site web
resource "aws_cloudfront_distribution" "website" {
origin {
domain_name = aws_s3_bucket_website_configuration.website.website_endpoint
origin_id = "S3-${aws_s3_bucket.website.id}"
custom_origin_config {
http_port = 80
https_port = 443
origin_protocol_policy = "http-only"
origin_ssl_protocols = ["TLSv1.2"]
}
}
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
price_class = "PriceClass_100" # Utiliser uniquement les emplacements les moins chers
# Alias pour le domaine personnalisé
aliases = ["www.example.com", "example.com"]
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-${aws_s3_bucket.website.id}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
compress = true
}
# Configuration pour les fichiers d'erreur personnalisés
custom_error_response {
error_code = 404
response_code = 404
response_page_path = "/error.html"
error_caching_min_ttl = 300
}
# Configuration des restrictions géographiques
restrictions {
geo_restriction {
restriction_type = "none"
}
}
# Certificat SSL/TLS
viewer_certificate {
acm_certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/abcdef01-2345-6789-abcd-ef0123456789"
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
}
Politiques de bucket et sécurité
Les politiques de bucket permettent un contrôle d'accès granulaire basé sur des conditions diverses :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket/*"
},
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD632BHDS5"
}
}
},
{
"Sid": "DenyUnencryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
},
{
"Sid": "RestrictToSpecificIP",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"192.0.2.0/24",
"198.51.100.0/24"
]
},
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
Intégration avec Lambda via des triggers d'événements
S3 peut déclencher des fonctions Lambda lors d'événements spécifiques :
# Configuration d'un trigger Lambda sur un événement S3 avec Terraform
# Définition d'une fonction Lambda qui sera déclenchée lors du téléversement de fichiers
resource "aws_lambda_function" "s3_trigger_function" {
function_name = "s3-event-processor"
handler = "index.handler"
runtime = "nodejs16.x"
role = aws_iam_role.lambda_exec.arn
filename = "lambda_function.zip"
environment {
variables = {
OUTPUT_BUCKET = aws_s3_bucket.processed_bucket.bucket
}
}
}
# Création d'une permission pour que S3 puisse invoquer la fonction Lambda
resource "aws_lambda_permission" "allow_s3" {
statement_id = "AllowExecutionFromS3Bucket"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.s3_trigger_function.function_name
principal = "s3.amazonaws.com"
source_arn = aws_s3_bucket.source_bucket.arn
}
# Configuration de la notification sur le bucket source
resource "aws_s3_bucket_notification" "bucket_notification" {
bucket = aws_s3_bucket.source_bucket.id
lambda_function {
lambda_function_arn = aws_lambda_function.s3_trigger_function.arn
events = ["s3:ObjectCreated:*"]
filter_prefix = "uploads/"
filter_suffix = ".jpg"
}
depends_on = [aws_lambda_permission.allow_s3]
}
# Code de la fonction Lambda (index.js)
/*
exports.handler = async (event, context) => {
// Récupération des informations sur l'événement S3
const bucket = event.Records[0].s3.bucket.name;
const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/+/g, ' '));
const outputBucket = process.env.OUTPUT_BUCKET;
console.log(`Nouveau fichier détecté: ${key} dans le bucket ${bucket}`);
try {
// Traitement du fichier (par exemple, redimensionnement d'image)
// ...
// Génération d'un nouveau nom de fichier pour la sortie
const outputKey = `processed/${path.basename(key)}`;
// Sauvegarde du fichier traité dans le bucket de sortie
// ...
console.log(`Traitement réussi, résultat sauvé dans ${outputBucket}/${outputKey}`);
return {
statusCode: 200,
body: JSON.stringify({ message: 'Traitement réussi' })
};
} catch (error) {
console.error('Erreur lors du traitement:', error);
throw error;
}
};
*/
Fonctionnalités avancées
- Classes de stockage : Différentes options pour optimiser les coûts en fonction des besoins d'accès (Standard, Intelligent-Tiering, Standard-IA, One Zone-IA, Glacier, Glacier Deep Archive)
- Versionnement : Conservation de plusieurs versions d'un même objet pour la protection contre les suppressions et modifications accidentelles
- Verrouillage d'objets : Prévention de la suppression ou du remplacement d'objets pendant une période définie (mode gouvernance ou conformité)
- Chiffrement : Chiffrement côté serveur (SSE-S3, SSE-KMS, SSE-C) et chiffrement côté client
- Gestion du cycle de vie : Configuration de règles pour transférer automatiquement les objets entre classes de stockage ou les supprimer après une période définie
- Réplication : Réplication entre régions (CRR) ou dans la même région (SRR) pour la résilience et la réduction de la latence
- Transfer Acceleration : Transferts de fichiers rapides sur de longues distances via les emplacements edge de CloudFront
- Points d'accès : Création de points d'entrée dédiés pour les buckets avec des politiques personnalisées
- Inventaire : Génération de rapports sur les objets et leurs métadonnées pour l'analyse et la gestion
- Analyses : Analyse des patterns d'accès pour optimiser les classes de stockage et les coûts
- Sélection d'objets : Requêtes SQL pour récupérer uniquement les données pertinentes d'objets volumineux
Performance et optimisation
- Préfixes parallèles : Distribution des objets avec différents préfixes pour une meilleure performance (3500+ requêtes PUT/COPY/POST/DELETE ou 5500+ requêtes GET/HEAD par seconde par préfixe)
- Téléversement multipartite : Division des fichiers volumineux en parties téléversées en parallèle
- Transfer Acceleration : Optimisation des transferts longue distance
- CloudFront : CDN pour la mise en cache et la distribution de contenu aux utilisateurs avec une latence minimale
- S3 Select : Filtrage côté serveur pour réduire la quantité de données transférées
- Requester Pays : Facturation des frais de transfert de données au demandeur plutôt qu'au propriétaire du bucket
Modèle de cohérence des données
- Cohérence forte (Strong Read-After-Write) : S3 offre désormais une cohérence forte par défaut pour toutes les opérations GET, PUT et LIST
- Implications pour les développeurs : Simplification du code, plus besoin d'implémenter des logiques complexes pour gérer les incoherences temporaires
Cas d'usage
Hébergement de sites statiques
S3 est parfait pour héberger des sites web statiques avec HTML, CSS et JavaScript. Combiné à CloudFront, il offre une distribution mondiale rapide et sécurisée avec HTTPS et permet d'atteindre une haute disponibilité à moindre coût.
Data lakes et analyse de données
S3 sert de fondation pour des data lakes à grande échelle, permettant de stocker des données brutes dans leur format natif. Avec des services comme Athena, Redshift Spectrum et
AWS Glue, il devient possible d'analyser ces données directement sans nécessiter d'extraction préalable.
Stockage de médias et distribution de contenu
Stockage et distribution efficace de contenus média (images, vidéos, audio) pour les applications et sites web. Avec CloudFront, les contenus sont diffusés rapidement aux utilisateurs du monde entier, réduisant la latence et améliorant l'expérience utilisateur. Les vidéos peuvent être traitées avec
MediaConvert.
Sauvegarde et archivage
Solution rentable pour les sauvegardes et l'archivage à long terme grâce aux classes de stockage économiques comme S3 Glacier. Les politiques de cycle de vie permettent de déplacer automatiquement les données vers des stockages moins coûteux à mesure qu'elles vieillissent.
Industries utilisant S3
S3 est utilisé par des entreprises de toutes tailles et dans divers secteurs :