# Azure Key Vault Encryption

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FtZIEOPkkqOXRYguSANka%2Fksm-azure.jpg?alt=media&#x26;token=ce2d93d5-12bf-405f-9a53-9c348ad52bcf" alt=""><figcaption></figcaption></figure>

Keeper Secrets Manager integrates with Azure Key Vault in order to provide encryption for Keeper Secrets Manager configuration files. With this integration, you can protect connection details on your machine while taking advantage of Keeper's zero-knowledge encryption of all your secret credentials.

## Features

* Encrypt and Decrypt your Keeper Secrets Manager configuration files with Azure Key Vault.
* Protect against unauthorized access to your Secrets Manager connections.
* Requires only minor changes to code for immediate protection. Works with all Keeper Secrets Manager SDK functionality.
* Supports RSA Asymmetric keys from Azure.

## Prerequisites

{% tabs %}
{% tab title="Java" %}

* Supports the Java/Kotlin [Secrets Manager SDK.](https://docs.keeper.io/en/keeperpam/secrets-manager/developer-sdk-library/java-sdk)
* Requires Azure packages: [`azure-identity`](https://mvnrepository.com/artifact/com.azure/azure-identity/1.18.1) and [`azure-keyvault-keys`](https://mvnrepository.com/artifact/com.azure/azure-security-keyvault-keys/4.10.4).
* Works with just RSA key types with `WrapKey` and `UnWrapKey` permissions.
  {% endtab %}

{% tab title="JavaScript" %}

* Supports the [JavaScript Secrets Manager SDK](https://docs.keeper.io/en/keeperpam/secrets-manager/developer-sdk-library/javascript-sdk)
* Azure dependencies ([`@azure/identity`](https://www.npmjs.com/package/@azure/identity), [`@azure/keyvault-keys`](https://www.npmjs.com/package/@azure/keyvault-keys)) are bundled — no separate install required
* Works with just RSA key types with `WrapKey` and `UnWrapKey` permissions.
  {% endtab %}

{% tab title="Python" %}

* Supports the [Python Secrets Manager SDK](https://docs.keeper.io/en/keeperpam/secrets-manager/developer-sdk-library/python-sdk)
* Requires package [azure-identity](https://pypi.org/project/azure-identity/) and [azure-keyvault-keys](https://pypi.org/project/azure-keyvault-keys/)
* Works with just RSA key types with `WrapKey` and `UnWrapKey` permissions.
  {% endtab %}

{% tab title=".Net" %}

* Supports the [.Net Secrets Manager SDK](https://docs.keeper.io/en/keeperpam/secrets-manager/developer-sdk-library/.net-sdk)
* Supports dotnet version `net9.0`
* Requires Azure packages: [`Azure.Identity`](https://www.nuget.org/packages/Azure.Identity/1.13.2) and [`Azure.Security.KeyVault.Keys`](https://www.nuget.org/packages/Azure.Security.KeyVault.Keys/4.7.0)
* Works with just RSA key types with `WrapKey` and `UnWrapKey` permissions.
  {% endtab %}
  {% endtabs %}

## Setup

### 1. Install Module

{% tabs %}
{% tab title="Java" %}
Setting up project using Gradle or Maven

**Gradle**

<pre><code>repositories {
  mavenCentral()
}

dependencies {
<strong>  implementation("com.keepersecurity.secrets-manager:azurekv:1.0.0")
</strong>  implementation("com.keepersecurity.secrets-manager:core:17.1.1")
  implementation("com.azure:azure-identity:1.18.1")
  implementation("com.azure:azure-security-keyvault-keys:4.10.4")
  implementation("com.fasterxml.jackson.core:jackson-databind:2.18.2")
  implementation("com.fasterxml.jackson.core:jackson-core:2.18.2")
  implementation("com.google.code.gson:gson:2.12.1")
  implementation("org.slf4j:slf4j-api:1.7.32"){
        exclude("org.slf4j:slf4j-log4j12")
    }
  implementation("ch.qos.logback:logback-classic:1.2.6")
  implementation("ch.qos.logback:logback-core:1.2.6")
  implementation("org.bouncycastle:bc-fips:2.1.1")
}
</code></pre>

**Maven**

<pre class="language-xml"><code class="lang-xml">&#x3C;!-- KMS-core -->
 &#x3C;dependency>
     &#x3C;groupId>com.keepersecurity.secrets-manager&#x3C;/groupId>
     &#x3C;artifactId>azurekv&#x3C;/artifactId>
     &#x3C;version>1.0.0&#x3C;/version>
&#x3C;/dependency>
&#x3C;dependency>
     &#x3C;groupId>com.keepersecurity.secrets-manager&#x3C;/groupId>
     &#x3C;artifactId>core&#x3C;/artifactId>
     &#x3C;version>17.1.1&#x3C;/version>
 &#x3C;/dependency>

 &#x3C;!-- Azure-identity -->
   &#x3C;dependency>
       &#x3C;groupId>com.azure&#x3C;/groupId>
       &#x3C;artifactId>azure-identity&#x3C;/artifactId>
       &#x3C;version>1.18.1&#x3C;/version>
        &#x3C;scope>compile&#x3C;/scope>
   &#x3C;/dependency>
  &#x3C;!-- Azure-keyvault -->
   &#x3C;dependency>
       &#x3C;groupId>com.azure&#x3C;/groupId>
       &#x3C;artifactId>azure-security-keyvault-keys&#x3C;/artifactId>
       &#x3C;version>4.10.4&#x3C;/version>
   &#x3C;/dependency>
      	
   &#x3C;!--gson -->
   &#x3C;dependency>
   	&#x3C;groupId>com.google.code.gson&#x3C;/groupId>
   	&#x3C;artifactId>gson&#x3C;/artifactId>
   	&#x3C;version>2.12.1&#x3C;/version>
   &#x3C;/dependency>

   &#x3C;!--jackson-core -->
   &#x3C;dependency>
   	&#x3C;groupId>com.fasterxml.jackson.core&#x3C;/groupId>
   	&#x3C;artifactId>jackson-core&#x3C;/artifactId>
   	&#x3C;version>2.18.2&#x3C;/version>
   &#x3C;/dependency>
   	
   &#x3C;!--jackson-databind -->
   &#x3C;dependency>
   	&#x3C;groupId>com.fasterxml.jackson.core&#x3C;/groupId>
   	&#x3C;artifactId>jackson-databind&#x3C;/artifactId>
   	&#x3C;version>2.18.2&#x3C;/version>
   &#x3C;/dependency>
   &#x3C;!-- slf4j-api -->
	&#x3C;dependency>
	   &#x3C;groupId>org.slf4j&#x3C;/groupId>
	   &#x3C;artifactId>slf4j-api&#x3C;/artifactId>
	   &#x3C;version>1.7.32&#x3C;/version>
	   &#x3C;scope>runtime&#x3C;/scope>
	&#x3C;/dependency>	
  &#x3C;!-- logback-classic -->
   &#x3C;dependency>
	&#x3C;groupId>ch.qos.logback&#x3C;/groupId>
	&#x3C;artifactId>logback-classic&#x3C;/artifactId>
	&#x3C;version>1.2.6&#x3C;/version>
	&#x3C;scope>compile&#x3C;/scope>
<strong>  &#x3C;/dependency>
</strong>&#x3C;!-- logback-core -->
   &#x3C;dependency>
      &#x3C;groupId>ch.qos.logback&#x3C;/groupId>
      &#x3C;artifactId>logback-core&#x3C;/artifactId>
      &#x3C;version>1.2.6&#x3C;/version>
      &#x3C;scope>compile&#x3C;/scope>
   &#x3C;/dependency>  	
   &#x3C;!-- bc-fips -->
   &#x3C;dependency>
   	&#x3C;groupId>org.bouncycastle&#x3C;/groupId>
   	&#x3C;artifactId>bc-fips&#x3C;/artifactId>
   	&#x3C;version>2.1.1&#x3C;/version>
   &#x3C;/dependency>
   	
</code></pre>

{% endtab %}

{% tab title="JavaScript" %}
The Secrets Manager Azure Key Vault module can be installed using npm

```bash
npm install @keeper-security/secrets-manager-azure
```

{% endtab %}

{% tab title="Python" %}
The Secrets Manager Storage module can be installed using pip:

```bash
pip3 install keeper-secrets-manager-storage
```

{% endtab %}

{% tab title=".Net" %}
The Secrets Manager KSM modules are located in the Keeper Secrets Manager storage module which can be installed using `dotnet`

```bash
dotnet add package Keeper.SecretsManager.AzureKeyVault
```

{% endtab %}
{% endtabs %}

### 2. Configure **Azure Key Vault** Connection

Ensure that you have an Azure Key Vault instance available. The following parameters are needed to connect to Azure Key Vault:\
`AZURE_TENANT_ID: The Microsoft Entra tenant (directory) ID.`

`AZURE_CLIENT_ID: The client (application) ID of an App Registration in the tenant.`

`AZURE_CLIENT_SECRET: A client secret that was generated for the App Registration.`

You will need an Azure App directory App to use the Azure Key Vault integration.

{% hint style="info" %}
For more information on Azure App Directory App registration and Permissions see the Azure documentation:

<https://learn.microsoft.com/en-us/azure/key-vault/general/authentication>
{% endhint %}

### 3. Add Azure Key Vault Storage to Your Code

Once the Azure connection has been configured, you can use Azure Key Vault to encrypt and decrypt KSM configurations. Tell the Secrets Manager SDK to utilize Key Vault as storage.

### Using **Azure Key Vault Integration**

Once setup, the Secrets Manager Azure Key Vault integration supports all Secrets Manager SDK functionality. Your code will need to be able to access the Azure Keys in order to manage the encryption and decryption of the KSM configuration file.\
\
**Using Specified Connection credentials**

{% tabs %}
{% tab title="Java" %}
To do this, create `AzureKeyValueStorage` instance and use this in `SecretManagerOptions` constructor.

The `AzureKeyValueStorage` will require the name of the Secrets Manager configuration file with `azure_key_id` , `azure_keyvault_URL` and configuration.

```java
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import static com.keepersecurity.secretsManager.core.SecretsManager.initializeStorage;
import com.keepersecurity.secretmanager.azurekv.AzureKeyValueStorage;
import com.keepersecurity.secretmanager.azurekv.AzureSessionConfig;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;


class Test {
	public static void main(String args[]){
		String oneTimeToken = "[One_Time_Token]";
		String keyId = "https://<vault-name>.vault.azure.net/keys/<keyname>/<keyversion>";
		String configFileLocation="<KSM-client-config.json>";
		String azTenantId = "<azure-tenant-id>";
		String azClientId = "<azure-client-id>";
		String azClientSecret = "<azure-client-secret>";
		String keyVaultUrl = "https://<vault-name>.vault.azure.net/";
		Security.addProvider(new BouncyCastleFipsProvider());
		try{
			//set azure KV configuration, 
			AzureSessionConfig azConfig= new AzureSessionConfig(azTenantId, azClientId, azClientSecret, keyVaultUrl);
			//Get Storage 
			AzureKeyValueStorage azkvstorage =  AzureKeyValueStorage.getInternalStorage(keyId, configFileLocation, azConfig);
			initializeStorage(azkvstorage, oneTimeToken);
			SecretsManagerOptions options = new SecretsManagerOptions(azkvstorage);
			//getSecrets(options)
		}catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
}

```

{% endtab %}

{% tab title="JavaScript" %}
To do this, use `AzureKeyValueStorage` as your Secrets Manager storage in the `SecretsManager` constructor.

The storage will require an `Azure Key ID`, as well as the name of the Secrets Manager configuration file which will be encrypted by Azure Key Vault.

<pre class="language-javascript"><code class="lang-javascript"><strong>import { getSecrets, initializeStorage } from '@keeper-security/secrets-manager-core';
</strong>import { AzureKeyValueStorage, AzureSessionConfig, LoggerLogLevelOptions } from '@keeper-security/secrets-manager-azure';

const getKeeperRecords = async () => {
    const tenantId = '&#x3C;tenant_id>';
    const clientId = '&#x3C;client_id>';
    const clientSecret = '&#x3C;client_secret>';
    const azureSessionConfig = new AzureSessionConfig(tenantId, clientId, clientSecret);

    const configPath = '&#x3C;path to ksm-client-config.json>';
    const logLevel = LoggerLogLevelOptions.info;

    // oneTimeToken is used only once to initialize the storage
    // after the first run, subsequent calls will use the config file
    const oneTimeToken = '&#x3C;One Time Token>';

    const keyId = 'https://&#x3C;vault_name>.vault.azure.net/keys/&#x3C;key_name>/&#x3C;version>';
    const storage = await new AzureKeyValueStorage(keyId, configPath, azureSessionConfig, logLevel).init();
    await initializeStorage(storage, oneTimeToken);

    const { records } = await getSecrets({ storage });
    console.log(records);
};
getKeeperRecords();

</code></pre>

{% endtab %}

{% tab title="Python" %}
To do this, use `AzureKeyValueStorage` as your Secrets Manager storage in the `SecretsManager` constructor as config along with a token.

The storage will require a Azure Key ID, as well as the location of the Secrets Manager configuration file which will be encrypted by Azure-KSM Integration and Azure session configuration as shown below.

```python
from keeper_secrets_manager_storage.storage_azure_keyvault import AzureSessionConfig,AzureKeyValueStorage
from keeper_secrets_manager_core import SecretsManager

tenant_id = "<Tenant_ID>"
client_id = "<CLIENT_ID>"
client_secret = "<CLIENT_SECRET>"

azure_session_config = AzureSessionConfig(tenant_id, client_id, client_secret)
config_path = "<path_to_client_config_python.json>"

token="<One Time Token>"

key_id = "<key_id>"

azure_key_value_storage = AzureKeyValueStorage(key_id=key_id,config_file_location=config_path ,az_session_config=azure_session_config)
    
secrets_manager = SecretsManager(token = token,config=azure_key_value_storage)
    
records  = secrets_manager.get_secrets()
    
for record in records:
    print(record)

```

{% endtab %}

{% tab title=".Net" %}
To do this, use `AzureKeyValueStorage` as your Secrets Manager storage in the `SecretsManager` constructor.

The storage will require an `Azure Key ID`, as well as the name of the Secrets Manager configuration file which will be encrypted by Azure Key Vault. Optionally `AzureSessionConfig` can be provided. If credentials are not provided the default credentials are used.

```csharp
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SecretsManager;

public class Program
{
   private static async Task getOneIndividualSecret()
    {
        var tenant_id = "<TENANT_ID>";
        var client_secret = "<CLIENT_SECRET>";
        var client_id = "<CLIENT_ID>";
        var keyId = "<KEY_ID>";
        var path = "ksmConfigDotnet.json";
        var dotnet_access_token = "<ACCESS_TOKEN>";
        var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.SetMinimumLevel(LogLevel.Debug);
            builder.AddConsole();
        });
        var logger = loggerFactory.CreateLogger<AzureKeyValueStorage>();
        var azure_session_config = new AzureSessionConfig(tenant_id, client_id, client_secret);
        AzureKeyValueStorage azure_storage = new AzureKeyValueStorage(keyId, path, azure_session_config, logger);
        SecretsManagerClient.InitializeStorage(azure_storage, dotnet_access_token);
        
        var options = new SecretsManagerOptions(azure_storage);
                    var records_list = await SecretsManagerClient.GetSecrets(options);
        records_list.Records.ToList().ForEach(record => Console.WriteLine(record.RecordUid + " - " + record.Data.title));
    }
	static async Task Main()
	{
		await getOneIndividualSecret();
	}
}
```

{% endtab %}
{% endtabs %}

## Additional Options

### Change Key

We can change key that is used for encrypting the KSM configuration, examples below show the code needed to use it

{% tabs %}
{% tab title="Java" %}

<pre class="language-java"><code class="lang-java"><strong>//The method changeKey(newKeyID) will be used to encrypt the KSM config file with new azure key. 
</strong>....
 String newKeyID = "https://&#x3C;vault-name>.vault.azure.net/keys/&#x3C;keyname>/&#x3C;keyversion>";
 AzureKeyValueStorage azkvstorage =  AzureKeyValueStorage.getInternalStorage(keyId, configFileLocation, azConfig);
 boolean isChanged = azkvstorage.changeKey(newKeyID);	 // Change the key for encryption/decryption
....
</code></pre>

{% endtab %}

{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>// To change the Azure Key Vault key used for encryption, you can call the `changeKey` method on the `AzureKeyValueStorage` instance.
</strong><strong>.....
</strong><strong> const keyId = 'https://&#x3C;vault_name>.vault.azure.net/keys/&#x3C;key_name>/&#x3C;version>'
</strong> const keyId2 = "https://&#x3C;vault_name>.vault.azure.net/keys/&#x3C;key_name>/&#x3C;version>"
 const storage = await new AzureKeyValueStorage(keyId, config_path, azureSessionConfig, logLevel).init();
 await storage.changeKey(keyId2);

.....
</code></pre>

{% endtab %}

{% tab title="Python" %}

```python
azure_key_value_storage = AzureKeyValueStorage(key_id=key_id,config_file_location=config_path ,az_session_config=azure_session_config)
new_key_id = "<new key id>"
is_changed = azure_key_value_storage.change_key(new_key_id = new_key_id)
print("Key is changed " + is_changed)
```

{% endtab %}

{% tab title=".Net" %}

```csharp
// To change the Azure key used for encryption, you can call the `ChangeKeyAsync` method on the `AzureKeyValueStorage` instance.
 using Microsoft.Extensions.Logging;
 ....
     var keyId2 = "<KEY_ID_2>";
     var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.SetMinimumLevel(LogLevel.Debug);
                builder.AddConsole();
            });
    var logger = loggerFactory.CreateLogger<AzureKeyValueStorage>();
    AzureKeyValueStorage azure_storage = new AzureKeyValueStorage(keyId, path, azure_session_config, logger);
    azure_storage.ChangeKeyAsync(keyId2).Wait();
 ....
```

{% endtab %}
{% endtabs %}

### Decrypt Config

We can decrypt the config if current implementation is to be migrated onto a different cloud or if you want your raw credentials back. The function accepts a boolean which when set to true will save the decrypted configuration to file and if it is false, will just return decrypted configuration.

{% tabs %}
{% tab title="Java" %}

```java
....
 AzureKeyValueStorage azkvstorage =  AzureKeyValueStorage.getInternalStorage(keyId, configFileLocation, azConfig);
 azkvstorage.decryptConfig(false); // Set false as a parameter to extract only plaintext.
 //OR 
 azkvstorage.decryptConfig(true); // Set true as a parameter to extract plaintext and save config as a plaintext.
....
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// To decrypt the config file, call the `decryptConfig` method on the `AzureKeyValueStorage` instance.
// ....
const storage = await new AzureKeyValueStorage(keyId, configPath, azureSessionConfig, logLevel).init();
const decryptedConfig = await storage.decryptConfig(true);  // Saves plaintext to file and returns it
// OR
const decryptedConfig = await storage.decryptConfig(false); // Returns plaintext without saving to file
// ....
```

{% endtab %}

{% tab title="Python" %}

```python
storage = AzureKeyValueStorage(key_id=key_id,config_file_location=config_path ,az_session_config=azure_session_config)
storage.decrypt_config() #saved plain config to file
 # or
storage.decrypt_config(False)# returns config as return value, file will stay encrypted
```

{% endtab %}

{% tab title=".Net" %}

```csharp
//To decrypt the config file and save it again in plaintext, you can call the `DecryptConfigAsync` method on the `AzureKeyValueStorage` instance.
.... 
var keyId2 = "<KEY_ID_2>";
 AzureKeyValueStorage azure_storage = new AzureKeyValueStorage(keyId, path, azure_session_config, logger);
await azure_storage.DecryptConfigAsync(true); // return decrypted and Saves to file
//OR
await azure_storage.DecryptConfigAsync(false); // returns the decrypted config 
.... 
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
You're ready to use the KSM Storage integration :thumbsup:
{% endhint %}

{% hint style="info" %}
Check out the [KSM SDKs documentation](https://docs.keeper.io/en/keeperpam/secrets-manager/developer-sdk-library) for more examples and functionality
{% endhint %}
