

# Restricción del acceso a un origen de URL de función de AWS Lambda
<a name="private-content-restricting-access-to-lambda"></a>

CloudFront proporciona un *control de acceso de origen* (OAC) para restringir el acceso a un origen de URL de función de Lambda.

**Topics**
+ [Creación de un nuevo OAC](#create-oac-overview-lambda)
+ [Configuración avanzada para el control de acceso de origen](#oac-advanced-settings-lambda)
+ [Código de plantilla de ejemplo](#example-template-code-lambda-oac)

## Creación de un nuevo OAC
<a name="create-oac-overview-lambda"></a>

Complete los pasos que se describen en los siguientes temas para configurar un nuevo OAC en CloudFront.

**importante**  
Si utiliza los métodos `PUT` o `POST` con la URL de función de Lambda, los usuarios deben calcular el SHA256 del cuerpo e incluir el valor del hash de carga útil del cuerpo de la solicitud en el encabezado `x-amz-content-sha256` al enviar la solicitud a CloudFront. Lambda no admite las cargas sin firmar.

**Topics**
+ [Requisitos previos](#oac-prerequisites-lambda)
+ [Concesión de permiso de CloudFront para acceder a la URL de función de Lambda](#oac-permission-to-access-lambda)
+ [Creación del OAC](#create-oac-lambda)

### Requisitos previos
<a name="oac-prerequisites-lambda"></a>

Antes de crear y configurar OAC, debe tener una distribución de CloudFront con una URL de función de Lambda como el origen. Para usar OAC, debe especificar `AWS_IAM` como valor para el parámetro `AuthType`. Para obtener más información, consulte [Uso de una URL de función de Lambda](DownloadDistS3AndCustomOrigins.md#concept_lambda_function_url).

### Concesión de permiso de CloudFront para acceder a la URL de función de Lambda
<a name="oac-permission-to-access-lambda"></a>

Antes de crear un OAC o configurarlo en una distribución de CloudFront, asegúrese de que CloudFront tiene permiso para acceder a la URL de función de Lambda. Realice esta acción después de crear una distribución de CloudFront, pero antes de agregar el OAC a la URL de función de Lambda en la configuración de distribución.

**nota**  
Para actualizar la política de IAM para la URL de función de Lambda, debe usar la AWS Command Line Interface (AWS CLI). En este momento, no se admite la edición de la política de IAM en la consola de Lambda.

El siguiente comando de la AWS CLI concede a la entidad principal de servicio de CloudFront (`cloudfront.amazonaws.com`) acceso a la URL de función de Lambda. El elemento `Condition` en la política permite que CloudFront acceda a Lambda *solo* cuando la solicitud sea en nombre de la distribución de CloudFront que contiene la URL de función de Lambda. Esta es la distribución con el origen de URL de función de Lambda a la que desea agregar OAC.

**Example : comando de la AWS CLI para actualizar una política con el fin de permitir el acceso de solo lectura a una distribución de CloudFront con OAC habilitado**  
Los siguientes comandos de la AWS CLI permiten que la distribución de CloudFront (`E1PDK09ESKHJWT`) acceda a su *`FUNCTION_URL_NAME`* de 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**  
Si crea una distribución y no tiene permiso para la URL de función de Lambda, puede elegir el **comando de copia de la CLI** en la consola de CloudFront y, a continuación, introducir este comando desde el terminal de la línea de comandos. Para obtener más información, consulte [Concesión de acceso a las funciones a los Servicios de AWS](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) en la *Guía para desarrolladores de AWS Lambda*. 

### Creación del OAC
<a name="create-oac-lambda"></a>

Para crear un OAC, puede utilizar la Consola de administración de AWS, CloudFormation, la AWS CLI o la API de CloudFront.

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

**Creación de un OAC**

1. Inicie sesión en la Consola de administración de AWS y abra la consola de CloudFront en [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. En el panel de navegación, elija **Origin access** (Acceso de origen).

1. Elija **Crear configuración de control**.

1. En el formulario **Crear nuevo OAC**, haga lo siguiente:

   1. Indique un **Nombre** y, opcionalmente, una **Descripción** para el OAC.

   1. En el panel **Configuración**, le recomendamos que deje la predeterminada, **Firmar solicitudes (recomendado)**. Para obtener más información, consulte [Configuración avanzada para el control de acceso de origen](#oac-advanced-settings-lambda).

1. En **Tipo de origen**, elija **Lambda**. 

1. Seleccione **Crear**.
**sugerencia**  
Después de crear el OAC, anote el **Nombre**. Lo necesita en el siguiente procedimiento.

**Cómo agregar un control de acceso de origen a la URL de una función de Lambda en una distribución**

1. Abra la consola de CloudFront en [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Elija una distribución con una URL de función de Lambda a la que desee agregar el OAC y, a continuación, elija la pestaña **Orígenes**.

1. Seleccione la URL de función de Lambda a la que desea agregar el OAC y, a continuación, elija **Editar**.

1. Seleccione **Solo HTTP** para el **Protocolo** de origen.

1. En el menú desplegable **Control de acceso de origen**, elija el nombre de OAC que desee utilizar.

1. Seleccione **Save changes (Guardar cambios)**.

La distribución comienza a implementarse en todas las ubicaciones periféricas de CloudFront. Cuando una ubicación periférica recibe la nueva configuración, firma todas las solicitudes que envía a la URL de función de Lambda.

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

Para crear un OAC con CloudFormation, utilice el tipo de recurso `AWS::CloudFront::OriginAccessControl`. En el siguiente ejemplo se muestra la sintaxis de plantilla de CloudFormation, en formato YAML, para crear un 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 obtener más información, consulte [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html) en la *Guía del usuario de AWS CloudFormation*.

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

Para crear un control de acceso de origen con la AWS Command Line Interface (AWS CLI), utilice el comando **aws cloudfront create-origin-access-control**. Puede utilizar un archivo de entrada para proporcionar los parámetros de entrada del comando, en lugar de especificar cada parámetro individual como entrada de la línea de comandos.

**Para crear un control de acceso de origen (CLI con archivo de entrada)**

1. Utilice el siguiente comando para crear un archivo llamado `origin-access-control.yaml`. Este archivo contiene todos los parámetros de entrada para el comando **create-origin-access-control**.

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

1. Abra el archivo `origin-access-control.yaml` que acaba de crear. Edite el archivo para agregar un nombre para el OAC, una descripción (opcional) y cambie `SigningBehavior` por `always`. A continuación, guarde el archivo.

   Para obtener información sobre otras configuraciones de OAC, consulte [Configuración avanzada para el control de acceso de origen](#oac-advanced-settings-lambda).

1. Utilice el siguiente comando para crear el control de acceso de origen mediante los parámetros de entrada del archivo `origin-access-control.yaml`.

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

   Anote el valor de `Id` en la salida del comando. Se necesita para agregar el OAC a una URL de función de Lambda en una distribución de CloudFront.

**Cómo adjuntar un OAC a una URL de función de Lambda en una distribución existente (CLI con archivo de entrada)**

1. Utilice el comando siguiente para guardar la configuración de distribución de la distribución de CloudFront a la que desea agregar el OAC. La distribución debe tener una URL de función de Lambda como el origen.

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

1. Abra el archivo llamado `dist-config.yaml` que acaba de crear. Edite el archivo y realice los siguientes cambios:
   + En el objeto `Origins`, agregue el ID de OAC al campo que se llama `OriginAccessControlId`.
   + Elimine el valor del campo que se llama `OriginAccessIdentity`, si existe.
   + Cambie el nombre del campo `ETag` a `IfMatch`, pero no cambie el valor del campo.

   Guarde el archivo cuando haya terminado.

1. Utilice el siguiente comando para actualizar la distribución y utilizar el control de acceso de origen.

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

La distribución comienza a implementarse en todas las ubicaciones periféricas de CloudFront. Cuando una ubicación periférica recibe la nueva configuración, firma todas las solicitudes que envía a la URL de función de Lambda.

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

Para crear un OAC con la API de CloudFront, utilice [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html). Para obtener más información sobre los campos que especifique en esta llamada a la API, consulte la documentación de referencia de la API para el SDK de AWS u otro cliente de la API.

Después de crear un OAC, puede adjuntarlo a una URL de función de Lambda en una distribución, mediante una de las siguientes llamadas a la API:
+ Para asociarlo a una distribución existente, utilice [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html).
+ Para asociarlo a una nueva distribución, utilice [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html).

Para estas dos llamadas a la API, proporcione el ID de OAC en el campo `OriginAccessControlId`, dentro de un origen. Para obtener más información sobre los otros campos que especifique en estas llamadas a la API, la documentación de referencia de la API para AWS SDK u otro cliente de la API.

------

## Configuración avanzada para el control de acceso de origen
<a name="oac-advanced-settings-lambda"></a>

La característica de OAC de CloudFront incluye configuraciones avanzadas que están pensadas solo para casos de uso específicos. Utilice la configuración recomendada a menos que tenga una necesidad específica de la configuración avanzada.

El OAC contiene una configuración denominada **Comportamiento de firma** (en la consola) o `SigningBehavior` (en la API, CLI y CloudFormation). Esta configuración proporciona las siguientes opciones:

**Firmar siempre las solicitudes de origen (configuración recomendada)**  
Recomendamos utilizar esta configuración, denominada **Firmar solicitudes (recomendado)** en la consola o `always` en la API, la CLI y CloudFormation. Con esta configuración, CloudFront siempre firma todas las solicitudes que envía a la URL de función de Lambda.

**Nunca firmar solicitudes de origen**  
Esta configuración se denomina **No firmar solicitudes** en la consola o `never` en la API, la CLI y CloudFormation. Utilice esta configuración con el fin de desactivar el OAC para todos los orígenes en todas las distribuciones que utilizan este OAC. Esto puede ahorrar tiempo y esfuerzo en comparación con la eliminación de un OAC de todos los orígenes y distribuciones que lo utilizan, uno por uno. Con esta configuración, CloudFront no ninguna solicitud que envía a la URL de función de Lambda.  
Para utilizar esta configuración, la URL de función de Lambda debe ser de acceso público. Si utiliza esta configuración con una URL de función de Lambda que no es de acceso público, CloudFront no podrá acceder al origen. La URL de función de Lambda devuelve errores a CloudFront y CloudFront pasa esos errores a los lectores. Para obtener más información, consulte [Modelo de seguridad y autenticación para URL de funciones de Lambda](https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html) en la *Guía del usuario de AWS Lambda*.

**No anular el encabezado `Authorization` del lector (cliente)**  
Esta configuración se denomina **Do not override authorization header** (No anular el encabezado authorization en la consola o `no-override` en la API, la CLI y CloudFormation. Utilice esta configuración cuando desee que CloudFront firme las solicitudes de origen solo cuando la solicitud del lector correspondiente no incluya un encabezado `Authorization`. Con esta configuración, CloudFront pasa el encabezado `Authorization` de la solicitud del lector cuando hay uno, pero firma la solicitud de origen (agrega su propio encabezado `Authorization`) cuando la solicitud del lector no incluye un encabezado `Authorization`.  
+ Si usa esta configuración, debe especificar la firma de Signature Version 4 para la URL de la función de Lambda en lugar del nombre o CNAME de la distribución de CloudFront. Cuando CloudFront reenvíe el encabezado `Authorization` de la solicitud del lector a la URL de la función de Lambda, Lambda validará la firma con respecto al host del dominio de la URL de Lambda. Si la firma no se basa en el dominio de la URL de Lambda, el host de la firma no coincidirá con el host utilizado por el origen de la URL de Lambda. Esto significa que la solicitud producirá un error, lo que provocará un error de validación de firma.
+ Para pasar el encabezado `Authorization` de la solicitud del lector, *debe* agregar el encabezado `Authorization` a una [política de caché](controlling-the-cache-key.md) para todos los comportamientos de caché que utilizan las URL de función de Lambda asociadas con este control de acceso de origen.

## Código de plantilla de ejemplo
<a name="example-template-code-lambda-oac"></a>

Si el origen de CloudFront es la URL de una función de Lambda asociada a un OAC, puede utilizar el siguiente script de Python para cargar archivos en la función de Lambda con el método `POST`. 

Este código asume que configuró el OAC con el comportamiento de firma predeterminado establecido en **Firmar siempre las solicitudes de origen** y que no seleccionó la configuración **No anular el encabezado authorization**.

Esta configuración permite al OAC administrar correctamente la autorización de SigV4 con Lambda mediante el nombre de host de Lambda. La carga útil se firma mediante SigV4 desde la identidad de IAM autorizada para la URL de la función de Lambda, que se designa como tipo `IAM_AUTH`. 

La plantilla muestra cómo administrar los valores hash de la carga útil firmados en el encabezado x-amz-content-sha256 de las solicitudes `POST` del lado del cliente. En concreto, esta plantilla está diseñada para administrar las cargas útiles de datos de los formularios. La plantilla permite cargar archivos de forma segura a una URL de la función de Lambda a través de CloudFront y utiliza mecanismos de autenticación de AWS para garantizar que solo las solicitudes autorizadas puedan acceder a la función de Lambda.

**El código incluye las siguientes funcionalidades:**  
Cumple con el requisito de incluir el hash de carga útil en el encabezado x-amz-content-sha256.
Utiliza la autenticación SigV4 para un acceso seguro de Servicio de AWS.
Admite la carga de archivos mediante el uso de datos de formularios multiparte
Incluye la gestión de errores para las excepciones de las solicitudes.

```
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)
```