¿Cuál es la forma preferida de almacenar configuraciones de aplicaciones?

38

La mayoría de las veces, almaceno la configuración de la aplicación de desarrollo en el directorio raíz del proyecto, así:

app
|-- config.json

Pero ese no parece ser el mejor enfoque, ya que esta configuración termina siendo almacenada en el sistema de control de versiones, posiblemente resultando en filtraciones de nombres de usuario, contraseñas y otras cosas confidenciales.

La guía de aplicaciones de 12 Factor recomienda soltar los archivos de configuración por completo y usar variables de entorno para la configuración de la configuración:

... almacena la configuración en variables de entorno. Las variables de entorno son fáciles de cambiar entre implementaciones sin cambiar ningún código; a diferencia de los archivos de configuración, hay pocas posibilidades de que se registren accidentalmente en el repositorio de código; y, a diferencia de los archivos de configuración personalizados u otros mecanismos de configuración, como las Propiedades del sistema Java, son un estándar independiente del lenguaje y del sistema operativo.

Eso me suena muy bien, pero ¿dónde se almacenan dichas variables de entorno, sin registrarlas en el control de origen? ¿Y qué herramientas puedo usar para pasar esas variables a la aplicación? Puede haber docenas de opciones de configuración, y escribirlas a mano cada vez que inicia la aplicación no es agradable, por lo que deben almacenarse en algún tipo de archivo en algún lugar. Dicho archivo terminará así en el control de origen, y volveremos a donde comenzamos.

¿Existe alguna forma universalmente aceptada de manejar las opciones de configuración, que no tenga el riesgo de almacenar la configuración local en el control de origen?

Rogach
fuente
1
Bueno, git al menos tiene algo así como .gitignoredonde puedo definir archivos o carpetas que no deberían ser controlados en el control de versiones. Como usted dice, no veo dónde realmente debería ayudar Env vars, ya que tiene un script para configurarlos y debe almacenarse junto con el proyecto o los tiene 'en algún lugar' en su sistema (directorio de inicio o incluso en el inicio de las máquinas scripts) que parece crear muchos problemas por sí solo, especialmente si se necesita mucha configuración. En cualquier caso, dividiría los archivos de configuración para que la información confidencial vaya en diferentes archivos.
thorsten müller
@ thorstenmüller: el único problema con .gitignore es que la configuración de base / plantilla aún debe almacenarse, lo que significa que la aplicación debe leer dos configuraciones: una base, con opciones predeterminadas (almacenadas en scm) y una local, que anula la base (y no se almacena en scm). Con los entornos, imagino que la implementación masiva se hace más fácil: es más sencillo especificar variables de entorno para la nueva configuración de la máquina virtual que escribir algo en algún archivo no estándar.
Rogach
Buena pregunta, después de que comencé a usar el almacén de datos de la aplicación normal específica del usuario para esto, la vida se volvió más fácil ;-)
Wolf
1
¿Has probado "Redis" redis.io . Está destinado especialmente para el almacenamiento de la estructura de valor-clave solamente.
Karan
2
@jporcenaluk: me gustan los almacenamientos de valores clave, pero agregar un redis completo a la aplicación solo para manejar la administración de la configuración se siente como un poco exagerado. Por otro lado, tal vez nunca trabajé en proyectos lo suficientemente grandes.
Rogach

Respuestas:

16

Posiblemente no haya una buena respuesta para esto. Parece que necesita almacenar estos datos en un lugar seguro, ya que algún día serán necesarios para fines de recuperación ante desastres. Esto se aplica igualmente a los archivos de propiedades y scripts que establecen variables de entorno.

  • Con el código fuente (en SVN / GIT, etc.) es una muy mala idea, ya que estos datos contendrán contraseñas de bases de datos de producción y similares.
  • Su respaldo corporativo nocturno puede ser suficiente, pero es poco probable que mantenga un historial de cambios fácilmente accesible.
  • Los datos deben ser versionados por separado para el software consumidor. En nuestro sistema actual, un cambio de configuración conduce a una nueva compilación de aplicaciones, y esto es simplemente incorrecto.

Actualmente estamos buscando soluciones a este problema y nos estamos inclinando hacia un repositorio de código con acceso restringido. Este repositorio contendría solo datos de configuración. ¿Otros tienen experiencias para compartir?

kiwiron
fuente
2
Parece que no es una buena idea tener dos repositorios separados para un proyecto: no puede hacer retrocesos limpios ni trabajar con sucursales, porque entonces deberá manipular dos repositorios simultáneamente (por ejemplo, otra sucursal requiere alguna nueva opción de configuración, y cuando cambiar a esa nueva rama sin cambiar también en el repositorio de configuración, las cosas se rompen de formas extrañas).
Rogach
2
@Rogach, entiendo tu punto. Hay razones válidas para mantener alguna configuración con el código, pero como usted dice en su pregunta, las cosas sensibles deben ir a otro lado. Entonces, dos repositorios parecen inevitables. Además, no mencioné que los servidores de aplicaciones a menudo ayudan aquí. El administrador puede configurar las fuentes de datos y las variables JNDI y no serán públicas.
kiwiron
Una segunda tienda tiene sentido. Puede haber otros tipos de datos, también confidenciales, que pueden almacenarse junto con la configuración (por ejemplo, datos de producción que se están analizando para solucionar los problemas de los clientes).
Wolf
1
@Rogach Parece que atraen mucho odio, pero los submódulos git manejarían esto muy bien, creo que si el principal estuviera configurado correctamente, y el repositorio de acceso restringido podría vivir dentro de él.
SeldomNeedy
9

Al examinar los problemas y las posibles soluciones, me ayuda a usar un método popularizado por Jeff Atwood : si Dios creara una forma de almacenar información de configuración confidencial, ¿cómo lo haría?

Bueno, él sabría quién necesita información de configuración y solo se la daría a esas personas, y nadie más podría acceder a la información.

La primera parte ya debe ser atendida: su sistema de control de fuente debe estar autenticando a los usuarios. Y este enfoque también tiene validez de acuerdo con el # 10 en los 10 Mandamientos de control de origen de Troy Hunt , "las dependencias deben estar en el control de origen".

Pero, ¿cómo mantenerlo seguro si se filtra? Bueno, ¡no necesita ser almacenado allí en texto plano! Utiliza encriptación. En .NET, hay pasos que puede seguir para cifrar los datos de la cadena de conexión en sus archivos de configuración . Tendría que encontrar los métodos equivalentes para hacerlo con su tecnología particular de elección.

jporcenaluk
fuente
3
Solo quería aclarar: ¿cómo ayudará la configuración de cifrado? Según tengo entendido, se le pedirá que comparta la misma contraseña de descifrado entre todos los desarrolladores, y eso suena como pedir problemas.
Rogach
Si alguien fuera de su empresa obtiene acceso a su repositorio, sus contraseñas se ofuscan. Si alguien copia los archivos de un proyecto en una unidad USB y lo deja en algún lugar, lo mismo. Será más trabajo de mantener, por supuesto. Más seguridad generalmente viene al precio de la conveniencia. Esta solución es un poco difícil de manejar, te lo daré. ¡Estoy abierto a una mejor manera de resolver la pregunta del OP!
jporcenaluk
5

Muchas personas critican el almacenamiento de la configuración en archivos normales junto con su código fuente, pero en mi experiencia, esta es realmente una buena solución:

  • Simple de implementar en cualquier idioma. En muchos, obtienes soporte para archivos de configuración complejos listos para usar. Por ejemplo, en el caso de Java con Spring Boot, obtienes compatibilidad con YAML que puede expresar cualquier estructura similar a un árbol, y es fácil tener archivos de configuración separados para diferentes entornos, así como una configuración de línea de base de la cual los archivos específicos del entorno pueden heredar.
  • La configuración es necesaria para ejecutar su software, y los cambios en el código a menudo requieren que se agreguen / modifiquen los ajustes de configuración, por lo que es natural mantener la configuración y el código juntos.
  • El almacenamiento de la configuración con la fuente le brinda todos los beneficios del control de la fuente, como saber quién modificó qué configuración y cuándo o si puede verificar las configuraciones durante una revisión de código regular.
  • A menos que trabajes para la CIA, el argumento de seguridad me parece exagerado. Por lo tanto, la contraseña de su base de datos se almacena en un archivo en la máquina donde se ejecuta su aplicación. Bueno, si alguien tiene acceso a la máquina con su aplicación, es probable que ya tenga muchos problemas, por ejemplo, puede quitar su aplicación y comenzar su propia aplicación en su lugar en el mismo puerto. En tal escenario, tener acceso a la contraseña de DB podría no ser un problema tan grande. A menos que todas sus conexiones estén completamente encriptadas y tengan acceso a su máquina, de todos modos pueden oler gran parte de los datos interesantes de las interfaces de red.
  • Puede usar una herramienta como Hiera para tener un archivo de configuración textual pero no almacenar contraseñas u otros datos confidenciales dentro de él.

Por lo tanto, para muchos casos, la configuración textual almacenada en el control de origen junto con el código es un buen comienzo.

Si está en sistemas distribuidos o desea poder intercambiar en caliente su configuración sin volver a implementar sus aplicaciones, puede encontrar una solución basada en un servidor de configuración mejor. Spring Cloud tiene soporte para tales mecanismos , y las configuraciones de servicio de back-end pueden ser un repositorio git o Eureka . También puedes rodar el tuyo usando, por ejemplo, Zookeeper . Cualquiera de estos enfoques facilitará la administración de configuraciones consistentes en muchos servidores para actualizar las configuraciones sin tener que reconstruir y volver a implementar su software. Esto tiene un costo, por supuesto, que es aprender el servidor de configuración y cómo usarlo desde sus aplicaciones, así como también otro sistema para implementar y mantener.

Michał Kosmulski
fuente
Pero el código cambia de manos a alguien que no posee los secretos en los archivos de configuración, va a haber un verdadero desastre.
Tim Ludwinski el
@TimLudwinski Las claves / secretos pertenecen a la empresa, no a los desarrolladores individuales, por lo que deben mantenerse de tal manera que no se pierdan si alguna persona se va. Pueden ser problemas y mantenidos por los administradores / equipo de seguridad, por ejemplo, para que haya un registro central.
Michał Kosmulski el
5

Estamos luchando contra el mismo problema donde trabajo. En este momento, todas nuestras configuraciones están basadas en archivos y controladas en origen con las aplicaciones individuales que las utilizan. Esto conduce a la duplicación y a que los desarrolladores tengan acceso a contraseñas de producción / qa en lugar de solo desarrollo.

Dicho esto, creo que hemos encontrado una buena solución en el futuro. Estamos moviendo nuestros archivos de configuración a un repositorio git separado (etiquetado como repositorio de configuración). Luego configuramos un servidor spring-cloud-config (java) que simplemente sirve los archivos del repositorio de configuración en función de los perfiles que se le pasan. Esto es ideal para aplicaciones Java que pueden usar el cliente y descargarlas en el momento del inicio. Para nuestras aplicaciones PHP / no Java, desplegaremos el archivo directamente. (No es ideal). En el futuro, podemos escribir algo que permita que la aplicación PHP descargue las configuraciones por sí misma y las guarde en caché en algún lugar, pero no es de alta prioridad para la primera ejecución. Pienso en esta solución como config-as-a-service que no viola explícitamente las recomendaciones de las aplicaciones de 12 factores.

Creo que zookeeper se puede usar para lo mismo (vi una configuración con kubernetes + zookeeper), así que no estoy muy seguro de por qué esa respuesta obtuvo un -1 arriba.

Campo de golf:

https://spring.io/guides/gs/centralized-configuration/

https://cloud.spring.io/spring-cloud-config/

ssjcory
fuente
3

En lugar de almacenar toda la configuración en un archivo, almacénelo en varios archivos.

  • Tener un directorio de configuración . Todos los archivos allí se interpretan como archivos de configuración, excepto tal vez README*.
  • Todos los nombres de archivo se ordenan alfabéticamente y los archivos se cargan en ese orden. Esta es la razón por archivos en estos casos suelen comenzar con un dígito o dos: 01-logging.json. 02-database.jsonetc.
  • Los datos de todos los archivos se cargan en la misma estructura de configuración disponible para la aplicación. Así es como varios archivos pueden complementar la configuración de los demás e incluso anularlos de manera predecible.
  • Solo almacene en el VCS los archivos de configuración con valores seguros o valores predeterminados. Agregue los archivos de configuración con secretos durante la implementación o, mejor aún, use un servicio de almacenamiento de secretos autenticado.

En su caja de Linux más cercana, eche un vistazo a /etc/sudoers.do /etc/nginx/conf.d. Muestra el mismo patrón.

La gestión de secretos es una bestia diferente. Puede administrarlos como un paso manual mientras sea pequeño. Puedes usar cosas como Zookeeper. Incluso puede verificar los secretos en un VCS en forma cifrada y descifrarlos como un paso de implementación. Existe una cantidad de otras opciones.

(También, un artículo de opinión: JSON no es un buen formato de archivo de configuración, porque no permite comentarios; los comentarios son cruciales. Los formatos TOML, YAML e incluso INI son mejores en el uso práctico).

9000
fuente
2

Creo que sus opciones están algo definidas por el sistema operativo en el que está implementando

Sugeriría, sí, poner los valores en el control de origen. PERO solo las versiones 'dev'. ¡Desea que su código fuente se compile Y funcione! no incluye pasos secretos adicionales

Su proceso de compilación e implementación debe intercambiar estos valores por entorno durante la implementación. (el pulpo tiene este tipo de modelo)

Ewan
fuente
0

Apache Zookeeper ofrece maravillosas opciones para almacenar las configuraciones de la aplicación para sistemas distribuidos. Los cambios realizados en zookeeper se pueden capturar y procesar teniendo un curador o un oyente de zookeeper al final de la aplicación.

Gmoney
fuente
66
¿Cuales son las opciones? ¿como funciona? ¿Dónde los almacena? ¿Se prefiere uno sobre otro? ¿Cuáles son las diversas ventajas y desventajas de cada opción? ¿Cómo interactúa esto en diferentes sistemas operativos?
3
@Gangz: me interesaría una respuesta más detallada, no se desanime por los votos negativos y mejore su respuesta para que pueda ser de ayuda.
Jay Elston