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