datacubeR

Nunca publiques código que contenga credenciales secretas.

Manejar Secretos

3 soluciones para evitar meter la pata.

picture of me picture of me El tío Ben decía que un gran poder conlleva grandes responsabilidades. Y eso es súper cierto cuando trabajamos con datos. Normalmente en cualquier área de datos vamos a encontrarnos con datos sensibles o información personal de clientes. Es responsabilidad del equipo de datos asegurarse que la información sea utilizada con fines correctos y que no caiga en personas que no tienen la necesidad de hacer uso de esos datos. Si tenemos claro que no podemos revelar ni dar acceso a datos sensibles, por qué en nuestros códigos (incluso en los míos) abunda lo siguiente:

from sqlalchemy import create_engine
user = 'mi_usuario_secreto'
password = 'mi_clave_supersecreta'
host = 'micluster_condatossecretos.rds.amazonaws.com'
puerto = 5432
db = 'mydb_produccion'
engine = create_engine(f'postgres://{user}:{password}@{host}:{puerto}/{db}')

Básicamente estamos regalando el acceso para que cualquier persona, con buenas o malas intenciones, pueda acceder a nuestros sistemas y hacer un uso indebido de nuestros datos. Aquí les dejo tres soluciones para resolver estos problemas:

input y getpass

Python tiene la función input() el cual permite ingresar datos de manera interactiva. Si bien no encripta la información puede ser una manera en la que las credenciales no van a quedar escritas en el código. Además la librería getpass, permite que el input sea oculto, para los passwords. Si reescribimos el código nos va a quedar así:

from sqlalchemy import create_engine
import getpass

user = input('Ingrese el usuario: ')
password = getpass.getpass('Ingrese su clave')
host = input('Ingrese el host a conectar: ')
port = input('Ingrese el puerto de conexión: ')
db = input('Ingrese la Base de Datos a utilizar: ')
engine = create_engine(f'postgres://{user}:{password}@{host}:{port}/{db}')

Una ejecución del programa se ve así:

picture of me

Pros:

  • Súper rápido de inplementar.
  • No requiere de librerías externas.

Contras:

  • No encripta los datos.
  • Es interactiva, requiere de alguien que ingrese los datos de manera manual.

Variables de Ambiente

Otra opción muy sencilla es el uso de variables de ambiente. En sistemas Unix esto es muy sencillo (en Windows, no tengo idea cómo se hace, lo siento). Por lo que basta con ir a nuestro archivo .bashrc o .zshrc dependiendo del shell que utilicemos y podemos agregar lo siguiente:

export USER='mi_usuario_secreto'
export PASSWORD='mi_clave_supersecreta'
export HOST='micluster_condatossecretos.rds.amazonaws.com'
export PORT=5432
export DB='mydb_produccion'

No sé si es convención o es obligación pero normalmente veo que las variables de ambiente se escriben en mayúsculas, probablemente también para evitar algún choque de nombre.

Luego se puede acceder a dichas variables de la siguiente manera:

from sqlalchemy import create_engine
import os

user = os.getenv('USER')
password = os.getenv('PASSWORD')
host = os.getenv('HOST')
port = os.getenv('PORT')
db = os.getenv('DB')
engine = create_engine(f'postgres://{user}:{password}@{host}:{port}/{db}')

Pros:

  • Sólo se puede acceder a estas variables teniendo acceso a la maquina local.
  • Se pueden automatizar procesos ya que no requiere intervención de alguien para ingresarlas.

Contras:

  • Sólo se puede acceder a estas variables teniendo acceso a la maquina local. Por lo que cada usuario debe ingresar estas variables en su maquina.
  • Hay que ser bien creativos para llamar muchas variables.
  • En caso de dejar de trabajar en algún lugar es dificil asegurarse que los secretos fueron eliminados.

AWS Secrets Manager

Primero que todo para esta solución tienes que tener una cuenta de AWS (al menos la gratuita). Luego debes ir a los servicios de AWS Secrets Manager:

picture of me

Acá debes clickear en Store a New Secret y llegarás a una pantalla como esta:

picture of me

Para poder tener acceso a los servicios debes instalar en tu maquina el AWS CLI, el cual es bastante sencillo, y debes hacer un pequeño setup agregando:

  • aws_access_key_id
  • aws_secret_access_key
  • aws_session_token

Dentro de tu misma cuenta de AWS están todas las instrucciones para llevar esto a cabo. En cuanto a nuestro código, debemos agregar lo siguiente:

import boto3
import pandas as pd
import json
secret_name = 'secrets_aws'
region = 'us-east-1'
session = boto3.session.Session()
client = session.client(service_name = 'secretsmanager',
                       region_name = region)
credentials = json.loads(client.get_secret_value(SecretId=secret_name)['SecretString'])
user = credentials['user']
password = credentials['password']
host = credentials['host']
port = credentials['puerto']
db = credentials['db']
engine = create_engine(f'postgres://{user}:{password}@{host}:{port}/{db}')

Pros:

  • Mucho más seguro, ya que está todo almacenado en AWS.
  • Es un servicio centralizado por lo que cualquier miembro del equipo en tu red puede acceder.
  • Permite la automatización de procesos ya que no requiere el ingreso de las claves manualmente.

Contras:

  • Es largo de setear la primera vez.
  • El código es más verboso
  • Se paga poco, pero se paga. Aunque con la capa gratis hay al menos un año de uso.

Espero que estos tips cortitos puedan ser útiles para evitar que expongamos datos cuando no es necesario.

Nos vemos,

Alfonso

Go to top