Azure / AppConfiguration

Questions, feedback and samples for Azure App Configuration service
MIT License
227 stars 68 forks source link

Spring Boot AppConfiguration is not respecting Azure CLI credentials. #941

Closed danzuckerberg closed 2 weeks ago

danzuckerberg commented 1 month ago

Background

I am creating a basic demo application using Java Spring Boot. The application has three requirements:

Problem

App Configuration does not respect my Azure CLI credentials for authentication, and fails to start the application. It claims it's using the DefaultAzureCredential, but it doesn't do the credentials chain properly. It gets to Managed Identity and then it attempts that over and over again until it aborts and the application fails to start.

AbstractAzureServiceClientBuilderFactory : No authentication credential configured for class ConfigurationClientBuilder.
AbstractAzureServiceClientBuilderFactory : Will configure the default credential of type DefaultAzureCredential for class com.azure.data.appconfiguration.ConfigurationClientBuilder.
[main] c.a.core.implementation.util.Providers   : Using com.azure.core.http.netty.NettyAsyncHttpClientProvider as the default com.azure.core.http.HttpClientProvider.
[main] c.a.c.h.n.implementation.NettyUtility    : The following is Netty version information that was found on the classpath: 'io.netty:netty-common' version: 4.1.111.Final, 'io.netty:netty-handler' version: 4.1.111.Final, 'io.netty:netty-handler-proxy' version: 4.1.111.Final, 'io.netty:netty-buffer' version: 4.1.111.Final, 'io.netty:netty-codec' version: 4.1.111.Final, 'io.netty:netty-codec-http' version: 4.1.111.Final, 'io.netty:netty-codec-http2' version: 4.1.111.Final, 'io.netty:netty-transport-native-unix-common' version: 4.1.111.Final, 'io.netty:netty-transport-native-epoll' version: 4.1.111.Final, 'io.netty:netty-transport-native-kqueue' version: 4.1.111.Final. The version of azure-core-http-netty being used was built with Netty version 4.1.108.Final and Netty Tcnative version 2.0.65.Final. If your application runs without issue this message can be ignored, otherwise please align the Netty versions used in your application. For more information, see https://aka.ms/azsdk/java/dependency/troubleshoot.
[main] .i.AppConfigurationReplicaClientsBuilder : Connecting to https://myconfigstore.azconfig.io using Azure System Assigned Identity.
[ForkJoinPool.commonPool-worker-1] c.a.i.implementation.IdentityClient      : ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt.
[ForkJoinPool.commonPool-worker-1] c.a.identity.ManagedIdentityCredential   : Azure Identity => ERROR in getToken() call for scopes [https://myconfigstore.azconfig.io/.default]: Managed Identity authentication is not available.

Caused by: java.util.concurrent.ExecutionException: com.azure.identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt.
com.azure.core.http.policy.RetryPolicy   : {"az.sdk.message":"Error resume.","exception":"Managed Identity authentication is not available.","tryCount":0}

c.a.i.implementation.IdentityClient      : ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt.
ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt.
c.m.a.m.ConfidentialClientApplication    : [Correlation ID: 838a2246-f41c-4f9f-97d5-30da7854e17a] Execution of class com.microsoft.aad.msal4j.AcquireTokenByClientCredentialSupplier failed: java.util.concurrent.ExecutionException: com.azure.identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt.
c.a.identity.ManagedIdentityCredential   : Azure Identity => ERROR in getToken() call for scopes [https://myconfigstore.azconfig.io/.default]: Managed Identity authentication is not available.
c.a.c.implementation.AccessTokenCache    : {"az.sdk.message":"Failed to acquire a new access token.","exception":"Managed Identity authentication is not available."}

com.azure.core.http.policy.RetryPolicy   : {"az.sdk.message":"Retry attempts have been exhausted.","exception":"Managed Identity authentication is not available.","tryCount":2}

.i.AppConfigurationPropertySourceLocator : Fail fast is set and there was an error reading configuration from Azure App Configuration store https://myconfigstore.azconfig.io.
o.s.boot.SpringApplication               : Application run failed

Key Vault does respect my Azure CLI credentials, and works out of the box.

c.azure.identity.ChainedTokenCredential  : Azure Identity => Attempted credential EnvironmentCredential is unavailable.
c.azure.identity.ChainedTokenCredential  : Azure Identity => Attempted credential WorkloadIdentityCredential is unavailable.
c.azure.identity.ChainedTokenCredential  : Azure Identity => Attempted credential ManagedIdentityCredential is unavailable.
c.azure.identity.ChainedTokenCredential  : Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable.
c.azure.identity.ChainedTokenCredential  : Azure Identity => Attempted credential IntelliJCredential is unavailable.
c.a.i.implementation.IdentityClient      : Azure CLI Authentication => A token response was received from Azure CLI, deserializing the response into an Access Token.
com.azure.identity.AzureCliCredential    : Azure Identity => getToken() result for scopes [https://vault.azure.net/.default]: SUCCESS
c.azure.identity.ChainedTokenCredential  : Azure Identity => Attempted credential AzureCliCredential returns a token
c.a.c.implementation.AccessTokenCache    : {"az.sdk.message":"Acquired a new access token."}

Project Details

Relevant pom.xml

<properties>
  <java.version>21</java.version>
</properties>

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

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter</artifactId>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-appconfiguration-config</artifactId>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-appconfiguration-config-web</artifactId>
  </dependency>
  <dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>spring-cloud-azure-starter-keyvault-secrets</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
  </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-dependencies</artifactId>
      <version>5.14.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

yml

spring:
  application:
    name: springboot-demo-app
  cloud:
    azure:
      appconfiguration:
        stores:
        - endpoint: https://myconfigstore.azconfig.io
          selects:
          - key-filter: /demo/
      keyvault:
        secret:
          endpoint: https://mykeyvault.vault.azure.net

Alternatives I've Tried

Add credential to yml

I figured if I explicitly skipped managed-identity, since that's where it's getting stuck, it would move on in the chain. However, I get the same errors and the app fails to start.

spring:
  application:
    name: springboot-demo-app
  cloud:
    azure:
      appconfiguration:
        stores:
        - endpoint: https://myconfigstore.azconfig.io
          selects:
          - key-filter: /demo/
        credential:
          managed-identity-enabled: false

Connection String

I have also tried using the connection-string instead of endpoint. This works, but it only authenticates me to the app configuration store, and not the key vault. This is also not a great solution, I want to use DefaultAzureCredential everywhere I can so that the app runs both locally and when deployed to Azure.

spring:
  application:
    name: springboot-demo-app
  cloud:
    azure:
      appconfiguration:
        stores:
          - connection-string: "Endpoint=https://myconfigstore.azconfig.io;Id=myid;Secret=mysecret"
            selects:
            - key-filter: /demo/

Coding it myself

As a sanity check, I wrote my own simple implementation of this and it works perfectly fine. I'd just prefer to take advantage of the ConfigurationProperties() mapping all of the values for me (the whole point of using this library over the sdk)

private final String endpoint = "https://myconfigstore.azconfig.io";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();

ConfigurationClient configurationClient = new ConfigurationClientBuilder().credential(credential).endpoint(endpoint)
        .buildClient();

public String getValue() {
    return configurationClient.getConfigurationSetting("/demo/myvalue", null).getValue();
}

public String getSecret() {
    return configurationClient.getConfigurationSetting("/demo/mysecret", null).getValue();
}

Final thoughts

Can someone please show me where I have this misconfigured? I'm just confused about why Key Vault works right out of the box, but App Configuration doesn't, especially because the logs indicate that App Configuration is using the DefaultAzureCredential.

If this is actually the intended behavior, can someone show me how to work around it so that Azure CLI is a valid authentication method?

Thanks!

btk467 commented 1 month ago

I got success with configuring my spring boot api connected to azure app configuration via connection string.

I am running api’s on local dev boxes and in Azure Spring Apps Service as target.

You will have to do IAM on Azure side.

Your api’s must have identity and have a reader role on keyvault to allow azure app config service to read key vault secrets.

you can use spring profiles to use app configuration labels (tags) if you want your local dev setup matching the target.

I am away from my computer for a couple weeks to provide you some code snippets.

H2H

Best Regards, Victor

On Thu, Jul 18, 2024 at 10:26 AM danzuckerberg @.***> wrote:

Background

I am creating a basic demo application using Java Spring Boot. The application has three requirements:

  • Retrieve App Configuration values (via App Configuration)
  • Retrieve App Configuration Key Vault backed values (via App Configuration)
  • Retrieve Key Vault Secrets (via Key Vault)

Problem

App Configuration does not respect my Azure CLI credentials for authentication, and fails to start the application. It claims it's using the DefaultAzureCredential, but it doesn't do the credentials chain properly. It gets to Managed Identity and then it attempts that over and over again until it aborts and the application fails to start.

AbstractAzureServiceClientBuilderFactory : No authentication credential configured for class ConfigurationClientBuilder. AbstractAzureServiceClientBuilderFactory : Will configure the default credential of type DefaultAzureCredential for class com.azure.data.appconfiguration.ConfigurationClientBuilder. [main] c.a.core.implementation.util.Providers : Using com.azure.core.http.netty.NettyAsyncHttpClientProvider as the default com.azure.core.http.HttpClientProvider. [main] c.a.c.h.n.implementation.NettyUtility : The following is Netty version information that was found on the classpath: 'io.netty:netty-common' version: 4.1.111.Final, 'io.netty:netty-handler' version: 4.1.111.Final, 'io.netty:netty-handler-proxy' version: 4.1.111.Final, 'io.netty:netty-buffer' version: 4.1.111.Final, 'io.netty:netty-codec' version: 4.1.111.Final, 'io.netty:netty-codec-http' version: 4.1.111.Final, 'io.netty:netty-codec-http2' version: 4.1.111.Final, 'io.netty:netty-transport-native-unix-common' version: 4.1.111.Final, 'io.netty:netty-transport-native-epoll' version: 4.1.111.Final, 'io.netty:netty-transport-native-kqueue' version: 4.1.111.Final. The version of azure-core-http-netty being used was built with Netty version 4.1.108.Final and Netty Tcnative version 2.0.65.Final. If your application runs without issue this message can be ignored, otherwise please align the Netty versions used in your application. For more information, see https://aka.ms/azsdk/java/dependency/troubleshoot. [main] .i.AppConfigurationReplicaClientsBuilder : Connecting to https://myconfigstore.azconfig.io using Azure System Assigned Identity. [ForkJoinPool.commonPool-worker-1] c.a.i.implementation.IdentityClient : ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt. [ForkJoinPool.commonPool-worker-1] c.a.identity.ManagedIdentityCredential : Azure Identity => ERROR in getToken() call for scopes [https://myconfigstore.azconfig.io/.default]: Managed Identity authentication is not available.

Caused by: java.util.concurrent.ExecutionException: com.azure.identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt. com.azure.core.http.policy.RetryPolicy : {"az.sdk.message":"Error resume.","exception":"Managed Identity authentication is not available.","tryCount":0}

c.a.i.implementation.IdentityClient : ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt. ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt. c.m.a.m.ConfidentialClientApplication : [Correlation ID: 838a2246-f41c-4f9f-97d5-30da7854e17a] Execution of class com.microsoft.aad.msal4j.AcquireTokenByClientCredentialSupplier failed: java.util.concurrent.ExecutionException: com.azure.identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt. c.a.identity.ManagedIdentityCredential : Azure Identity => ERROR in getToken() call for scopes [https://myconfigstore.azconfig.io/.default]: Managed Identity authentication is not available. c.a.c.implementation.AccessTokenCache : {"az.sdk.message":"Failed to acquire a new access token.","exception":"Managed Identity authentication is not available."}

com.azure.core.http.policy.RetryPolicy : {"az.sdk.message":"Retry attempts have been exhausted.","exception":"Managed Identity authentication is not available.","tryCount":2}

.i.AppConfigurationPropertySourceLocator : Fail fast is set and there was an error reading configuration from Azure App Configuration store https://myconfigstore.azconfig.io. o.s.boot.SpringApplication : Application run failed

Key Vault does respect my Azure CLI credentials, and works out of the box.

c.azure.identity.ChainedTokenCredential : Azure Identity => Attempted credential EnvironmentCredential is unavailable. c.azure.identity.ChainedTokenCredential : Azure Identity => Attempted credential WorkloadIdentityCredential is unavailable. c.azure.identity.ChainedTokenCredential : Azure Identity => Attempted credential ManagedIdentityCredential is unavailable. c.azure.identity.ChainedTokenCredential : Azure Identity => Attempted credential SharedTokenCacheCredential is unavailable. c.azure.identity.ChainedTokenCredential : Azure Identity => Attempted credential IntelliJCredential is unavailable. c.a.i.implementation.IdentityClient : Azure CLI Authentication => A token response was received from Azure CLI, deserializing the response into an Access Token. com.azure.identity.AzureCliCredential : Azure Identity => getToken() result for scopes [https://vault.azure.net/.default]: SUCCESS c.azure.identity.ChainedTokenCredential : Azure Identity => Attempted credential AzureCliCredential returns a token c.a.c.implementation.AccessTokenCache : {"az.sdk.message":"Acquired a new access token."}

Project Details Relevant pom.xml

21 org.springframework.boot spring-boot-starter-parent 3.3.1 org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test com.azure.spring spring-cloud-azure-starter com.azure.spring spring-cloud-azure-appconfiguration-config com.azure.spring spring-cloud-azure-appconfiguration-config-web com.azure.spring spring-cloud-azure-starter-keyvault-secrets org.springframework.boot spring-boot-configuration-processor true com.azure.spring spring-cloud-azure-dependencies 5.14.0 pom import

yml

spring: application: name: springboot-demo-app cloud: azure: appconfiguration: stores:

Alternatives I've Tried Add credential to yml

I figured if I explicitly skipped managed-identity, since that's where it's getting stuck, it would move on in the chain. However, I get the same errors and the app fails to start.

spring: application: name: springboot-demo-app cloud: azure: appconfiguration: stores:

Connection String

I have also tried using the connection-string instead of endpoint. This works, but it only authenticates me to the app configuration store, and not the key vault. This is also not a great solution, I want to use DefaultAzureCredential everywhere I can so that the app runs both locally and when deployed to Azure.

spring: application: name: springboot-demo-app cloud: azure: appconfiguration: stores:

Coding it myself

As a sanity check, I wrote my own simple implementation of this and it works perfectly fine. I'd just prefer to take advantage of the ConfigurationProperties() mapping all of the values for me (the whole point of using this library over the sdk)

private final String endpoint = "https://myconfigstore.azconfig.io"; DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();

ConfigurationClient configurationClient = new ConfigurationClientBuilder().credential(credential).endpoint(endpoint) .buildClient();

public String getValue() { return configurationClient.getConfigurationSetting("/demo/myvalue", null).getValue(); }

public String getSecret() { return configurationClient.getConfigurationSetting("/demo/mysecret", null).getValue(); }

Final thoughts

Can someone please show me where I have this misconfigured? I'm just confused about why Key Vault works right out of the box, but App Configuration doesn't, especially because the logs indicate that App Configuration is using the DefaultAzureCredential.

If this is actually the intended behavior, can someone show me how to work around it so that Azure CLI is a valid authentication method?

Thanks!

— Reply to this email directly, view it on GitHub https://github.com/Azure/AppConfiguration/issues/941, or unsubscribe https://github.com/notifications/unsubscribe-auth/AF462ZKKSIU6LPXAYC2S2DLZM7NCLAVCNFSM6AAAAABLC5JU5CVHI2DSMVQWIX3LMV43ASLTON2WKOZSGQYTMNZSHEZDCMA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

danzuckerberg commented 1 month ago

Thank you for the reply. As I mentioned in my post, I was able to get it working with the connection string but that method has several drawbacks.

This is not an issue with IAM on the Azure side, I have full access to both the App Configuration Store and the Key Vault (which is working as expected).

My issue is with this library not using the DefaultAzureCredentials chain for App Configuration.

mrm9084 commented 1 month ago

@danzuckerberg, I don't think we document anywhere that we use a DefaultAzureCredential by default for providing an Endpoint. We only use ManagedIdentityCredential by default if nothing else was provided.

We support a few ways of providing a credential, which should also work with key vault. See: https://learn.microsoft.com/en-us/azure/azure-app-configuration/howto-convert-to-the-new-spring-boot?tabs=spring-boot-3#using-client-customizers

We should support any credential method here, https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/authentication#other-credential-types.

If I had a guess there might be a miss documentation of us doing the top part of that doc. We've always defaulted to a System Assigned Managed Identity, we have talked about changing but never have.

danzuckerberg commented 1 month ago

@mrm9084 thank you for the quick response. You're correct in that it's not explicitly documented. I assumed the App Configuration service would conveniently work the same way Key Vault does. I also observed the following in the logs when attempting to run the application:

AbstractAzureServiceClientBuilderFactory : No authentication credential configured for class ConfigurationClientBuilder.
AbstractAzureServiceClientBuilderFactory : Will configure the default credential of type DefaultAzureCredential for class com.azure.data.appconfiguration.ConfigurationClientBuilder.

I forgot to mention in my post that I also tried using a ConfigurationClientCustomerizer but it didn't have an effect.

@Configuration
public class ConfigurationClientCustomizerImpl implements ConfigurationClientCustomizer {

    @Override
    public void customize(ConfigurationClientBuilder builder, String endpoint) {
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
        builder.credential(credential);
    }
}
mrm9084 commented 1 month ago

@danzuckerberg, I think there is a slight oversight when we tried making our App Config Spring library work better with the other Spring libraries. We use there builder to get a client, but we have different defaults and the SDK just overrides there default with ours.

We are working on a new Major version, we are discussing updating this then.

Something about your code doesn't look right. I don't think Spring is picking it up. Have you tried adding an @Component to it. I usually just add it as an @Bean to an existing @Configuration it shouldn't really be an @Configuration itself.

danzuckerberg commented 1 month ago

Hey @mrm9084 you're right, that configuration was not valid. That said, I tried two other options and they didn't work either. Clearly, I'm missing something

Option 1:

@Configuration
public class AzureCredentialsConfig {

    @Bean
    ConfigurationClientCustomizer configurationClientCustomizer() {
        return new ConfigurationClientCustomizer() {
            @Override
            public void customize(ConfigurationClientBuilder builder, String endpoint) {
                DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
                builder.credential(credential);
            }
        };
    }
}

Option 2 (create an Impl class and wire it as a bean in a @Configuration)

public class ConfigurationClientCustomizerImpl implements ConfigurationClientCustomizer {

    @Override
    public void customize(ConfigurationClientBuilder builder, String endpoint) {
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
        builder.credential(credential);
    }
}
@Configuration
public class AzureCredentialsConfig {

    @Bean
    ConfigurationClientCustomizer configurationClientCustomizer() {
        return new ConfigurationClientCustomizerImpl();
    }
}
mrm9084 commented 1 month ago

How do you have AzureCredentialsConfig wired up? Do you have @AutoConfiguration setup or a spring.factories file pointing to it?

mrm9084 commented 1 month ago

I can't find a sample that show it in action, but this Integration test is rather basic and uses it. https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/spring/spring-cloud-azure-integration-test-appconfiguration-config

danzuckerberg commented 1 month ago

Yeah, it's wired up. I use the SpringBootApplication annotation and have it scanning all of my base packages.

@SpringBootApplication(scanBasePackages = { "com.demo.demo" })

I can also hit my actuator/beans endpoint and see the bean in context (I think this is correct?)

Does it need to have a specific name?

"configurationClientCustomizer": {
    "aliases": [],
    "scope": "singleton",
    "type": "com.demo.demo.config.ConfigurationClientCustomizerImpl",
    "resource": "class path resource [com/demo/demo/config/AzureCredentialsConfig.class]",
    "dependencies": [
        "azureCredentialsConfig"
    ]
},
mrm9084 commented 1 month ago

Does anything seem off compared to the linked sample? And did the error message change?

Also, are you using key vault references. If so, you would need to extend SecretClientCustomizer too. As it would use that client.

mrm9084 commented 1 month ago

It doesn't need any specific name, it picks up it by the interface class.

danzuckerberg commented 1 month ago

Yeah I have it set up like the test project. I renamed a couple of things but here's what I have compared to the test project.

AzureCredentialsCustomClient.java (similar to CustomClient.java)

public class AzureCredentialsCustomClient implements ConfigurationClientCustomizer, SecretClientCustomizer {

    @Override
    public void customize(ConfigurationClientBuilder builder, String endpoint) {
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
        builder.credential(credential);
    }

    @Override
    public void customize(SecretClientBuilder builder, String endpoint) {
        DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
        builder.credential(credential);
    }

}

AzureCredentialsConfig.java (similar to AppConfiguration.java)

@Configuration
public class AzureCredentialsConfig {

    @Bean
    AzureCredentialsCustomClient azureCredentials() {
        return new AzureCredentialsCustomClient();
    }
}

The bean is loaded into context:

"azureCredentials": {
    "aliases": [],
    "scope": "singleton",
    "type": "com.demo.demo.config.AzureCredentialsCustomClient",
    "resource": "class path resource [com/demo/demo/config/AzureCredentialsConfig.class]",
    "dependencies": [
        "azureCredentialsConfig"
    ]
},

Still stuck in a loop trying to get Managed Identity:

Caused by: com.azure.identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Connection to IMDS endpoint cannot be established, Network is unreachable: getsockopt.
zhenlan commented 4 weeks ago

@mrm9084 any updates for this issue?

mrm9084 commented 4 weeks ago

@danzuckerberg, have you had any luck on this? I have been unable to replicate after trying quite a few things. My only thought is that maybe that your AzureCredentialsCustomClient Bean is not being created till after we create our stuff. But that should only be the case if you deprioritized it in some way.

Also, to answer one of your above questions, we don't look for a bean by name, we do it by type we grab the bean of ConfigurationClientCustomizer.

danzuckerberg commented 3 weeks ago

@mrm9084 still no luck on the workaround. I even threw it over the fence to a more seasoned Java developer to try in his project and it doesn't work for him either.

This is preventing us from running the application locally (blocker). The connection string approach only authenticates you to the app configuration store (and includes a secret so obviously we can't commit that), so if you have any key vault-backed values (which we do), it will fail because the connection string doesn't authenticate you to the key vault. Even if this did work, it would require us to maintain two sets of configurations (local/nonlocal), which is fine, but not ideal.

That said, when we deploy the application to an environment, it works as expected because our VM has a managed identity.

Back to my op, if this would just use the DefaultAzureCredential it would work out of the box, both locally and when deployed, and my developers can just use their own identities via az login

mrm9084 commented 2 weeks ago

@danzuckerberg, I'm not sure what is going on. Here is a sample that shows how it should work. Can you let me know if it works for you and if anything is different than what you are trying to do?

danzuckerberg commented 2 weeks ago

@mrm9084 thank you, we will try it out. At first glance, I'm noticing that the only difference is the JAR that's being brought in.

We're using:

<dependency>
   <groupId>com.azure.spring</groupId>
   <artifactId>spring-cloud-azure-appconfiguration-config-web</artifactId>
</dependency>

But the sample is using:

<dependency>
   <groupId>com.azure.spring</groupId>
   <artifactId>spring-cloud-azure-starter-appconfiguration-config</artifactId>
</dependency>

What is the difference/purpose for having distinct JARs here? Are we supposed to be using the starter JARs? The code wrote and the code you wrote is identical in this case, so it might be as simple as swapping it out in our POM?

mrm9084 commented 2 weeks ago

spring-cloud-azure-starter-appconfiguration-config is just a starter library. It has no code, just contains spring-cloud-azure-appconfiguration-config-web and spring-cloud-azure-feature-management-web in a single pom file.

danzuckerberg commented 2 weeks ago

@mrm9084 thank you for that clarification. I cloned the sample repo and was able to get it working as expected.

The piece we were missing is the spring.factories file that specifies the load order. The documentation doesn't mention that file anywhere, but I noticed it in both the integration test and sample app you sent us.

Once I plugged that into my own application, it started working as expected. For a sanity check, I removed that file from the sample application you provided, and it broke/stopped working, confirming the file is the missing piece.

mrm9084 commented 2 weeks ago

I this can be closed then. A new issue can be created if any other issues come up.