AWS AccessDeniedException: So beheben Sie IAM-Fehlkonfigurationen
2026-03-22 · 9 Min. Lesezeit
Sie deployen ein neues Feature und alles funktioniert in Ihrer Entwicklungsumgebung. Sie pushen auf Staging und plötzlich schlägt jeder API-Aufruf mit dieser Meldung fehl:
An error occurred (AccessDeniedException) when calling the PutObject operation:
User: arn:aws:iam::123456789012:user/deploy-user is not authorized to perform:
s3:PutObject on resource: arn:aws:s3:::my-bucket/uploads/file.txt
Oder vielleicht sehen Sie eine noch weniger hilfreiche Variante:
An error occurred (AccessDenied) when calling the AssumeRole operation:
User: arn:aws:sts::123456789012:assumed-role/lambda-role/my-function is not
authorized to perform: sts:AssumeRole on resource:
arn:aws:iam::987654321098:role/cross-account-role
Die AccessDeniedException ist der mit Abstand häufigste Fehler in AWS. Jeder Ingenieur, der mit AWS arbeitet, begegnet ihm regelmäßig — und dennoch bleibt er einer der frustrierendsten Fehler beim Debugging, weil die Fehlermeldung selten die vollständige Geschichte erzählt. Es gibt mindestens sechs verschiedene Gründe, warum eine IAM-Anfrage abgelehnt werden kann, und die richtige Ursache zu finden, erfordert einen systematischen Ansatz.
Hier ist der exakte Prozess, den ich verwende, wenn ein Kunde mit einem Access-Denied-Problem zu uns kommt. Er funktioniert jedes Mal.
Schritt 1: Bestätigen Sie Ihre Identität
Bevor Sie Policies debuggen, überprüfen Sie, welche Identität den Request tatsächlich ausführt. Das fängt eine überraschend hohe Anzahl von Problemen ab — falsches Profil, abgelaufene Credentials oder eine angenommene Rolle, die Sie nicht erwartet haben.
aws sts get-caller-identity
Die Ausgabe verrät alles:
{
"UserId": "AIDAEXAMPLEID",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/deploy-user"
}
Falls Sie erwartet haben, eine IAM-Rolle zu verwenden, die Ausgabe aber einen IAM-User zeigt, ist das Ihr erster Hinweis. Wenn die Kontonummer falsch ist, befinden Sie sich im falschen Account. Ich habe Produktionsausfälle gesehen, die durch nichts anderes als eine abgelaufene AWS_SESSION_TOKEN-Umgebungsvariable verursacht wurden — die CLI fiel auf eine andere Credential-Quelle zurück.
Prüfen Sie Ihre Credential-Kette:
# Sehen Sie, welche Credentials verwendet werden und woher sie kommen
aws configure list
Name Value Type Location
---- ----- ---- --------
profile <not set> None None
access_key ****************ABCD env
secret_key ****************1234 env
region us-east-1 config-file ~/.aws/config
Wenn die Type-Spalte env anzeigt, überschreiben Umgebungsvariablen Ihre Profilkonfiguration. Das ist einer der häufigsten Fallstricke beim Wechsel zwischen Accounts.
Schritt 2: Die genaue Ablehnung in CloudTrail finden
Die Fehlermeldung in Ihrem Terminal ist nur eine Zusammenfassung. CloudTrail hat die vollständige Geschichte — einschließlich welche Policy den Request abgelehnt hat und warum.
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=PutObject \
--start-time "2026-03-22T10:00:00Z" \
--end-time "2026-03-22T11:00:00Z" \
--query 'Events[?contains(CloudTrailEvent, `AccessDenied`)].CloudTrailEvent' \
--output text | jq '.'
Achten Sie auf die Felder errorCode und errorMessage im CloudTrail-Event. Bei neueren Events enthält CloudTrail ein accessDeniedException-Feld, das Ihnen genau sagt, welche Policy die Ablehnung verursacht hat.
Falls Sie CloudTrail Lake aktiviert haben, ist diese Abfrage noch leistungsfähiger:
SELECT eventTime, eventName, errorCode, errorMessage,
userIdentity.arn, requestParameters
FROM cloudtrail_events
WHERE errorCode = 'AccessDenied'
AND eventTime > '2026-03-22 10:00:00'
ORDER BY eventTime DESC
LIMIT 20
Ursache 1: Fehlende Actions in der IAM Policy
Die naheliegendste Ursache: Die Policy gewährt die benötigte Aktion einfach nicht. Hier ein Beispiel einer Policy, die korrekt aussieht, aber fehlschlägt:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
Diese Policy gewährt s3:GetObject und s3:ListBucket, aber wenn die Anwendung auch Dateien hochladen muss, fehlt s3:PutObject. Die Lösung ist einfach — die fehlende Aktion hinzufügen.
Aber hier gibt es eine Subtilität. Die Aktion s3:ListBucket benötigt den Bucket-ARN ohne das Suffix /*, während s3:GetObject es mit dem Suffix braucht. Das ist einer der häufigsten IAM-Fehler:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-bucket"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
Nutzen Sie den IAM Policy Simulator zum Testen vor dem Deployment:
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::123456789012:user/deploy-user \
--action-names s3:PutObject \
--resource-arns arn:aws:s3:::my-bucket/uploads/file.txt \
--query 'EvaluationResults[*].[EvalActionName, EvalDecision]' \
--output table
Das liefert ein klares allowed oder implicitDeny Ergebnis, ohne einen tatsächlichen API-Aufruf durchzuführen.
Ursache 2: Falsches Resource-ARN-Format
Resource-ARNs in IAM-Policies müssen exakt übereinstimmen. Ein fehlender Wildcard, eine falsche Region oder eine inkorrekte Kontonummer führen stillschweigend zur Ablehnung. Hier sind Fehler, die ich regelmäßig sehe:
// FALSCH: Fehlendes /* Suffix für Object-Level-Aktionen
"Resource": "arn:aws:s3:::my-bucket"
// RICHTIG: Enthält /* für Object-Level-Aktionen
"Resource": "arn:aws:s3:::my-bucket/*"
// FALSCH: S3-Buckets haben keine Region oder Account im ARN
"Resource": "arn:aws:s3:us-east-1:123456789012:my-bucket/*"
// RICHTIG: S3-Bucket-ARNs haben leere Region- und Account-Felder
"Resource": "arn:aws:s3:::my-bucket/*"
// FALSCH: Fehlender Pfadseparator für DynamoDB-Tabellen
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:my-table"
// RICHTIG: DynamoDB-Tabellen verwenden table/ als Präfix
"Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/my-table"
Im Zweifel prüfen Sie den tatsächlichen Resource-ARN:
# Den exakten ARN einer DynamoDB-Tabelle ermitteln
aws dynamodb describe-table \
--table-name my-table \
--query 'Table.TableArn' \
--output text
# Den exakten ARN einer Lambda-Funktion ermitteln
aws lambda get-function \
--function-name my-function \
--query 'Configuration.FunctionArn' \
--output text
Ursache 3: Explizites Deny überschreibt Allow
Die IAM-Policy-Evaluierung folgt einer strikten Hierarchie: Ein explizites Deny gewinnt immer. Wenn irgendeine Policy, die dem Principal zugeordnet ist, ein explizites "Effect": "Deny" enthält, das auf den Request passt, überschreibt es alle Allow-Statements überall.
Dies wird häufig durch Permission Boundaries oder Organizations-SCPs eingeführt, ohne dass das Team es bemerkt. Prüfen Sie auf Deny-Statements:
# Alle dem User zugeordneten Policies auflisten
aws iam list-attached-user-policies \
--user-name deploy-user \
--query 'AttachedPolicies[*].[PolicyName, PolicyArn]' \
--output table
# Inline-Policies auflisten
aws iam list-user-policies \
--user-name deploy-user
# Gruppen-Policies ebenfalls prüfen
aws iam list-groups-for-user \
--user-name deploy-user \
--query 'Groups[*].GroupName' \
--output text
Dann jede Policy auf Deny-Statements überprüfen:
# Eine bestimmte Policy-Version abrufen
aws iam get-policy-version \
--policy-arn arn:aws:iam::123456789012:policy/my-policy \
--version-id v1 \
--query 'PolicyVersion.Document' \
--output json | jq '.Statement[] | select(.Effect == "Deny")'
Ein häufiges Muster, das Verwirrung stiftet, ist eine Deny-All-Policy mit Ausnahmen. Zum Beispiel verweigert diese Policy alles außerhalb einer bestimmten Region:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["us-east-1", "eu-central-1"]
}
}
}
]
}
Wenn Ihr Service in us-west-2 läuft, wird jeder Aufruf abgelehnt — unabhängig davon, was Ihre Allow-Policies sagen.
Ursache 4: Service Control Policies (SCPs)
Wenn Sie sich in einer AWS Organization befinden, wirken SCPs auf OU- oder Account-Ebene als Berechtigungsgrenze für den gesamten Account. Selbst der Root-User des Accounts kann ein SCP-Deny nicht überschreiben.
# Prüfen, ob der Account in einer Organization ist
aws organizations describe-organization 2>/dev/null
# SCPs auflisten, die den aktuellen Account betreffen
aws organizations list-policies-for-target \
--target-id 123456789012 \
--filter SERVICE_CONTROL_POLICY \
--query 'Policies[*].[Name, Id]' \
--output table
Um den tatsächlichen SCP-Inhalt zu sehen:
aws organizations describe-policy \
--policy-id p-abc123def4 \
--query 'Policy.Content' \
--output text | jq '.'
SCPs basieren auf Allowlists. Wenn die SCP eine Aktion nicht explizit erlaubt, wird sie implizit abgelehnt — selbst wenn die IAM-Policy sie gewährt.
Ursache 5: Permission Boundaries
Permission Boundaries sind ein fortgeschrittenes IAM-Feature, das die maximalen Berechtigungen einer IAM-Entität festlegt. Die effektiven Berechtigungen sind die Schnittmenge aus Identity Policy und Permission Boundary — nicht die Vereinigung.
# Prüfen, ob ein User eine Permission Boundary hat
aws iam get-user \
--user-name deploy-user \
--query 'User.PermissionsBoundary' \
--output json
# Prüfen, ob eine Rolle eine Permission Boundary hat
aws iam get-role \
--role-name my-lambda-role \
--query 'Role.PermissionsBoundary' \
--output json
Wenn die Permission Boundary die benötigte Aktion nicht enthält, hilft es nicht, sie zur Identity Policy hinzuzufügen. Sie müssen sie auch zur Boundary hinzufügen.
Ursache 6: Session Policies und AssumeRole-Einschränkungen
Beim Annehmen einer Rolle können Sie optional eine Session Policy übergeben, die die Berechtigungen der Rolle weiter einschränkt. Außerdem muss die Trust Policy der Rolle dem Principal explizit erlauben, sie anzunehmen.
Prüfen Sie die Trust Policy:
aws iam get-role \
--role-name cross-account-role \
--query 'Role.AssumeRolePolicyDocument' \
--output json | jq '.'
Ein häufiger Trust-Policy-Fehler ist die fehlende sts:ExternalId-Condition oder ein falscher Principal:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "my-external-id"
}
}
}
]
}
Wenn Sie AssumeRole ohne den --external-id-Parameter aufrufen, schlägt es fehl. Wenn Sie den falschen Account im Principal angeben, schlägt es fehl. Beides erzeugt denselben generischen AccessDenied-Fehler.
Die IAM-Policy-Evaluierungslogik
Das Verständnis der Evaluierungsreihenfolge ist entscheidend. AWS evaluiert Policies in dieser Reihenfolge:
- Explizites Deny — Jedes Deny in jeder Policy blockiert den Request sofort
- Organization SCPs — Müssen die Aktion erlauben (falls zutreffend)
- Resource-basierte Policies — Können Cross-Account-Zugriff unabhängig gewähren
- Permission Boundaries — Müssen die Aktion erlauben (falls gesetzt)
- Session Policies — Müssen die Aktion erlauben (falls gesetzt)
- Identity-basierte Policies — Müssen die Aktion erlauben
Wenn eine Ebene den Request nicht erlaubt (oder ihn explizit ablehnt), wird der Request abgelehnt. Deshalb können Sie eine völlig korrekte IAM Policy haben und trotzdem AccessDenied erhalten — die Ablehnung kommt von einer anderen Ebene.
Best Practices zur Prävention
Nach dem Debugging von Hunderten von IAM-Problemen sind hier die Praktiken, die ich jedem Kunden empfehle:
- Nutzen Sie IAM Access Analyzer zur Validierung von Policies vor dem Deployment:
aws accessanalyzer validate-policy \
--policy-document file://policy.json \
--policy-type IDENTITY_POLICY \
--query 'findings[*].[findingType, issueCode, learnMoreLink]' \
--output table
-
Aktivieren Sie CloudTrail in allen Regionen und allen Accounts. Sie können nicht debuggen, was Sie nicht sehen können.
-
Verwenden Sie das Prinzip der minimalen Berechtigung mit schrittweiser Erweiterung. Beginnen Sie mit minimalen Berechtigungen und erweitern Sie nach Bedarf.
-
Tag-basierte Zugriffskontrolle reduziert ARN-Matching-Fehler:
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Environment": "production"
}
}
}
-
Testen Sie mit dem IAM Policy Simulator vor jedem Deployment. Automatisieren Sie dies als Teil Ihrer CI/CD-Pipeline.
-
Verwenden Sie AWS CloudFormation oder CDK zur Verwaltung von IAM-Policies. Manuelle Konsolenänderungen sind die häufigste Quelle von Fehlkonfigurationen, die wir in Kunden-Audits sehen.
Wann Sie Hilfe rufen sollten
IAM-Fehlkonfigurationen sind selten isolierte Probleme. Sie offenbaren oft tiefere architektonische Probleme — übermäßig komplexe Berechtigungsmodelle, fehlende Automatisierung oder inkonsistente Praktiken zwischen Teams. Wenn Ihr Team mehr als einige Stunden pro Woche mit dem Debugging von Zugriffsproblemen verbringt, ist es an der Zeit, einen Schritt zurückzutreten und Ihre IAM-Strategie ganzheitlich zu überprüfen.
Wir helfen AWS-Teams, saubere und wartbare IAM-Architekturen zu entwerfen, die diese Fehler minimieren. Wenn Sie häufiger als nötig mit der AccessDeniedException kämpfen, kontaktieren Sie uns für eine kostenlose Beratung — wir überprüfen Ihr IAM-Setup und zeigen Ihnen genau, wo sich die Probleme verstecken.
Brauchen Sie Hilfe mit Ihrer AWS-Infrastruktur?
Buchen Sie ein kostenloses 30-Minuten-Gespräch.