Wie man mit AWS Cognito auf private S3-Objekte zugreift

Szenario
Nehmen wir an, Sie entwickeln einige Anwendungen für Ihren Kunden. Es gibt jedoch einige Dateien wie PDF, Word, Excel usw., die mit Datensätzen in den Anwendungen verbunden sind. Der Einfachheit halber nehmen wir an, dass diese Dateien in einem einzigen privaten (private) S3-Bucket in AWS gespeichert sind.
Benutzer müssen über einen URL-Link in den Anwendungen auf diese zugehörigen Dateien aus dem privaten S3-Bucket zugreifen können. Unsere Lösung muss als portable (portable) Lösung für jede firmeninterne Software funktionieren.
Einführung
Der Zweck dieses Artikels ist zu zeigen, wie Dateien aus einem privaten S3-Bucket mit Cognito-Benutzerpools (User Pools) heruntergeladen werden können. Neben Cognito wird der Ablauf von Cognito zu API Gateway mit Authorizer und die Zusammenarbeit von API Gateway mit Lambda demonstriert.
Für jeden Schritt wurden so viele Screenshots wie möglich von der AWS-Konsole geteilt. Besonders für Anfänger wurden viele Bilder hinzugefügt, um die Schritte klarer zu machen.
Hintergrund
Einige Vorlektüre kann hilfreich sein, um das in diesem Artikel Entwickelte besser zu verstehen. Besonders für AWS-Anfänger werden die folgenden Links nützlich sein:
Was muss getan werden?
Für eine solche Aufgabe können viele Abläufe oder Methoden codiert werden. Hier werden wir die unten gezeigte Methode implementieren. Eine kurze Erklärung, wie das Szenario implementiert werden soll, wird im folgenden Bild dargestellt.
Das folgende Bild zeigt, dass wir einige Elemente wie Cognito User Pool, S3-Buckets, API Gateway-Methoden, Lambda-Funktionen usw. erstellen müssen. Nachdem wir alle Entitäten in der AWS-Umgebung erstellt haben, müssen wir sie richtig konfigurieren, damit alle zusammenarbeiten können.

Es ist besser, alle Elemente in der AWS-Umgebung in umgekehrter Reihenfolge zu erstellen. Zum Beispiel, wenn Lambda mit einer API-Methode verwendet werden soll und die Lambda-Funktion zuerst entwickelt wird, kann diese Funktion leicht angebunden werden, wenn die API Gateway-Methode erstellt wird. Ähnlich sollten wir in Schritt 5 den S3-Web-Bucket erstellen und die
callback.html-Datei darin ablegen, damit wir diese Datei in Schritt 6 beim Erstellen des Cognito User Pools verwenden können. Natürlich ist dies nicht zwingend erforderlich, aber diese Reihenfolge wird die Entwicklung erleichtern. Daher wurde dieser Ansatz hier bevorzugt.Entwurf
Wir werden nach Antworten auf die folgenden Fragen suchen. Vergessen Sie nicht, dass Sie ein AWS-Konto haben müssen, um alle Schritte in diesem Artikel anzuwenden.
- Wie erstellt man einen privaten S3-Bucket?
- Wie erstellt man eine benutzerdefinierte Policy für den Zugriff auf Objekte im privaten S3-Bucket?
- Wie erstellt man eine Lambda-Funktion zum Zugriff auf Objekte im privaten S3-Bucket?
- Wie erstellt man eine Gateway-API zur Verwendung der Lambda-Funktion?
- Wie erstellt man einen öffentlichen S3-Bucket zur Verwendung als Webordner?
- Wie erstellt und konfiguriert man einen Cognito User Pool?
- Wie testet man das Szenario?
1. Wie erstellt man einen privaten S3-Bucket?
S3 ist einer der regionsbasierten (region-based) Services in AWS. Elemente in S3-Buckets werden Objekte (object) genannt. Daher können die Begriffe Objekt und Datei für S3-Buckets in AWS austauschbar verwendet werden.
Lassen Sie das Kontrollkästchen "Block All Public Access" (Alle öffentlichen Zugriffe blockieren) aktiviert. Hier wurde ein privater S3-Bucket erstellt. Obwohl es viele zusätzliche Konfigurationsoptionen gibt, erstellen wir ihn der Einfachheit halber mit Standardwerten.

Laden Sie einige Objekte in den S3-Bucket hoch, um den privaten Zugriff zu testen. Versuchen Sie dann, mit nicht autorisierten Benutzern oder möglichen Zugangslinks auf diese Objekte zuzugreifen. Obwohl wir Dateien wie PDF, DOC, XLS usw. kennen, werden sie in der AWS S3-Terminologie alle als Objekte bezeichnet.

2. Policy für den Zugriff auf Objekte im privaten S3-Bucket erstellen
In AWS ist IAM (Identity and Access Management) die Grundlage aller Services! Benutzer, Gruppen, Rollen und Policies sind grundlegende Konzepte, mit denen wir vertraut sein müssen.
Es gibt viele integrierte (built-in) Rollen, und jede Rolle hat viele integrierte Policies, die Berechtigungen bedeuten. Diese werden "AWS Managed" genannt. Es ist jedoch auch möglich, "Customer Managed" (Kundenverwaltete) Rollen und Policies zu erstellen. Daher wurde hier eine benutzerdefinierte Policy erstellt.
- Erstellen Sie eine benutzerdefinierte IAM-Policy, um Objekte aus Ihrem privaten S3-Bucket abzurufen.
- Finden Sie die vorhandene Policy-Liste in AWS und erstellen Sie eine neue, um nur die
GetObject-Operation aus Ihrem privaten S3-Bucket durchzuführen, wie unten gezeigt:

Erstellen Sie eine benutzerdefinierte Policy wie unten gezeigt. Wählen Sie S3 als Service und nur
GetObject als Aktion (action):
Wählen Sie "specific" als Ressource (resource) und geben Sie Ihren privaten S3-Bucket an, damit die Policy die gewünschten Fähigkeiten hat:

Geben Sie Ihrer Policy einen Namen und erstellen Sie sie. Sie können einen beliebigen Namen geben, aber Sie müssen sich diesen merken.

Die Zusammenfassung Ihrer benutzerdefinierten Policy wird wie folgt aussehen. Es ist auch möglich, eine Policy zu erstellen, indem Sie diesen JSON-Inhalt direkt verwenden:

Policy JSON-Definition:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::private-s3-for-interfacing/*"
}
]
}
3. Lambda-Funktion zum Zugriff auf Objekte im privaten S3-Bucket erstellen
Hier wurde die neueste Version von NodeJS für die Lambda-Funktion verwendet. Erstellen Sie eine Lambda-Funktion und wählen Sie NodeJS. Es ist möglich, eine beliebige unterstützte Sprache wie Python, Go, Java, .NET Core usw. für die Lambda-Funktion zu wählen.

Wenn Sie eine Lambda-Funktion erstellen, wird ein Beispiel-"hello"-Code angezeigt. Stattdessen müssen wir unseren eigenen Code entwickeln.
Wie zu sehen ist, ähnelt die Lambda-Entwicklungsumgebung einer webbasierten leichten IDE.

Ersetzen Sie den vorhandenen Code durch den gegebenen kurzen Beispielcode. Die neue Version des Codes wird wie folgt aussehen. Drücken Sie nach dem Ändern des Codes die Schaltfläche "Deploy", um die Lambda-Funktion zu verwenden.
Der Einfachheit halber wird der Bucket-Name statisch verwendet. Der Dateiname wird als Parameter mit dem Namen
fn gesendet. Obwohl der Standard-Inhaltstyp (content type) als pdf angenommen wird, kann es ein beliebiger im Lambda-Funktionscode implementierter Dateityp sein. Da wir die Proxy-Funktion der Lambda-Funktion in der API Gateway-Verbindung bevorzugen, enthält der Antwortheader (response header) einige zusätzliche erforderliche Daten.NodeJS Lambda-Code (Rückgabe als Blob):
JavaScript
// Lambda-Funktionscode sieht so aus
// Dieser Code gibt die Antwort als Blob-Inhalt zurück
// Callback-to-Download-Blob.html in den Anhängen kann zum Herunterladen der Datei verwendet werden
const AWS = require('aws-sdk');
const S3= new AWS.S3();
exports.handler = async (event, context) => {
let fileName;
let bucketName;
let contentType;
let fileExt;
try {
bucketName = 'private-s3-for-interfacing';
fileName = event["queryStringParameters"]['fn']
contentType = 'application/pdf';
fileExt = 'pdf';
//------------
fileExt = fileName.split('.').pop();
switch (fileExt) {
case 'pdf': contentType = 'application/pdf'; break;
case 'png': contentType = 'image/png'; break;
case 'gif': contentType = 'image/gif'; break;
case 'jpeg': case 'jpg': contentType = 'image/jpeg'; break;
case 'svg': contentType = 'image/svg+xml'; break;
case 'docx': contentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; break;
case 'xlsx': contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; break;
case 'pptx': contentType = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; break;
case 'doc': contentType = 'application/msword'; break;
case 'xls': contentType = 'application/vnd.ms-excel'; break;
case 'csv': contentType = 'text/csv'; break;
case 'ppt': contentType = 'application/vnd.ms-powerpoint'; break;
case 'rtf': contentType = 'application/rtf'; break;
case 'zip': contentType = 'application/zip'; break;
case 'rar': contentType = 'application/vnd.rar'; break;
case '7z': contentType = 'application/x-7z-compressed'; break;
default: ;
}
//------------
const data = await S3.getObject({Bucket: bucketName, Key: fileName}).promise();
return {
headers: {
'Content-Type': contentType,
'Content-Disposition': 'attachment; filename=' + fileName, // Schlüssel zum Erfolg
'Content-Encoding': 'base64',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
'Access-Control-Allow-Methods': 'GET,OPTIONS'
},
body: data.Body.toString('base64'),
isBase64Encoded: true,
statusCode: 200
}
} catch (err) {
return {
statusCode: err.statusCode || 400,
body: err.message || JSON.stringify(err.message) + ' - fileName: '+ fileName + ' - bucketName: ' + bucketName
}
}
}
Es ist auch möglich, Python-Code in der Lambda-Funktion zu verwenden, wie unten gezeigt:
Python
# Der folgende Code kann wie das obige NodeJS-Beispiel entwickelt werden
import base64
import boto3
import json
import random
s3 = boto3.client('s3')
def lambda_handler(event, context):
try:
fileName = event['queryStringParameters']['fn']
bucketName = 'private-s3-for-interfacing'
contentType = 'application/pdf'
response = s3.get_object(
Bucket=bucketName,
Key=fileName,
)
file = response['Body'].read()
return {
'statusCode': 200,
'headers': {
'Content-Type': contentType,
'Content-Disposition': 'attachment; filename='+ fileName,
'Content-Encoding': 'base64'
# Bei Bedarf können hier CORS-bezogene Codes hinzugefügt werden
},
'body': base64.b64encode(file).decode('utf-8'),
'isBase64Encoded': True
}
except:
return {
'headers': { 'Content-type': 'text/html' },
'statusCode': 200,
'body': 'Error occurred in Lambda!'
}
Eine andere Methode könnte sein, eine presigned URL mit Lambda zu erstellen:
JavaScript
// Diese Methode stellt eine presigned URL bereit
// Callback-for-preSignedUrl.html kann verwendet werden, um den presigned URL-Link zu verwenden
var AWS = require('aws-sdk');
var S3 = new AWS.S3({
signatureVersion: 'v4',
});
exports.handler = async (event, context) => {
let fileName;
let bucketName;
let contentType;
bucketName = 'private-s3-for-interfacing';
fileName = event["queryStringParameters"]['fn'];
contentType = 'application/json';
const presignedUrl = S3.getSignedUrl('getObject', {
Bucket: bucketName,
Key: fileName,
Expires: 300 // Sekunden
});
let responseBody = {'presignedUrl': presignedUrl};
return {
headers: {
'Content-Type': contentType,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
'Access-Control-Allow-Methods': 'GET,OPTIONS'
},
body: JSON.stringify(responseBody),
statusCode: 200
}
};
Wenn eine Lambda-Funktion erstellt wird, wird eine Rolle damit erstellt. Diese Rolle hat jedoch keine Zugriffsberechtigung auf Objekte in Ihrem privaten S3-Bucket. Jetzt müssen wir die "Customer Managed"-Policy, die wir in den vorherigen Schritten erstellt haben, zu dieser mit der Lambda-Funktion erstellten Rolle hinzufügen.
Nachdem Sie die Lambda-Funktion erstellt haben, können Sie die automatisch erstellte Rolle wie unten gezeigt finden:

Fügen Sie die im vorherigen Schritt erstellte benutzerdefinierte Policy zu dieser Rolle hinzu; so hat die Lambda-Funktion eingeschränkte
GetObject-Zugriffsrechte auf Ihren S3-Bucket.
Das ist alles, was für den Lambda-Zugriff auf Ihren S3-Bucket getan werden muss. Jetzt ist es Zeit, eine AWS Gateway-Methode zu erstellen, um unsere Lambda-Funktion zu verwenden.
4. Gateway-API zur Verwendung der Lambda-Funktion erstellen
Erstellen Sie eine AWS Gateway REST-API wie unten gezeigt. Es gibt viele Optionen, aber wir erstellen eine "REST"-API als "New API". Geben Sie Ihrer API Gateway einen Namen.

Es gibt einige Schritte zum Erstellen und Ausführen einer AWS GW API:
- API erstellen
- Resource erstellen
- Method erstellen
- API bereitstellen (Deploy)
Erstellen Sie eine
Resource für Ihre REST-API wie unten gezeigt:
Die hier erstellte Ressource (resource) wird später in der URL der API verwendet.

Erstellen Sie eine
GET-Methode für die erstellte Ressource:
Hier kann jede HTTP-Methode wie
GET, POST, PUT, DELETE usw. erstellt werden. Für unsere Anforderungen erstellen wir nur GET. Vergessen Sie nicht, die Lambda-Funktion, die wir in den vorherigen Schritten erstellt haben, mit dieser Methode zu verbinden.Lambda Proxy Integration ist hier aktiviert. Dieser Ansatz ermöglicht es uns, alle antwortbezogenen Inhalte in der Lambda-Funktion zu verarbeiten.

Nachdem die
GET-Methode erstellt wurde, wird der Ablauf zwischen API Gateway-Methode und Lambda-Funktion wie folgt aussehen:
Aktivieren Sie CORS für die Gateway-API wie unten gezeigt. Default 4xx und Default 5xx Optionen können aktiviert werden; so können sogar Fehler reibungslos zurückgegeben werden.

Nachdem Sie alles im Zusammenhang mit der AWS Gateway-Methode erstellt und konfiguriert haben, ist es jetzt Zeit, die API bereitzustellen (deploy). Die API wird wie gezeigt auf einer Stufe (stage) bereitgestellt. Dieser Stufenname wird auch in der öffentlichen API-URL verwendet.

Nach der Bereitstellung wird die URL wie folgt aussehen. Jetzt ist es möglich, diesen Link von jeder Anwendung aus zu verwenden.

Um den Zugriff auf das API Gateway einzuschränken, müssen wir einen Authorizer (Yetkilendirici) definieren. Wir können einen Cognito-Authorizer wie unten gezeigt definieren.
Wie im folgenden Bild zu sehen ist, ist Authorization das JWT-Token (Belirteç), das dem Header der Anfrage hinzugefügt werden muss, um die autorisierte API-Methode zu verwenden.
Wenn die Cognito Hosted UI mit einem Cognito-Benutzer/Passwort gesendet wird, leitet Cognito den Benutzer zur Callback-URL weiter und überträgt das
id_token und zusätzliche state-Daten.Beachten Sie, dass das Token, das wir dem Header hinzufügen müssen, unter Token Source als "Authorization" benannt ist.

Nach der Definition des Cognito-basierten Authorizers kann er wie folgt verwendet werden:

Wenn Sie andererseits keinen Authorizer für API Gateway definieren möchten, können Sie den Zugriff auf die API-URL mit "Resource Policy" (Ressourcen-Policy) wie unten gezeigt einschränken.
Wenn die Resource Policy geändert/hinzugefügt wird, muss die API erneut bereitgestellt werden. Die als
xxx.xxx.xxx.xxx gezeigte IP kann die Server-IP sein. Wenn jemand versucht, von einer anderen IP auf die URL zuzugreifen, wird die folgende Nachricht angezeigt:{"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:eu-west-2:********8165:... with an explicit deny"}
Resource Policy JSON-Code wird wie folgt aussehen:
JSON
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "*"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "xxx.xxx.xxx.xxx"
}
}
}
]
}
5. Öffentlicher S3-Bucket zur Verwendung als Webordner
Wir benötigen zwei S3-Buckets für die Lösung. Der erste wurde in den vorherigen Abschnitten erstellt. Der zweite wird jetzt erstellt und als Webordner verwendet. Der erste wurde als privater Bucket zum Speichern aller Dateien verwendet.

Erstellen Sie einen öffentlichen S3-Bucket als Webordner. Dieser Bucket enthält eine
callback.html-Datei, sodass er als Cognito-Callback-Adresse verwendet werden kann.
Der S3-Bucket für das Web muss öffentlich (public) sein. Daher kann die folgende Policy angewendet werden:
JSON
// Policy JSON wird so aussehen
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::web-s3-for-interfacing/*"
}
]
}
Quelldateien herunterladen
Sie können
Callback.html und andere Quelldateien über die folgenden Links herunterladen:6. Cognito User Pool erstellen und konfigurieren
- Callback-Adresse:
https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.html - OAuth 2.0 Flows: Aktivieren Sie die Option "implicit grant".
- OAuth 2.0 Scopes: email, openid, profile.
Überprüfen Sie den unten stehenden hosted UI-Link.
Um Parameter an die Hosted Cognito-Anmeldeseite zu senden, fügen Sie einen zusätzlichen "state"-URL-Parameter hinzu. Der "state"-Parameter wird an die
Callback.html-Datei weitergeleitet.Der Cognito Hosted UI-Link enthält viele URL-Parameter wie unten gezeigt:
https://test-for-user-pool-for-s3.auth.eu-west-2.amazoncognito.com/login?client_id=7uuggclp7269oguth08mi2ee04&response_type=token&scope=openid+profile+email&redirect_uri=https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.html&state=fn=testFile.pdfFelder:
client_id=7uuggclp7269oguth08mi2ee04response_type=tokenscope=openid+profile+emailredirect_uri=https://web-s3-for-interfacing.s3.eu-west-2.amazonaws.com/Callback.htmlstate=fn=testFile.pdf
state ist ein spezieller URL-Parameter. Er kann an die Hosted UI-Seite gesendet und an die Callback.html-Seite zurückgegeben werden.Eine Client-App muss wie unten gezeigt erstellt werden:

App-Client-Einstellungen können wie unten gezeigt bestätigt werden:

Ein Domain-Name muss festgelegt werden, damit er als URL für die Hosted UI verwendet werden kann.

7. Wie testet man das Szenario?
Sehen wir, wie die API mit eingeschränktem Zugriff unter Verwendung des Cognito User Pools getestet wird.
Jeder Endbenutzer kann auf einen Link klicken, um diesen Prozess zu starten. Nehmen wir an, wir haben eine Webseite, die den folgenden HTML-Inhalt hostet. Wie zu sehen ist, ist der Link für jede Datei die URL der Cognito hosted UI.
Die
LinkToS3Files.html-Datei kann zum Testen des Szenarios verwendet werden.Testdateien herunterladen
Fazit
Ich hoffe, dieser Artikel war hilfreich für Anfänger in der AWS-Cloud-Umgebung.
Cloud-Computing-Dienste
Wir bieten Infrastrukturdesign, Migration, Management und Optimierungsdienste auf AWS-, Azure- und Google Cloud-Plattformen.
Unseren Service erkundenKontaktieren Sie uns
Kontaktieren Sie unser Team für detaillierte Informationen über unsere AWS- und Cloud-Computing-Lösungen.
Kontakt