subversion - tortoise svn server
¿Deben almacenarse los archivos de configuración del servidor/base de datos, incluidas las contraseñas, en el control de código fuente? (13)
Creo que esta pregunta es más sobre propiedad de la información, confianza y organización. Debería preguntarse: ¿en qué parte de su organización confiaría para mantener las contraseñas de su sistema a salvo de la divulgación y el uso indebido?
He estado en organizaciones donde fueron custodiados por las personas responsables del negocio. En otros, han sido delegados en el equipo de operaciones que también poseía los procesos en torno a la creación y el uso, etc.
Lo más importante es que esté claramente definido en su organización quién debería tener acceso a las contraseñas del sistema. Después de eso, puede decidir sobre soluciones técnicas apropiadas para proteger las contraseñas.
Estoy buscando escuchar algunas mejores prácticas ...
Suponiendo una aplicación web que interactúa con unos pocos servidores de producción diferentes (bases de datos, etc.) ... ¿deberían almacenarse los archivos de configuración que incluyen las contraseñas de la base de datos en el control de código fuente (p. Ej., Git, svn)?
De lo contrario, ¿cuál es la mejor manera de realizar un seguimiento de la base de datos del servidor (u otras contraseñas relacionadas) a las que necesita acceder su aplicación?
Editar: se agregó una recompensa para alentar una mayor discusión y escuchar lo que más personas consideran la mejor práctica.
Dejando de lado el punto de que las contraseñas nunca deben almacenarse en texto plano en cualquier lugar (que no sea el cráneo de alguien o una bóveda bloqueada accesible solo para el CEO, CFO y CIO (y necesita las tres claves a la vez)), debe almacenar todo en control de origen eso es necesario para construir su producto.
Eso significa no solo su fuente, sino incluso las especificaciones para las máquinas de compilación, las opciones del compilador, los propios compiladores, etc.
Si pudiéramos encontrar una manera de verificar el hardware físico, lo haríamos también :-)
Todo lo que puede ser reproducido por el proceso de compilación, o cualquier cosa para ejecutar en lugar de construir el software (como sus contraseñas) generalmente no pertenece al control de código fuente, pero algunas tiendas lo harán por sus ejecutables, documentos generados y demás, solo para que puedan obtener rápidamente un lanzamiento específico para la instalación.
Descubrí que usar una secuencia de comandos de compilación (Phing en mi caso) era la mejor forma de ingresar contraseñas.
Ejemplo de archivo de configuraciones, seguro, las pondría bajo control de versiones. Pero generalmente no con datos de acceso en el mundo real como direcciones de servidor o contraseñas. Más como algo
# program.conf # # mysql option for $myprog. # #SERVER_ADDR=127.0.0.1 #SERVER_USER=mysql #SERVER_PASSWD=abcdef
En general, estoy de acuerdo con paxdiablo: pon todo lo que puedas bajo el control de la fuente. Eso incluye archivos de configuración de producción con credenciales de base de datos.
Piense en la situación en la que su servidor falla, las copias de seguridad resultan ser malas y necesita volver a hacer ese servidor. Creo que usted y su cliente (o jefe) definitivamente estarían de acuerdo en que tener todo lo necesario para implementar el sitio en el control de la fuente es una gran ventaja.
Si desea crear paquetes fácilmente implementables a partir de sus fuentes mediante la integración continua (otra práctica recomendada), deberá colocar los archivos de configuración bajo el control de la fuente.
Tenga en cuenta también que, en la mayoría de los casos, los desarrolladores que tienen acceso de control de origen no pueden acceder directamente al servidor de la base de datos de producción. Las contraseñas de producción son inútiles para ellos.
Si las personas equivocadas obtuvieron acceso a sus fuentes, aún necesitan obtener acceso al servidor de producción para dañar las contraseñas. Por lo tanto, si su entorno de producción está protegido adecuadamente, los riesgos de seguridad de las contraseñas en el control de la fuente son muy limitados.
En mis repositorios de Subversion para PHP, los archivos de configuración que contienen contraseñas se registran como config.php.sample
con sugerencias sobre lo que debe proporcionarse y los scripts que dependen requieren que config.php
esté presente en la misma ubicación.
El repositorio está configurado para ignorar config.php
para ese directorio para evitar agregaciones o registros "accidentales".
Las contraseñas no deben almacenarse en el control de fuente. En absoluto. Nunca. Vea Cómo mantener secretos en secreto
Las contraseñas, nombres de servidor, etc. son parte de la configuración de implementación realizada por el administrador del servidor. Es esencial documentar este procedimiento y colocar el procedimiento documentado bajo control.
Alternativamente, la configuración de implementación podría ser realizada por un script que el administrador del sistema ejecutaría para realizar la configuración, y durante la ejecución del script le pediría a sysadmin que proporcionara la información requerida. De nuevo, este script debe mantenerse en control de versión.
Todo lo demás, aparte de la configuración del servidor, debe estar en control de fuente.
Almacenar la configuración del servidor en el control de fuente generalmente es una mala idea porque obstaculiza las implementaciones y puede causar pequeños desastres (por ejemplo, cuando alguien no se da cuenta de que su versión de prueba implementada desde el control de origen se está comunicando con un servicio en vivo).
Mantenga siempre estos archivos de configuración fuera de la raíz web.
Las conexiones confiables pueden ser una opción, permitiendo que las direcciones IP conocidas se conecten a los servicios mediante la configuración de ese servicio.
- Cuando se ejecuta en Windows usa autenticación integrada. Consulte Cómo asegurar el acceso a los datos
- MySQL configura para permitir conexiones de localhost y para no requerir una contraseña. Vea el Paso 7: Proteger un servidor MySQL en Windows
- PostgreSQL puede usar ~/.pgpass .
No hay una sola respuesta de "bala de plata" aquí y todo dependería en gran medida de los detalles.
Antes que nada, considero la mejor práctica separar todo el código fuente de la configuración en un repositorio separado. Entonces, el código fuente sigue siendo el código fuente, pero su instalación o despliegue (con configuración, contraseñas, etc.) es todo lo demás. De esta forma, separará con firmeza las tareas de los desarrolladores de las tareas de los administradores de sistemas y, en última instancia, podrá crear 2 equipos distintos que harán lo que les conviene.
Cuando tiene repositorio de distribución de repositorio de código fuente separado, su mejor apuesta siguiente es considerar las opciones de implementación. La mejor forma que veo aquí es mediante el uso de procedimientos de implementación típicos para un sistema operativo elegido (es decir, crear paquetes autónomos para un sistema operativo elegido de la misma manera que los mantenedores del sistema operativo).
Por ejemplo, los procedimientos de empaquetado de Red Hat o Debian normalmente implican tomar un tarball de software del sitio externo (que estaría exportando fuentes desde su código fuente VCS), desempaquetarlo, compilar y preparar paquetes listos para la implementación. La implementación en sí misma debería significar simplemente hacer un comando rápido y simple que instalaría los paquetes, como rpm -U package.rpm
, dpkg --install package.deb
o apt-get dist-upgrade
(dado que los paquetes construidos van a un repositorio donde apt-get podría encontrarlos).
Obviamente, para que funcione de esta manera, deberá proporcionar todos los archivos de configuración de todos los componentes de un sistema en pleno funcionamiento, incluidas todas las direcciones y credenciales.
Para ser más concisos, consideremos una situación típica de "servicio pequeño": una aplicación PHP implementada en n servidores de aplicaciones que ejecutan apache / mod_php, accediendo a m servidores MySQL. Todos estos servidores (o contenedores virtuales, que realmente no importan) residen en una red privada protegida. Para simplificar este ejemplo, supongamos que toda la conectividad real de Internet está liderada por un grupo de k http aceleradores / proxies inversos (como nginx / lighttpd / apache) que tienen una configuración muy sencilla (solo direcciones IP internas para reenviar).
¿Qué tenemos para que estén conectados y funcionando completamente?
- Servidores MySQL: configure direcciones IP / nombres de host, configure bases de datos, proporcione inicios de sesión y contraseñas
- Aplicación PHP: configure direcciones IP / nombres de host, cree un archivo de configuración que mencione IP de servidores MySQL, inicios de sesión, contraseñas y bases de datos
Tenga en cuenta que aquí hay 2 "tipos" de información diferentes: IP / nombres de host es algo fijo, es probable que desee asignarlos de una vez por todas. Los inicios de sesión y las contraseñas (e incluso los nombres de las bases de datos), por otro lado, son puramente con fines de conectividad aquí, para asegurarnos de que MySQL realmente se conecte a nuestra aplicación PHP. Entonces, mis recomendaciones aquí serían dividir estos 2 "tipos":
- La información "permanente", como IP, debe almacenarse en algunos VCS (diferente del código fuente VCS)
- La información "transitoria", como las contraseñas entre 2 aplicaciones, nunca debe almacenarse, sino generarse durante la generación de paquetes de implementación.
La última y más difícil pregunta queda aquí: ¿cómo crear paquetes de implementación? Hay varias técnicas disponibles, 2 formas principales son:
- Código fuente exportado de VCS1 + configuración "permanente" de VCS2 + script de creación de VCS3 = paquetes
- El código fuente está en VCS1; VCS2 es un control de versión distribuida (como git o hg) que esencialmente contiene "horquillas" de información de configuración VCS1 + + scripts de construcción que pueden generar. Personalmente, me gusta este enfoque, es mucho más corto y, en última instancia, más fácil de usar, pero la curva de aprendizaje puede ser un poco más pronunciada, especialmente para los chicos de administración que tendrán que dominar git o hg por ello.
Para un ejemplo anterior, crearía paquetes como:
-
my-application-php
- que dependería de mod_php, apache e incluiría un archivo generado como/etc/my-php-application/config.inc.php
que incluirá las bases de datos de MySQL IP / hostnames y login / password generados comomd5(current source code revision + salt)
. Este paquete se instalaría en cada uno de los n servidores de aplicaciones. Idealmente, debería ser capaz de instalarse en un sistema operativo limpio instalado y crear un nodo de clúster de aplicación totalmente funcional sin ninguna actividad manual. -
my-application-mysql
- que dependería del servidor MySQL e incluiría un script posterior a la instalación que:- inicia el servidor MySQL y se asegura de que se inicie automáticamente en el inicio del SO
- se conecta al servidor MySQL
- comprueba si la base de datos requerida existe
- si no, crea la base de datos, la inicia con los contenidos y crea un inicio de sesión con contraseña (los mismos inicios de sesión y contraseñas que se generaron en
/etc/my-php-application/config.inc.php
, utilizando el algoritmo md5) - En caso afirmativo, se conecta a la base de datos, aplica migraciones para llevarla a la nueva versión, elimina todas las contraseñas / inicios de sesión anteriores y recrea el nuevo par de inicio de sesión / contraseña (nuevamente, generado mediante el método md5 (revisión + sal))
En última instancia, debería brindar el beneficio de actualizar su implementación mediante un solo comando como generate-packages && ssh-all apt-get dist-upgrade
. Además, no almacena contraseñas entre aplicaciones en ninguna parte y se regeneran en cada actualización.
Este ejemplo bastante simple ilustra una gran cantidad de métodos que puede emplear aquí, pero, en última instancia, depende de usted decidir qué solución es mejor aquí y cuál es excesiva. Si va a poner más detalles aquí o como una pregunta separada, gustosamente trataré de entrar en detalles.
No. La contraseña de producción debe configurarse directamente en el servidor. Debe crear instrucciones de implementación para el equipo / persona de implementación para cambiar el archivo de propiedades correcto durante la implementación.
Prefiero tener un archivo local_settings junto al archivo de configuración principal. Esta local_settings no se debe agregar al repositorio, pero agregaré un sample.local_setting al repositorio para mostrar la estructura de este archivo.
En tiempo de ejecución si existe un local_settings, sus valores anularán los valores del archivo de configuración principal.
Por ejemplo en python:
settings.py:
log=''error.log''
db=lambda:None
db.host=''localhost''
db.user=''''
db.password=''''
try:
import local_settings
except ImportError:
pass
local_settings.py:
from settings import *
db.user=''abcd''
db.password=''1234''
Problemas con las contraseñas en el código fuente:
- difícil de variar de una implementación a otra (no quiero tener que modificar el código fuente en producción)
- probabilidad aumentada de corromper accidentalmente la base de datos de producción al hacer el desarrollo
- problema de seguridad (en la mayoría de las tiendas no hay ninguna razón para que el código / los desarrolladores conozcan las contraseñas de los productos)
- la contraseña cambiada requiere redespliegue
Lo que he encontrado funciona lo mejor es tener una configuración activada que utiliza los valores predeterminados de la combinación de las cuerdas y los marcadores de posición para los datos específicos de la implementación. Nuestras aplicaciones siempre buscan una configuración de sistema que permita anular cualquier variable. Esto permite que la máquina de producción tenga una configuración adecuada para su implementación.
Nota: Cuando funciono como administrador, siempre administro las configuraciones por separado del código (por una buena razón).
Siempre excluiría los archivos de configuración vitales que contienen contraseñas u otros detalles de acceso (como para las bases de datos), es puramente la mejor práctica. Además de eso, el control de fuente y versión sirve generalmente a más de un usuario y no todos trabajan con los mismos detalles de base de datos o incluso con la misma configuración de servidor (dominios, etc.) y para ello los archivos de configuración deben permanecer excluidos del mucho.
Sin un proceso de compilación adecuado, estoy usando esta estrategia (para aplicaciones PHP):
- Crear una carpeta
/etc/companyname
En él, coloca dos archivos:
<?php // env.php return ''prod'';
<?php // appname-prod.php return array( ''db'' => array( /* credentials */ ), /* other host-specific conf data */ );
Haga que ambos archivos sean legibles solo por su proceso PHP
Ahora el archivo de configuración de su aplicación será algo así como:
<?php // config.php
$env = (require "/etc/companyname/env.php");
$creds = (require "/etc/companyname/appname-{$env}.php");
Con esto en su lugar, el entorno define las credenciales utilizadas, y puede mover el código entre entornos preconfigurados (y controlar algunas opciones con $env
). Esto, por supuesto, se puede hacer con las variables de entorno del servidor, pero esto a) es más fácil de configurar y b) no expone las credenciales a cada script en el servidor (no se mostrará en una basura de phpinfo()
errores como phpinfo()
)
Para facilitar la lectura fuera de PHP, puede crear los archivos de credenciales JSON o algo así y simplemente aguantar el pequeño golpe de rendimiento (APC no los almacenará en caché).