Wie legen Sie ein Standardstammobjekt für Unterverzeichnisse für eine statisch gehostete Website in Cloudfront fest?

96

Wie legen Sie ein Standardstammobjekt für Unterverzeichnisse auf einer statisch gehosteten Website in Cloudfront fest? Insbesondere möchte www.example.com/subdir/index.htmlich bedient werden, wann immer der Benutzer dies wünscht www.example.com/subdir. Beachten Sie, dass dies für die Bereitstellung einer statischen Website in einem S3-Bucket vorgesehen ist. Darüber hinaus möchte ich eine Ursprungszugriffsidentität verwenden, um den Zugriff auf den S3-Bucket nur auf Cloudfront zu beschränken.

Jetzt ist mir bewusst, dass Cloudfront anders funktioniert als S3 und Amazon speziell :

Das Verhalten von CloudFront-Standardstammobjekten unterscheidet sich vom Verhalten von Amazon S3-Indexdokumenten. Wenn Sie einen Amazon S3-Bucket als Website konfigurieren und das Indexdokument angeben, gibt Amazon S3 das Indexdokument zurück, auch wenn ein Benutzer ein Unterverzeichnis im Bucket anfordert. (Eine Kopie des Indexdokuments muss in jedem Unterverzeichnis enthalten sein.) Weitere Informationen zum Konfigurieren von Amazon S3-Buckets als Websites und zu Indexdokumenten finden Sie im Kapitel Hosting von Websites auf Amazon S3 im Amazon Simple Storage Service-Entwicklerhandbuch.

Obwohl Cloudfront es uns ermöglicht, ein Standardstammobjekt anzugeben, funktioniert dies nur für www.example.comund nicht für www.example.com/subdir. Um diese Schwierigkeit zu umgehen, können wir den Ursprungsdomänennamen so ändern, dass er auf den von S3 angegebenen Website-Endpunkt verweist. Dies funktioniert hervorragend und ermöglicht die einheitliche Angabe der Stammobjekte. Leider scheint dies nicht mit den Ursprungszugriffsidentitäten kompatibel zu sein . Im Einzelnen heißt es in den obigen Links:

Wechseln Sie in den Bearbeitungsmodus:

Webdistributionen - Klicken Sie auf die Registerkarte Ursprünge, klicken Sie auf den Ursprung, den Sie bearbeiten möchten, und klicken Sie auf Bearbeiten. Sie können eine Ursprungszugriffsidentität nur für Ursprünge erstellen, für die der Origin-Typ S3 Origin ist.

Grundsätzlich verwenden wir zum Festlegen des richtigen Standardstammobjekts den S3-Website-Endpunkt und nicht den Website-Bucket selbst. Dies ist nicht kompatibel mit der Verwendung der Ursprungszugriffsidentität. Als solche laufen meine Fragen auf beides hinaus

  1. Ist es möglich, ein Standardstammobjekt für alle Unterverzeichnisse für eine statisch gehostete Website in Cloudfront anzugeben?

  2. Ist es möglich, eine Ursprungszugriffsidentität für Inhalte einzurichten, die von Cloudfront bereitgestellt werden, wobei der Ursprung ein S3-Website-Endpunkt und kein S3-Bucket ist?

wyer33
quelle
1
Ich denke, dass dies jetzt mit Lambda @ edge möglich ist, indem eine Funktion verwendet wird, die alle URLs umleitet, die auf / to /index.html enden. Ich werde es auf meiner Website ausprobieren und die Ergebnisse zurückmelden und die detaillierte Konfiguration als Antwort veröffentlichen.
Cristian Măgherușan-Stanciu

Antworten:

1

UPDATE: Es sieht so aus, als wäre ich falsch! Siehe JBaczuks Antwort, die die akzeptierte Antwort in diesem Thread sein sollte.

Leider lautet die Antwort auf beide Fragen nein.

1. Ist es möglich, ein Standardstammobjekt für alle Unterverzeichnisse für eine statisch gehostete Website in Cloudfront anzugeben?

Wie in den AWS CloudFront-Dokumenten angegeben ...

... Wenn Sie ein Standardstammobjekt definieren, gibt eine Endbenutzeranforderung für ein Unterverzeichnis Ihrer Distribution das Standardstammobjekt nicht zurück. Angenommen, es index.htmlhandelt sich um Ihr Standardstammobjekt, und CloudFront empfängt eine Endbenutzeranforderung für das Installationsverzeichnis unter Ihrer CloudFront-Distribution:

http://d111111abcdef8.cloudfront.net/install/

CloudFront gibt das Standardstammobjekt nicht zurück, selbst wenn eine Kopie von index.htmlim Installationsverzeichnis angezeigt wird.

...

Das Verhalten von CloudFront-Standardstammobjekten unterscheidet sich vom Verhalten von Amazon S3-Indexdokumenten. Wenn Sie einen Amazon S3-Bucket als Website konfigurieren und das Indexdokument angeben, gibt Amazon S3 das Indexdokument zurück, auch wenn ein Benutzer ein Unterverzeichnis im Bucket anfordert. (In jedem Unterverzeichnis muss eine Kopie des Indexdokuments erscheinen.)

2. Ist es möglich, eine Ursprungszugriffsidentität für Inhalte einzurichten, die von Cloudfront bereitgestellt werden, wobei der Ursprung ein S3-Website-Endpunkt und kein S3-Bucket ist?

Nicht direkt. Ihre Optionen für Ursprünge mit CloudFront sind S3-Buckets oder Ihr eigener Server.

Es ist jedoch diese zweite Option, die einige interessante Möglichkeiten eröffnet. Dies macht wahrscheinlich den Zweck Ihres Versuchs zunichte, aber Sie könnten Ihren eigenen Server einrichten, dessen einzige Aufgabe darin besteht, ein CloudFront-Ursprungsserver zu sein.

Wenn eine Anfrage für http://d111111abcdef8.cloudfront.net/install/ eingeht, leitet CloudFront diese Anfrage an Ihren Ursprungsserver weiter und fragt nach /install. Sie können Ihren Ursprungsserver so konfigurieren, wie Sie möchten, auch index.htmlin diesem Fall.

Oder Sie schreiben eine kleine Web-App, die diesen Anruf einfach entgegennimmt und ihn trotzdem direkt von S3 erhält.

Mir ist jedoch klar, dass das Einrichten eines eigenen Servers und die Sorge um dessen Skalierung den Zweck dessen, was Sie überhaupt versuchen, zunichte machen können.

Josh Padnick
quelle
Das einzige Problem, das ich damit habe, ist, dass dies funktioniert, wenn Sie zwei (2) URLs haben, die auf s3 auf Ihre Website zugreifen können. Ihre Cloud-Front-URL und Ihre S3-URL (Bucket_Name.s3-website-us-east-1.amazonaws.com)
Hayden
217

Es IST eine Möglichkeit , dies zu tun. Zeigen Sie es nicht auf Ihren Bucket, indem Sie es in der Dropdown-Liste (www.example.com.s3.amazonaws.com) auswählen, sondern auf die statische Domäne Ihres Buckets (z. B. www.example.com.s3-website-us) -west-2.amazonaws.com):

Geben Sie hier die Bildbeschreibung ein

Vielen Dank an diesen AWS Forum Thread

JBaczuk
quelle
6
Weiß jemand, ob dies bei einem s3-Ursprung anders ist als bei einem Web-Ursprung?
Fideloper
3
Funktioniert dies einwandfrei, wenn ich HTTPSnur meine gesamte Website und Dateien bereitstellen möchte ?
Manjit Kumar
3
Bedeutet das, dass der S3 als Webserver aktiviert sein muss?
Anthony Kong
6
OP erklärte ausdrücklich, dass dieser Ansatz für ihn nicht funktioniert: "Um diese Schwierigkeit zu umgehen, können wir den Ursprungsdomänennamen so ändern, dass er auf den von S3 angegebenen Website-Endpunkt verweist. Dies funktioniert hervorragend und ermöglicht die einheitliche Angabe der Stammobjekte. Leider Dies scheint nicht mit den Ursprungszugriffsidentitäten kompatibel zu sein. " AWS selbst scheint lamda
icyitscold
3
Dies ist nicht kompatibel mit Cloud Front - Origin Access Identity. Auf diese Weise können Sie den Zugriff auf Ihren S3-Bucket nicht einschränken.
Raketenabstandhalter
15

Wenn Sie das S3-Hosting aktivieren, müssen Sie den Eimer für die Welt öffnen. In meinem Fall musste ich den Bucket privat halten und die Ursprungszugriffsidentitätsfunktion verwenden, um den Zugriff nur auf Cloudfront einzuschränken. Wie von @Juissi vorgeschlagen, kann eine Lambda-Funktion die Weiterleitungen beheben:

'use strict';

/**
 * Redirects URLs to default document. Examples:
 *
 * /blog            -> /blog/index.html
 * /blog/july/      -> /blog/july/index.html
 * /blog/header.png -> /blog/header.png
 *
 */

let defaultDocument = 'index.html';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    if(request.uri != "/") {
        let paths = request.uri.split('/');
        let lastPath = paths[paths.length - 1];
        let isFile = lastPath.split('.').length > 1;

        if(!isFile) {
            if(lastPath != "") {
                request.uri += "/";
            }

            request.uri += defaultDocument;
        }

        console.log(request.uri);
    }

    callback(null, request);
};

Wechseln Sie nach der Veröffentlichung Ihrer Funktion zu Ihrer Cloudfront-Distribution in der AWS-Konsole. Gehen Sie zu Behaviors, wählen Sie dann Origin Requestunter Lambda Function Associationsund fügen Sie die ARN schließlich in Ihre neue Funktion ein.

Kenske
quelle
5
Es ist ein gebrauchsfertige Lambda - Funktion ähnlich , dass man implementieren: serverlessrepo.aws.amazon.com/applications/...
marcanuy
Das Problem hierbei ist, dass diese Funktion für us-east-1 bereitgestellt werden muss. Wenn Sie also ein Unternehmen unter strenger DSGVO-Regulierung haben, das kein einziges Bit außerhalb Deutschlands zulässt, ist dies nichts für Sie.
Renato Gama
5

Es gibt eine andere Möglichkeit, eine Standarddatei in einem Unterverzeichnis bereitzustellen, z example.com/subdir/. Sie können tatsächlich (programmgesteuert) eine Datei mit dem Schlüssel subdir/im Bucket speichern . Diese Datei wird nicht in der S3-Verwaltungskonsole angezeigt, ist jedoch tatsächlich vorhanden, und CloudFront stellt sie bereit.

Johan Gorter
quelle
S3 converst subdir / to subdir; wenn Sie versuchen, den HTML-Code hochzuladen. Wenn Sie versuchen, auf example.com/subdir/ zuzugreifen, schlägt dies fehl, und wenn Sie versuchen, auf example.com/subdir zuzugreifen. Es lädt die HTML-Datei herunter, anstatt sie zu rendern.
Jacobfogg
4

Umgehung des Problems besteht darin, lambda @ edge zum Umschreiben der Anforderungen zu verwenden. Man muss nur das Lambda für das Viewer-Anforderungsereignis der CloudFront-Distribution einrichten und alles neu schreiben, was mit '/' AND endet und nicht gleich '/' mit dem Standardstammdokument ist, z. B. index.html.

Juissi
quelle
Weitere Details zu diesem Ansatz finden Sie hier: aws.amazon.com/blogs/compute/…
Henrik Aasted Sørensen
Leider funktioniert Lambda @ Edge nur in der Region us-east-1, Quelle: github.com/awslabs/serverless-application-model/issues/635
mruanova
4

Auf dem AWS-Blog wird ein "offizieller" Leitfaden veröffentlicht , in dem empfohlen wird, eine Lambda @ Edge-Funktion einzurichten, die von Ihrer CloudFront-Distribution ausgelöst wird:

Natürlich ist es eine schlechte Benutzererfahrung zu erwarten, dass Benutzer immer index.html am Ende jeder URL eingeben (oder sogar wissen, dass es dort sein sollte). Bisher gab es keine einfache Möglichkeit, Benutzern diese einfacheren URLs (entspricht der DirectoryIndex-Direktive in einer Apache-Webserverkonfiguration) über CloudFront bereitzustellen. Nicht, wenn Sie den Zugriff auf den S3-Ursprung mithilfe einer OAI weiterhin einschränken möchten. Mit der Veröffentlichung von Lambda @ Edge können Sie jedoch eine JavaScript-Funktion verwenden, die auf den CloudFront-Randknoten ausgeführt wird, um nach diesen Mustern zu suchen und den entsprechenden Objektschlüssel vom S3-Ursprung anzufordern.

Lösung

In diesem Beispiel verwenden Sie die Rechenleistung am CloudFront-Rand, um die Anforderung zu überprüfen, wenn sie vom Client eingeht. Schreiben Sie dann die Anforderung neu, sodass CloudFront ein Standardindexobjekt (in diesem Fall index.html) für jeden Anforderungs-URI anfordert, der mit '/' endet.

Wenn eine Anforderung an einen Webserver gestellt wird, gibt der Client das Objekt an, das in der Anforderung abgerufen werden soll. Sie können diesen URI verwenden und einen regulären Ausdruck darauf anwenden, damit diese URIs in ein Standardindexobjekt aufgelöst werden, bevor CloudFront das Objekt vom Ursprung anfordert. Verwenden Sie den folgenden Code:

'use strict';
exports.handler = (event, context, callback) => {

    // Extract the request from the CloudFront event that is sent to Lambda@Edge
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');

    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    // Return to CloudFront
    return callback(null, request);

};

Befolgen Sie die oben verlinkte Anleitung, um alle zum Einrichten erforderlichen Schritte anzuzeigen, einschließlich S3-Bucket, CloudFront-Verteilung und Erstellung der Lambda @ Edge- Funktion.

Max Desiatov
quelle
2

Eine andere Alternative zur Verwendung von lambda @ edge ist die Verwendung der Fehlerseiten von CloudFront. Richten Sie eine benutzerdefinierte Fehlerantwort ein , um alle 403 an eine bestimmte Datei zu senden. Fügen Sie dieser Datei dann Javascript hinzu, um index.html an URLs anzuhängen, die mit einem / enden. Beispielcode:

if ((window.location.href.endsWith("/") && !window.location.href.endsWith(".com/"))) {
    window.location.href = window.location.href + "index.html";
}
else {
    document.write("<Your 403 error message here>");
}
user1333371
quelle
1

Ich weiß, dass dies eine alte Frage ist, aber ich habe mich selbst darum gekämpft. Letztendlich war es weniger mein Ziel, eine Standarddatei in einem Verzeichnis festzulegen, als vielmehr das Endergebnis einer Datei zu erhalten, die .htmlam Ende ohne geliefert wurde

Am Ende habe ich .htmlaus dem Dateinamen entfernt und den MIME-Typ programmgesteuert / manuell auf gesetzt text/html. Es ist nicht der traditionelle Weg, aber es scheint zu funktionieren und erfüllt meine Anforderungen an die hübschen URLs, ohne die Vorteile der Cloudformation zu beeinträchtigen. Das Einstellen des MIME-Typs ist ärgerlich, aber meiner Meinung nach ein kleiner Preis für die Vorteile

whtevn
quelle