Hot questions for Spring Cloud Config

Hot questions for Spring Cloud Config

Top 10 Java Open Source / Spring / Spring Cloud Config

Question:

Is it possible to use Spring Cloud Config without using any Git repo at all? I'm trying to test it with a local directory with this in application.properties:

spring.cloud.config.server.git.uri=file://${user.dir}/src/main/resources/config-repo

But I get the following error:

java.lang.IllegalStateException: No .git at file://path/to/src/main/resources/config-repo

So is it not possible to use Spring Cloud if one is not using Git at all?

UPDATE:

Thanks to Spencer's advice, I added the following:

spring.profiles.active=native spring.cloud.config.server.native.searchLocations=${user.dir}/src/main/resources/configs

And I have a file "bar.properties" inside "configs" with the following contents:

foo: bar

But the response I get is not reading the file:

{
  "name": "bar",
  "profiles": [
    "default"
  ],
  "label": "master",
  "propertySources": []
}

The URL I'm using is http://localhost:8888/bar/default

Am I missing something else? Thanks again in advance!


Answer:

Run with spring.profiles.active=native. See the File System Backend for more details. You'll want to set spring.cloud.config.server.native.searchLocations to the dirs you want to look at.

Question:

I know should set following properties, but still confused about where they should be set.

spring:
    cloud:
        config:
            allowOverride: true
            failFast: true
            overrideNone: false

application.properties file on spring cloud server side or client side or remote git repository?

I set them in application.yml on server side, but don't work.

I try set in application.yml on remote git, and again not work, hope you could give me some help, thanks.


Answer:

I set the following configurations in remote git repo. It works this time.

spring:
  cloud:
    config:
      allowOverride: true
      overrideNone: true
      overrideSystemProperties: false

Question:

I found many questions and tutorials before finally putting this all together. Wanted to document it so somebody else can save many hours of frustration.

I am trying to get a private git repository on BitBucket to work with Spring Boot Config Server using deploy keys and have it run in Docker. I am running into many issues.

  1. How to actually configure using the application.yml files.

I cant seem to figure out where I should put the SSH info. All tutorials seem to be for https.

  1. How to provide the private key to the configuration. For Dev the syntax for inline in YML is a pain. For production, you have to provide it via an environment variable, which is another syntax chore.

I keep getting an error that the private key is invalid.

  1. How to get the Docker container to trust the host key without that pesky "do you trust this guy" prompt.

There seems to be several ways to make this work, but only one that worked for me.


Answer:

First piece is the configuration. You want to ignore the standard private key and use one provided as an environment variable. (SSH_KEY). Also, the git repo is an EV (GIT_URL) but you can hardcode if you want.

spring:
  cloud:
    config:
      server:
        git:
          uri:  ${GIT_URL}
          ignore-local-ssh-settings: true
          private-key: ${SSH_KEY}

Part 2 is tricky. For Dev, you want the key inline, so you need to use a pipe to prefix the block in YAML. (Note this key is throw away as in I just generated it and have now thrown it away)

private-key: |
                    -----BEGIN RSA PRIVATE KEY-----
                    MIIEpAIBAAKCAQEAszmCR06LVHk/kNYV6LoYgEfHlK4rp75sCsRJ7rdAbWNED+yB
                    bneOm5gue0LGIhT7iTP9D7aN6bKVHv1SBconCA7Pa2NMA9epcMT5ecJc8ndpZOFn
                    iqM77jmMMPvj8EIC06w5oK5zoYwpGotYQFHllf8M+20HtW2fZdPYAYwLcVdmc5tI
                    vLoS+10qw5D3X9zrwk2Cbt37Iqnz1cHOQq+g7sxgVgt18aIKKeg0JslaGqSlWMoT
                    ICUMHj89E4BMHj8ND8otSXHL+VhN+ghd7w1MpckxLWBsNs1+G1FuiJEVAtRq/j+8
                    SOilxgifvI1LqpZ5kO01XFlmkcuN4NMT03qpcwIDAQABAoIBAB5oQGk2sz7mv1kk
                    aV0tzaBeDUd1cWSpUw1UljKRFrY4ZEDLYH5MfH57iE9TWehIZRC3KFU1JMikitZS
                    JktjK9IbKSfQFgKE4XOHh8gXqMteZRw/feCwpydYzic1ZUvK903QZ4qSbn3XGNYv
                    FA79lhUny50Qt4EZkzSkh35js0FMSR9VmyXENxN6IgXUZyoaNAATr44Vkd488BY2
                    7PvdOniemo8/8p4Ij0Aq9Q7rOtm77ZXjyFRX5mDTi2ndSllMEhVcWXHSii+ukbvF
                    117Ns+8M7VWroNfRzI+Ilm/Xz/ePOLlNoYcY0h5+QM9vMPTX9Cpl5WofgOMK1sKd
                    mSdI4ukCgYEA12kcu0aDyIrEPHcyaT9izSFply0Uon2QKS9EQn6cr83vaEGViamh
                    f5q1coYouGnsLfbgKolEMKsYtbmJvInPFDCdc2x0Fmc207Wp1OECsN+HwElEXkrs
                    uPDpGQgs5odjN5Grue9837920oG3UBBdVDAKly2dTOcvoWW+88seFSUCgYEA1P7f
                    p78HDMQ8zTy5+3Rd4+lmJjPsY618XxSQ80j8Elrhi/DyTMA0XGc5c3cKRPmSj+JD
                    GN34WQbw7JO2mKM7YJs+tkSBeTKce8F3cZQy1jy3LNHCtfXylOxmxOFKynV5h2b/
                    jno+pGdmAPK5yvnGASd2eujtzt+AL07XiD2LnLcCgYEAsFRz131WfP/SuShdlLf1
                    WbODKuQVIxojuwLdHo1kF6k805v0G/dGoxzycOgPRz41vj57q3Yn4qr8FC3n6PTq
                    FT3idUyPDpO41r67Ye469KxWBHo1Q/aTJqTWOs5tatvixOcyqoa3MrUZQCI8+4YZ
                    z8Nvt+b3/66zV6vhDtHzMx0CgYAvWW2M0+mUS/ecRHivzqGkrdkYewh87C8uz9qd
                    SsdGqU9kla63oy7Ar+3Unkz5ImYTeGAkIgw4dlOOtBOugPMNOdXKHRaPQ9IHrO2J
                    oUFf4OVzoDnhy4ge1SLPd6nxsgXPNPVwzfopABdr9Ima9sWusgAjuK5NA+ByI9vE
                    HLJxpwKBgQCTM938cdx457ag1hS6EaEKyqljS1/B8ozptB4cy3h0hzw0crNmW84/
                    1Lt9MJmeR4FrWitQkkVLZL3SrYzrP2i+uDd4wVVD5epvnGP/Bk6g05/eB9LgDRx/
                    EeBgS282jUBkXZ6WpzqHCcku3Avs3ajzsC1WaEYx0tCiBxSkiJlaLQ==
                    -----END RSA PRIVATE KEY-----

On the production front, you need to use a bash variable at the command prompt to store your key before you pass it to the Docker command that runs your container. Example:

$ pem=$( cat path_to_key )
$ docker run -e "SSH_KEY=$pem" configserver

At this point you should have the application taken care of. Now all you need is to get past the ssh host not trusted problem. For this, add these lines in your Dockerfile. Replace "bitbucket.org" with whatever host you want. These commands create the ssh config directory, fix the permissions, and then create and populate the knownhosts file.

RUN mkdir -p /root/.ssh
RUN chmod 700 /root/.ssh
RUN ssh-keyscan bitbucket.org > /root/.ssh/known_hosts

Question:

Spring cloud config server supports reading property files with name ${spring.application.name}.properties. However I have 2 properties files in my application.

a.properties
b.properties

Can I get the config server to read both these properties files?


Answer:

Rename your properties files in git or file system where your config server is looking at.

a.properties -> <your_application_name>.properties
a.properties -> <your_application_name>-<profile-name>.properties

For example, if your application name is test and you are running your application on dev profile, below two properties will be used together.

test.properties
test-dev.properties

Also you can specify additional profiles in bootstrap.properties of your config client to retrieve more properties files like below. For example,

spring:
  profiles: dev
  cloud:
    config:
      uri: http://yourconfigserver.com:8888
      profile: dev,dev-db,dev-mq

If you specify like above, below all files will be used together.

test.properties
test-dev.properties
test-dev-db.prpoerties
test-dev-mq.properties

Question:

I am trying to setup a Spring Cloud Config server that uses a custom location for the ssh private key. The reason i need to specify a custom location for the key is because the user running the application has no home directory ..so there is not way for me to use the default ~/.ssh directory for my key. I know that there is the option of creating a read-only account and provide the user/password in the configuration but the ssh way seams more clean.Is there a way I can setup this?


Answer:

After reading a lot more code... I found a relatively simple work around to allow you to set whatever SSH keys you want.

First: Create a class as follows:

/**
 * @file FixedSshSessionFactory.java 
 * 
 * @date Aug 23, 2016 2:16:11 PM 
 * @author jzampieron
 */

import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig.Host;
import org.eclipse.jgit.util.FS;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
 * Short Desc Here.
 * 
 * @author jzampieron
 *
 */
public class FixedSshSessionFactory extends JschConfigSessionFactory
{

   protected String[] identityKeyPaths;

   /**
    * @param string
    */
   public FixedSshSessionFactory( String... identityKeyPaths )
   {
      this.identityKeyPaths = identityKeyPaths;
   }

   /* (non-Javadoc)
    * @see org.eclipse.jgit.transport.JschConfigSessionFactory#configure(org.eclipse.jgit.transport.OpenSshConfig.Host, com.jcraft.jsch.Session)
    */
   @Override
   protected void configure( Host hc, Session session )
   {
      // nothing special needed here.
   }

   /* (non-Javadoc)
    * @see org.eclipse.jgit.transport.JschConfigSessionFactory#getJSch(org.eclipse.jgit.transport.OpenSshConfig.Host, org.eclipse.jgit.util.FS)
    */
   @Override
   protected JSch getJSch( Host hc, FS fs ) throws JSchException
   {
      JSch jsch = super.getJSch( hc, fs );
      // Clean out anything 'default' - any encrypted keys
      // that are loaded by default before this will break.
      jsch.removeAllIdentity();
      for( final String identKeyPath : identityKeyPaths )
      {
         jsch.addIdentity( identKeyPath );
      }
      return jsch;
   }


}

Then register it with jgit:

...
import org.eclipse.jgit.transport.SshSessionFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigserverApplication 
{

    public static void main(String[] args) {
       URL res = ConfigserverApplication.class.getClassLoader().getResource( "keys/id_rsa" );
       String path = res.getPath();
       SshSessionFactory.setInstance( new FixedSshSessionFactory( path ) );

       SpringApplication.run(ConfigserverApplication.class, args);
    }

}

For this example I'm storing the keys in the src/main/resources/keys folder and I'm using the class loader to get at them.

The removeAllIdentities is important b/c JSch was loading my default ssh key before the one I specified and then Spring Cloud was crashing out b/c its encrypted.

This allowed me to successfully authenticate with bitbucket.