Current version is 3.14.0, click here for the index

Azure Key Vault Certificates Spring Boot starter client library for Java

Azure Key Vault Certificates Spring Boot Starter is Spring starter for Azure Key Vault Certificates, it allows you to securely manage and tightly control your certificates.

Package (Maven) | API reference documentation | Samples

Getting started

Prerequisites

Include the package

  1. [Add azure-spring-boot-bom].
  2. Add dependency. <version> can be skipped because we already add azure-spring-boot-bom`.
<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId>
</dependency>

Log into Azure

  az login

Create a resource group

To create an Azure resource group, use the command line below. Please replace myresourcegroup with a unique resource group name.

  export RESOURCE_GROUP=myresourcegroup
  az group create -l westus -n ${RESOURCE_GROUP}

Create an Azure Key Vault

To create an Azure Key Vault use the command line below. Please replace mykevault with a unique key vault name and store vaultUri returned for later use.

  export KEY_VAULT=mykeyvault
  az keyvault create --name ${KEY_VAULT} -g ${RESOURCE_GROUP}

Create a self-signed certificate

To create a self-signed certificate use the command line below:

  export CERTIFICATE_ALIAS=self-signed
  az keyvault certificate create --vault-name ${KEY_VAULT} \
    -n ${CERTIFICATE_ALIAS} -p "$(az keyvault certificate get-default-policy)"

Key concepts

This starter provides a KeyStore (AzureKeyVault) which can get certificates from JRE / specific path / Azure Key Vault / classpath .

Examples

Server side SSL

Option 1 - Use an Azure client ID and Azure client secret to identify your app

To create an Azure client and an Azure client secret use the command line below. Please store the values returned such as appId, password, tenant.

  export APP_NAME=myApp
  az ad sp create-for-rbac --skip-assignment --name ${APP_NAME}
  export CLIENT_ID=$(az ad sp list --display-name ${APP_NAME} | jq -r '.[0].appId')
  az ad app credential reset --id ${CLIENT_ID}

Store the values returned, which will be used later.

Make sure the client-id can access target Key Vault. Here are steps to configure access policy:

To grant access, use the command line below:

  az keyvault set-policy --name ${KEY_VAULT} \
        --spn ${CLIENT_ID} \
        --secret-permissions get list \
        --certificate-permissions get list \
        --key-permissions get list

Add the following items to your application.yml:

azure:
  keyvault:
    uri:                 # The URI to the Azure Key Vault used. The vaultUri returned from a previous step
    tenant-id:           # The Tenant ID for your Azure Key Vault (needed if you are not using managed identity). The tenant returned from a previous step.
    client-id:           # The Client ID that has been setup with access to your Azure Key Vault (needed if you are not using managed identity). The appId returned from a previous step.  
    client-secret:       # The Client Secret that will be used for accessing your Azure Key Vault (needed if you are not using managed identity). The password returned from a previous step.
server:
  port: 8443
  ssl:
    key-alias:           # The alias corresponding to the certificate in Azure Key Vault. The certificate created in a previous step.
    key-store-type: AzureKeyVault  # The keystore type that enables the use of Azure Key Vault for your server-side SSL certificate.

Option 2 - Use a managed identity to identify your app.

If you use managed identity, you need deploy your app on the Azure Spring Cloud or in Azure virtual machine, please refer to Deploy Application Azure Spring Cloud and Azure Spring Cloud TLS If you deploy your app on the Azure Spring Cloud, please refer to the following steps: Firstly, you need have an Azure Spring Cloud instance. If you don't have one, you can create it via the command line below:

  export AZURE_SPRING_CLOUD_INSTANCE=myspringcloundinstance
  az spring-cloud create --name ${AZURE_SPRING_CLOUD_INSTANCE} --resource-group ${RESOURCE_GROUP}

Secondly, you need create an Apps instance in the Azure Spring Cloud instance via the command line below:

  export CLOUD_APP_INSTANCE=myappinstance
  az spring-cloud app create --name ${CLOUD_APP_INSTANCE} --resource-group ${RESOURCE_GROUP}  --service ${AZURE_SPRING_CLOUD_INSTANCE} --assign-endpoint true

Thirdly, assign a managed identity to Apps instance, use the command line below and store the value returned for later use:

  az spring-cloud app identity assign --name ${CLOUD_APP_INSTANCE} -g ${RESOURCE_GROUP} -s ${AZURE_SPRING_CLOUD_INSTANCE}
  export MANAGED_IDENTITY=$(az spring-cloud app show \
    --name ${SPRING_CLOUD_APP} --query identity.principalId --output tsv -g ${RESOURCE_GROUP} -s ${AZURE_SPRING_CLOUD_INSTANCE})
  echo ${MANAGED_IDENTITY}

Fourthly, enable TLS for your Apps instance, use the command line below:

  az spring-cloud app update --enable-end-to-end-tls -n ${CLOUD_APP_INSTANCE} -s ${AZURE_SPRING_CLOUD_INSTANCE} -g ${RESOURCE_GROUP}

Make sure the managed identity can access target Key Vault. To grant access use the command line below:

  az keyvault set-policy --name ${KEY_VAULT} \
        --object-id ${MANAGED_IDENTITY} \
        --key-permissions get list \
        --secret-permissions get list \
        --certificate-permissions get list

Add the following items to your application.yml:

azure:
  keyvault:
    uri: <the URI of the Azure Key Vault to use>
#    managed-identity: #  managed identity to use, returned from a previous step. If empty, then system-assigned managed identity will be used.
server:
  ssl:
    key-alias: <the name of the certificate in Azure Key Vault to use>
    key-store-type: AzureKeyVault

Client side SSL

Using a client ID and client secret

Add the following items to your application.yml:

azure:
  keyvault:
    uri:                 # The URI to the Azure Key Vault used
    tenant-id:           # The Tenant ID for your Azure Key Vault (needed if you are not using managed identity).
    client-id:           # The Client ID that has been setup with access to your Azure Key Vault (needed if you are not using managed identity).
    client-secret:       # The Client Secret that will be used for accessing your Azure Key Vault (needed if you are not using managed identity).

Make sure the client-id can access target Key Vault.

Configure a RestTemplate bean which set the AzureKeyVault as trust store:

@Bean
public RestTemplate restTemplateWithTLS() throws Exception {
    KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
    KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
        System.getProperty("azure.keyvault.uri"),
        System.getProperty("azure.keyvault.tenant-id"),
        System.getProperty("azure.keyvault.client-id"),
        System.getProperty("azure.keyvault.client-secret"));
    azureKeyVaultKeyStore.load(parameter);
    SSLContext sslContext = SSLContexts.custom()
                                       .loadTrustMaterial(azureKeyVaultKeyStore, null)
                                       .build();
    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
                                                                              (hostname, session) -> true);
    CloseableHttpClient httpClient = HttpClients.custom()
                                                .setSSLSocketFactory(socketFactory)
                                                .build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(requestFactory);
}

Using a managed identity

If you are using managed identity instead of App registration, add the following items to your application.yml:

azure:
  keyvault:
    uri: <the URI of the Azure Key Vault to use>
#    managed-identity:  # client-id of the user-assigned managed identity to use. If empty, then system-assigned managed identity will be used.

Make sure the managed identity can access target Key Vault.

Configure a RestTemplate bean which set the AzureKeyVault as trust store:

@Bean
public RestTemplate restTemplateWithTLS() throws Exception {
    KeyStore trustStore = KeyStore.getInstance("AzureKeyVault");
    KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
        System.getProperty("azure.keyvault.uri"),
        System.getProperty("azure.keyvault.managed-identity"));
    trustStore.load(parameter);
    SSLContext sslContext = SSLContexts.custom()
                                       .loadTrustMaterial(trustStore, null)
                                       .build();
    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
        (hostname, session) -> true);
    CloseableHttpClient httpClient = HttpClients.custom()
                                                .setSSLSocketFactory(socketFactory)
                                                .build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(requestFactory);
}

Enable mutual SSL (mTLS).

Step 1. On the server side, add the following items to your application.yml:

server:
  ssl:
    client-auth: need
    trust-store-type: AzureKeyVault

Step 2. On the client side, update RestTemplate. Example:

@Bean
public RestTemplate restTemplateWithMTLS() throws Exception {
    KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
    KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
        System.getProperty("azure.keyvault.uri"),
        System.getProperty("azure.keyvault.tenant-id"),
        System.getProperty("azure.keyvault.client-id"),
        System.getProperty("azure.keyvault.client-secret"));
    azureKeyVaultKeyStore.load(parameter);
    SSLContext sslContext = SSLContexts.custom()
                                       .loadTrustMaterial(azureKeyVaultKeyStore, null)
                                       .loadKeyMaterial(azureKeyVaultKeyStore, "".toCharArray(), new ClientPrivateKeyStrategy())
                                       .build();
    SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
        (hostname, session) -> true);
    CloseableHttpClient httpClient = HttpClients.custom()
                                                .setSSLSocketFactory(socketFactory)
                                                .build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

    return new RestTemplate(requestFactory);
}

private static class ClientPrivateKeyStrategy implements PrivateKeyStrategy {
    @Override
    public String chooseAlias(Map<String, PrivateKeyDetails> map, Socket socket) {
        return "self-signed"; // It should be your certificate alias used in client-side
    }
}

Configuring Spring Cloud Gateway

To configure Spring Cloud Gateway for outbound SSL, add the following configuration:

azure:
  keyvault:
    uri: <the URI of the Azure Key Vault to use>
    jca: 
      overrideTrustManagerFactory: true

Note: if any of your routes point to a service where the FQDN does not match the issued certificate you will need to disable hostname verification. This will be the case if your service is dynamically assigned a hostname by the hosting platform you use. In this particular case add the configuration below to disable hostname verification:

azure:
  keyvault:
    jca:
      disableHostnameVerification: true

If you are developing you can completely disable the certificate and hostname validation altogether by using the configuration below. Note this is NOT recommended for production!

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          useInsecureTrustManager: true

Refresh certificate periodically

KeyVaultKeyStore can fetch certificates from KeyVault periodically if the following property is configured:

azure:
  keyvault:
    jca:
       certificates-refresh-interval-in-ms: 1800000

Its value is 0(ms) by default, and certificate will not automatically refresh when its value <= 0.

Refresh certificates when have un trust certificate

When the inbound certificate is not trusted, the KeyVaultKeyStore can fetch certificates from KeyVault if the following property is configured:

azure:
  keyvault:
    jca:
      refresh-certificates-when-have-un-trust-certificate: true

Note: If you set refresh-certificates-when-have-un-trust-certificate=true, your server will be vulnerable to attack, because every untrusted certificate will cause your application to send a re-acquire certificate request.

Specific path certificates

AzureKeyVault keystore will load certificates in the specific path:

well-know path: /etc/certs/well-known/ custom path: /etc/certs/custom/ The 2 paths can be configured by these propreties:

azure:
  cert-path:
    well-known:     # The file location where you store the well-known certificate
    custom:         # The file location where you store the custom certificate

Classpath certificates

AzureKeyVault keystore will load certificates in the classpath.

Add the certificates to src/main/resources/keyvault as classpath certificates.

Notes: 1. The alias (certificate name) is constructed from the filename of the certificate (minus the extension). So if your filename is mycert.x509 the certificate will be added with the alias of mycert. 2. The priority order of the certificates is: 1. Certificates from JRE. 2. Certificates from well-known file path. 3. Certificates from custom file path. 4. Certificates from Azure Key Vault. 5. Certificates from classpath.

Key-Less certificates

You can set the private key as [non-exportable] to ensure the security of the key.

Note if you want to use key less certificate, you must add sign permission.

You can add permission in portal:

Or add permission by cli command:

  az keyvault set-policy --name ${KEY_VAULT} \
        --object-id ${MANAGED_IDENTITY} \
        --key-permissions get list sign\
        --secret-permissions get list \
        --certificate-permissions get list

Supported key type

Content Type | Key Type | Key Size or Elliptic curve name | Sign algorithm | Support | -------------|----------|---------------------------------|---------------- |-------- | PKCS #12 | RSA | 2048 | RSASSA-PSS | ✔ | PKCS #12 | RSA | 3072 | RSASSA-PSS | ✔ | PKCS #12 | RSA | 4096 | RSASSA-PSS | ✔ | PKCS #12 | EC | P-256 | SHA256withECDSA | ✔ | PKCS #12 | EC | P-384 | SHA384withECDSA | ✔ | PKCS #12 | EC | P-521 | SHA512withECDSA | ✔ | PKCS #12 | EC | P-256K | | ✘ | PEM | RSA | 2048 | RSASSA-PSS | ✔ | PEM | RSA | 3072 | RSASSA-PSS | ✔ | PEM | RSA | 4096 | RSASSA-PSS | ✔ | PEM | EC | P-256 | SHA256withECDSA | ✔ | PEM | EC | P-384 | SHA384withECDSA | ✔ | PEM | EC | P-521 | SHA512withECDSA | ✔ | PEM | EC | P-256K | | ✘ |

Troubleshooting

Logging setting

Please refer to [spring logging document] to get more information about logging.

Logging setting examples

  • Example: Setting logging level of hibernate
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

Next steps

The following section provide a sample project illustrating how to use the starter.

More sample code

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.

Please follow instructions here to build from source or contribute.

Packages 
Package Description
com.azure.spring.security.keyvault.certificates.starter
The Azure Key Vault Certificate Spring Boot starter package.