Authentifizierung bei MongoDB Atlas mit AWS Outbound Identity Federation

Diese Datei wurde automatisch von KI übersetzt, es können Fehler auftreten
Ich habe mehrere Beiträge zu Authentifizierungs- und Autorisierungsthemen geschrieben, die das PEP- und PDP-Muster verwenden. PEP und PDP für sichere Autorisierung mit Cognito, dann erweitert mit Amazon Verified Permissions, und später ABAC darüber gelegt. All das betraf die Autorisierung von Benutzer zu Dienst. Das bedeutet, ein Mensch meldet sich an, erhält ein Token, und das Backend entscheidet, was er tun kann.
Aber was ist mit Dienst-zu-Dienst? Maschine-zu-Maschine? Ihr Lambda muss mit einer Datenbank sprechen oder eine externe API aufrufen, und es gibt keinen Menschen im Loop. Sie würden trotzdem Credentials benötigen.
Der gesamte Quellcode ist verfügbar im Serverless Handbook.
Die übliche Art, M2M-Tokens zu verwalten
Einer der häufigsten Ansätze, die ich sehe, ist die Verwendung von Cognito User Pools, Auth0 oder ähnlichen mit dem OAuth 2.0 Client-Credential-Flow. Sie erstellen einen Ressourcen-Server, registrieren einen App-Client mit einer Client-ID und einem Secret, und Ihr Lambda tauscht diese gegen ein Access-Token aus. Es funktioniert gut, und wenn Sie bereits Cognito für die Benutzerauthentifizierung verwenden, fühlt es sich natürlich an, es auch für M2M zu erweitern. Was zu beachten ist, ist, dass M2M-Tokens von diesen Diensten schnell teuer werden können.
Ein anderer klassischer Ansatz besteht darin, Credentials einfach in Secrets Manager zu speichern. Datenbankpasswörter, API-Schlüssel, was auch immer Sie benötigen. Aktivieren Sie die Rotation und machen Sie weiter. Es funktioniert, aber es ist eine weitere Sache zu verwalten, eine weitere Sache, die kaputt gehen kann, und ein weiteres Secret, das durchsickern kann.
Outbound Identity Federation
Kurz vor re:Invent 2025 gab es eine sehr interessante Veröffentlichung: AWS IAM Outbound Identity Federation.
Wir verwenden seit langem Identity Federation in AWS. Google, Okta, Entra oder andere geben ein Token aus, AWS vertraut ihm, und Sie erhalten Zugriff auf AWS-Ressourcen. Das ist inbound Federation. AWS ist derjenige, der vertraut.
Outbound Identity Federation ist das Umgekehrte. Jetzt ist AWS derjenige, der Tokens ausgibt. Ihr Lambda (oder EC2 oder ECS-Task) ruft STS auf, um eine IAM-Rolle gegen ein signiertes JWT-Token auszutauschen, das im Grunde sagt: "Hey, ich bin diese IAM-Rolle, und hier ist ein kryptographischer Nachweis." Dann übergeben Sie dieses Token an jeden externen oder internen Dienst, mit dem Sie sprechen, und sie können es mit Standardflüssen überprüfen.
Das bedeutet: Keine Client-Secrets oder gespeicherten Passwörter. Das ausgegebene Token ist kurzlebig, an die IAM-Rolle gebunden und von AWS signiert. Der empfangende Dienst muss nur den Aussteller vertrauen.
Was steht im Token?
Wenn wir sts:GetWebIdentityToken aufrufen, erhalten wir ein Standard-JWT-Token mit einigen Claims, die wichtig sind:
iss - Der Aussteller. Dies ist die Token-Issuer-URL, die wir erhalten, wenn wir die Funktion aktivieren. Sie sieht so aus: "https://a1810f8a-5a75-4e21-b1cd-a6b09f1836cb.tokens.sts.global.api.aws". Sie ist einzigartig für unser AWS-Konto und wir können sie nicht ändern.sub - Das Subjekt. Dies ist die IAM-Rollen-ARN. Es ist die Identität.aud - Das Publikum. Dies wird von uns festgelegt, und es kann alles sein, "my-api", "atlas-demo", was auch immer. Beide Seiten müssen sich nur auf den Wert einigen.exp - Ablaufzeit. Kurzlebigkeit ist der ganze Sinn.
Architekturüberblick
In diesem Beitrag werden wir zwei verschiedene Lösungen bauen, die die Outbound Identity Federation verwenden, nur um zu zeigen, wie man sie für einen internen Dienst einrichtet, der auf Lambda hinter API Gateway gehostet wird, und eine externe Datenbank, in diesem Fall MongoDB Atlas.
In unserem internen Anwendungsfall haben wir eine Worker-Lambda-Funktion, die STS aufruft, um ein signiertes Outbound-JWT-Token zu erhalten. Die Funktion ruft eine API in API Gateway auf, wo wir einen Lambda-Autorisierer haben, der die öffentlichen Schlüssel von STS verwendet, um das JWT zu validieren.

Im MongoDB-Fall haben wir so ziemlich das Gleiche. Wir etablieren Vertrauen zwischen MongoDB und STS, indem wir einige Konfigurationen auf der MongoDB-Seite vornehmen. Unser Worker-Lambda ruft STS auf, um das JWT zu erhalten, und verwendet dies als Authentifizierung gegenüber MongoDB, das die öffentlichen Schlüssel usw. von STS verwendet, um den Benutzer zu validieren. Für den MongoDB-Anwendungsfall müssen wir all dies auf einen Benutzer abbilden, aber mehr zu dieser Konfiguration später.

Jetzt lassen Sie uns bauen!
Outbound Identity Federation aktivieren
Bevor wir die Outbound Identity Federation verwenden können, müssen wir sie aktivieren, standardmäßig ist sie deaktiviert. Gehen Sie also zum AWS-Konsolen und IAM > Kontoeinstellungen.

Scrollen Sie nach unten zum Abschnitt Outbound Identity Federation und klicken Sie einfach auf Aktivieren.

Sobald aktiviert, erhalten Sie sofort Ihre kontospezifische Token-Issuer-URL. Kopieren Sie diese, Sie werden sie später benötigen.

Sie können es auch über CLI aktivieren, wenn Sie das bevorzugen:
aws iam enable-outbound-web-identity-federationJetzt lassen Sie uns dies ausprobieren und STS aufrufen, um ein Token zu erhalten. Wir führen den folgenden CLI-Befehl aus, um ein Token für unseren angemeldeten Principal zu erhalten.
aws sts get-web-identity-token --audience "my-api" --signing-algorithm RS256Wir erhalten eine Antwort wie:
{
"WebIdentityToken": "Base64 Encoded Token",
"Expiration": "2026-03-19T08:20:06.177000+00:00"
}Wenn wir das WebIdentityToken entschlüsseln, zum Beispiel mit einer Webseite wie jwt.io, können wir die verschiedenen Claims sehen.
{
"aud": "my-api",
"sub": "arn:aws:iam::<account_id><iam_role>",
"https://sts.amazonaws.com/": {
"org_id": "<AWS_Org_Id>",
"aws_account": "<account_id>",
"ou_path": [
"...."
],
"original_session_exp": "2026-03-19T10:15:04Z",
"source_region": "eu-west-1",
"principal_id": "<iam_principal>",
"identity_store_user_id": "...."
},
"iss": "https://....tokens.sts.global.api.aws",
"exp": 1773908406,
"iat": 1773908106,
"jti": "..."
}Token mit API Gateway überprüfen
Nachdem das funktioniert, bauen wir eine einfache API, die eine Lambda-Funktion aufruft, bei der wir einen Lambda-Autorisierer haben, der das Token validiert.
Wir beginnen mit der Erstellung der Aufruferfunktion, dies ist ziemlich einfach, wir rufen STS auf, um ein Token zu erhalten, und präsentieren dies dann beim Aufruf der API.
import json
import logging
import os
import boto3
import requests
logger = logging.getLogger()
logger.setLevel(logging.INFO)
sts_client = boto3.client("sts")
API_ENDPOINT = os.environ["API_ENDPOINT"]
AUDIENCE = os.environ["AUDIENCE"]
def get_token():
response = sts_client.get_web_identity_token(
Audience=[AUDIENCE],
DurationSeconds=300,
SigningAlgorithm="RS256",
)
return response["WebIdentityToken"]
def handler(event, context):
try:
token = get_token()
response = requests.get(
API_ENDPOINT,
headers={"Authorization": f"Bearer {token}"},
timeout=10,
)
return {
"statusCode": response.status_code,
"body": json.dumps(
{
"api_status_code": response.status_code,
"api_response": response.json() if response.ok else response.text,
"request_id": context.aws_request_id,
}
),
}
except Exception as e:
return {
"statusCode": 500,
"body": json.dumps(
{
"message": "Error calling protected API",
"error": str(e),
}
),
}Wenn wir uns die Funktion get_token() ansehen, ist sie denkbar einfach, nur drei Parameter und fertig. Wir müssen keine Credentials von irgendwo abrufen. Das Lambda sagt einfach: "Gib mir ein Token für dieses Publikum" und STS signiert eines mit der eigenen Identität des Lambda.
Der Lambda-Autorisierer
Der Lambda-Autorisierer, der an API Gateway angehängt ist, hier wird es wirklich interessant. Was wir tun werden, ist die öffentlichen Schlüssel von STS abzurufen und dann das Token mit einer Standard-JWT-Bibliothek zu validieren.
Wir erstellen die Discovery mit der Issuer-URL und hängen /.well-known/openid-configuration an. Das sagt uns, wo wir die öffentlichen Schlüssel finden können und was der Issuer-Wert sein sollte. Dann erstellen wir einen PyJWKClient, der das Abrufen und Zwischenspeichern von Schlüsseln übernimmt.
import json
import logging
import os
import urllib.request
import jwt
logger = logging.getLogger()
logger.setLevel(logging.INFO)
AUDIENCE = os.environ["AUDIENCE"]
ISSUER_URL = os.environ["ISSUER_URL"]
DISCOVERY_URL = f"{ISSUER_URL}/.well-known/openid-configuration"
discovery_doc = json.loads(urllib.request.urlopen(DISCOVERY_URL).read())
JWKS_URI = discovery_doc["jwks_uri"]
EXPECTED_ISSUER = discovery_doc["issuer"]
jwks_client = jwt.PyJWKClient(JWKS_URI)
def handler(event, context):
try:
token = extract_token(event)
if not token:
return generate_policy("Deny", event["methodArn"])
signing_key = jwks_client.get_signing_key_from_jwt(token)
decoded = jwt.decode(
token,
signing_key.key,
algorithms=["RS256"],
audience=OIDC_AUDIENCE,
issuer=EXPECTED_ISSUER,
)
return generate_policy(
"Allow",
event["methodArn"],
principal_id=decoded.get("sub", "unknown"),
context={"sub": decoded.get("sub", ""), "iss": decoded.get("iss", "")},
)
except jwt.ExpiredSignatureError:
logger.warning("Token has expired")
except jwt.InvalidAudienceError:
logger.warning("Invalid audience claim")
except jwt.InvalidIssuerError:
logger.warning("Invalid issuer claim")
except Exception as e:
logger.error("Token verification failed: %s", e)
return generate_policy("Deny", event["methodArn"])Die Funktion jwt.decode() ist der Kern von allem und validiert die tatsächlichen Tokens gegen die erwarteten Werte und wirft eine Ausnahme im Fehlerfall.
Wenn alles passt, erlauben wir die Anfrage und leiten die sub-Claim weiter, damit das Backend weiß, wer anruft.
Wichtig zu beachten ist, dass es an dieser Validierungslogik nichts AWS-spezifisches gibt. Dies ist nur eine Standard-JWT-Token-Validierung.
Authentifizierung bei MongoDB Atlas
Jetzt setzen wir dies in einen echten Anwendungsfall um, die Verbindung zu einem MongoDB Atlas-Cluster unter Verwendung von Tokens von IAM Outbound Federation, wodurch die Notwendigkeit entfällt, Passwörter in Secrets Manager zu speichern.
Es gibt eine sehr wichtige Sache zu beachten. Damit dies funktioniert, müssen Sie einen M10+-Dedizierten MongoDB Atlas-Cluster mit MongoDB 7.0.11 oder höher verwenden. Workload Identity Federation wird nicht auf kostenlosen oder freigegebenen Ebenen (M0, M2, M5) unterstützt.
Die Idee ist ziemlich einfach und geradlinig. Unsere Lambda-Funktion ruft STS auf, um ein Token zu erhalten, das wir dann Atlas anstelle von Benutzernamen und Passwort präsentieren. Atlas validiert das Token mit Standardflüssen und ordnet die IAM-Rolle einem Datenbankbenutzer zu.
Atlas einrichten
Der erste Schritt besteht nun darin, die Dinge auf der MongoDB-Seite einzurichten, melden Sie sich bei Ihrem Konto an und navigieren Sie zu Federation unter Identity and Access.

Unter Federation wählen Sie Identity Providers aus, und wir beginnen mit der Einrichtung.

Auf dem nächsten Bildschirm wählen Sie Workload Identity aus, damit wir anfangen können, Details hinzuzufügen.

Auf dem Konfigurationsbildschirm füllen Sie name und description aus. Die issuer URL ist die aus dem AWS IAM-Konsolen, die wir früher in diesem Beitrag gesehen haben. Für audience legen Sie einen Wert Ihrer Wahl fest, wichtig ist, dass er sowohl auf MongoDB als auch auf AWS-Konfiguration übereinstimmt (wenn Sie STS aufrufen). Die Audience muss übereinstimmen. Für den Benutzer-Claim behalten Sie den Standard sub bei.

Speichern und beenden Sie Ihre Einrichtung, und Sie sollten mit dem Überblicksbildschirm präsentiert werden.

Als Nächstes müssen wir den gerade erstellten Identity Provider mit unserer Organisation verbinden. Wählen Sie Organizations im Menü aus und beginnen Sie mit der Verbindung.

Im Popup-Dialog wählen Sie den gerade erstellten Anbieter aus und klicken Sie auf Connect.

In der nächsten Ansicht sollten wir den Überblick über die Verbindung sehen.

Testanwendung bereitstellen
Das waren viele Schritte, aber jetzt können wir unsere Testanwendung bereitstellen und dann die abschließende Einrichtung in Atlas durchführen, bevor wir testen. Wir halten die Testinfrastruktur minimal. Nur eine Lambda-Funktion, die die Berechtigung sts:GetWebIdentityToken hat:
Resources:
DatabaseOpFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${Application}-database-op
CodeUri: src/DatabaseOp/
Handler: database_op.handler
Environment:
Variables:
MONGODB_URI: !Ref MongoDbUri
OIDC_AUDIENCE: !Ref OidcAudience
Policies:
- Statement:
- Effect: Allow
Action:
- sts:GetWebIdentityToken
Resource: "*"
Outputs:
DatabaseOpFunctionRoleArn:
Description: IAM Role ARN for the Lambda function (use this in Atlas OIDC role mapping)
Value: !GetAtt DatabaseOpFunctionRole.ArnWir fügen die Rollen-ARN zum Ausgabe der Stack hinzu, da wir diese für den abschließenden Atlas-Teil benötigen. Der Code ist in der Lambda-Handler und einem Client aufgeteilt, der die Verbindung zur MongoDB-Datenbank übernimmt.
Der pymongo-Treiber hat einen großartigen Callback-Mechanismus für OIDC. Wir geben ihm eine Klasse, und der Treiber ruft sie auf, wann immer er ein Token benötigt. Der Treiber ruft fetch() beim ersten Verbinden und erneut, wenn das Token kurz vor dem Ablauf steht. Wir setzen den Wert auf 280 Sekunden, was etwas unter der tatsächlichen 300 liegt, damit es eine Pufferzeit gibt.
Durch das Setzen von authMechanism="MONGODB-OIDC" sagen wir dem Treiber, Benutzernamen/Passwort zu überspringen und stattdessen OIDC zu verwenden.
import os
import boto3
from pymongo import MongoClient
from pymongo.auth_oidc import OIDCCallback, OIDCCallbackResult
sts_client = boto3.client("sts")
cached_client = None
def get_oidc_token():
audience = os.environ["OIDC_AUDIENCE"]
response = sts_client.get_web_identity_token(
Audience=[audience],
DurationSeconds=300,
SigningAlgorithm="RS256",
)
return response["WebIdentityToken"]
class AwsOidcCallback(OIDCCallback):
def fetch(self, context):
token = get_oidc_token()
return OIDCCallbackResult(access_token=token, expires_in_seconds=280)
def get_mongo_client():
global cached_client
if cached_client is not None:
return cached_client
uri = os.environ["MONGODB_URI"]
properties = {"OIDC_CALLBACK": AwsOidcCallback()}
cached_client = MongoClient(
uri,
authMechanism="MONGODB-OIDC",
authMechanismProperties=properties,
)
return cached_clientDann erstellen wir in unserem Lambda-Handler den MongoDB-Client und interagieren mit der Datenbank, in diesem einfachen Beispiel fügen wir nur ein Dokument in eine items-Sammlung ein.
def handler(event, context):
try:
client = get_mongo_client()
db = client["sample_db"]
collection = db["items"]
document = {
"message": "Hello from Lambda with OIDC auth",
"timestamp": datetime.now(timezone.utc).isoformat(),
"request_id": context.aws_request_id,
}
result = collection.insert_one(document)
doc = collection.find_one({"_id": result.inserted_id})
return {
"statusCode": 200,
"body": json.dumps({
"message": "Successfully connected to MongoDB Atlas with OIDC",
"insertedId": str(result.inserted_id),
}),
}
except Exception as e:
logger.error("Error: %s", e)
return {"statusCode": 500, "body": json.dumps({"error": str(e)})}Datenbankbenutzer in Atlas erstellen
Jetzt müssen wir den letzten Schritt in Atlas durchführen, einen Datenbankbenutzer erstellen und diesen der IAM-Rollen-ARN zuordnen, damit wir Berechtigungen zum Interagieren mit der Datenbank erhalten. Gehen Sie zu Database Access und fügen Sie einen neuen Datenbankbenutzer hinzu.

Wählen Sie Federated Auth als Authentifizierungsmethode und legen Sie den Benutzernamen auf die IAM-Rollen-ARN der Lambda-Funktion fest. Holen Sie dies aus dem Stack-Ausgabe. Weisen Sie dem Benutzer Lesen und Schreiben auf jeder Datenbank zu.

Diese Rollen-ARN wird mit der sub-Claim im JWT übereinstimmen. So weiß Atlas, welchen Datenbankbenutzer es verwenden soll.
Netzwerkzugriff zulassen
Bevor wir alles testen, müssen wir noch eine Sache tun, wir müssen den Netzwerkzugriff für unsere Lambda-Funktion zulassen. Da wir nicht in einem VPC laufen, müssen wir 0.0.0.0/0 in einer Produktionsumgebung zulassen, tun Sie dies nicht, aber für diesen Test ist es in Ordnung.
Navigieren Sie zu IP Access List im Menü

Dann fügen Sie 0.0.0.0/0 hinzu, setzen Sie es als temporär, damit es automatisch entfernt wird.

Das war's! Wir können jetzt die Outbound Identity Federation in STS verwenden, um sich bei MongoDB Atlas zu authentifizieren und Daten lesen und schreiben, keine Passwörter, keine Secrets zu verwalten!!
Testen
Zeit für einen kleinen Test, dazu rufen Sie einfach die bereitgestellte Lambda-Funktion auf. Dann gehen Sie zu Data Explorer in Atlas und überprüfen Sie, ob die Daten vorhanden sind.

Abschließende Worte
Ich mag dieses Muster wirklich. Keine gespeicherten Secrets. Tokens, die in 5 Minuten ablaufen. Sie wissen genau, welche IAM-Rolle jede Verbindung hergestellt hat. Und es funktioniert mit allem, was OIDC spricht, nicht nur MongoDB. Jeder externe Dienst, der OIDC-Tokens überprüfen kann, kann die gleiche get_oidc_token()-Funktion verwenden. Derselbe Code, anderes Ziel.
Schauen Sie sich meine anderen Beiträge auf jimmydqv.com an und folgen Sie mir auf LinkedIn und X für weitere Serverless-Inhalte.
Jetzt loslegen!
