Skip to content

[BUG] A single disabled certificate in Key Vault breaks JCA KeyStore initialization for the entire vault, even for unrelated SSL bundles #49692

Description

@vplme

Describe the bug
When an Azure Key Vault contains multiple certificates and any one of them is disabled, the JCA KeyStore (AzureKeyVault / DKS) fails to initialize — even when the disabled certificate is not the alias referenced by the application's Spring SSL bundle.

KeyVaultCertificates.refreshCertificates() eagerly iterates over every alias in the vault and fetches the key, certificate, and certificate chain for each one. There is no per-certificate error handling, so a 403 Forbidden returned for a single disabled certificate propagates up, aborts KeyVaultKeyStore.<init>, and prevents the SSL bundle from being created. The Spring Boot application then fails to start.

The net effect: one disabled certificate takes down the whole application, regardless of whether that certificate is actually used.

Exception or Stack Trace

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.server.autoconfigure.servlet.ServletWebServerFactoryCustomizer]: Factory method 'servletWebServerFactoryCustomizer' threw exception with message: Error creating bean with name 'sslBundleRegistry' defined in class path resource [org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.class]: Failed to instantiate [org.springframework.boot.ssl.DefaultSslBundleRegistry]: Factory method 'sslBundleRegistry' threw exception with message: Failed to load Key Vault keystore for SSL bundle 'client-bundle'
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:183) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:72) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:152) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-7.0.8.jar:7.0.8]
	... 33 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sslBundleRegistry' defined in class path resource [org/springframework/boot/autoconfigure/ssl/SslAutoConfiguration.class]: Failed to instantiate [org.springframework.boot.ssl.DefaultSslBundleRegistry]: Factory method 'sslBundleRegistry' threw exception with message: Failed to load Key Vault keystore for SSL bundle 'client-bundle'
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:645) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1360) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1192) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:565) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:333) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:371) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:331) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:201) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:229) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1769) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory$DependencyObjectProvider.getIfAvailable(DefaultListableBeanFactory.java:2575) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.boot.web.server.autoconfigure.servlet.ServletWebServerConfiguration.servletWebServerFactoryCustomizer(ServletWebServerConfiguration.java:69) ~[spring-boot-web-server-4.0.7.jar:4.0.7]
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:155) ~[spring-beans-7.0.8.jar:7.0.8]
	... 36 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.ssl.DefaultSslBundleRegistry]: Factory method 'sslBundleRegistry' threw exception with message: Failed to load Key Vault keystore for SSL bundle 'client-bundle'
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:183) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:72) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:152) ~[spring-beans-7.0.8.jar:7.0.8]
	at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-7.0.8.jar:7.0.8]
	... 52 common frames omitted
Caused by: java.lang.RuntimeException: Failed to load Key Vault keystore for SSL bundle 'client-bundle'
	at com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca.AzureKeyVaultSslBundleRegistrar.initilizeKeyVaultKeyStore(AzureKeyVaultSslBundleRegistrar.java:158) ~[spring-cloud-azure-autoconfigure-7.3.0.jar:7.3.0]
	at com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca.AzureKeyVaultSslBundleRegistrar.lambda$registerBundles$0(AzureKeyVaultSslBundleRegistrar.java:91) ~[spring-cloud-azure-autoconfigure-7.3.0.jar:7.3.0]
	at java.base/java.util.HashMap.forEach(HashMap.java:1430) ~[na:na]
	at com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca.AzureKeyVaultSslBundleRegistrar.registerBundles(AzureKeyVaultSslBundleRegistrar.java:80) ~[spring-cloud-azure-autoconfigure-7.3.0.jar:7.3.0]
	at org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration.lambda$sslBundleRegistry$0(SslAutoConfiguration.java:64) ~[spring-boot-autoconfigure-4.0.7.jar:4.0.7]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:186) ~[na:na]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1604) ~[na:na]
	at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:395) ~[na:na]
	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:261) ~[na:na]
	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:261) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:571) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:560) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:153) ~[na:na]
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:176) ~[na:na]
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:265) ~[na:na]
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:632) ~[na:na]
	at org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration.sslBundleRegistry(SslAutoConfiguration.java:64) ~[spring-boot-autoconfigure-4.0.7.jar:4.0.7]
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:565) ~[na:na]
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:155) ~[spring-beans-7.0.8.jar:7.0.8]
	... 55 common frames omitted
Caused by: java.security.KeyStoreException: DKS not found
	at java.base/java.security.KeyStore.getInstance(KeyStore.java:926) ~[na:na]
	at com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca.AzureKeyVaultSslBundleRegistrar.initilizeKeyVaultKeyStore(AzureKeyVaultSslBundleRegistrar.java:152) ~[spring-cloud-azure-autoconfigure-7.3.0.jar:7.3.0]
	... 74 common frames omitted
Caused by: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: DKS, provider: AzureKeyVault, class: com.azure.security.keyvault.jca.KeyVaultKeyStore)
	at java.base/java.security.Provider$Service.newInstance(Provider.java:1758) ~[na:na]
	at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:227) ~[na:na]
	at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:197) ~[na:na]
	at java.base/java.security.Security.getImpl(Security.java:762) ~[na:na]
	at java.base/java.security.KeyStore.getInstance(KeyStore.java:923) ~[na:na]
	... 75 common frames omitted
Caused by: java.lang.RuntimeException: Fail to get response from Key Vault because return http status code is 403. It can be caused by missing permissions or roles. To know how to add permissions or roles, see https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/keyvault/azure-security-keyvault-jca#prerequisites.
	at com.azure.security.keyvault.jca.implementation.utils.HttpUtil.lambda$createResponseHandler$0(HttpUtil.java:154) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.shaded.org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:247) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.shaded.org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:188) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.shaded.org.apache.hc.client5.http.impl.classic.CloseableHttpClient.execute(CloseableHttpClient.java:162) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.utils.HttpUtil.get(HttpUtil.java:73) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.KeyVaultClient.getKey(KeyVaultClient.java:455) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.lambda$refreshCertificates$0(KeyVaultCertificates.java:164) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1604) ~[na:na]
	at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.refreshCertificates(KeyVaultCertificates.java:163) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.refreshCertificatesIfNeeded(KeyVaultCertificates.java:147) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.getAliases(KeyVaultCertificates.java:106) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at com.azure.security.keyvault.jca.KeyVaultKeyStore.<init>(KeyVaultKeyStore.java:151) ~[azure-security-keyvault-jca-2.11.0.jar:2.11.0]
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[na:na]
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483) ~[na:na]
	at java.base/java.security.Provider$Service.newInstanceOf(Provider.java:1769) ~[na:na]
	at java.base/java.security.Provider$Service.newInstanceUtil(Provider.java:1776) ~[na:na]
	at java.base/java.security.Provider$Service.newInstance(Provider.java:1751) ~[na:na]
	... 79 common frames omitted

To Reproduce
Steps to reproduce the behavior:

  1. Create a Key Vault with two enabled self-signed certificates: client-cert-active and client-cert-unused.

  2. Configure a Spring SSL bundle that references only client-cert-active (see code snippet below).

  3. Start the app — it starts successfully (both certs enabled).

  4. Disable the unused certificate:

    az keyvault certificate set-attributes --vault-name <vault> --name client-cert-unused --enabled false
  5. Start the app again — it fails to start with a 403, even though client-cert-unused is never referenced.

A complete, runnable reproduction (Terraform to provision the vault + two certs, a minimal Spring Boot app, and a disable-cert.sh helper) is available here: https://github.com/vplme/azure-jca-spring-reproduction

Code Snippet

application.yml:

spring:
  cloud:
    azure:
      keyvault:
        jca:
          vaults:
            my-vault:
              endpoint: ${AZURE_KEY_VAULT_URI}
  ssl:
    bundle:
      keyvault:
        client-bundle:
          for-client-auth: true
          key:
            alias: client-cert-active   # the only alias the app needs
          keystore:
            keyvault-ref: my-vault

Expected behavior
The SSL bundle references client-cert-active only, so the bundle should initialize successfully as long as that alias resolves to a valid, enabled certificate. A disabled certificate elsewhere in the vault should be skipped (and ideally logged at WARN), not cause the whole keystore load to fail.

Screenshots
N/A

Setup (please complete the following information):

  • OS: macOS 26.4.1
  • IDE: N/A (Maven CLI, ./mvnw spring-boot:run)
  • Library/Libraries: com.azure:azure-security-keyvault-jca:2.11.0 (transitive), com.azure.spring:spring-cloud-azure-starter-keyvault-jca:7.3.0, com.azure.spring:spring-cloud-azure-dependencies:7.3.0 (BOM)
  • Java version: 21+ (reproduced on 25.0.1)
  • App Server/Environment: embedded Tomcat 11 (Spring Boot)
  • Frameworks: Spring Boot 4.0.7, Spring Framework 7.0.8

If you suspect a dependency version mismatch (e.g. you see NoClassDefFoundError, NoSuchMethodError or similar), please check out Troubleshoot dependency version conflict article first. If it doesn't provide solution for the problem, please provide:

  • verbose dependency tree (mvn dependency:tree -Dverbose)
  • exception message, full stack trace, and any available logs

Additional context

Information Checklist
Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report

  • Bug Description Added
  • Repro Steps Added
  • Setup information Added

Metadata

Metadata

Assignees

No one assigned

    Labels

    ClientThis issue points to a problem in the data-plane of the library.KeyVaultcustomer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK teamquestionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Untriaged

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions