Distributed Configuration

WIP

This page is a work in progress


Overview

Centralized configuration via mod-configuration is problematic from a security perspective. It provides a convenient mechanism for storing configuration, but the permission granularity is too coarse. Granting a user the ability to access an entry for one app means that they will also have access to ALL configuration entries.

One idea was proposed that all modules have a multiple interface which can be implement (or not), which presents a common interface for accessing configuration specific to various modules.  This means the clients (the UI for instance) are presented a common interface for getting configuration instead of each module doing it their own way.

The "Configuration" Multiple Interface

Modules can choose to implement this multiple interface "configuration"

  • GET /configurations/entries
  • GET /configurations/entries/<id>
  • POST /configurations/entries
  • PUT /configurations/entries/<id>
  • DELETE /configurations/entries/<id>

Each of which would be protected by discrete permissions, e.g. mod-foo might have:

  • foo.configurations.collection.get,
  • foo.configurations.item.get (put/post/delete)

Storage Layer

UPDATE  This part probably doesn't make much sense from a security standpoint - it put's us right back to where we started.  See comments section.

TBD... Just because the configuration APIs are distributed doesn't mean the configuration information must be.  In the case of storage modules, they may choose to just store their configuration in postgres as doing so would probably require little effort.  For business logic modules, or modules which have specific needs (e.g. the configuration is sensitive and should be encrypted, etc.) could choose to use a central configuration module for storage.

Here's where it might make sense to pull in additional technologies that are better suited to these requirements.  See the Technologies section below.  Having a module that presents a common interface in front of these technologies which is used internally (i.e. intended to be called only by other modules, not directly by clients) is an option that provides flexibility and opens the door to many potential benefits.

mod-configuration-storage

  • Implements the configuration interface, or something that looks very similar.
  • Uses a java interface to allow developers to add support for various underlying storage technologies - Maybe the default is just postgresql?
  • Could enable multiple storage technologies, and the ability for the client to specify which storage they want to use...
    • This should be implemented via something like attributes so that the client doesn't need to know which storage technologies are available... just that there's one that has the attributes it cares about.
      • For instance - store this thing somewhere that's "secure".  The module then looks for a configured storage that has the "secure" attribute, and stores it there. 
      • We'd have to allow for the administrator/operator to specify an order of precedence to help the module choose the right one in some cases.

Configuration

  • Via json and/or properties config file(s)...
  • System property:  -DstorageConfigs=vault-config.properties,postgres-config.json

    • postgres-config.json:

      {
        "host":"localhost",
        "port":5432,
        "username":"folio",
        "password":"letmein",
        "database":"folio"
      }
    • vault-config.properties: 

      # Used by the factory class to match impl w/ config
      type=vault
      
      # the address of your vault
      # Default: http://127.0.0.1:8200
      address={VAULT_ADDR}
      
      # whether or not to use SSL [true|false]
      # Default: false
      enableSSL=true
      #
      # NOTE: JKS-based config trumps PEM-based config. If you provide both JKS and PEM configs,
      # then the JKS config will be used.
      # You cannot "mix-and-match", providing a JKS-based truststore and PEM-based client auth data.
      #
      # the path to an X.509 certificate in unencrypted PEM format, using UTF-8 encoding
      ssl.pem.path={PEM_PATH}
      #
      # the path to a JKS truststore file containing Vault server certs that can be trusted
      #ssl.truststore.jks.path={TRUSTSTORE_PATH}
      #
      # the path to a JKS keystore file containing a client cert and private key
      #ssl.keystore.jks.path={KEYSTORE_PATH}
      #
      # the password used to access the JKS keystore (optional)
      #ssl.keystore.password={KEYWORD_PASSWORD}
      

Technologies

This list isn't intended to be comprehensive, just to give an idea of the types of things I'm referring to.

Other Considerations

  • Migration of config data would need to be done on a per-module basis.  We could effectively deprecate mod-configuration and then at some later date retire/end-of-life it entirely.

JIRA

Drawbacks

The "Externalized configuration" microservice pattern applies to deployment configuration (infrastructure and 3rd party services) only, not to business logic configuration. The business login configuration is completely independent of the deployment – it depends on the tenant or other properties.

Using mod-configuration for per-tenant business logic configuration violates the single responsibility principle (separation of concerns) where each service should be loosely coupled with other services and independently deployable. There is no benefit in moving them into a centralized configurations module.

Moving the per-tenant business logic configuration from mod-configuration into mod-*-storage but keeping a unified configuration interface has these drawbacks:

  • Client needs to pass a parameter with the module name, this adds complexity.
  • The configuration must fit into the 8 fields (mod-configuration API):  "module", "configName", "code", "description", "default", "enabled", "value", "userId"
  • The API documentation cannot explain the configuration options: mod-configuration API

These drawbacks can be avoided by using module specific configuration APIs. Example: https://s3.amazonaws.com/foliodocs/api/mod-orders-storage/configuration.html

Only those configuration options (deployment configuration) should be unified/centralized that really require it (some advanced features of redis/vault/...).