spring-cloud / spring-cloud-config

External configuration (server and client) for Spring Cloud
Apache License 2.0
1.95k stars 1.29k forks source link

Error Unauthorized: 401 while starting the application #2314

Open dyleph opened 1 year ago

dyleph commented 1 year ago

Hi Spring Cloud team,

I am going to upgrade Spring cloud from 2022.0.2 to 2022.0.4. And I got an issue while starting my application.

Spring boot: v3.1.1 Spring cloud: v2022.0.4

In application.yml:

spring.cloud.config:
  enabled: true
  username: config-service
  password: test-password

In helm-chart/dev.values.yaml:

namespace: dev

replicaCount: 1

springProfile: dev

env:
  - name: SPRING_CLOUD_CONFIG_ENABLED
    value: 'true'
  - name: SPRING_CONFIG_IMPORT
    value: configserver:http://config-service

secretEnv:
  - name: SPRING_CLOUD_CONFIG_PASSWORD
    secretKeyRefName: spring-cloud-config-password
    secretKeyRefKey: spring-cloud-config-password

Here is the error log:

09:58:35.387 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
org.springframework.cloud.config.client.ConfigClientFailFastException: Could not locate PropertySource and the resource is not optional, failing
        at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:201)
        at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:102)
        at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:61)
        at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:96)
        at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:132)
        at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:87)
        at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:115)
        at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:242)
        at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:229)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96)
        at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109)
        at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:94)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
        at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
        at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64)
        at java.base/java.lang.Iterable.forEach(Iterable.java:75)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
        at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63)
        at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:356)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
        at ch.autoscout24.SampleServiceApplication.main(SampleServiceApplication.java:14)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:95)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: org.springframework.web.client.HttpClientErrorException$Unauthorized: 401 : [no body]
        at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:106)
        at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:183)
        at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:137)
        at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
        at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:915)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:864)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:764)
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:646)
        at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.getRemoteEnvironment(ConfigServerConfigDataLoader.java:306)
        at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:119)
        ... 36 common frames omitted

It looks like the application couldn't get username in application.yml. I was trying to set it as an environment variable SPRING_CLOUD_CONFIG_USERNAME in helm-chart/dev.values.yml, and it starts successfully.

  - name: SPRING_CLOUD_CONFIG_USERNAME
    value: config-service

Could you please help to check this case? In new Spring cloud version, do we have to set SPRING_CLOUD_CONFIG_USERNAME as an environment variable on each deployed environment? For example, I have 2 environments of dev and prod

Thanks for your help!

ryanjbaxter commented 1 year ago

If you move the spring.config.import statement into the application.yaml instead of an environment variable does it work?

spring-cloud-issues commented 1 year ago

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

dyleph commented 1 year ago

Hey, sorry about late. It works when I added spring.config.import into application.yml file

ryanjbaxter commented 1 year ago

This is because when you have spring.config.import in an environment variable spring boot tries to load that configuration before it has even loaded your application.yaml, so it does not know the username or password. We made some changes recently so that the config server takes advantage of spring boots 2 part config data loading so that is why you might see this after the upgrade.

GethDeeo commented 1 year ago

Somewhat slightly related. I'm using Spring Boot/Cloud in Docker with the application getting the URL as environment variable, while the credentials are set via a combination of Docker secrets and configtree. With the changed loading mechanism, this sentence from the docs has become extremely important:

Locations will be processed in the order that they are defined, with later imports taking precedence.

Notice the order in my (now) working client Compose environment snippet:
SPRING_CONFIG_IMPORT: configserver:${CONFIG_SERVER_URL:-http://config-server:8888},configtree:/run/secrets/
(Previously it was reversed. 🤦)