1. Gateway Service
The gateway service provides a central API gateway that hides the various microservices from an application. It is based on Spring Cloud Gateway.
Unlike the other services, Spring Cloud Gateway uses the Reactive Stack. This stack requires a Netty runtime environment. For this reason, the Gateway Service cannot be used in a traditional servlet container like Apache Tomcat. |
1.1. Route configuration
Routes can be configured in the configuration file of the service. There are many options to match requests against configured routes. The official documentation contains details about those options.
The following example shows a simple configuration with two routes for a system containing two services: A service called repository and a service called userservice. The route uses the path predicate to match requests, so an application can simply prefix requests to the different services by adding the service’s name to the path.
spring:
cloud:
gateway:
routes:
- id: repository
uri: "lb://ecr-service"
predicates:
- Path=/repository/**
filters:
- RewritePath=/repository/(?<path>.*), /$\{path}
- id: userservice
uri: "lb://cmn-user-management-service"
predicates:
- Path=/userservice/**
filters:
- RewritePath=/userservice/(?<path>.*), /$\{path}
The following table contains some of the properties of the Gateway Service and their description. The rest of the properties can be found in the official Spring documentation.
Property | Description |
---|---|
id |
The ID of the route |
uri |
The URI to forward to. The uri |
predicates |
A list of predicates to match. The example uses tha path predicate and matches all paths containing /repository/. |
filters |
A list of loadbalancer filters. Here, the rewrite filter is used to cut off the /repository/ prefix from the URI. |
Using this configuration, a request like http://<gateway>/repository/api/definitions
would be forwarded to an
instance of the repository service to the path http://<repository>/api/definitions
.
1.2. Extension points
There are two global filters, that are active by default in all routes: The ResponseFilter
and the X509Filter
. Both
filters serve as extension points for project specific logic.
1.2.1. ResponseFilter
The ResponseFilter
is executed after a request was handled by the filter chain. It calls all beans of type
RequestContextConsumer
, passing the current ServerWebExchange
. To hook into that filter, just implement the interface
RequestContextConsumer
and add a custom spring boot starter, which registers a bean for your consumer, to the classpath.
1.2.2. X509Filter
The X509Filter
is executed before a request is handled by the filter chain. It can be used to check the client’s
certificates. It calls all beans of type X509CertificateConsumer
, passing the current client’s certificates.
To hook into that filter, you have to implement the interface X509CertificateConsumer
and add a custom spring boot
starter, which registers a bean for your consumer, to the classpath.
2. Registry Service
The registry service provides the central registration for service instances. The services can register with the registry service and a client can use the registry to query the available instances. In this way it can be checked whether all services are running properly. The service is based on the Spring Cloud Netflix stack.
3. Configuration Service
The {product-name} configuration service provides the configuration parameters for the other services centrally. It runs on the Spring Cloud Config Service and has its own endpoint for distributing the configuration files for the type system.
Spring Cloud Config can read configuration parameters from various sources and in various formats. The source can e.g. be the file system, a Git repository, or a database. The service includes the features of the personal configuration of Spring Boot such as different profile (e.g. test and production).
There are certain points to be mentioned in this context:
-
At present, the service can only deliver data, not write it.
-
There is still no GUI for viewing or changing configuration data.
-
Secure storage of confidential data (e.g. database passwords): Spring Cloud Config offers the option of encrypting data. In addition to that, Vault can be used as a secure repository. The best option has yet to be determined.
-
The concept of separation of functional (scenario, usually the same via test, integration and prod, e.g. scheme, status values, etc.) and technical configurations (often different in the deployment stages, e.g. storage location, database, passwords, etc.) will be implemented in future releases.
The Configuration Service provides a central configuration service that is based on the Spring Cloud Config project and can thus be integrated very easily into Spring Boot-based applications.
3.1. External configuration in Spring Boot
Spring Boot itself provides a mechanism for externalised configuration parameters: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config.
Configuration parameters can be injected via annotation @Value into a bean managed by Spring. The configuration data is read from different locations in a defined order of priority:
-
Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active)
-
@TestPropertySource annotations on your tests
-
@SpringBootTest#properties annotation attribute on your tests
-
Command line arguments
-
Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)
-
ServletConfig init parameters
-
ServletContext init parameters
-
JNDI attributes from java:comp/env
-
Java system properties (System.getProperties())
-
OS environment variables
-
A RandomValuePropertySource that has properties only in random.*
-
Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
-
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
-
Application properties outside of your packaged jar (application.properties and YAML variants)
-
Application properties packaged inside your jar (application.properties and YAML variants)
-
@PropertySource annotations on your @Configuration classes
-
Default properties (specified by setting SpringApplication.setDefaultProperties)
-
Spring Cloud Config service.
The data read from the configuration service thus overwrites all other configuration sources. Spring also offers the possibility to define profiles, e.g. to easily separate different configurations for a local development environment and the production environment.
Spring automatically loads the data from the configuration service if the following dependency has been defined:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
3.2. Typed configuration classes
Spring configuration can also be used to create typed structured configuration classes: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-typesafe-configuration-properties
3.3. Backends
The Spring Cloud Config Service inherently offers various options for storing configuration parameters https://cloud.spring.io/spring-cloud-static/spring-cloud-config/2.0.0.RC2/single/spring-cloud-config.html#_environment_repository:
-
Git repository (local or remote, default).
-
File system
-
Vault
-
Database.
3.3.1. File format
In the file-based backends (Git, file system), the configuration parameters can be stored either as a normal .properties file or in YAML.
3.4. Securing parameters in the Configuration Service
Some parameters like database passwords, or the master password for the data encryption should not be accessible for everyone. The configuration service is based on the Spring Cloud Configuration Service, so all security measures described in the Spring documentation apply.
3.4.1. SSL transport encryption and x509 access
The configuration service can serve SSL encrypted data and it can enforce client certificate checks to limit access. Both features can be enabled in the bootstrap.yaml file for the configuration service. Access to this file must be protected by operating system measures like file system access restrictions.
server:
ssl:
key-store-type: "PKCS12"
key-store: "/path/keyStore.p12"
key-store-password: "changeit"
trust-store-type: "JKS"
trust-store: "/path/trustStore.jks"
trust-store-password: "changeit"
client-auth: "need"
Parameter | Meaning |
---|---|
client-auth |
Enforces client certificate checks when set to "need" |
key-store |
The path to the keystore file |
key-store-password |
The password for the keystore |
key-store-type |
The type of keystore used for the server’s certificate, JKS or PKCS12 |
trust-store |
The path to the keystore file for the client certificates |
trust-store-password |
The password for the keystore |
trust-store-type |
The type of keystore used for the accepted client certificates, JKS or PKCS12 |
To enable the services to use SSL encrypted connections to the configuration service and to authenticate with a certificate, the following changes have to be made in the bootstrap.yaml file for each service. Access to this file must be protected by operating system measures like file system access restrictions.
spring:
cloud:
config:
uri: "https://<host>:<port>"
client:
ssl:
client-auth: true
key-store: "/path/keyStore.p12"
key-store-password: "changeit"
key-store-type: "PKCS12" # this is the default - can be omitted
protocol: "TLSv1" # this is the default - can be omitted
Parameter | Meaning |
---|---|
client-auth |
Enables authentication with certificate |
key-store |
The path to the keystore file |
key-store-password |
The password for the keystore |
trust-store-type |
The type of keystore used for the accepted client certificates, JKS or PKCS12 |
protocol |
The encryption protocol to use |
The certificate the client uses to authenticate must be signed by a certificate that is contained in the server’s trust-store.
3.5. Encrypting parameters in the yaml files
The configuration properties for the different services are stored in yaml files or in a database. It is possible to encrypt values in those files to secure sensitive data like passwords. The configuration service can automatically decrypt those values when they are requested by a service. So the encryption feature should be used in combination with transport encryption and access restrictions to the configuration service. To enable encryption, an encryption key must be defined in the bootstrap.yaml file of the configuration service. Access to this file must be protected by operating system measures like file system access restrictions.
encrypt:
key: "secret_password"
Encrypted properties can then be stored in the yaml files like this:
password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'
The configuration service provides a special endpoint that can be used to encrypt properties as is described in the Spring documentation.