Hay algunas opciones para almacenar contraseñas y otros secretos que un programa Python necesita usar, particularmente un programa que necesita ejecutarse en segundo plano donde no puede simplemente pedirle al usuario que escriba la contraseña.
Problemas a evitar:
- Verificando la contraseña en el control de fuente donde otros desarrolladores o incluso el público pueden verla.
- Otros usuarios en el mismo servidor leyendo la contraseña de un archivo de configuración o código fuente.
- Tener la contraseña en un archivo de origen donde otros puedan verla por encima del hombro mientras la edita.
Opción 1: SSH
Esta no siempre es una opción, pero probablemente sea la mejor. Su clave privada nunca se transmite a través de la red, SSH solo ejecuta cálculos matemáticos para demostrar que tiene la clave correcta.
Para que funcione, necesita lo siguiente:
- La base de datos o lo que sea que esté accediendo debe ser accesible por SSH. Intente buscar "SSH" más cualquier servicio al que esté accediendo. Por ejemplo, "ssh postgresql" . Si esta no es una característica de su base de datos, pase a la siguiente opción.
- Cree una cuenta para ejecutar el servicio que hará llamadas a la base de datos y generará una clave SSH .
- Agregue la clave pública al servicio al que va a llamar o cree una cuenta local en ese servidor e instale la clave pública allí.
Opción 2: Variables de entorno
Este es el más simple, por lo que podría ser un buen lugar para comenzar. Se describe bien en la aplicación Twelve Factor . La idea básica es que su código fuente simplemente extrae la contraseña u otros secretos de las variables de entorno, y luego configura esas variables de entorno en cada sistema donde ejecuta el programa. También podría ser un buen toque si usa valores predeterminados que funcionarán para la mayoría de los desarrolladores. Debe equilibrar eso con hacer que su software sea "seguro por defecto".
A continuación, se muestra un ejemplo que extrae el servidor, el nombre de usuario y la contraseña de las variables de entorno.
import os
server = os.getenv('MY_APP_DB_SERVER', 'localhost')
user = os.getenv('MY_APP_DB_USER', 'myapp')
password = os.getenv('MY_APP_DB_PASSWORD', '')
db_connect(server, user, password)
Busque cómo establecer variables de entorno en su sistema operativo y considere ejecutar el servicio con su propia cuenta. De esa manera, no tendrá datos confidenciales en las variables de entorno cuando ejecute programas en su propia cuenta. Cuando configure esas variables de entorno, tenga especial cuidado de que otros usuarios no puedan leerlas. Compruebe los permisos de los archivos, por ejemplo. Por supuesto, cualquier usuario con permiso de root podrá leerlos, pero eso no se puede evitar. Si está usando systemd, mire la unidad de servicio y tenga cuidado de usar en EnvironmentFile
lugar de Environment
para cualquier secreto. Environment
Los valores pueden ser vistos por cualquier usuario con systemctl show
.
Opción 3: archivos de configuración
Esto es muy similar a las variables de entorno, pero lee los secretos de un archivo de texto. Todavía encuentro las variables de entorno más flexibles para cosas como herramientas de implementación y servidores de integración continua. Si decide utilizar un archivo de configuración, Python admite varios formatos en la biblioteca estándar, como JSON , INI , netrc y XML . También puede encontrar paquetes externos como PyYAML y TOML . Personalmente, encuentro que JSON y YAML son los más simples de usar, y YAML permite comentarios.
Tres cosas a considerar con los archivos de configuración:
- ¿Dónde está el archivo? Tal vez una ubicación predeterminada como
~/.my_app
, y una opción de línea de comandos para usar una ubicación diferente.
- Asegúrese de que otros usuarios no puedan leer el archivo.
- Obviamente, no confíe el archivo de configuración al código fuente. Es posible que desee enviar una plantilla que los usuarios puedan copiar en su directorio de inicio.
Opción 4: Módulo Python
Algunos proyectos simplemente ponen sus secretos directamente en un módulo de Python.
db_server = 'dbhost1'
db_user = 'my_app'
db_password = 'correcthorsebatterystaple'
Luego importe ese módulo para obtener los valores.
from settings import db_server, db_user, db_password
db_connect(db_server, db_user, db_password)
Un proyecto que utiliza esta técnica es Django . Obviamente, no debe comprometerse settings.py
con el control de código fuente, aunque es posible que desee enviar un archivo llamado settings_template.py
que los usuarios pueden copiar y modificar.
Veo algunos problemas con esta técnica:
- Los desarrolladores pueden enviar accidentalmente el archivo al control de código fuente. Agregarlo
.gitignore
reduce ese riesgo.
- Parte de su código no está bajo control de fuente. Si eres disciplinado y solo pones cadenas y números aquí, eso no será un problema. Si comienza a escribir clases de filtro de registro aquí, ¡deténgase!
Si su proyecto ya utiliza esta técnica, es fácil realizar la transición a las variables de entorno. Simplemente mueva todos los valores de configuración a las variables de entorno y cambie el módulo de Python para leer esas variables de entorno.