Private S3-Inhalte mit CloudFront bereitstellen

AWSBeginner
Jetzt üben

Einführung

Dein Team möchte Kunden eine Version über CloudFront bereitstellen und den S3-Ursprung privat halten. Lade die bereitgestellte Seite hoch, verbinde eine Distribution mit einer Ursprungszugriffssteuerung und erlaube nur dieser Distribution, die Objekte zu lesen. Teste den funktionierenden Viewer-Weg und den abgewiesenen direkten Zugriff auf den Ursprung.

Schließe zuerst AWS Foundations, S3-Objektoperationen und die Konzepte der IAM-Ressourcenrichtlinien ab. Diese unabhängige VM stellt konfigurierten AWS-CLI-Zugriff, index.html und einen separaten Referenz-Bucket bereit. Beobachte Distribution und Ursprung oben in AWS View und arbeite unten im Terminal. Ein persönliches AWS-Konto oder eine öffentliche Domain ist nicht erforderlich. Dieses Lab verwendet einen gewöhnlichen S3-Ursprung; Viewer-Caching und HTTPS folgen in separaten Labs.

Bezug zur Zertifizierung

Zertifizierung Prüfungsaufgabe Übung
Solutions Architect – Associate (SAA-C03) Aufgabe 1.1 S3-Lesezugriffe durch eine Ressourcenrichtlinie auf die vorgesehene CloudFront-Distribution begrenzen.

Lab-Übersicht

Konzeptdiagramm: Ein Viewer fragt CloudFront an, das den privaten S3-Ursprung lesen darf; eine anonyme direkte Anfrage wird abgewiesen.

Private Ursprungsinhalte vorbereiten

In diesem Schritt erstelle einen privaten S3-Bucket und lade die vorbereitete Seite hoch.

Der Ursprung (Origin) speichert die Inhalte, die CloudFront abruft. Ein Viewer ist ein Client, der Inhalte von CloudFront anfordert. Viewer- und Ursprungszugriff sind unterschiedliche Berechtigungen: Eine Seite kann über die Distribution lesbar sein, während anonyme direkte S3-Lesezugriffe abgewiesen bleiben.

Arbeite im bereitgestellten Projektverzeichnis. Lasse den Referenz-Bucket labex-n02-reference unverändert:

cd /home/labex/project
cat index.html
aws s3api create-bucket \
  --bucket labex-n02-content

Setze die Objekteigentümerschaft auf Bucket owner enforced. Das Eigentum bleibt beim Bucket-Eigentümer, und ACL-basierte Freigaben werden deaktiviert; OAC verwendet stattdessen die Bucket-Richtlinie. Aktiviere alle vier Block Public Access-Schutzoptionen gegen öffentliche ACL- oder Richtlinienfreigaben:

aws s3api put-bucket-ownership-controls \
  --bucket labex-n02-content \
  --ownership-controls '{"Rules":[{"ObjectOwnership":"BucketOwnerEnforced"}]}'
aws s3api put-public-access-block \
  --bucket labex-n02-content \
  --public-access-block-configuration '{"BlockPublicAcls":true,"IgnorePublicAcls":true,"BlockPublicPolicy":true,"RestrictPublicBuckets":true}'

Lade die bereitgestellte Seite hoch. --content-type text/html kennzeichnet das Objekt als HTML-Dokument:

aws s3api put-object \
  --bucket labex-n02-content \
  --key index.html \
  --body index.html \
  --content-type text/html
aws s3api head-object \
  --bucket labex-n02-content \
  --key index.html

Prüfe Objektgröße und ContentType. Deine CLI-Anfrage ist als konfigurierter Operator authentifiziert. Vergleiche sie mit einer anonymen HTTP-Anfrage ohne AWS-Zugangsdaten:

curl --noproxy '*' \
  --output /dev/null \
  --write-out 'Direct origin: HTTP %{http_code}\n' \
  http://127.0.0.1:5000/labex-n02-content/index.html

Erwarte Direct origin: HTTP 403. --output /dev/null verwirft den Fehlertext; --write-out zeigt den HTTP-Status. Dieser ausdrücklich gewählte Übungsendpunkt testet den direkten S3-Objektzugriff und macht den Bucket nicht öffentlich. Führe die Prüfung des privaten Ursprungs aus.

Beispiel nach dem Upload: Das 91 Byte große Ursprungsobjekt erscheint neben dem unveränderten Referenzobjekt; es gibt noch keine Distribution.

Die Distribution mit ihrem Ursprung verbinden

In diesem Schritt verbinde eine CloudFront-Distribution mit dem S3-Bucket und beobachte, dass die Verbindung allein keine Ursprungsberechtigung erteilt.

Eine Ursprungszugriffssteuerung (OAC) legt fest, wie CloudFront Ursprungsanfragen authentifiziert. Wähle S3, Signature Version 4 und Signieren mit always. Schreibe die gewöhnliche CLI-Konfiguration:

cat > oac.json <<'JSON'
{
  "Name": "labex-n02-oac",
  "Description": "Read the private release origin",
  "SigningProtocol": "sigv4",
  "SigningBehavior": "always",
  "OriginAccessControlOriginType": "s3"
}
JSON
OAC_ID=$(aws cloudfront create-origin-access-control \
  --origin-access-control-config file://oac.json \
  --query OriginAccessControl.Id \
  --output text)

$(...) speichert die zurückgegebene OAC-ID in OAC_ID. --query wählt nur die ID, damit die nächste Konfiguration darauf verweisen kann. Lasse dieses Terminal während des gesamten Labs geöffnet.

Die Distributionskonfiguration verbindet content-origin mit dem gewöhnlichen S3-Bucket-Endpunkt, nicht mit einem S3-Website-Endpunkt. TargetOriginId wählt diesen Ursprung; DefaultRootObject ordnet / dem Objekt index.html zu. Der ältere Block ForwardedValues verhindert die Weitergabe von Cookies und Query-Strings. Alle TTL-Werte sind null, damit der Berechtigungstest keinen zwischengespeicherten Erfolg wiederverwendet. allow-all erlaubt die hier verwendete HTTP-Viewer-Anfrage; HTTPS wird separat behandelt.

Das nächste Here-Dokument ist nicht in Anführungszeichen gesetzt; die Shell ersetzt daher $OAC_ID in der JSON-Datei:

cat > distribution.json <<JSON
{
  "CallerReference": "labex-n02-release",
  "Comment": "labex-n02:private-content",
  "Enabled": true,
  "DefaultRootObject": "index.html",
  "Origins": {
    "Quantity": 1,
    "Items": [{
      "Id": "content-origin",
      "DomainName": "labex-n02-content.s3.amazonaws.com",
      "S3OriginConfig": {"OriginAccessIdentity": ""},
      "OriginAccessControlId": "$OAC_ID"
    }]
  },
  "DefaultCacheBehavior": {
    "TargetOriginId": "content-origin",
    "ViewerProtocolPolicy": "allow-all",
    "TrustedSigners": {"Enabled": false, "Quantity": 0},
    "ForwardedValues": {"QueryString": false, "Cookies": {"Forward": "none"}},
    "MinTTL": 0,
    "DefaultTTL": 0,
    "MaxTTL": 0
  }
}
JSON
DIST_ID=$(aws cloudfront create-distribution \
  --distribution-config file://distribution.json \
  --query Distribution.Id \
  --output text)
DIST_DOMAIN=$(aws cloudfront get-distribution \
  --id "$DIST_ID" \
  --query Distribution.DomainName \
  --output text)

Prüfe den verbundenen Ursprung:

aws cloudfront get-distribution-config \
  --id "$DIST_ID" \
  --query DistributionConfig.Origins

S3-Domain und OriginAccessControlId sollten zu deinem Bucket und deiner OAC passen. Warte vor dem Test auf die Bereitstellung in der Steuerungsebene. Der offizielle Waiter liest wiederholt den Status und erzeugt keinen Viewer-Verkehr:

aws cloudfront wait distribution-deployed \
  --id "$DIST_ID"

Teste jetzt den Viewer-Weg. --resolve leitet genau diesen Distributionsnamen mit dem Übungsport zum bereitgestellten Verteilungsendpunkt der VM. Es ändert weder das System-DNS noch registriert es eine Domain:

curl --noproxy '*' \
  --resolve "${DIST_DOMAIN}:8082:127.0.0.1" \
  --output /dev/null \
  --write-out 'Viewer before permission: HTTP %{http_code}\n' \
  "http://${DIST_DOMAIN}:8082/index.html"

Erwarte HTTP 403. Distribution und OAC beschreiben eine Verbindung; S3 benötigt weiterhin eine Richtlinie, die dieser Distribution Zugriff erlaubt. Mache den Bucket zur Behebung nicht öffentlich. Führe die Verbindungsprüfung aus.

Beispiel vor der Ursprungsfreigabe: Die verbundene Distribution antwortet auf die tatsächliche Viewer-Anfrage mit HTTP 403.

Der vorgesehenen Distribution Zugriff erlauben

In diesem Schritt erlaube der ausgewählten CloudFront-Distribution das Lesen der Objekte, während anonyme direkte Ursprungszugriffe abgewiesen bleiben.

Ein ARN identifiziert eine AWS-Ressource und ihr Konto. Lies den ARN deiner Distribution:

DIST_ARN=$(aws cloudfront get-distribution \
  --id "$DIST_ID" \
  --query Distribution.ARN \
  --output text)

Die Bucket-Richtlinie nennt cloudfront.amazonaws.com als Service-Principal, erlaubt nur s3:GetObject und begrenzt die Freigabe auf Objekte deines Buckets. Die Bedingung AWS:SourceArn beschränkt die Service-Anfrage auf deine konkrete Distribution. Dies unterscheidet sich von einer öffentlichen Richtlinie mit Principal: "*". Schreibe sie mit dem ermittelten ARN:

cat > bucket-policy.json <<JSON
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "cloudfront.amazonaws.com"},
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::labex-n02-content/*",
    "Condition": {"StringEquals": {"AWS:SourceArn": "$DIST_ARN"}}
  }]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-n02-content \
  --policy file://bucket-policy.json

Fordere das Objekt erneut an. --fail lässt den Befehl bei einem erfolglosen HTTP-Status scheitern; --include zeigt Header und tatsächliches Dokument:

curl --fail --include --noproxy '*' \
  --resolve "${DIST_DOMAIN}:8082:127.0.0.1" \
  "http://${DIST_DOMAIN}:8082/index.html"

Erwarte HTTP 200, den Inhaltstyp text/html und eine Seite mit Release one. Du hast Objektbytes über die Distribution beobachtet, nicht lediglich eine erfolgreiche Konfigurationsantwort.

Wiederhole sofort den anonymen direkten Ursprungstest:

curl --noproxy '*' \
  --output /dev/null \
  --write-out 'Direct origin after viewer success: HTTP %{http_code}\n' \
  http://127.0.0.1:5000/labex-n02-content/index.html

Er muss weiterhin HTTP 403 liefern. Der Viewer-Weg funktioniert, der direkte Ursprung bleibt privat. AWS View zeigt den verbundenen Ursprung und das letzte Viewer-Ergebnis. Führe die Zugriffsprüfung aus.

Beispiel nach der Freigabe: Die tatsächliche Viewer-Anfrage erhält HTTP 200 über die verbundene Distribution.

Nur deine Verteilungsressourcen entfernen

In diesem Schritt deaktiviere und lösche deine Distribution, bevor du ihre OAC und S3-Inhalte entfernst. Lasse den Referenz-Bucket unverändert.

CloudFront verwendet ein ETag als Versionskennung für Konfigurationsänderungen. Rufe die aktuelle Konfiguration und ihr ETag ab, statt eine Kennung zu raten:

aws cloudfront get-distribution-config \
  --id "$DIST_ID" \
  --query DistributionConfig \
  --output json > distribution-current.json
DIST_ETAG=$(aws cloudfront get-distribution-config \
  --id "$DIST_ID" \
  --query ETag \
  --output text)

In dieser Konfiguration ist Enabled der Distribution die einzige gleichnamige Eigenschaft mit dem Wert true. Die folgende gewöhnliche sed-Ersetzung erstellt eine deaktivierte Kopie und erhält die Ursprungseinstellungen:

sed 's/"Enabled": true/"Enabled": false/' distribution-current.json > distribution-disabled.json
aws cloudfront update-distribution \
  --id "$DIST_ID" \
  --if-match "$DIST_ETAG" \
  --distribution-config file://distribution-disabled.json

Warte auf die Bereitstellung der deaktivierten Konfiguration. Bei AWS kann die Verteilung von Änderungen dauern; diese Übung misst keine globale Bereitstellungslatenz:

aws cloudfront wait distribution-deployed \
  --id "$DIST_ID"

Das Update ändert das ETag. Lies vor dem Löschen der deaktivierten Distribution die neueste Kennung:

DIST_ETAG=$(aws cloudfront get-distribution-config \
  --id "$DIST_ID" \
  --query ETag \
  --output text)
aws cloudfront delete-distribution \
  --id "$DIST_ID" \
  --if-match "$DIST_ETAG"

Entferne die OAC mit ihrem eigenen ETag. Distributions-ID und OAC-ID bezeichnen unterschiedliche Ressourcen:

OAC_ETAG=$(aws cloudfront get-origin-access-control \
  --id "$OAC_ID" \
  --query ETag \
  --output text)
aws cloudfront delete-origin-access-control \
  --id "$OAC_ID" \
  --if-match "$OAC_ETAG"

Entferne nur das von dir erstellte Objekt und den Bucket:

aws s3api delete-object \
  --bucket labex-n02-content \
  --key index.html
aws s3api delete-bucket \
  --bucket labex-n02-content
aws s3api list-buckets \
  --query Buckets[].Name

Der Referenz-Bucket sollte erhalten und der Inhalts-Bucket entfernt sein. AWS View sollte keine Inhaltsdistribution und nur das Referenzobjekt zeigen. Führe die Bereinigungsprüfung aus. Eine erfolglose API-Anfrage beweist keine Ressourcenlöschung.

Beispiel nach der Bereinigung: Inhaltsdistribution und Bucket sind entfernt, das unabhängige Referenzobjekt bleibt erhalten.

Zusammenfassung

Du hast eine Distribution mit einem gewöhnlichen privaten S3-Ursprung verbunden, stets signierte OAC-Anfragen konfiguriert und nur der vorgesehenen Distribution Lesezugriff erlaubt. Tatsächliche HTTP-Tests trennten erlaubten Viewer-Zugriff von abgewiesenem anonymem Ursprungszugriff. Anschließend hast du mit aktuellen ETags deine Ressourcen deaktiviert und entfernt, ohne unabhängige Inhalte zu verändern. Als Nächstes beobachtest du Cache-Wiederverwendung und invalidierst ein aktualisiertes Objekt.