Writing Client Applications

Refer to the “Cook” sample application to follow along with the code in this topic.

To use a Spring Boot application as a client for a Config Server instance, you must add the dependencies listed in the Client Dependencies topic to your application’s build file. Be sure to include the dependencies for Config Server as well.

Important: Because of a dependency on Spring Security, the Spring Cloud® Config Client starter will by default cause all application endpoints to be protected by HTTP Basic authentication. If you wish to disable this, please see Disable HTTP Basic Authentication below.

Add Self-Signed SSL Certificate to JVM Truststore

Spring Cloud Services uses HTTPS for all client-to-service communication. If your Pivotal Cloud Foundry installation is using a self-signed SSL certificate, the certificate will need to be added to the JVM truststore before your client application can consume properties from a Config Server service instance.

Spring Cloud Services can add the certificate for you automatically. For this to work, you must set the TRUST_CERTS environment variable on your client application to the API endpoint of your Elastic Runtime instance:

$ cf set-env cook TRUST_CERTS api.cf.wise.com
Setting env variable 'TRUST_CERTS' to 'api.cf.wise.com' for app cook in org myorg / space development as user...
OK
TIP: Use 'cf restage' to ensure your env variable changes take effect

$ cf restage cook

Note: The CF_TARGET environment variable was formerly recommended for configuring Spring Cloud Services to add a certificate to the truststore. CF_TARGET is still supported for this purpose, but TRUST_CERTS is more flexible and is now recommended instead.

As the output from the cf set-env command suggests, restage the application after setting the environment variable.

Use Configuration Values

When the application requests a configuration from the Config Server, it will use a path containing the application name (as described in the Configuration Clients topic). You can declare the application name in bootstrap.properties, bootstrap.yml, application.properties, or application.yml.

In bootstrap.yml:

spring:
  application:
    name: cook

This application will use a path with the application name cook, so the Config Server will look in its configuration source for files whose names begin with cook, and return configuration properties from those files.

Now you can (for example) inject a configuration property value using the @Value annotation. The Menu class reads the value of special from the cook.special configuration property.

@RefreshScope
@Component
public class Menu {

  @Value("${cook.special}")
  String special;

  //...

  public String getSpecial() {
    return special;
  }

  //...

}

The Application class is a @RestController. It has an injected menu and returns the special (the value of which will be supplied by the Config Server) in its restaurant() method, which it maps to /restaurant.

@RestController
@SpringBootApplication
public class Application {

    @Autowired
    private Menu menu;

    @RequestMapping("/restaurant")
    public String restaurant() {
      return String.format("Today's special is: %s", menu.getSpecial());
    }
    //...

Vary Configurations Based on Profiles

You can provide configurations for multiple profiles by including appropriately-named .yml or .properties files in the Config Server instance’s configuration source (the Git repository). Filenames follow the format {application}-{profile}.{extension}, as in cook-production.yml. (See the The Config Server topic.)

The application will request configurations for any active profiles. To set profiles as active, you can use the SPRING_PROFILES_ACTIVE environment variable, set for example in manifest.yml.

applications:
  - name: cook
    host: cookie
    services:
      - config-server
    env:
      SPRING_PROFILES_ACTIVE: production

The sample configuration source cook-config contains the files cook.properties and cook-production.properties. With the active profile set to production as in manifest.yml above, the application will make a request of the Config Server using the path /cook/production, and the Config Server will return properties from both cook-production.properties (the profile-specific configuration) and cook.properties (the default configuration); for example:

{
  "name":"cook",
  "profiles":[
    "production"
  ],
  "label":"master",
  "propertySources":[
    {
      "name":"https://github.com/spring-cloud-services-samples/cook-config/cook-production.properties",
      "source":
        {
          "cook.special":"Cake a la mode"
        }
    },
    {
      "name":"https://github.com/spring-cloud-services-samples/cook-config/cook.properties",
      "source":
        {
          "cook.special":"Pickled Cactus"
        }
    }
  ]
}

As noted in the Configuration Clients topic, the application must decide what to do when the server returns multiple values for a configuration property, but a Spring application will take the first value for each property. In the example response above, the configuration for the specified profile (production) is first in the list, so the Boot sample application will use values from that configuration.

View Client Application Configuration

Spring Boot Actuator adds an env endpoint to the application and maps it to /env. This endpoint displays the application’s profiles and property sources from the Spring ConfigurableEnvironment. (See “Endpoints” in the “Spring Boot Actuator” section of the Spring Boot Reference Guide.) In the case of an application which is bound to a Config Server service instance, env will display properties provided by the instance.

To use Actuator, you must add the spring-boot-starter-actuator dependency to your project. If using Maven, add to pom.xml:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

If using Gradle, add to build.gradle:

compile("org.springframework.boot:spring-boot-starter-actuator")

You can now visit /env to see the application environment’s properties (the following shows an excerpt of an example response):

$ curl http://cookie.apps.wise.com/env
{
  "profiles":[
    "dev","cloud"
  ],
  "configService:https://github.com/spring-cloud-services-samples/cook-config/cook.properties":{
    "cook.special":"Pickled Cactus"
  },
  "vcap":{
    "vcap.application.limits.mem":"512",
    "vcap.application.application_uris":"cookie.apps.wise.com",
    "vcap.services.config-server.name":"config-server",
    "vcap.application.uris":"cookie.apps.wise.com",
    "vcap.application.application_version":"179de3f9-38b6-4939-bff5-41a14ce4e700",
    "vcap.services.config-server.tags[0]":"configuration",
    "vcap.application.space_name":"development",
    "vcap.services.config-server.plan":"standard",
//...

Refresh Client Application Configuration

Spring Boot Actuator also adds a refresh endpoint to the application. This endpoint is mapped to /refresh, and a POST request to the refresh endpoint refreshes any beans which are annotated with @RefreshScope. You can thus use @RefreshScope to refresh properties which were initialized with values provided by the Config Server.

The Menu.java class is marked as a @Component and also annotated with @RefreshScope.

import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@RefreshScope
@Component
public class Menu {

  @Value("${cook.special}")
  String special;
  //...

This means that after you change values in the configuration source repository, you can update the special on the Application class’s menu with a refresh event triggered on the application:

$ curl http://cookie.apps.wise.com/restaurant
Today's special is: Pickled Cactus

$ git commit -am "new special"
[master 3c9ff23] new special
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git push

$ curl -X POST http://cookie.apps.wise.com/refresh
["cook.special"]

$ curl http://cookie.apps.wise.com/restaurant
Today's special is: Birdfeather Tea

Use Client-Side Decryption

On the Config Server, the decryption features are disabled, so encrypted property values from a configuration source are delivered to client applications unmodified. You can use the decryption features of Spring Cloud Config Client to perform client-side decryption of encrypted values.

To use the decryption features in a client application, you must use a Java buildpack which contains the Java Cryptography Extension (JCE) Unlimited Strength policy files. These files are contained in the Cloud Foundry Java buildpack from version 3.7.1.

You must also include Spring Security RSA as a dependency.

If using Maven, include in pom.xml:

    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-rsa</artifactId>
    </dependency>

If using Gradle, include in build.gradle:

    compile("org.springframework.security:spring-security-rsa")

Encrypted values must be prefixed with the string {cipher}. If using YAML, enclose the entire value in single quotes, as in '{cipher}vALuE'; if using a properties file, do not use quotes. The configuration source for the Cook application has a secretMenu property in its cook-encryption.properties:

secretMenu={cipher}AQA90Q3GIRAMu6ToMqwS++En2iFzMXIWX99G66yaZFRHrQNq64CntqOzWymd3xE7uJpZK
Qc9XBIkfyRz/HUGhXRdf3KZQ9bqclwmR5vkiLmN9DHlAxS+6biT+7f8ptKo3fzQ0gGOBaR4kTnWLBxmVaIkjq1Qz
e4aIgsgUWuhbEek+3znkH9+Mc+5zNPvwN8hhgDMDVzgZLB+4YnvWJAq3Au4wEevakAHHxVY0mXcxj1Ro+H+ZelIz
fF8K2AvC3vmvlmxy9Y49Zjx0RhMzUx17eh3mAB8UMMRJZyUG2a2uGCXmz+UunTA5n/dWWOvR3VcZyzXPFSFkhNek
w3db9XZ7goceJSPrRN+5s+GjLCPr+KSnhLmUt1XAScMeqTieNCHT5I=

Put the key on the client application classpath. You can either add the keystore to the buildpack’s resources/open_jdk_jre/lib/security directory (as described above for the JCE policy files) or include it with the source for the application. In the Cook application, the key is placed in src/main/resources.

cook
└── src
    └── main
        └── resources
            ├── application.yml
            ├── bootstrap.yml
            └── server.jks

Important: Cook is an example application, and the key is packaged with the application source for example purposes. If at all possible, use the buildpack for keystore distribution.

Specify the key location and credentials in bootstrap.properties or bootstrap.yml using the encrypt.keyStore properties:

encrypt:
  keyStore:
    location: classpath:/server.jks
    password: letmein
    alias: mytestkey
    secret: changeme

The Menu class has a String property secretMenu.

  @Value("${secretMenu}")
  String secretMenu;

  //...

  public String getSecretMenu() {
    return secretMenu;
  }

A default value for secretMenu is in bootstrap.yml:

secretMenu: Animal Crackers

In the Application class, the method secretMenu() is mapped to /restaurant/secret-menu. It returns the value of the secretMenu property.

    @RequestMapping("/restaurant/secret-menu")
    public String secretMenu() {
      return menu.getSecretMenu();
    }

After making the key available to the application and installing the JCE policy files in the Java buildpack, you can cause the Config Server to serve properties from the cook-encryption.properties file by activating the encryption profile on the application, e.g. by running cf set-env to set the SPRING_PROFILES_ACTIVE environment variable:

$ cf set-env cook SPRING_PROFILES_ACTIVE dev,encryption
Setting env variable 'SPRING_PROFILES_ACTIVE' to 'dev,encryption' for app cook in org myorg / space development as user...
OK
TIP: Use 'cf restage' to ensure your env variable changes take effect

$ cf restage cook

The application will decrypt the encrypted property after receiving it from the Config Server. You can view the property value by visiting /restaurant/secret-menu on the application.

Disable HTTP Basic Authentication

The Spring Cloud Config Client starter has a dependency on Spring Security. Unless your application has other security configuration, this will cause all application endpoints to be protected by HTTP Basic authentication.

If you do not yet want to address application security, you can turn off Basic authentication by setting the security.basic.enabled property to false. In application.yml or bootstrap.yml:

security:
  basic:
    enabled: false

You might make this setting specific to a profile (such as the dev profile if you want Basic authentication disabled only for development):

---
spring:
  profiles: dev

security:
  basic:
    enabled: false

For more information, see “Security” in the Spring Boot Reference Guide.

Note: Because of the Spring Security dependency, HTTPS Basic authentication will also be enabled for Spring Boot Actuator endpoints. If you wish to disable that as well, you must also set the management.security.enabled property to false. See “Customizing the management server port” in the Spring Boot Reference Guide.

Create a pull request or raise an issue on the source for this page in GitHub