S3 Presigned URL erstellen: Temporären Dateizugriff mit AWS SDK generieren
Du hast eine private S3-Datei und musst einem externen Nutzer für genau eine Stunde Lesezugriff gewähren — ohne IAM-Credentials weiterzugeben, ohne den Bucket öffentlich zu machen. Genau für diesen Fall existiert die S3 Presigned URL: ein signierter Link, der temporären Zugriff auf ein einzelnes Objekt erlaubt.
TL;DR — S3 Presigned URL auf einen Blick
| Aspekt | Detail |
|---|---|
| Zweck | Temporärer Zugriff auf private S3-Objekte ohne Bucket-Öffnung |
| Ablaufzeit | Konfigurierbar — typisch 15 Minuten bis 7 Tage (je nach Signing-Methode) |
| Signierungsidentität | IAM-User oder IAM-Role, die die URL generiert |
| SDK-Methode (Python) | generate_presigned_url via boto3 |
| SDK-Methode (Node.js) | getSignedUrl / getSignedUrlPromise via AWS SDK v2 oder getSignedUrl aus @aws-sdk/s3-request-presigner via v3 |
| Kritische Abhängigkeit | URL-Gültigkeit ist an die signierende Identität gebunden |
Wie S3 Presigned URLs funktionieren
Eine Presigned URL ist kein Token — sie ist eine vollständige HTTPS-URL, in die Authentifizierungsinformationen als Query-Parameter eingebettet sind. Wenn ein Nutzer die URL aufruft, prüft S3 die Signatur gegen die Credentials der Identität, die die URL erzeugt hat. Ist die Signatur gültig und die Ablaufzeit nicht überschritten, liefert S3 das Objekt aus — unabhängig davon, ob der Bucket privat ist.
Entscheidend: Die Berechtigungen der URL entsprechen den Berechtigungen der signierenden Identität zum Zeitpunkt des Abrufs, nicht zum Zeitpunkt der Generierung. Wird die IAM-Role oder der IAM-User in der Zwischenzeit deaktiviert oder die Berechtigung entzogen, ist die URL sofort wirkungslos — auch wenn die Ablaufzeit noch nicht erreicht ist.
- Generierung: Deine Anwendung ruft die SDK-Methode mit Bucket, Key und Ablaufzeit auf. Das SDK signiert die URL mit den aktuellen Credentials der Laufzeitidentität (z.B. EC2-Instance-Role).
- Weitergabe: Die signierte URL wird an den Endnutzer übergeben — per E-Mail, API-Response oder Download-Link.
- Abruf: Der Nutzer ruft die URL direkt auf. S3 validiert Signatur und Ablaufzeit, dann liefert es das Objekt aus — ohne dass deine Anwendung involviert ist.
- Ablauf: Nach Überschreiten der konfigurierten Ablaufzeit gibt S3 einen Fehler zurück. Die URL ist dauerhaft ungültig.
Voraussetzungen: IAM-Berechtigungen für Presigned URLs
Die signierende Identität muss s3:GetObject auf das Zielobjekt besitzen. Ohne diese Berechtigung erzeugt das SDK zwar eine URL, aber S3 verweigert den Zugriff beim Abruf mit einem 403 AccessDenied.
Minimale IAM-Policy für die signierende Identität:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mein-privater-bucket/*"
}
]
}
Wenn die Anwendung nur auf einen bestimmten Ordner zugreifen soll, empfiehlt sich eine engere Resource-Einschränkung, z.B. arn:aws:s3:::mein-privater-bucket/downloads/*.
S3 Presigned URL mit Python (boto3) generieren
Das folgende Beispiel erzeugt eine Presigned URL mit einer Ablaufzeit von 3600 Sekunden (1 Stunde) für ein GetObject-Request.
import boto3
from botocore.exceptions import ClientError
def generate_presigned_url(bucket_name: str, object_key: str, expiration: int = 3600) -> str | None:
s3_client = boto3.client('s3', region_name='eu-central-1')
try:
url = s3_client.generate_presigned_url(
ClientMethod='get_object',
Params={
'Bucket': bucket_name,
'Key': object_key
},
ExpiresIn=expiration
)
return url
except ClientError as e:
print(f'Fehler beim Generieren der Presigned URL: {e}')
return None
# Beispielaufruf
presigned_url = generate_presigned_url(
bucket_name='mein-privater-bucket',
object_key='reports/quartalsbericht-q1-2024.pdf'
)
print(presigned_url)
Der Parameter ExpiresIn erwartet Sekunden als Integer. 3600 entspricht einer Stunde. Das SDK berechnet die Ablaufzeit relativ zum Zeitpunkt der Generierung.
S3 Presigned URL mit Node.js (AWS SDK v3) generieren
Mit AWS SDK v3 wird getSignedUrl aus dem Paket @aws-sdk/s3-request-presigner in Kombination mit einem GetObjectCommand verwendet.
🔽 Node.js Beispiel aufklappen (AWS SDK v3)
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
const s3Client = new S3Client({ region: 'eu-central-1' });
async function generatePresignedUrl(
bucketName: string,
objectKey: string,
expiresInSeconds: number = 3600
): Promise<string> {
const command = new GetObjectCommand({
Bucket: bucketName,
Key: objectKey,
});
const url = await getSignedUrl(s3Client, command, {
expiresIn: expiresInSeconds,
});
return url;
}
// Beispielaufruf
generatePresignedUrl('mein-privater-bucket', 'reports/quartalsbericht-q1-2024.pdf')
.then(url => console.log(url))
.catch(err => console.error('Fehler:', err));
Presigned URL über die AWS CLI generieren
Für schnelle Tests oder Skripte ohne SDK-Integration funktioniert die CLI direkt. Die Ablaufzeit wird in Sekunden angegeben.
aws s3 presign s3://mein-privater-bucket/reports/quartalsbericht-q1-2024.pdf \
--expires-in 3600 \
--region eu-central-1
Die CLI gibt die vollständige signierte URL auf stdout aus. Die signierende Identität ist die aktive CLI-Konfiguration — also entweder ein IAM-User-Profil oder eine angenommene Role.
Häufige Fehlerquelle: STS-temporäre Credentials und Ablaufzeit
Hier liegt eine der häufigsten Fallen in der Praxis: Eine Lambda-Funktion oder EC2-Instance läuft unter einer IAM-Role. Das SDK holt sich intern STS-temporäre Credentials. Die Presigned URL wird mit diesen temporären Credentials signiert — und die URL ist nur so lange gültig, wie die zugrundeliegenden STS-Credentials gültig sind.
Stell dir vor, du druckst einen Türschlüssel mit einem Ablaufdatum auf. Wenn der Schlosser, der den Schlüssel autorisiert hat, seinen Ausweis verliert, werden alle damit gedruckten Schlüssel sofort ungültig — unabhängig vom aufgedruckten Datum.
Konkret: Wenn eine Lambda-Funktion eine URL mit ExpiresIn=3600 generiert, die zugrundeliegenden STS-Credentials aber in 15 Minuten ablaufen, ist die URL nach 15 Minuten ungültig — nicht nach einer Stunde. S3 gibt dann einen 403 Request has expired zurück.
Für langlebige Presigned URLs empfiehlt sich eine dedizierte IAM-User-Identität mit langfristigen Credentials, oder eine IAM-Role mit ausreichend langer Session-Duration. Die maximale Session-Duration einer IAM-Role ist konfigurierbar und liegt standardmäßig bei einer Stunde.
ExpiresIn=3600s] --> B{Signierende Identität?} B --> C[IAM User
Langfristige Credentials] B --> D[IAM Role
STS-Credentials] C --> E[URL läuft nach
genau 3600s ab] D --> F{STS Session
länger als 3600s?} F -->|Ja| G[URL läuft nach
genau 3600s ab] F -->|Nein| H[URL läuft mit
STS-Session ab
403 vor ExpiresIn]
- Szenario A (sicher): IAM-User-Credentials sind langfristig gültig. Die URL läuft nach genau
ExpiresInSekunden ab. - Szenario B (Falle): STS-Credentials der Lambda-Role laufen in 15 Minuten ab. Die URL mit
ExpiresIn=3600wird nach 15 Minuten ungültig — nicht nach 60. - Szenario C (korrekt konfiguriert): IAM-Role mit Session-Duration von 4 Stunden. URL mit
ExpiresIn=3600läuft nach genau einer Stunde ab, da die STS-Session länger gültig ist.
Ablaufzeit und Signing-Methode: SigV4-Limit beachten
AWS Signature Version 4 (SigV4) ist die aktuelle Signing-Methode für S3 Presigned URLs. Bei SigV4 beträgt die maximale Ablaufzeit 7 Tage (604800 Sekunden). Wird ein höherer Wert übergeben, gibt das SDK einen Fehler zurück. Für kurzlebige Zugriffslinks — etwa für Download-Buttons in Web-Applikationen — sind 15 bis 60 Minuten operativ sinnvoll.
Presigned URL für Upload (PutObject) generieren
Presigned URLs funktionieren nicht nur für Downloads. Mit put_object als ClientMethod kann ein Nutzer direkt in S3 hochladen, ohne Zugriff auf den Bucket zu benötigen. Die signierende Identität muss dann s3:PutObject besitzen.
upload_url = s3_client.generate_presigned_url(
ClientMethod='put_object',
Params={
'Bucket': 'mein-privater-bucket',
'Key': 'uploads/nutzer-upload.pdf',
'ContentType': 'application/pdf'
},
ExpiresIn=900
)
Der Client muss beim Upload den gleichen Content-Type-Header setzen, der bei der Generierung angegeben wurde — sonst schlägt die Signaturvalidierung fehl.
Diagnose: Warum gibt S3 403 zurück?
Ein 403 AccessDenied bei einer Presigned URL hat in der Praxis drei häufige Ursachen. Jede erfordert einen anderen Diagnosepfad.
Schritt 1 — Bucket-Policy prüfen: Eine explizite Deny-Regel in der Bucket-Policy überschreibt jede IAM-Allow-Berechtigung. Das ist die erste Stelle, die nach einem unerklärlichen 403 geprüft werden sollte, weil IAM-Berechtigungen allein keinen vollständigen Überblick geben.
aws s3api get-bucket-policy \
--bucket mein-privater-bucket \
--region eu-central-1
Schritt 2 — Effektive Berechtigungen der signierenden Identität prüfen: Wenn die Bucket-Policy sauber ist, liegt das Problem möglicherweise bei der IAM-Identität. Mit dem IAM Policy Simulator lässt sich prüfen, ob s3:GetObject für die spezifische Identität und den spezifischen Ressourcen-ARN erlaubt ist.
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:role/MeineAppRole \
--action-names s3:GetObject \
--resource-arns arn:aws:s3:::mein-privater-bucket/reports/quartalsbericht-q1-2024.pdf \
--region us-east-1
Schritt 3 — STS-Credential-Ablauf prüfen: Wenn die URL kurz nach der Generierung funktioniert, aber nach wenigen Minuten einen 403 zurückgibt, sind abgelaufene STS-Credentials die wahrscheinlichste Ursache. Die aktuelle Session-Duration der Role lässt sich so prüfen:
aws iam get-role \
--role-name MeineAppRole \
--query 'Role.MaxSessionDuration' \
--output text
Schritt 4 — Block Public Access und Object-Ownership-Einstellungen: Diese Einstellungen betreffen primär ACL-basierte Zugriffe, können aber in bestimmten Konfigurationen das Verhalten beeinflussen. Prüfe die aktuellen Einstellungen:
aws s3api get-public-access-block \
--bucket mein-privater-bucket \
--region eu-central-1
Wrap-up: S3 Presigned URL produktionsreif einsetzen
Eine S3 Presigned URL für temporären Dateizugriff ist in wenigen Zeilen SDK-Code implementiert. Die kritischen Punkte in der Praxis sind nicht die Generierung selbst, sondern die Abhängigkeit der URL-Gültigkeit von der Laufzeit der signierenden Credentials — besonders bei STS-basierten Identitäten wie Lambda-Roles oder ECS-Task-Roles.
Für produktive Implementierungen empfiehlt sich:
- Ablaufzeiten so kurz wie operativ sinnvoll halten (15–60 Minuten für Download-Links)
- Bei Verwendung von IAM-Roles die
MaxSessionDurationexplizit auf einen Wert setzen, der die gewünschte URL-Ablaufzeit übersteigt - Bucket-Policies regelmäßig auf unbeabsichtigte Deny-Regeln prüfen
- Presigned URLs niemals in Logs oder Monitoring-Systemen speichern — sie enthalten eingebettete Signaturinformationen
Weiterführende Dokumentation: AWS Dokumentation — Using presigned URLs
Glossar
| Begriff | Bedeutung |
|---|---|
| Presigned URL | Signierte S3-URL mit eingebetteten Credentials und Ablaufzeit für temporären Objektzugriff |
| SigV4 | AWS Signature Version 4 — aktuelles Signierungsprotokoll für AWS API-Requests |
| STS (Security Token Service) | AWS-Dienst zur Ausstellung temporärer Credentials für IAM-Roles |
| ExpiresIn | SDK-Parameter für die Ablaufzeit der Presigned URL in Sekunden |
| s3:GetObject | IAM-Action, die der signierenden Identität erlaubt, S3-Objekte zu lesen |
Kommentare
Kommentar veröffentlichen