DEV Community

camilo cabrales
camilo cabrales

Posted on

Agregar Autorización a Api Gateway HTTP

En este post vamos a profundizar un poco más en el uso de Api GateWay Http y vamos a ver cómo agregar un método de autorización de acceso a los métodos de nuestro Api.

Vamos a partir del ejemplo realizado en el siguiente post:
Api Gateway Http en donde creamos un Api que hace referencia a servicios externos. Este Api no tiene ningún control de acceso por lo que cualquier persona puede consumirlo sin ninguna restricción. en esta ocasión para tener acceso al Api vamos a tener que enviar una cabecera de autorización para tener acceso a sus métodos.

Pasos a realizar:

1.Creación función Lambda para rotar el secreto.
2.Creación de Secreto.
3.Crear función lamba de autorización.
4.Creación de autorizar en Api Gateway.
5.Asociar autorizador.

Vamos a comenzar creando la función Lambda que va a ser la encargada de rotar nuestro secreto.

Rotate Secret

Una vez creada nuestra función vamos a la pestaña de código y copiamos lo siguiente:

import json
import uuid
import boto3

client = boto3.client('secretsmanager')

def lambda_handler(event, context):
    # TODO implement
    secret = { "secret_header":str(uuid.uuid4())}
    id = 'reemplazar por arn del secreto'
    client.update_secret(SecretId = id,SecretString=json.dumps(secret))

Enter fullscreen mode Exit fullscreen mode

Después de tener nuestro código damos click en Deploy para que nuestros cambios queden guardados.

Deploy Rotate Secret

Hasta el momento hemos creado la función Lambda que va a ser la encargada de rotar el valor del secreto que va servir para la autorización a nuestra api. Sin embargo para que Secrets Manager pueda invocar la función debemos asignarle al Rol de la función la Política que le permita realizar esta acción.

Para este vamos a la pestaña de configuración y damos click en el nombre del Rol.

Select

Ya en la pantalla del ROl vamos a Add Permissions - Attach Policies.

Attach Policy

En la barra de búsqueda colocamos Secrests ,seleccionamos SecretsManagerReadWritey damos click en Attach policies

Attach Policy1

Finish Attach Policy1

Ya que la función Lambda tiene el rol adecuado para modificar nuestro secreto cuando la ejecutemos, el siguiente paso es agregar una politica a la función Lambda para que pueda ser llamada desde Secrets Manager. Para esto debemos ejecutar el siguiente comando en la terminal reemplazando ARN_of_lambda_function por el ARN de la función Lambda que acabamos de crear.

aws lambda add-permission --function-name ARN_of_lambda_function --principal secretsmanager.amazonaws.com --action lambda:InvokeFunction --statement-id SecretsManagerAccess

Terminada la configuración anterior, nuestra función Lambda ya puede realizar modificaciones a nuestro secreto.

El siguiente paso es definir el secreto que vamos a utilizar para autorizar el acceso a nuestro Api. Para esto buscamos en la barra de búsqueda de servicios: *Secrets Manager * y en la pantalla principal damos click en Store a new Secret

Store a new Secret

Empezamos por definir el tipo de secreto y el nombre y valor por defecto que vamos a establecer a nuestro secreto.

Key Value Secret

Definimos un nombre para el secreto: secret-header-api.

Key Value Secret

Ahora definimos cada cuando queremos que nuestro secreto cambie (1 día) y qué función Lambda (la que creamos con anterioridad) va a ser la encargada de realizar la rotación.

Rotation Secret

La siguiente pantalla nos va a mostrar el resumen de la configuración de nuestro secret, damos click en Store.

Store Secret

En la pantalla del listado de secretos damos click en el secreto que acabamos de crear.

Store Secret

En la pantalla debemos copiar el ARN del secreto para reemplazarlo en la variable id de la función Lambda que creamos. Con el objetivo que cuando ejecutemos la función Lambda modifique el valor de nuestro secreto.

Adicional podemos ver el valor del secreto dando click en Retrive secret value.

ARN Secret

En la parte inferior de la pantalla vamos a encontrar el código fuente para obtener el secreto utilizando el lenguaje de programación de nuestra preferencia, que para nuestro caso es Python.

ARN Secret

Hasta el momento hemos creado un secreto con un tiempo definido para su rotación y una función Lambda que es la encargada de cambiar el valor de nuestro secreto.

El siguiente paso es crear la función Lambda que va autorizar el acceso a nuestro Api.

El siguiente código es el que debe tener nuestra función:

import json
import boto3
import base64
from botocore.exceptions import ClientError
# Use this code snippet in your app.
# If you need more information about configurations or implementing the sample code, visit the AWS docs:   
# https://aws.amazon.com/developers/getting-started/python/


secret_name = "arn:aws:secretsmanager:us-east-1:385033107168:secret:secret-header-api4-Yt9jGg"
region_name = "us-east-1"
# Create a Secrets Manager client
session = boto3.session.Session()
client = session.client(service_name='secretsmanager',region_name=region_name)


def get_secret():
    secret =""
    # In this sample we only handle the specific exceptions for the 'GetSecretValue' API.
    # See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
    # We rethrow the exception by default.

    try:
        get_secret_value_response = client.get_secret_value(
            SecretId=secret_name
        )
    except ClientError as e:
        if e.response['Error']['Code'] == 'DecryptionFailureException':
            # Secrets Manager can't decrypt the protected secret text using the provided KMS key.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response['Error']['Code'] == 'InternalServiceErrorException':
            # An error occurred on the server side.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response['Error']['Code'] == 'InvalidParameterException':
            # You provided an invalid value for a parameter.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response['Error']['Code'] == 'InvalidRequestException':
            # You provided a parameter value that is not valid for the current state of the resource.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
        elif e.response['Error']['Code'] == 'ResourceNotFoundException':
            # We can't find the resource that you asked for.
            # Deal with the exception here, and/or rethrow at your discretion.
            raise e
    else:
        # Decrypts secret using the associated KMS key.
        # Depending on whether the secret is a string or binary, one of these fields will be populated.
        if 'SecretString' in get_secret_value_response:
            secret = get_secret_value_response['SecretString']
        else:
            secret = base64.b64decode(get_secret_value_response['SecretBinary'])

    # Your code goes here. 
    return json.loads(secret)["secret_header"]


def lambda_handler(event, context):

    secret = get_secret()
    # TODO implement
    if event["headers"]["authorization"] == secret:
        return {
            "isAuthorized": True
        }
    else:
        return {
            "isAuthorized": False
        }
Enter fullscreen mode Exit fullscreen mode

Básicamente el código es muy parecido al que nos muestra Secrets Manager para obtener nuestro secreto, solamente se le hicieron algunas modificaciones.
Debemos modificar el Rol de la función Lambda para que nos permita obtener el secreto.Debemos seguir los mismos pasos que realizamos con la función Lambda definida anteriormente.

Para finalizar debemos crear nuestro autorizador y asociarlo a los métodos que creamos convenientes.

Vamos a API Gateway y buscamos nuestro API y damos click.

List API

Ya en la pagina principal de nuestro API, vamos al menu: Authorization, buscamos la opción Manage authorizers y damos click en el botón Create.

Create Authorizer

En la configuración de nuestro Autorizar realizamos lo siguiente:

Configure Authorizer

Lo que hicimos fue definir, que nuestro autorizador va a ser la función Lambda que creamos, que el tipo de respuesta es simple (json con un valor True o False) ,que nuestra respuesta no va estar en cache y le dimos autorización a API Gateway para que pueda hacer llamados a nuestra función Lambda.

El siguiente paso es asociar nuestro autorizador a las rutas que necesitemos. Vamos al tab Attach authorizers to routes, seleccionamos la ruta a la cual queremos asociarle el autorizardor, seleccionamos el autorizar y damos click en el boton Attach authorizer.

Attach Authorizer

Ahora podemos ver al lado del tipo de método que nuestra ruta cuenta con un autorizador.

Attach Authorizer

Con esto finalizamos la configuración de agregar un método de autorización para las rutas o métodos de nuestro API.Vamos a realizar las pruebas utilizando PostMan.Agregamos el header Authorization y colocamos el valor del secreto para realizar la prueba.

Test Authorizer

Como siguiente paso pueden realizar un llamado al Api con su lenguaje de programación favorito para validar su funcionamiento.

Una función Lambda en Python seria:

import json
import requests

def lambda_handler(event, context):

    r=requests.get("https://d95ca2fimh.execute-api.us-east-1.amazonaws.com/api/timezone", headers={"Authorization":"6a7acb2b-5c79-4951-b051-503dca83225c"})
    # TODO implement
    print(r.json())
    return {
        'statusCode': 200,
        'body': r.json()
    }
Enter fullscreen mode Exit fullscreen mode

Me pueden encontrar en

Camilo Cabrales

Referencias

Permisos

Lambda Authorizer

Boto3

Discussion (0)