pivotal-cf / java-cfenv

Apache License 2.0
91 stars 56 forks source link

Vault Incompatible with Spring Boot 2.4 #133

Closed gm-bcgooding closed 3 years ago

gm-bcgooding commented 3 years ago

There are a couple of compatibility issues with Spring Boot 2.4

1) Requires Legacy File Processing to be enabled 2) Values set in application.yml are ignored when configuring a service

Details on Legacy File Processing

When launching an application with Vault as a bound service using Spring Boot 2.4's Data Config API, Spring Cloud 2020.0.2 and Java CFEnv the application fails with java.lang.IllegalArgumentException: Token (spring.cloud.vault.token) must not be empty .

Spring Boot 2.4 introduced changes in how Config Files are being processed in Spring. This change breaks how CFEnv works with Spring Boot.

Workaround

The only way to avoid this error is to enable legacy file processing. spring.config.use-legacy-processing must be set to true in the application's manifest file or via CLI. This change results in the proper processing of the Spring Configuration which in turns creates the Vault source.

However, this leads us into the second issue

Values set in application.yml are ignored

When legacy processing is enabled the values from the application.yml file are apparently not available. This results in any additional configuration settings such as spring.cloud.application-name not being accessed when the Vault source is configured.

If keys are stored under the application's name and not under application the keys will fail to be found resulting in application failure. This also causes issues when an application is not using the backend of secret for KV backends. Configuring the setting spring.cloud.vault.kv.backend does not result in the proper backend being accessed. To resolve this, a custom processor for vault had to be created so that the correct backend would be read.

Workaround

Set these values as environment variables in the manifest file. This will result in the proper configuration of the application. Caveat, only tested this with spring.application.name.

Configuration Details

Used a parent pom and application pom.

Relevant Parent Pom

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
    </parent>

    <modules>
        <module>hello-world</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <dependencies>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

    </dependencies>

Application Pom

<dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-vault-config</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.vault</groupId>
                    <artifactId>spring-vault-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.springframework.vault</groupId>
            <artifactId>spring-vault-core</artifactId>
            <version>2.3.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>spring-core</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>spring-beans</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>spring-web</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>io.pivotal.cfenv</groupId>
            <artifactId>java-cfenv-boot</artifactId>
            <version>2.3.0</version>
        </dependency>

    </dependencies>

Main

@SpringBootApplication
public class HelloWorldApplication {

    @Autowired
    private Environment env;

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(HelloWorldApplication.class);
        application.run();
    }

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

    @Value("${hello.world}")
    String helloWorld;

    @PostConstruct
    private void postConstruct() {
        System.out.println("##########################");
        System.out.println(mykey);
        System.out.println(helloWorld);
        System.out.println("------ From Environment ---------");
        System.out.println("Vault URI: " + env.getProperty("spring.cloud.vault.uri"));
        System.out.println("Vault token: " + env.getProperty("spring.cloud.vault.token"));
        System.out.println("Application Name: " + env.getProperty("spring.application.name"));
        System.out.println("##########################");
    }
}
dyroberts commented 3 years ago

Hi @gm-bcgooding. Thanks for bringing this up. Your first issue is known, unfortunately. I've run into it with spring-cloud-services config-server client libraries as well.

As you've noticed, the new config import mechanism in boot 2.4 runs so early in the boot-up process as to prevent java-cf-env-boot from setting the required property. You can still use java-cf-env-core though. Here's an example of that: https://github.com/pivotal-cf/spring-cloud-services-starters/blob/7eb0004a4635308393d970d8cf10cc208d013426/spring-cloud-services-config-client-autoconfigure/src/main/java/io/pivotal/spring/cloud/config/client/ConfigClientEnvironmentPostProcessor.java#L43 Notice the Order that EnvironmentPostProcessor is using, as well.

Taking this approach should clear up all the issues you mentioned, for you. That is, once you turn off legacy-processing. The issue you're experiencing with legacy-processing is something I will look into further though. I'll file a separate issue and link it here, if you're interested.

gm-bcgooding commented 3 years ago

Are there plans to update java-cf-env-boot to function in a similar fashion to the link you provided?

Should there be documentation added to the Spring Boot portion of the readme to reflect this known issue?