Configuración de la Aplicación

Se ha introducido una convención para un IPF application configuración de inicio. El objetivo era proporcionar un enfoque consistente y predecible para la configuración, pero lo suficientemente flexible para integration tests que utilizan varias anotaciones de Spring para inyectar la configuración dinámicamente.

Jerarquía de Configuración

Al preparar la aplicación para su implementación, se observará la jerarquía de configuración siempre que se sigan estas reglas:

  1. Solo HOCON Los archivos (.conf) se utilizan para la configuración de aplicaciones.

  2. Los desarrolladores deben completar el archivo de configuración apropiado siguiendo esta jerarquía de precedencia descendente:

application-override.conf

¿Dónde? Configuración de despliegue (es decir,k8s configmap) o en el sistema de archivos montado en [app-name]/conf al contenedor.

¿Cuándo utilizarlo? Esto debe ser utilizado en una emergencia que no puede ser atendida por la jerarquía existente.

application.conf

¿Dónde? Configuración de despliegue (es decir,k8s configmap) o en el sistema de archivos montado en [app-name]/conf al contenedor.

¿Cuándo utilizarlo? Debe contener configuración específica del entorno, como URLs o configuración de seguridad. Si tuviéramos que desplegar la misma aplicación en diferentes entornos, las diferencias en el application.conf debería consistir principalmente en la configuración específica del entorno.

ipf-impl.conf

¿Dónde? src/main/resources de aplicaciones basadas en IPF.

¿Cuándo utilizar? Como valores predeterminados para mantener la aplicación para la ejecución local. También puede proporcionar marcadores de posición adicionales como reemplazos que deben ser establecidos por application.conf para la configuración común entre los módulos. Por ejemplo,ipf-impl.conf en sample-client proporciona anulaciones a través de un archivo de inclusión llamado endpoint-overrides.conf que anula la configuración de cifrado para cada punto final conocido.

ipf.conf

¿Dónde? src/main/resources de los módulos utilizados por la aplicación basada en IPF.

¿Cuándo utilizarlo? Definiendo valores predeterminados sensatos para aplicaciones que utilizarán este módulo. Los módulos no deben establecer la misma configuración ya que están al mismo nivel. El problema es que no será predecible cuál configuración "ganará". La excepción es si += se utiliza en listas (por ejemplo,akka.cluster.roles). Se deben evitar los marcadores de posición a menos que sean necesarios o recomendados por la biblioteca subyacente. Por ejemplo,Alpakka Kafka recomienda utilizar herencia de configuración para asignar valores predeterminados para Kafka configuración.

Esto puede verse como la versión de IPFs de Akka’s reference.conf para los diversos módulos.

reference.conf

¿Dónde? src/main/resources de los módulos utilizados por la aplicación basada en IPF

¿Cuándo usar? El propósito de reference.conf los archivos son para bibliotecas, como Akka, para definir valores predeterminados que se utilizan si una aplicación no define un valor más específico. También es un buen lugar para documentar la existencia y el significado de las propiedades de configuración. Una biblioteca no debe intentar anular propiedades en su propia reference.conf para propiedades definidas originalmente por otra biblioteca reference.conf, porque el valor efectivo sería no determinista al cargar la configuración.

Sobrescritura adicional

Si la configuración a través de la jerarquía de archivos no es suficiente, es posible realizar una anulación adicional con variables de entorno y JVM propiedades.

Variables de Entorno

Al establecer el JVM propiedad -Dconfig.override_with_env_vars=true(a través de IPF_JAVA_ARGS en los contenedores IPF) es posible anular cualquier valor de configuración utilizando variables de entorno, incluso si no se especifica una sustitución explícita.

El valor de la variable de entorno anulará cualquier valor preexistente y también cualquier valor proporcionado como Java propiedad.

Con esta opción habilitada, solo se consideran las variables de entorno que comienzan con CONFIG_FORCE_, y el nombre se modifica de la siguiente manera:

  • el prefijo CONFIG_FORCE_ es eliminado-un guion bajo(_) se convierte en un punto(.)

  • doble guion bajo (__) se convierte en un guion (-)

  • triple underscore(_) se convierte en un solo guion bajo(_)

Es decir, la variable de entorno CONFIG_FORCE_a_bc_d establece la clave de configuración a.b-c_d.

Esto solo es compatible desde com.typesafe:config:1. 4. 0 hacia adelante. Si esto no funciona, es probable que su aplicación esté utilizando una versión anterior como una dependencia transitiva.

Propiedades del Sistema

Cualquier valor de configuración puede ser anulado como un Java -D propiedad (nuevamente a través de IPF_JAVA_ARGS sobre los contenedores IPF). Estos anularán las propiedades de configuración establecidas en la jerarquía de archivos. Sin embargo, las variables de entorno establecidas con CONFIG_FORCE_ aún tienen prioridad.

Lightbend HOCON+ Configuración

El proceso está impulsado por la combinación de HOCON y el Lightbend Config biblioteca. Mientras que la biblioteca Config también admite YAML y archivos.properties, adoptando solo HOCON proporciona consistencia y flexibilidad, ya que tiene capacidades adicionales sobre los otros dos formatos de archivo.

Son dignas de mención las funcionalidades de herencia y sustitución de bloques, pero también que Akka sirve como la base para IPF. Muchas opciones de configuración estándar serían difíciles o incómodas de realizar, como definir listas de nodos semilla.

La legibilidad de HOCON lo hace adecuado tanto como documentación como configuración predeterminada. De esta manera, se ahorra mucho esfuerzo en la redacción de documentación de soporte adicional cuando se puede comentar sobre la configuración predeterminada. También hay un impulso adicional para que los desarrolladores mantengan la configuración ordenada, ya que puede ser utilizada como customer enfrentando colateral.

Detalle de Implementación

La jerarquía de configuración se utiliza como respaldo para Spring PropertySource, cargada antes de la application context se inicializa. Esto es intencionadamente para mantener el uso de las diversas anotaciones de Spring que pueden ser utilizadas para inyectar dinámicamente propiedades en integration tests. A medida que evitamos utilizar cualquier mecanismo de configuración de Spring (por ejemplo, application.* o perfiles de Spring)HOCON y la jerarquía de Configuración debe convertirse en la única fuente de configuración en las implementaciones actuales.

Es posible utilizar tanto la configuración de Spring, por ejemplo,application.properties, y el Jerarquía de configuración de IPF, p. ej.application.conf, pero cuando sea posible siempre prefiera la jerarquía de configuración.

El uso de application.properties de Spring se desaconseja encarecidamente para mantener la consistencia en la configuración de nuestro paisaje en expansión de componentes.

Enmascaramiento de Datos Sensibles en Registros

El enmascaramiento se realiza con nuestro MaskPatternLayout clase, que extiende logback’s PatternLayout. Básicamente, hemos reemplazado los diseños predeterminados con el nuevo en el DefaultLogbackConfigInitializer, que obtiene triggered después DefaultHoconConfigInitialiser. Hocon la configuración debe ser inicializada primero ya que la configuración de enmascaramiento existe allí.

La configuración de enmascaramiento contiene dos partes:

  • masking.enabled - valor booleano que indica si la función en sí está habilitada o no

  • masking.mask-config-objects - que representa un arreglo de objetos. Cada objeto contiene información de reg-ex y estrategia para el valor que deseamos enmascarar.

Hemos introducido las siguientes estrategias de enmascaramiento:

  • MASK_ALL - enmascare todos los caracteres

  • MASK_FIRST_N_CHARS - enmascarar los primeros n caracteres

  • MASK_LAST_N_CHARS - enmascarar los últimos n caracteres

  • MASK_M_TO_N_CHARS - enmascarar caracteres desde la posición m hasta la n

  • NO_MASK_FIRST_N_CHARS - no oculte los primeros n caracteres

  • NO_MASK_LAST_N_CHARS - no oculte los últimos n caracteres

  • NO_MASK_M_TO_N_CHARS - no oculte caracteres desde la posición m hasta la n

Aquí tiene un ejemplo de cómo se ve la configuración de enmascaramiento:

masking {
  enabled = true
  mask-config-objects = [
    //objects matching json fields
    {
      pattern = "\"Nm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Id\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_FIRST_N_CHARS",
        args = {
            n = 3
        }
      }
    },
    {
      pattern = "\"Dept\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "NO_MASK_M_TO_N_CHARS",
        args = {
            m = 3,
            n = 5
        }
      }
    }
  ]
}

Como se mencionó anteriormente, hay una expresión regular para cada valor que deseamos enmascarar. Esto capturará toda la línea con la clave/etiqueta y el valor, pero solo el grupo que representa el valor se coincide para el enmascaramiento.

Aquí hay algunos ejemplos de enmascaramiento xml etiquetas, mostrando cómo debe funcionar cada estrategia:

MASK_ALL -> <Dept>****</Dept>,
MASK_FIRST_N_CHARS(3) -> <SubDept>***Dept</SubDept>,
MASK_LAST_N_CHARS(2) -> <StrtNm>Strt**</StrtNm>,
NO_MASK_FIRST_N_CHARS(4) -> <BldgNb>Bldg**</BldgNb>,
NO_MASK_LAST_N_CHARS(2) -> <BldgNm>****Nm</BldgNm>.
MASK_M_TO_N_CHARS(4, 7) -> <TwnLctnNm>Twn****Nm</TwnLctnNm>,
NO_MASK_M_TO_N_CHARS(5, 7) -> <CtrySubDvsn>****Sub****</CtrySubDvsn>

Objetos de enmascaramiento ya definidos

  mask-config-objects = [
    //objects matching json fields
    {
      pattern = "\"Nm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Id\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Dept\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"SubDept\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"StrtNm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"BldgNb\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"BldgNm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Flr\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"PstBx\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Room\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"PstCd\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"TwnNm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"TwnLctnNm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"DstrctNm\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"CtrySubDvsn\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Ctry\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Adrline\"\\s*:\\s*\\[\\s*\"([^\"]+)\\s*\\]\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"BirthDt\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"PrvcOfBirth\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"CityOfBirth\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"CtryOfRes\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"CtryOfBirth\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"NmPrfx\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"PhneNb\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"MobNb\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"FaxNb\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"TaxId\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"RegnId\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"EmailAdr\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"EmailPurp\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"JobTitl\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Rspnsblty\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "\"Titl\"\\s*:\\s*\"([^\"]+)\"",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },

    //objects matching xml tags
    {
      pattern = "<(?:\\w+:)?Nm>(.+)</(?:\\w+:)?Nm>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Id>(.+)</(?:\\w+:)?Id>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Dept>(.+)</(?:\\w+:)?Dept>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?SubDept>(.+)</(?:\\w+:)?SubDept>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?StrtNm>(.+)</(?:\\w+:)?StrtNm>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?BldgNb>(.+)</(?:\\w+:)?BldgNb>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?BldgNm>(.+)</(?:\\w+:)?BldgNm>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Flr>(.+)</(?:\\w+:)?Flr>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?PstBx>(.+)</(?:\\w+:)?PstBx>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Room>(.+)</(?:\\w+:)?Room>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?PstCd>(.+)</(?:\\w+:)?PstCd>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?TwnNm>(.+)</(?:\\w+:)?TwnNm>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?TwnLctnNm>(.+)</(?:\\w+:)?TwnLctnNm>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?DstrctNm>(.+)</(?:\\w+:)?DstrctNm>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?CtrySubDvsn>(.+)</(?:\\w+:)?CtrySubDvsn>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Ctry>(.+)</(?:\\w+:)?Ctry>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Adrline>(.+)</(?:\\w+:)?Adrline>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?BirthDt>(.+)</(?:\\w+:)?BirthDt>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?PrvcOfBirth>(.+)</(?:\\w+:)?PrvcOfBirth>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?CityOfBirth>(.+)</(?:\\w+:)?CityOfBirth>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?CtryOfRes>(.+)</(?:\\w+:)?CtryOfRes>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?CtryOfBirth>(.+)</(?:\\w+:)?CtryOfBirth>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?NmPrfx>(.+)</(?:\\w+:)?NmPrfx>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?PhneNb>(.+)</(?:\\w+:)?PhneNb>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?MobNb>(.+)</(?:\\w+:)?MobNb>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?FaxNb>(.+)</(?:\\w+:)?FaxNb>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?TaxId>(.+)</(?:\\w+:)?TaxId>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?RegnId>(.+)</(?:\\w+:)?RegnId>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?EmailAdr>(.+)</(?:\\w+:)?EmailAdr>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?EmailPurp>(.+)</(?:\\w+:)?EmailPurp>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?JobTitl>(.+)</(?:\\w+:)?JobTitl>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Rspnsblty>(.+)</(?:\\w+:)?Rspnsblty>",
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    },
    {
      pattern = "<(?:\\w+:)?Titl>(.+)</(?:\\w+:)?Titl>"
      strategy {
        name = "MASK_ALL",
        args = {}
      }
    }
  ]
La implementación de esta característica depende de la biblioteca logback; para que funcione, no se puede utilizar ninguna otra implementación de logger.