Introdução
Sua equipe quer que os clientes leiam uma versão pelo CloudFront, mantendo a origem S3 privada. Envie a página fornecida, conecte uma distribuição e um controle de acesso à origem e conceda somente a essa distribuição permissão para ler os objetos. Teste o caminho funcional do cliente e o acesso direto à origem que deve ser negado.
Conclua primeiro AWS Foundations, operações de objetos S3 e conceitos de políticas de recursos do IAM. Esta VM independente fornece acesso AWS CLI configurado, index.html e um bucket de referência separado. Observe a distribuição e a origem no AWS View, acima, e trabalhe no Terminal, abaixo. Não é necessária uma conta AWS pessoal nem um domínio público. Este laboratório utiliza uma origem S3 comum; cache do cliente e HTTPS serão tratados separadamente.
Relação com a certificação
| Certificação | Tarefa do exame | Prática |
|---|---|---|
| Solutions Architect – Associate (SAA-C03) | Tarefa 1.1 | Usar uma política de recursos para restringir leituras do S3 à distribuição CloudFront desejada. |
Visão geral do laboratório

Preparar o conteúdo da origem privada
Nesta etapa, crie um bucket S3 privado e envie a página preparada.
A origem armazena o conteúdo que o CloudFront busca. Um viewer é o cliente que solicita conteúdo ao CloudFront. O acesso do cliente e o acesso à origem são permissões diferentes: uma página pode ser lida pela distribuição enquanto leituras anônimas diretas do S3 continuam negadas.
Trabalhe no diretório do projeto fornecido. Mantenha intacto o bucket de referência labex-n02-reference:
cd /home/labex/project
cat index.html
aws s3api create-bucket \
--bucket labex-n02-content
Defina a propriedade dos objetos como Bucket owner enforced. O proprietário do bucket mantém a propriedade e as concessões por ACL são desativadas; OAC utiliza a política do bucket. Ative as quatro proteções Block Public Access para impedir concessões públicas por ACL ou política:
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}'
Envie a página fornecida. --content-type text/html descreve o objeto como documento HTML:
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
Examine o tamanho do objeto e ContentType. A solicitação CLI está autenticada como o operador configurado. Compare com uma solicitação HTTP anônima, sem credenciais AWS:
curl --noproxy '*' \
--output /dev/null \
--write-out 'Direct origin: HTTP %{http_code}\n' \
http://127.0.0.1:5000/labex-n02-content/index.html
Espere Direct origin: HTTP 403. --output /dev/null descarta o corpo do erro; --write-out imprime o status HTTP. Este endpoint explícito de prática testa o acesso direto ao objeto S3 sem tornar o bucket público. Execute a verificação da origem privada.

Conectar a distribuição à origem
Nesta etapa, conecte uma distribuição CloudFront ao bucket S3 e observe que somente a conexão não concede permissão na origem.
Um controle de acesso à origem (OAC) informa como o CloudFront autentica suas solicitações à origem. Selecione S3, Signature Version 4 e assinatura always. Escreva a configuração CLI comum:
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)
$(...) salva o ID de OAC retornado em OAC_ID. --query seleciona apenas o ID para a próxima configuração referenciá-lo. Mantenha este Terminal aberto durante todo o laboratório.
A configuração conecta content-origin ao endpoint comum do bucket S3, não a um endpoint de site S3. TargetOriginId seleciona a origem; DefaultRootObject associa / a index.html. O bloco legado ForwardedValues evita encaminhar cookies ou strings de consulta. Todos os TTLs são zero, impedindo que o teste de permissões reutilize um sucesso em cache. allow-all permite a solicitação HTTP do cliente utilizada aqui; HTTPS é ensinado separadamente.
O próximo here-document está sem aspas, portanto o shell expande $OAC_ID no arquivo JSON:
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)
Examine a origem conectada:
aws cloudfront get-distribution-config \
--id "$DIST_ID" \
--query DistributionConfig.Origins
O domínio S3 e OriginAccessControlId devem corresponder ao bucket e ao OAC. Aguarde a implantação no plano de controle antes do teste. O waiter oficial consulta repetidamente o status, sem gerar tráfego de clientes:
aws cloudfront wait distribution-deployed \
--id "$DIST_ID"
Agora teste o caminho do cliente. --resolve envia este nome exato da distribuição e a porta de prática ao endpoint de entrega fornecido na VM; não altera o DNS do sistema nem registra um domínio:
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"
Espere HTTP 403. Criar a distribuição e selecionar um OAC descreve uma conexão; o S3 ainda precisa de uma política que conceda acesso a essa distribuição. Não torne o bucket público para corrigir o resultado. Execute a verificação da conexão.

Conceder acesso à distribuição desejada
Nesta etapa, permita que a distribuição CloudFront selecionada leia os objetos, mantendo negado o acesso anônimo direto à origem.
Um ARN identifica um recurso AWS e sua conta. Leia o ARN da distribuição:
DIST_ARN=$(aws cloudfront get-distribution \
--id "$DIST_ID" \
--query Distribution.ARN \
--output text)
A política do bucket identifica cloudfront.amazonaws.com como principal de serviço, permite apenas s3:GetObject e limita a concessão aos objetos do bucket. A condição AWS:SourceArn restringe a solicitação do serviço à sua distribuição específica. Essa concessão difere de uma política pública com Principal: "*". Escreva-a usando o ARN obtido:
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
Solicite o objeto novamente. --fail agora faz o comando falhar diante de um status HTTP sem sucesso, e --include mostra os cabeçalhos junto com o documento real:
curl --fail --include --noproxy '*' \
--resolve "${DIST_DOMAIN}:8082:127.0.0.1" \
"http://${DIST_DOMAIN}:8082/index.html"
Espere HTTP 200, tipo de conteúdo text/html e a página contendo Release one. Você observou os bytes do objeto pela distribuição, além de uma resposta de configuração bem-sucedida.
Repita imediatamente o teste anônimo direto à origem:
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
Ele ainda deve retornar HTTP 403. O caminho do cliente funciona, enquanto a origem direta permanece privada. AWS View mostra a origem conectada e o último resultado do cliente. Execute a verificação do acesso.

Remover somente seus recursos de entrega
Nesta etapa, desative e exclua a distribuição antes de remover o OAC e o conteúdo S3. Mantenha intacto o bucket de referência.
O CloudFront utiliza um ETag como token de versão para mudanças de configuração. Obtenha a configuração e seu ETag atuais, sem adivinhar o token:
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)
Nesta configuração, Enabled da distribuição é a única propriedade desse nome com valor true. A substituição padrão com sed produz uma cópia desativada e mantém as configurações da origem:
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
Aguarde a implantação da configuração desativada. Na AWS, a propagação pode levar tempo; este exercício não mede a latência global de implantação:
aws cloudfront wait distribution-deployed \
--id "$DIST_ID"
A atualização altera o ETag. Leia o token mais recente antes de excluir a distribuição desativada:
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"
Remova o OAC com seu próprio ETag. O ID da distribuição e o do OAC representam recursos diferentes:
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"
Remova somente o objeto e o bucket que você criou:
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
O bucket de referência deve permanecer e o de conteúdo deve estar ausente. AWS View deve mostrar nenhuma distribuição de conteúdo e somente o objeto de referência. Execute a verificação da limpeza. Uma solicitação API malsucedida não comprova a exclusão de um recurso.

Resumo
Você conectou uma distribuição a uma origem S3 privada comum, configurou solicitações OAC sempre assinadas e concedeu leitura somente à distribuição desejada. Testes HTTP reais distinguiram o acesso permitido do cliente do acesso anônimo à origem negado. Depois, utilizou ETags atuais para desativar e remover seus recursos, preservando o conteúdo independente. Em seguida, observe a reutilização do cache e invalide um objeto atualizado.



