Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configuring Spring Cloud Config Server and Spring Cloud Vault for production

I am attempting to setup a Spring Cloud Config Server backed by Spring Cloud Vault secret management. I'm relatively new to Spring but I have tried following instructions and examples here:-

http://cloud.spring.io/spring-cloud-vault-config/

Everything works fine provided you follow the default settings like http, localhost and 8200 for the vault endpoint and tls_disable = 1 to switch off SSL. However these are not practical settings for any real environment and there are few examples anywhere that help with this. Can anyone help with a working example?

I have Successfully set up vault with TLS enable. I have successfully set up a config server that connects using a self signed cert. I can even inject a secret value into the config server and expose it via @Value and @PostConstruct.

All of this is working. However when I try to leverage Spring Conig endpoints to access vault, I get the following:-

{
  "timestamp": 1486413850574,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "org.springframework.web.client.ResourceAccessException",
  "message": "I/O error on GET request for \"http://127.0.0.1:8200/v1/secret/myapp\": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect",
  "path": "/myapp/default"
}

Config server is using default values even though I have set overrides in the bootstrap.yml.:-

server:
    port: 8888

spring:
    profiles:
        active: vault

spring.cloud.vault:
    host: myhost.mydomain.com
    port: 8200
    scheme: https
    authentication: TOKEN
    token: 0f1887c3-d8a8-befd-a5a2-01e4e066c50
    ssl:
        trust-store: configTrustStore.jks
        trust-store-password: changeit

As you can see it should be pointing to myhost.mydomain.com not 127.0.0.1 and it should be using https, not http as the protocol scheme.

I'm not sure why it uses these defaults for config server endpoints but uses correct settings during spring cloud vault startup. I'm using all the latest stable builds of Spring Dalsten.M1 and Spring Cloud Vault 1.0.0.M1. I realize these are milestone releases. I've also tried Camden and Brixton combos with no luck. I can supply code if required.

Any help greatly appreciated.

like image 884
Codesnooper Avatar asked Feb 06 '17 21:02

Codesnooper


2 Answers

As I mention in my response to spensergibb, I have had some success in resolving this myself. Based on his comments I will clarify my intent as it will help with a common understanding of the issue. I am attempting to do two things:-

  1. Stand up a configuration server that uses Vault as a backend, (as opposed to the default GIT backend) and expose the Vault API to client applications (over TLS) so that they can retrieve their own secrets. I do not want all my client applications to connect to Vault directly. I want them to get their configuration from a config server by having the config server connect to Vault. Until last night I was unable to achieve this goal, unless I set everything up as default with TLS disabled and using loopback address, port 8200 for the Vault software etc. Obviously defaults are not practical for any of our deployed environments. I will mention that the link posted by spencergibb does help me understand why this was not working but the subtlety of the reason is why I missed it before. Read on for my explanation.

  2. I want the config server to configure itself from Vault directly. That is, connect to Vault via Spring Cloud Vault Config. This worked right away for me as described in the documentation. However this goal is somewhat trivial as I do not have a real use case at this time. But I wanted to understand if it could be done since I saw no real reason why not and it seemed like good first steps in integrating Vault.

The distinction between these two capabilities helped me understand that the problem derives from the fact that Spring Cloud Config Server and Spring Cloud Vault appear to be using two different beans to inject the Vault configuration properties. Spring Cloud Config Server uses VaultEnvironmentRepository annotated with @ConfigurationProperties("spring.cloud.config.server.vault") and Spring Cloud Vault uses VaultProperties annotated with @ConfigurationProperties("spring.cloud.vault").

This caused me to add two different configs to my bootstrap yml.

server:
    port: 8888

spring:
    profiles:
        active: local, vault

    application:
        name: quoting-domain-configuration-server

    cloud:
        vault:
            host: VDDP03P-49A26EF.lm.lmig.com
            port: 8200
            scheme: https
            authentication: TOKEN
            token: 0f1997c3-d8a8-befd-a5a2-01e4e066c50a
            ssl:
                trust-store: configTrustStore.jks
                trust-store-password: changeit

        config:
            server:
                vault:
                    host: VDDP03P-49A26EF.lm.lmig.com
                    port: 8200
                    scheme: https
                    authentication: TOKEN
                    token: 0f1997c3-d8a8-befd-a5a2-01e4e066c50a

Note the same config details. Just different yml paths. This is the subtle point I missed given that I started by getting goal number 1 to work first and assuming the same config would work for both goals. (Note: Token and password are contrived).

This almost worked except for an SSL handshake error. As you can see there are no SSL attributes set on the spring.cloud.config.server.vault path. The VaultProperties bean does not support them. I was not sure how to deal with this (perhaps another non-vault specific bean that I could not find). My solution was to simply force the cert configuration myself like this:-

@SpringBootApplication
@EnableConfigServer
public class Application
{
    public static void main(String[] args)
    {
        System.setProperty("javax.net.ssl.trustStore",
            Application.class.getResource("/configTrustStore.jks").getFile());
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
        SpringApplication.run(Application.class, args);
    }
}

This SSL solution is pretty ugly. I'm sure there must be a better way to do this part. So I am open to other suggestions. However once I completed all above steps everything now works.

like image 76
Codesnooper Avatar answered Oct 25 '22 10:10

Codesnooper


Thanks for your write up. I was struggling to get this working. I was able to get a client service to connect to a Spring Cloud Config server and a Vault server but I was not able to get a Spring Cloud Config server to connect to a Vault server.

I even struggled after copying your configuration into my Spring Cloud Config server. While I eventually got it working with your configuration I was able to pare it down quite a bit. The key was that the token does not belong in the Spring Cloud Config server. It belongs in the client.

I was trying http://localhost:8888/{application}/default in the browser but got the following:

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Thu May 11 14:21:31 EDT 2017
There was an unexpected error (type=Bad Request, status=400).
Missing required header: X-Config-Token

I used PostMan to send the request with a X-Config-Token header containing the Vault token and it worked.

Here is my final config.

server:
  port: ${PORT:8888}

management:
  context-path: /manage
  security:
    enabled: true

spring:
  profiles:
    active: git,vault

  application:
    name: config-server

  cloud:
    config:
      server:
        git:
          order: 1
          uri: file:///temp/config-server/config

        vault:
          order: 0
          host: localhost
          port: 8200
          scheme: http

So it looks like you need to add the token to the client. Maybe using spring.cloud.config.token.

like image 27
Wes Avatar answered Oct 25 '22 10:10

Wes