Créer une URL Présignée S3 : Accès Temporaire à un Fichier Privé
Vous avez un fichier privé dans S3 et vous devez donner à un utilisateur un accès temporaire pour le télécharger — sans exposer vos credentials, sans rendre le bucket public, et sans passer par un proxy applicatif. C'est exactement le cas d'usage des URLs présignées S3 : générer un lien à durée limitée qui porte la signature de votre identité IAM, valide pendant la fenêtre que vous définissez.
TL;DR — Résumé Opérationnel
| Élément | Détail |
|---|---|
| Objectif | Générer une URL présignée S3 avec expiration de 1 heure |
| SDK recommandé | AWS SDK v3 pour Python (boto3) ou JavaScript (v3) |
| Opération signée | GetObject |
| Durée maximale (credentials IAM) | 7 jours (604 800 secondes) avec credentials à long terme |
| Durée maximale (rôle IAM / STS) | Limitée à la durée de session du token STS |
| Prérequis IAM | s3:GetObject sur la ressource cible |
| Visibilité bucket | Le bucket reste privé — aucune modification de politique nécessaire |
Comment Fonctionnent les URLs Présignées S3
Une URL présignée n'est pas un token opaque géré côté AWS. C'est une URL HTTP standard dont les paramètres de requête encodent la signature HMAC-SHA256 de la requête, calculée avec vos credentials au moment de la génération. Quand l'utilisateur accède à l'URL, S3 revalide cette signature — si elle est valide et non expirée, S3 sert le fichier directement au client, sans que votre application soit dans la boucle.
Conséquence directe : si les credentials utilisés pour signer sont révoqués ou expirés avant la fin de la fenêtre d'expiration, l'URL devient immédiatement invalide. C'est particulièrement important avec les rôles IAM assumés via STS — la durée de validité de l'URL est bornée par la durée de vie du token de session, pas seulement par le paramètre ExpiresIn que vous passez au SDK.
avec credentials IAM actifs SDK-->>App: URL présignée (chaîne) App-->>User: Transmission de l'URL (API, email...) User->>S3: GET HTTP direct sur l'URL présignée Note over S3: Vérifie signature + expiration S3-->>User: 200 OK + contenu du fichier
- Votre application appelle le SDK avec les credentials IAM actifs et génère l'URL localement — aucun appel réseau vers S3 à cette étape.
- L'URL signée est transmise à l'utilisateur final (email, réponse API, etc.).
- L'utilisateur effectue un
GETHTTP direct sur l'URL — son navigateur ou client HTTP contacte S3 directement. - S3 vérifie la signature et l'expiration, puis sert le fichier ou retourne une erreur
403 AccessDenied/403 Request has expired.
Prérequis IAM pour Générer une URL Présignée S3
La génération de l'URL elle-même est une opération locale au SDK — elle ne nécessite pas d'appel API vers AWS. Mais l'URL générée ne sera utilisable que si l'identité IAM qui a signé dispose de la permission s3:GetObject sur l'objet cible. Sans cette permission, S3 retournera une erreur 403 au moment où l'utilisateur tentera d'utiliser l'URL.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowGetObjectForPresigning",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::nom-de-votre-bucket/chemin/vers/fichiers/*"
}
]
}
Appliquez ce principe de moindre privilège : restreignez la ressource au préfixe exact des objets que votre application doit présigner, pas à l'ensemble du bucket.
Générer une URL Présignée S3 avec boto3 (Python)
boto3 expose la méthode generate_presigned_url sur le client S3. Le paramètre ExpiresIn est en secondes — 3600 pour une heure.
import boto3
from botocore.exceptions import ClientError
def generer_url_presignee(nom_bucket: str, cle_objet: str, expiration: int = 3600) -> str | None:
"""
Génère une URL présignée S3 pour l'opération GetObject.
:param nom_bucket: Nom du bucket S3 contenant l'objet
:param cle_objet: Clé (chemin) de l'objet dans le bucket
:param expiration: Durée de validité en secondes (défaut : 3600 = 1 heure)
:return: URL présignée sous forme de chaîne, ou None en cas d'erreur
"""
client_s3 = boto3.client('s3', region_name='us-east-1')
try:
url = client_s3.generate_presigned_url(
ClientMethod='get_object',
Params={
'Bucket': nom_bucket,
'Key': cle_objet
},
ExpiresIn=expiration
)
return url
except ClientError as e:
print(f'Erreur lors de la génération de l\'URL présignée : {e}')
return None
# Exemple d'utilisation
url = generer_url_presignee(
nom_bucket='mon-bucket-prive',
cle_objet='rapports/2024/rapport-annuel.pdf',
expiration=3600
)
if url:
print(f'URL valide pendant 1 heure : {url}')
La méthode retourne directement l'URL sous forme de chaîne. Aucun appel réseau n'est effectué — la signature est calculée localement par le SDK à partir des credentials résolus dans la chaîne de credential providers de boto3 (variables d'environnement, profil, rôle EC2/ECS, etc.).
Générer une URL Présignée S3 avec le SDK JavaScript v3
Avec le SDK AWS JavaScript v3, la génération d'URL présignées passe par le package @aws-sdk/s3-request-presigner combiné au client S3 v3. L'API est différente du SDK v2 — getSignedUrl est une fonction importée séparément, pas une méthode du client.
🔽 Cliquer pour afficher le code JavaScript (SDK v3)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const clientS3 = new S3Client({ region: 'us-east-1' });
async function genererUrlPresignee(
nomBucket,
cleObjet,
expirationSecondes = 3600
) {
const commande = new GetObjectCommand({
Bucket: nomBucket,
Key: cleObjet,
});
try {
const url = await getSignedUrl(clientS3, commande, {
expiresIn: expirationSecondes,
});
return url;
} catch (erreur) {
console.error('Erreur génération URL présignée :', erreur);
throw erreur;
}
}
// Exemple d'utilisation
const url = await genererUrlPresignee(
'mon-bucket-prive',
'rapports/2024/rapport-annuel.pdf',
3600
);
console.log('URL présignée :', url);
Générer une URL Présignée via l'AWS CLI
Pour tester rapidement sans écrire de code, la CLI AWS propose la commande presign. C'est utile en phase de débogage pour vérifier que les permissions IAM sont correctes avant d'intégrer la génération dans votre application.
aws s3 presign s3://mon-bucket-prive/rapports/2024/rapport-annuel.pdf \
--expires-in 3600 \
--region us-east-1
La commande retourne l'URL complète dans stdout. Copiez-la dans un navigateur ou via curl pour valider que S3 sert bien le fichier avec les credentials actifs de votre profil CLI.
Piège Classique : URL Présignée Invalide avec un Rôle IAM Assumé
Le scénario se présente comme ça : votre Lambda génère une URL présignée avec ExpiresIn=3600. L'URL est envoyée à l'utilisateur. Quelques minutes plus tard, l'utilisateur clique sur le lien et obtient une erreur 403 Request has expired — alors que l'heure n'est pas écoulée.
Le diagnostic instinctif est de vérifier l'horloge système ou le fuseau horaire. Mauvaise piste.
La vraie cause : votre Lambda s'exécute avec un rôle IAM assumé via STS. Le token de session STS associé à ce rôle avait une durée de vie de, disons, 15 minutes. L'URL présignée est signée avec ce token temporaire. Quand le token expire, l'URL expire avec lui — indépendamment du paramètre ExpiresIn que vous avez passé.
C'est comme signer un chèque avec un compte bancaire qui sera fermé dans 15 minutes. Peu importe la date d'encaissement inscrite sur le chèque — si le compte est fermé, le chèque est refusé.
Pour diagnostiquer, vérifiez la durée de session configurée sur le rôle IAM et comparez-la à votre ExpiresIn :
aws iam get-role \
--role-name NomDeVotreRole \
--query 'Role.MaxSessionDuration' \
--output text \
--region us-east-1
Si MaxSessionDuration est inférieur à votre ExpiresIn, l'URL sera invalide avant son expiration théorique. La solution est soit d'augmenter MaxSessionDuration sur le rôle (jusqu'à 43 200 secondes), soit de réduire ExpiresIn pour rester dans la fenêtre de validité du token.
- Token STS valide : L'URL présignée fonctionne normalement, S3 sert le fichier.
- Token STS expiré : Même si
ExpiresInn'est pas atteint, S3 retourne403— la signature ne peut plus être validée. - ExpiresIn dépassé : S3 retourne
403 Request has expiredindépendamment de l'état du token.
Vérification et Débogage d'une URL Présignée S3
Avant d'intégrer la génération d'URL dans un flux de production, validez chaque couche indépendamment. Les erreurs 403 sur une URL présignée ont plusieurs causes distinctes et le message d'erreur S3 ne les distingue pas toujours clairement.
Étape 1 — Vérifier que l'objet existe : Une URL présignée pour un objet inexistant retourne 404 NoSuchKey, pas 403. Confirmez d'abord l'existence de l'objet.
aws s3api head-object \
--bucket mon-bucket-prive \
--key rapports/2024/rapport-annuel.pdf \
--region us-east-1
Étape 2 — Vérifier les permissions IAM de l'identité signataire : Simulez l'appel GetObject avec l'identité qui génère l'URL pour confirmer que la permission est bien accordée.
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/NomDeVotreRole \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::mon-bucket-prive/rapports/2024/rapport-annuel.pdf \
--region us-east-1
Étape 3 — Vérifier qu'une politique de bucket ne bloque pas l'accès : Une politique de bucket avec Deny explicite sur s3:GetObject écrase les permissions IAM. Inspectez la politique du bucket.
aws s3api get-bucket-policy \
--bucket mon-bucket-prive \
--query 'Policy' \
--output text \
--region us-east-1
Étape 4 — Tester l'URL générée immédiatement : Générez une URL via la CLI et testez-la dans les secondes qui suivent pour éliminer les problèmes d'expiration.
URL=$(aws s3 presign s3://mon-bucket-prive/rapports/2024/rapport-annuel.pdf \
--expires-in 3600 \
--region us-east-1)
curl -I "$URL"
Un HTTP/1.1 200 OK confirme que la chaîne complète fonctionne — permissions IAM, politique bucket, existence de l'objet. Un 403 immédiat pointe vers un problème de permissions, pas d'expiration.
Considérations de Sécurité pour les URLs Présignées S3
Une URL présignée est un credential à usage général pendant sa durée de validité — quiconque possède l'URL peut télécharger le fichier. Quelques points opérationnels à garder en tête :
- Durée d'expiration minimale nécessaire : Ne générez pas des URLs valides 24 heures si l'utilisateur a besoin de 5 minutes. Réduisez la fenêtre au strict nécessaire.
- Transmission sécurisée : Transmettez l'URL uniquement via HTTPS. Une URL présignée transmise en clair peut être interceptée et réutilisée.
- Révocation impossible : Une fois générée, une URL présignée ne peut pas être révoquée directement. La seule façon d'invalider une URL active est de révoquer les credentials IAM qui l'ont signée — ce qui a des effets de bord importants si ces credentials sont partagés.
- Chiffrement côté serveur : Les URLs présignées fonctionnent avec les objets chiffrés SSE-S3 et SSE-KMS. Pour SSE-KMS, l'identité signataire doit également avoir les permissions
kms:GenerateDataKeyetkms:Decryptsur la clé KMS utilisée.
Prochaines Étapes et Ressources
Les URLs présignées S3 couvrent le cas d'usage du téléchargement temporaire, mais si vous avez besoin de permettre à un utilisateur d'uploader un fichier directement dans S3 sans passer par votre serveur, la même mécanique s'applique avec l'opération PutObject — boto3 supporte ClientMethod='put_object' dans generate_presigned_url, et le SDK JS v3 utilise PutObjectCommand avec getSignedUrl.
Pour les uploads multi-parts présignés ou les formulaires HTML POST directs vers S3, consultez la documentation AWS sur les uploads via URL présignée et les POST policies S3.
Glossaire des Termes Clés
| Terme | Définition |
|---|---|
| URL Présignée | URL HTTP dont les paramètres de requête encodent une signature HMAC permettant un accès temporaire à un objet S3 privé sans credentials supplémentaires. |
| STS (Security Token Service) | Service AWS qui émet des credentials temporaires (access key + secret + session token) pour les rôles IAM assumés. |
| ExpiresIn | Paramètre SDK définissant la durée de validité de l'URL en secondes à partir du moment de génération. |
| SSE-KMS | Chiffrement côté serveur S3 utilisant une clé AWS KMS gérée par le client. Requiert des permissions KMS supplémentaires pour les URLs présignées. |
| Politique de bucket | Politique de ressource attachée au bucket S3 pouvant accorder ou refuser l'accès indépendamment des politiques IAM — un Deny explicite écrase les permissions IAM. |
Commentaires
Enregistrer un commentaire