

# Restringir o acesso a uma origem do URL de função do AWS Lambda
<a name="private-content-restricting-access-to-lambda"></a>

O CloudFront fornece *controle de acesso à origem* (OAC) para restringir o acesso a uma origem do URL da função do Lambda.

**Topics**
+ [Criar um OAC](#create-oac-overview-lambda)
+ [Configurações avançadas para controle de acesso à origem](#oac-advanced-settings-lambda)
+ [Exemplo de código de modelo](#example-template-code-lambda-oac)

## Criar um OAC
<a name="create-oac-overview-lambda"></a>

Conclua as etapas descritas nos tópicos a seguir para configurar um novo OAC no CloudFront.

**Importante**  
Se você usar os métodos `PUT` ou `POST` com o URL da função do Lambda, os usuários deverão calcular o SHA256 do corpo e incluir o valor de hash da carga útil no cabeçalho `x-amz-content-sha256` ao enviar a solicitação ao CloudFront. O Lambda não é compatível com cargas úteis não conectadas.

**Topics**
+ [Pré-requisitos](#oac-prerequisites-lambda)
+ [Conceder permissão ao CloudFront para acessar o URL da função do Lambda](#oac-permission-to-access-lambda)
+ [Criar o OAC](#create-oac-lambda)

### Pré-requisitos
<a name="oac-prerequisites-lambda"></a>

Antes de criar e configurar o OAC, você deve ter uma distribuição do CloudFront com um URL da função do Lambda como origem. Para usar o OAC, você deve especificar o `AWS_IAM` como valor para o parâmetro `AuthType`. Para obter mais informações, consulte [Usar um URL da função do Lambda](DownloadDistS3AndCustomOrigins.md#concept_lambda_function_url).

### Conceder permissão ao CloudFront para acessar o URL da função do Lambda
<a name="oac-permission-to-access-lambda"></a>

Antes de criar um OAC ou configurá-lo em uma distribuição do CloudFront, este deve ter permissão para acessar o URL da função do Lambda. Faça isso depois de criar uma distribuição do CloudFront, mas antes de adicionar o OAC ao URL da função do Lambda na configuração de distribuição.

**nota**  
Para atualizar a política do IAM para o URL da função do Lambda, você deve usar o AWS Command Line Interface (AWS CLI). Não há suporte para a edição da política do IAM no console do Lambda, no momento.

O comando AWS CLI a seguir concede ao serviço de entidade principal (`cloudfront.amazonaws.com`) do CloudFront acesso ao URL da função do Lambda. O elemento `Condition` na política permite que o CloudFront acesse o Lambda *somente* quando a solicitação for em nome da distribuição do CloudFront que contém o URL da função do Lambda. Essa é a distribuição com a origem do URL da função do Lambda à qual você deseja adicionar o OAC.

**Example : comando da AWS CLI para atualizar uma política e permitir acesso somente leitura a uma distribuição do CloudFront com OAC habilitado**  
O comando da AWS CLI a seguir permite que a distribuição do CloudFront (`E1PDK09ESKHJWT`) acesse o *`FUNCTION_URL_NAME`* do Lambda.

```
aws lambda add-permission \
--statement-id "AllowCloudFrontServicePrincipal" \
--action "lambda:InvokeFunctionUrl" \
--principal "cloudfront.amazonaws.com" \
--source-arn "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT" \
--function-name FUNCTION_URL_NAME
```

```
aws lambda add-permission \
--statement-id "AllowCloudFrontServicePrincipalInvokeFunction" \
--action "lambda:InvokeFunction" \
--principal "cloudfront.amazonaws.com" \
--source-arn "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT" \
--function-name FUNCTION_URL_NAME
```

**nota**  
Se você criar uma distribuição e ela não tiver permissão para o URL da função do Lambda, é possível selecionar **Copy CLI command** (Copiar comando CLI) no console do CloudFront e, em seguida, inserir esse comando no seu terminal de linha de comando. Para ter mais informações, consulte [Conceder acesso de função aos Serviços da AWS](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) no *Guia do desenvolvedor do AWS Lambda*. 

### Criar o OAC
<a name="create-oac-lambda"></a>

Para criar um OAC, é possível usar o Console de gerenciamento da AWS, o CloudFormation, a AWS CLI ou a API do CloudFront.

------
#### [ Console ]

**Para criar um OAC**

1. Faça login no Console de gerenciamento da AWS e abra o console do CloudFront em [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. No painel de navegação, selecione **Origem access** (Acesso à origem).

1. Selecione **Create control setting** (Criar configuração de controle).

1. No formulário **Create new OAC** (Criar novo OAC), faça o seguinte:

   1. Informe um **Name** (Nome) e (opcionalmente) uma **Description** (Descrição) para o OAC.

   1. Em **Signing behavior** (Comportamento de assinatura), recomendamos que deixe a configuração padrão (**Sign requests (recommended)** [Solicitações de assinatura (recomendado)]. Para obter mais informações, consulte [Configurações avançadas para controle de acesso à origem](#oac-advanced-settings-lambda).

1. Em **Origin type** (Tipo de origem), selecione **Lambda**. 

1. Escolha **Criar**.
**dica**  
Depois que criar OAC, anote o **Name** (Nome). Você precisará dele no procedimento a seguir.

**Como adicionar um controle de acesso à origem a um URL da função do Lambda em uma distribuição**

1. Abra o console do CloudFront em [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Escolha uma distribuição com um URL da função do Lambda ao qual você deseja adicionar o OAC e, depois, selecione a guia **Origins** (Origens).

1. Selecione o URL da função do Lambda ao qual você deseja adicionar o OAC e, depois, **Edit** (Editar).

1. Selecione **HTTPS only** (Somente HTTPS) para o **Protocol** (Protocolo) de sua origem.

1. No menu suspenso **Origin access control** (Controle de acesso à origem), selecione o nome do OAC que você deseja usar.

1. Escolha **Salvar alterações**.

A distribuição começa a ser implantada em todos os locais da borda do CloudFront. Quando um local da borda recebe a nova configuração, ele assina todas as solicitações enviadas ao URL da função do Lambda.

------
#### [ CloudFormation ]

Para criar um OAC com o CloudFormation, use o tipo de recurso `AWS::CloudFront::OriginAccessControl`. O exemplo a seguir mostra a sintaxe do modelo CloudFormation no formato YAML, para criar um OAC.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: lambda
      SigningBehavior: always
      SigningProtocol: sigv4
```

Para obter mais informações, consulte [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html) no *Guia do usuário do AWS CloudFormation*.

------
#### [ CLI ]

Para criar um controle de acesso à origem com a AWS Command Line Interface (AWS CLI), use o comando **aws cloudfront create-origin-access-control**. É possível usar um arquivo de entrada para fornecer os parâmetros de entrada do comando, em vez de especificar cada parâmetro individual como entrada na linha de comando.

**Como criar um controle de acesso à origem (CLI com arquivo de entrada)**

1. Use o comando a seguir para criar um arquivo chamado `origin-access-control.yaml`. Esse arquivo contém todos os parâmetros de entrada para o comando **create-origin-access-control**.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. Abra o arquivo `origin-access-control.yaml` que você acabou de criar. Edite o arquivo para adicionar um nome para o OAC, uma descrição (opcional) e alterar `SigningBehavior` para `always`. Salve o arquivo.

   Para obter mais informações sobre outras configurações de OAC, consulte [Configurações avançadas para controle de acesso à origem](#oac-advanced-settings-lambda).

1. Use o comando a seguir para criar o controle de acesso à origem usando parâmetros de entrada do arquivo `origin-access-control.yaml`.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   Anote o valor do `Id` na saída do comando. Você precisa dele para adicionar o OAC a um URL da função do Lambda em uma distribuição do CloudFront.

**Como anexar um OAC a um URL da função do Lambda em uma distribuição existente (CLI com arquivo de entrada)**

1. Use o comando a seguir para salvar a configuração da distribuição do CloudFront à qual você deseja adicionar o OAC. A distribuição deve ter um URL da função do Lambda como origem.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. Abra o arquivo chamado `dist-config.yaml` que você acabou de criar. Edite o arquivo fazendo as seguintes alterações:
   + No objeto `Origins`, adicione o ID do OAC ao campo chamado `OriginAccessControlId`.
   + Remova o valor do campo chamado `OriginAccessIdentity`, se houver.
   + Renomeie o campo `ETag` para `IfMatch`, mas não altere o valor do campo.

   Ao concluir, salve o arquivo.

1. Use o comando a seguir para atualizar a distribuição para usar o controle de acesso à origem.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

A distribuição começa a ser implantada em todos os locais da borda do CloudFront. Quando um local da borda recebe a nova configuração, ele assina todas as solicitações enviadas ao URL da função do Lambda.

------
#### [ API ]

Para criar um OAC com a API do CloudFront, use [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html). Para obter mais informações sobre os campos especificados nessa chamada de API, consulte a documentação de referência de API do seu AWS SDK ou de outro cliente de API.

Assim que criar um controle de acesso à origem, é possível anexá-lo a um URL da função do Lambda em uma distribuição usando uma das seguintes chamadas de API:
+ Para anexá-lo a uma distribuição existente, use [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html).
+ Para anexá-lo a uma nova distribuição, use [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html).

Para as duas chamadas de API, forneça o ID de OAC no campo `OriginAccessControlId`, dentro de uma origem. Para ter mais informações sobre os outros campos especificados nessas chamadas de API, consulte a documentação de referência da API do SDK ou de outro cliente de API da AWS.

------

## Configurações avançadas para controle de acesso à origem
<a name="oac-advanced-settings-lambda"></a>

O atributo de OAC do CloudFront inclui configurações avançadas destinadas somente a casos de uso específicos. Use as configurações recomendadas, a menos que você precise usar as configurações avançadas para uma necessidade específica.

O OAC contém uma configuração chamada **Signing behavior** (Comportamento de assinatura) (no console) ou `SigningBehavior` (na API, na CLI e no CloudFormation). Essa configuração fornece as seguintes opções:

**Always sign origin requests (recommended setting) [Sempre assinar solicitações de origem (configuração recomendada)]**  
Recomendamos usar essa configuração, chamada **Sign requests (recommended)** [Assinar solicitações (recomendado)] no console, ou `always` na API, na CLI e no CloudFormation. Com essa configuração, o CloudFront sempre assina todas as solicitações enviadas ao URL da função do Lambda.

**Never sign origin requests (Nunca assinar solicitações de origem)**  
Essa configuração é chamada **Do not sign requests** (Não assinar solicitações) no console ou `never` na API, na CLI e no CloudFormation. Use essa configuração para desativar o OAC para todas as origens em todas as distribuições que usam esse OAC. Isso pode economizar tempo e esforço em comparação com a remoção individual de um OAC de todas as origens e distribuições que o usam. Com essa configuração, o CloudFront não assina nenhuma solicitação enviada ao URL da função do Lambda.  
Para usar essa configuração, o URL da função do Lambda deve estar acessível de forma pública. Se você usar essa configuração com um URL da função do Lambda que não esteja acessível de forma pública, o CloudFront não poderá acessar a origem. A origem do URL da função do Lambda retorna erros ao CloudFront e o CloudFront transmite esses erros aos visualizadores. Para ter mais informações, consulte [Modelo de segurança e autenticação para URLs de função do Lambda](https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html) no *Guia do usuário do AWS Lambda*.

**Não substituir o cabeçalho `Authorization` do visualizador (cliente)**  
Essa configuração é chamada **Do not override authorization header** (Não substituir o cabeçalho de autorização) no console ou `no-override` na API, na CLI e no CloudFormation. Use essa configuração quando quiser que o CloudFront assine solicitações de origem somente quando a solicitação do visualizador correspondente não incluir um cabeçalho `Authorization`. Com essa configuração, o CloudFront transmite o cabeçalho `Authorization` da solicitação do visualizador quando houver, mas assina a solicitação de origem (adicionando seu próprio cabeçalho `Authorization`) quando a solicitação do visualizador não inclui um cabeçalho `Authorization`.  
+ Se usar essa configuração, você deverá especificar a assinatura do Signature versão 4 para o URL da função do Lambda em vez do nome ou CNAME da distribuição do CloudFront. Quando o CloudFront encaminha o cabeçalho `Authorization` da solicitação do visualizador para o URL da função do Lambda, o Lambda valida a assinatura em relação ao host do domínio de URL do Lambda. Se a assinatura não for baseada no domínio de URL do Lambda, o host na assinatura não corresponderá ao host usado pela origem do URL do Lambda. Isso significa que a solicitação falhará, ocasionando um erro de validação da assinatura.
+ Para transmitir o cabeçalho de `Authorization` da solicitação do visualizador, você *deve* adicionar o cabeçalho de `Authorization` a uma [política de cache](controlling-the-cache-key.md) para todos os comportamentos de cache que usam URLs da função do Lambda associados a esse controle de acesso à origem.

## Exemplo de código de modelo
<a name="example-template-code-lambda-oac"></a>

Se a origem do CloudFront for um URL da função do Lambda associado a um OAC, você poderá usar o script do Python a seguir para carregar arquivos na função do Lambda com o método `POST`. 

Esse código pressupõe que você configurou o OAC com o comportamento de assinatura padrão definido como **Sempre assinar solicitações para a origem** e que você não selecionou a configuração **Não substituir o cabeçalho de autorização**.

Essa configuração permite que o OAC gerencie a autorização SigV4 corretamente com o Lambda usando o nome de host do Lambda. A carga útil é assinada usando SigV4 da identidade do IAM autorizada para o URL da função do Lambda, que é designada como o tipo `IAM_AUTH`. 

O modelo demonstra como lidar com valores de hash de carga útil assinados no cabeçalho x-amz-content-sha256 para solicitações `POST` do lado do cliente. Esse modelo foi projetado especificamente para gerenciar cargas úteis de dados de formulário. Ele permite o upload seguro de arquivos para um URL da função do Lambda por meio do CloudFront e usa mecanismos de autenticação da AWS para garantir que somente solicitações autorizadas acessem a função do Lambda.

**O código inclui as seguintes funcionalidades:**  
Atende ao requisito de incluir o hash da carga útil no cabeçalho x-amz-content-sha256.
Usa a autenticação SigV4 para acesso seguro ao AWS service (Serviço da AWS).
Permite uploads de arquivos usando dados de formulário de várias partes.
Inclui tratamento de erros para exceções de solicitação.

```
import boto3
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
import requests
import hashlib
import os


def calculate_body_hash(body):
    return hashlib.sha256(body).hexdigest()


def sign_request(request, credentials, region, service):
    sigv4 = SigV4Auth(credentials, service, region)
    sigv4.add_auth(request)


def upload_file_to_lambda(cloudfront_url, file_path, region):
    # AWS credentials
    session = boto3.Session()
    credentials = session.get_credentials()

    # Prepare the multipart form-data
    boundary = "------------------------boundary"

    # Read file content
    with open(file_path, 'rb') as file:
        file_content = file.read()

    # Get the filename from the path
    filename = os.path.basename(file_path)

    # Prepare the multipart body
    body = (
        f'--{boundary}\r\n'
        f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'
        f'Content-Type: application/octet-stream\r\n\r\n'
    ).encode('utf-8')
    body += file_content
    body += f'\r\n--{boundary}--\r\n'.encode('utf-8')

    # Calculate SHA256 hash of the entire body
    body_hash = calculate_body_hash(body)

    # Prepare headers
    headers = {
        'Content-Type': f'multipart/form-data; boundary={boundary}',
        'x-amz-content-sha256': body_hash
    }

    # Create the request
    request = AWSRequest(
        method='POST',
        url=cloudfront_url,
        data=body,
        headers=headers
    )

    # Sign the request
    sign_request(request, credentials, region, 'lambda')

    # Get the signed headers
    signed_headers = dict(request.headers)

    # Print request headers before sending
    print("Request Headers:")
    for header, value in signed_headers.items():
        print(f"{header}: {value}")

    try:
        # Send POST request with signed headers
        response = requests.post(
            cloudfront_url,
            data=body,
            headers=signed_headers
        )

        # Print response status and content
        print(f"\nStatus code: {response.status_code}")
        print("Response:", response.text)

        # Print response headers
        print("\nResponse Headers:")
        for header, value in response.headers.items():
            print(f"{header}: {value}")

    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}")


# Usage
cloudfront_url = "https://d111111abcdef8.cloudfront.net"
file_path = r"filepath"
region = "us-east-1"  # example: "us-west-2"

upload_file_to_lambda(cloudfront_url, file_path, region)
```