Ein Agent ist ein Aufrufer, den du nicht vollständig vorhersagen kannst, und genau das ist der Aufrufer, der Least Privilege haben sollte. Der Instinkt bei einem neuen Agenten ist, ihm eine breite Rolle zu geben, damit er "einfach funktioniert", während du iterierst. Dieser Instinkt ist der Grund, warum du am Ende ein Sprachmodell mit Credentials hast, das jeden Bucket lesen und jede Tabelle löschen kann, gesteuert von Text, den ein Angreifer beeinflussen kann. Least Privilege war schon immer die Regel. Ein nicht-deterministischer Aufrufer macht sie nicht verhandelbar.

Der gedankliche Wechsel besteht darin, aufzuhören, den Agenten als deinen Code zu betrachten, und ihn stattdessen als teilweise vertrauenswürdigen Akteur zu sehen, der in deinem Namen handelt. Dein Code tut, was du geschrieben hast. Ein Agent tut, was das Modell entschieden hat, und das Modell hat basierend auf Input entschieden, den du nicht kontrollierst. Die IAM-Grenze ist das, was zwischen "der Agent hat eine seltsame Entscheidung getroffen" und "der Agent hat eine seltsame Entscheidung mit Admin-Rechten getroffen" steht.

Eine Rolle pro Tool, nicht eine Rolle pro Agent

Das gängige Anti-Pattern ist eine einzige Ausführungsrolle, die am gesamten Agenten hängt und die Vereinigung aller Berechtigungen trägt, die irgendein Tool je brauchen könnte. Diese Rolle ist jetzt der Blast Radius aller Tools zugleich. Eine Prompt Injection, die das schwächste Tool erreicht, erbt die Berechtigungen des stärksten.

Beschränke Berechtigungen auf das Tool, nicht auf den Agenten. Die Lambda-Funktion hinter einem lookup_order-Tool bekommt eine Rolle, die eine Tabelle lesen kann und sonst nichts. Die Funktion hinter send_email bekommt eine Rolle, die SES für eine verifizierte Identität aufrufen kann. Kein Tool trägt eine Berechtigung, die es nicht nutzt, sodass ein kompromittierter Tool-Aufruf nur die eine Aufgabe dieses Tools erledigen kann.

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": "dynamodb:GetItem",
    "Resource": "arn:aws:dynamodb:eu-west-1:111122223333:table/orders",
    "Condition": {
      "ForAllValues:StringEquals": {
        "dynamodb:LeadingKeys": ["${aws:PrincipalTag/tenant}"]
      }
    }
  }]
}

Das ist die gesamte Berechtigung für das Order-Lookup-Tool: ein Item lesen, aus einer Tabelle, und nur Zeilen für den Tenant des Aufrufers. Es gibt nichts anderes, das eine injizierte Anweisung erreichen könnte.

Die Rolle zur Laufzeit mit Session Policies weiter verengen

Rollen pro Tool sind der Boden. Für Multi-Tenant-Systeme willst du die Berechtigung zusätzlich auf die konkrete Anfrage beschränken. Session Policies erlauben genau das: Wenn dein Backend die Rolle des Tools annimmt, übergibt es eine Inline-Policy, die sich mit den Berechtigungen der Rolle für diese eine Session schneidet, sodass eine Anfrage für Tenant A die Daten von Tenant B nicht anrühren kann, obwohl die Rolle technisch die gesamte Tabelle umfasst.

aws sts assume-role \
  --role-arn arn:aws:iam::111122223333:role/order-lookup \
  --role-session-name agent-tenant-a \
  --policy '{"Version":"2012-10-17","Statement":[{
    "Effect":"Allow","Action":"dynamodb:GetItem",
    "Resource":"arn:aws:dynamodb:eu-west-1:111122223333:table/orders",
    "Condition":{"ForAllValues:StringEquals":
      {"dynamodb:LeadingKeys":["tenant-a"]}}}]}'

Die effektive Berechtigung ist die Schnittmenge aus Rolle und Session Policy, sodass die Credentials, die das Tool tatsächlich hält, auf diese Anfrage verengt sind. Session Tags plus eine Tenant-Bedingung auf der Rolle erreichen dasselbe deklarativ. So oder so sind die Credentials, die dem modellgesteuerten Aufruf übergeben werden, die kleinstmögliche Menge, die die aktuelle Aufgabe erfüllt.

Policy vor den Credentials

IAM entscheidet, was ein Principal tun darf. Es entscheidet nicht, ob dieser bestimmte Agent, in diesem bestimmten Turn, dieses Tool überhaupt aufrufen sollte. Diese Autorisierungsfrage hat jetzt eine zweckgebaute Antwort auf AWS: Policy in Amazon Bedrock AgentCore, seit Anfang dieses Monats generell verfügbar, bewertet jede Agent-zu-Tool-Anfrage gegen Regeln, die du in natürlicher Sprache verfasst und die zu Cedar kompiliert werden, durchgesetzt an einem AgentCore Gateway, bevor der Aufruf fortfährt. Lies das als Schicht vor IAM, nicht als Ersatz: Das Gateway entscheidet, ob der Tool-Aufruf erlaubt ist, und eine enge IAM-Rolle entscheidet, wie wenig Schaden er anrichten kann, falls doch.

Protokolliere die Rollenannahme, nicht nur den API-Aufruf

Weil Tools eng gefasste Rollen annehmen, gibt dir CloudTrail einen sauberen Audit-Trail: welche Rolle wurde angenommen, mit welchem Session-Namen, für welche Aufgabe. Setz den role-session-name auf etwas, das sich auf den Agenten-Turn und den Tenant zurückverfolgen lässt, und du kannst exakt rekonstruieren, was ein Agent getan hat und unter wessen Autorität. Wenn sich ein Agent daneben benimmt, ist dieser Trail der Unterschied zwischen einem begrenzten Vorfall, den du erklären kannst, und einem Rätsel, das du nicht lösen kannst.

Das Fazit

Least Privilege lockert sich nicht, weil der Aufrufer clever ist. Es zieht sich enger zusammen, weil der Aufrufer nicht-deterministisch ist und von nicht vertrauenswürdigem Input beeinflusst wird. Gib jedem Tool seine eigene enge Rolle, schneide sie mit einer Session Policy pro Anfrage, setz eine Autorisierungsschicht wie AgentCore Policy davor, und protokolliere jede Rollenannahme. Wenn das Modell eine schlechte Entscheidung trifft, und das wird es, entscheidet IAM, dass diese schlechte Entscheidung klein bleibt.

Lesen Sie als Nächstes

Das tiefe Ende von IAM und Account-Härtung lebt in den Cloud-Field-Notes: Absicherung deines AWS-Accounts, auf ercan.cloud. Der Hub ist ercanermis.com.