Ya he hablado un poco de serverless en el blog, pero este es un stack bastante grande y que siempre se pueden encontrar tips que pueden llegar a servir, como contexto cuando se despliegan lambdas, se trabaja con CI/CD sobre todo por que es uno de los objetivos, tener entregas continuas, el repositorio de código es la base y donde se construyen las estrategias de despliegue, ya sea en el momento de crear los pipelines, de establecer las reglas y los permisos de las ramas etc, en este punto generalmente el código no se pueden guardar ciertas datos, en general por que no deberia, pero la realidad es que esto puede llegar a afectar cualquier proceso de certificación (ya que se expone información sensible), en este punto hay que buscar opciones para guardar esos valores, las variables de entorno lo podemos  solucionar de manera sencilla usando parameter store, pero si en el repositorio debemos guardar archivos que no pueden quedar expuestos como lo hacemos?

Hooks en serverless

Cuando se trabaja con serverless cli, este SDK brinda acceso a algunos comandos, estos comandos son esenciales para usar en los ambientes de CI/CD, en donde se pueden conectar fácilmente con la herramienta de despliegues que tiene serverless (la cual hablaremos en otro post) esencialmente la importancia de estos comandos es su ciclo de vida, ya que internamente cuando se digita un comando, este pasa por ciertas etapas siguiendo un orden establecido como se puede apreciar en la Figura 1, los hooks consisten precisamente en estas etapas dentro de cada comando y nuestro trabajo es ubicarnos en cierto momento de la ejecución para activar nuestro custom script

Figura 1: Estructura del ciclo de vida de los comandos de serverless

Inyectando archivos desde S3

Con la definición del concepto de hook lo podemos entender como un script propio que vamos a ejecutar ubicándonos en algún momento del ciclo de vida de la ejecución de los comandos de serverless, para la problemática que mencionamos de contexto, queremos inyectar algunos archivos, simulare algún archivo .pem que descargamos de un bucket , para ello necesitamos tener configuradas las credenciales por defecto de AWS (es el caso común de los ambientes de CI/CD) , ahora debemos ubicar el script en qué momento lo debemos ejecutar, como se aprecia en la Figura 2 nos debemos ubicar dentro del  hook before package:initialize , para que modificar nuestro proyecto antes que se cree el .zip a subir

Figura 2: Agregar hook personalizado al ciclo de vida de serverless

Código

Después de entender un poco el concepto de los hooks en serverless, vamos a pasar al código, lo primero es escribir el script en python que descargara los files del bucket de s3 y los guardara en la carpeta que necesitamos el código se vería así

import boto3
from io import BytesIO


class AWSS3:
    def __init__(self) -> None:
        self.s3_client = boto3.client("s3")

    def get_file_s3(self, bucket_name:str, key_file:str) -> BytesIO:
        faker_memory = BytesIO()
        self.s3_client.download_fileobj(
            bucket_name, key_file, faker_memory
        )
        faker_memory.seek(0)
        return faker_memory


def save_file_secret():
    bucket_name = "ejemplo-test"
    key_file = "secret.pem"
    aws_s3 = AWSS3()
    file_secret = aws_s3.get_file_s3(bucket_name, key_file)
    with open("scripts/secret.pem", "wb") as myfile:
        myfile.write(file_secret.read())


print("Started!")
save_file_secret()
print("Finished!")

después de tener el script, debemos ubicarlo en el hook, utilizando serverless, para ello debemos instalar serverless scripts

npm install --save serverless-plugin-scripts

y realizamos la configuración en nuestro archivo serverless.yml de la siguiente forma


service: myproject-hooks

custom:
  scripts:
    hooks:
      'before:package:initialize': poetry run python scripts/download_secret_file.py
provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221


functions:
  hello:
    handler: handler.hello


plugins:
  - serverless-plugin-script

para probarlo ejecutamos el comando de despliegue y se vería de la siguiente forma

Figura 3: Despliegue de serverless usando hooks

se puede validar que en el empaquetado efectivamente se encuentre el archivo .pem y validarlo también en tu folder como se ve puede apreciar en la siguiente Figura  es muy importante aclarar  que esto se enfoca en máquinas que hacen el despliegue y se destruyen, por eso en cada despliegue lo que sucede es que se inyectan estos archivos, en mi caso como es prueba local ya quedaría el archivo para hacer pruebas

Figura 4: Inyección del archivo secret.pem al proyecto

Como se puede observar el código se conecta a AWS por medio del SDK por lo tanto existen algunas dependencias que se deben instalar antes, para ello podemos mejorar un poco la ejecución agregando el siguiente script de bash

#!/bin/bash
if type -P x >/dev/null 2>&1
then
poetry install
poetry run python scripts/download_secret_file.py
else
  echo "Error poetry is not installed"
  exit  1
fi

y cambiamos el serverless.yml un poco


service: myproject-hooks

custom:
  scripts:
    hooks:
      'before:package:initialize': ./script.sh
provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221


functions:
  hello:
    handler: handler.hello


plugins:
  - serverless-plugin-scripts

ejecutamos y podemos ver el resultado cuando esta poetry instalado y cuando no

Figura 5: Despliegue exitoso con mejora del script
Figura 6: Despliegue fallido con mejora del script

con el cambio lo que garantizamos es que tenemos poetry instalado, pero también instalar las dependencias que necesitamos, por que la máquina en donde se ejecutara el CI/CD debe incluirlas para poder acceder a los servicios, en este caso de AWS con el SDK, pero si necesitase otra librería adicional podría instalarla sin problema, si en el proceso definido de CI/CD ya se cubre la instalación de dependencias, se podría obviar este paso, pero siempre sería mejor mantenerlo unido al proyecto para que cuando se ejecute en una máquina nueva se pueda entender cuál fue el error

Conclusiones

Cuando se trabaja en proyectos en donde existen certificaciones de por medio, a veces hay algunas restricciones con información que puede contener datos sensibles por ende así el repositorio se ha privado y solamente tenga acceso el personal de la empresa, estos archivos no pueden permanecer allí, y estar compartiendolos con cada dev cada vez que desea probar es algo un poco tedioso, una opción es utilizar la nube de su preferencia para conectarse a ella y obtener estos archivos, esto funciona muy bien con los despliegues automáticos en donde estas instancias se crean y se destruyen durante el proceso, aquí estos hooks de serverless aportan un gran valor pues el proceso de agregar los archivos sensibles se transforma en algo mas fácil de gestionar

Te gusto el post y quisieras poder aplicar lo aprendido?

Únete al equipo de Simetrik AQUI