# Oracle Cloud Infrastructure (OCI) Vault Encryption

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2Fk7JhuXGQGjiECfkHvQch%2Fksm-Oracle.jpg?alt=media&#x26;token=77d4c030-e9d0-4aae-929b-b1c8baf60aa9" alt=""><figcaption></figcaption></figure>

Keeper Secrets Manager integrates with Oracle Cloud Infrastructure (OCI) Vault in order to provide protection 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 OCI 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

## Prerequisites

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

* Support the [Java/Kotlin Secrets Manager SDK.](https://github.com/Keeper-Security/gitbook-secrets-manager/blob/master/keeperpam/secrets-manager/developer-sdk-library/java-sdk/README.md)
* Required Oracle packages: [oci-java-sdk-keymanagement](https://mvnrepository.com/artifact/com.oracle.oci.sdk/oci-java-sdk-keymanagement), [oci-java-sdk-common](https://mvnrepository.com/artifact/com.oracle.oci.sdk/oci-java-sdk-common) and [oci-java-sdk-common-httpclient-jersey](https://mvnrepository.com/artifact/com.oracle.oci.sdk/oci-java-sdk-common-httpclient-jersey).
* OCI Key needs `ENCRYPT` and `DECRYPT` [permissions](https://docs.oracle.com/en-us/iaas/Content/Identity/policyreference/keypolicyreference.htm#permissions).
  {% endtab %}

{% tab title="JavaScript" %}

* Supports the [JavaScript Secrets Manager SDK](https://github.com/Keeper-Security/gitbook-secrets-manager/blob/master/keeperpam/secrets-manager/developer-sdk-library/javascript-sdk/README.md)
* `oci-keymanagement` is bundled — no separate install required.
* OCI KMS Key needs `ENCRYPT` and `DECRYPT` [permissions](https://docs.oracle.com/en-us/iaas/Content/Identity/policyreference/keypolicyreference.htm#permissions).
  {% endtab %}

{% tab title="Python" %}

* Supports the [Python Secrets Manager SDK](https://github.com/Keeper-Security/gitbook-secrets-manager/blob/master/keeperpam/secrets-manager/developer-sdk-library/python-sdk/README.md)
* Requires `oci` [package](https://pypi.org/project/oci/)
* User credentials to be used will need to have OCI vault [permissions](https://docs.oracle.com/en-us/iaas/Content/Identity/policyreference/keypolicyreference.htm#permissions)
  {% endtab %}

{% tab title=".Net" %}

* Supports the [.Net Secrets Manager SDK](https://github.com/Keeper-Security/gitbook-secrets-manager/blob/master/keeperpam/secrets-manager/developer-sdk-library/.net-sdk/README.md).
* Requires [OCI.DotNetSDK.Keymanagement](https://www.nuget.org/packages/OCI.DotNetSDK.Keymanagement).
* Requires `Encrypt` and `Decrypt` [permissions](https://docs.oracle.com/en-us/iaas/Content/Identity/policyreference/keypolicyreference.htm#permissions).
  {% endtab %}
  {% endtabs %}

## Setup

### 1. Install Module

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

**Gradle**

<pre class="language-java"><code class="lang-java">repositories {
  mavenCentral()
}

dependencies {
<strong>  implementation("com.keepersecurity.secrets-manager:oracle:1.0.0")
</strong>  implementation("com.keepersecurity.secrets-manager:core:17.0.0")
  implementation("com.oracle.oci.sdk:oci-java-sdk-keymanagement:3.60.0")
  implementation("com.oracle.oci.sdk:oci-java-sdk-common-httpclient-jersey:3.60.0") // or the latest version
  implementation("com.oracle.oci.sdk:oci-java-sdk-common:3.60.0")
  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-simple:2.0.16")
  implementation("org.bouncycastle:bc-fips:1.0.2.4")
}
</code></pre>

**Maven**

```xml
<!-- KMS-core -->
    <dependency>
     <groupId>com.keepersecurity.secrets-manager</groupId>
     <artifactId>oracle</artifactId>
     <version>1.0.0</version>
    </dependency>
    <dependency>
     <groupId>com.keepersecurity.secrets-manager</groupId>
     <artifactId>core</artifactId>
     <version>17.0.0</version>
    </dependency>

<!-- oci-kv -->
   <dependency>
       <groupId>com.oracle.oci.sdk</groupId>
       <artifactId>oci-java-sdk-keymanagement</artifactId>
       <version>3.60.0</version>
   </dependency>
   <dependency>
       <groupId>com.oracle.oci.sdk</groupId>
       <artifactId>oci-java-sdk-common-httpclient-jersey</artifactId>
       <version>3.60.0</version>
   </dependency>
   <dependency>
       <groupId>com.oracle.oci.sdk</groupId>
       <artifactId>oci-java-sdk-common</artifactId>
       <version>3.60.0</version>
   </dependency>
   	
   <!--gson -->
   <dependency>
   	<groupId>com.google.code.gson</groupId>
   	<artifactId>gson</artifactId>
   	<version>2.12.1</version>
   </dependency>

   <!--jackson-core -->
   <dependency>
   	<groupId>com.fasterxml.jackson.core</groupId>
   	<artifactId>jackson-core</artifactId>
   	<version>2.18.2</version>
   </dependency>
   	
   <!--jackson-databind -->
   <dependency>
   	<groupId>com.fasterxml.jackson.core</groupId>
   	<artifactId>jackson-databind</artifactId>
   	<version>2.18.2</version>
   </dependency>
   	
   <!-- slf4j-api -->
   <dependency>
   	<groupId>org.slf4j</groupId>
   	<artifactId>slf4j-api</artifactId>
   	<version>1.7.32</version>
   	<scope>runtime</scope>
   </dependency>

   <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
       <version>2.0.16</version>
   </dependency>   	
   <!-- bc-fips -->
   <dependency>
   	<groupId>org.bouncycastle</groupId>
   	<artifactId>bc-fips</artifactId>
   	<version>1.0.2.4</version>
   </dependency>
   	
```

{% endtab %}

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

```bash
npm install @keeper-security/secrets-manager-oracle-kv
```

{% endtab %}

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

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

oci is a prerequisite for the OCI Vault integration. Install it to your machine using pip.

```bash
pip3 install oci
```

{% endtab %}

{% tab title=".Net" %}
The Secrets Manager OCI Vault module can be installed using dotnet nuget package manager.

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

{% endtab %}
{% endtabs %}

### 2. Configure OCI Vault Connection

Ensure that you have an OCI Vault instance available, and you know its OCID (Oracle Cloud Identifier). By default, the \`oci key management\` library will use the default OCI configuration file (`~/.oci/config`)

{% hint style="info" %}
See the Oracle documentation for more information on setting up OCI Keys:

<https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm>
{% endhint %}

Alternatively, You will need to add the correct configuration for your OCI environment, including the details for accessing OCI Vault.

{% hint style="info" %}
The configuration file should look like this (replace with your actual details):

\
\[DEFAULT]\
user=ocid1.user.oc1..example\_unique\_id\
fingerprint=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx\
key\_file=/path/to/your/private/api/key.pem\
tenancy=ocid1.tenancy.oc1..example\_unique\_id\
region=us-phoenix-1
{% endhint %}

### 3. Add OCI Vault Storage to Your Code

Once the OCI Vault connection has been configured, you can use the OCI Vault integration to encrypt and decrypt the KSM configuration. Tell the Secrets Manager SDK to use OCI Vault as storage.

## Using OCI Vault **Integration**

Once setup, the Secrets Manager OCI Vault integration supports all Secrets Manager SDK functionality. Your code will need to be able to access the OCI 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 `OracleKeyValueStorage` instance and use this in `SecretManagerOptions` constructor.

The `OracleKeyValueStorage` will require the name of the Secrets Manager configuration file with profile 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.oracle.kv.OracleKeyValueStorage;
import com.keepersecurity.secretmanager.oracle.kv.OracleSessionConfig;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
import com.oracle.bmc.Region;


class Test {
	public static void main(String args[]){
		String configPath = "<~/.oci/config>";
		String cryptoEndpoint = "https://<>-crypto.kms.<oracle_cloud_region>.oraclecloud.com";
		String vaultId = "<OCI VAULT ID>";
		String keyId = "<OCI KEY ID>";
		String keyVersionId = "<OCI KEY VERSION>";
		String configFileLocation = "<KSM CONFIG FILE LOCATION>";
		String profile = "<OCI CONFIG PROFILE EX: DEFAULT>"; // name of your profile
		String oneTimeToken = "<Keeper One Time Token>";
		String managementEndpoint =  "https://<>-management.kms.<oracle_cloud_region>.oraclecloud.com";
		Region region = Region.<cloud_region>;
		Security.addProvider(new BouncyCastleFipsProvider());
		try{
			//set OCI Vault configuration, 
			OracleSessionConfig oracleSessionConfig = new OracleSessionConfig(configPath, cryptoEndpoint, managementEndpoint, vaultId, keyId, keyVersionId, region);
			//Get Storage 
			OracleKeyValueStorage oracleKeyValueStorage = new OracleKeyValueStorage(configFileLocation, profile, oracleSessionConfig);
			initializeStorage(oracleKeyValueStorage, oneTimeToken);
			SecretsManagerOptions options = new SecretsManagerOptions(oracleKeyValueStorage);
			//getSecrets(options)
		}catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
}

```

{% endtab %}

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

The storage will require an `OCI config file location`, `OCI configuration profile` (if there are multiple profile configurations) and the `OCI KMS Crypto endpoint` , `OCI KMS Management endpoint` as well as the name of the `Secrets Manager configuration file` which will be encrypted by OCI Vault.

```javascript
import { getSecrets, initializeStorage } from "@keeper-security/secrets-manager-core";
import { OCISessionConfig, OciKeyValueStorage, LoggerLogLevelOptions } from "@keeper-security/secrets-manager-oracle-kv";

const getKeeperRecordsOCI = async () => {
    const oracleConfigFileLocation = "/home/<user>/.oci/config";
    const oracleProfile = "DEFAULT";
    const kmsCryptoEndpoint = "https://<id>-crypto.kms.<region>.oraclecloud.com";
    const kmsManagementEndpoint = "https://<id>-management.kms.<region>.oraclecloud.com";
    const ociSessionConfig = new OCISessionConfig(oracleConfigFileLocation, oracleProfile, kmsCryptoEndpoint, kmsManagementEndpoint);
    const logLevel = LoggerLogLevelOptions.info;
    const configPath = "<path_to_client-config.json>";

    // oneTimeToken is used only once to initialize the storage
    // after the first run, subsequent calls will use the encrypted config file
    const oneTimeToken = "<one_time_token>";

    const keyId = "ocid1.key.oc1.iad.<unique_id>";
    const keyVersionId = "ocid1.keyversion.oc1.iad.<unique_id>";

    const storage = await new OciKeyValueStorage(keyId, keyVersionId, configPath, ociSessionConfig, logLevel).init();
    await initializeStorage(storage, oneTimeToken);

    const { records } = await getSecrets({ storage: storage });
    const firstRecord = records[0];
    const password = firstRecord.data.fields.find((x) => x.type === "password");
    console.log(password.value[0]);
};
getKeeperRecordsOCI();

```

{% endtab %}

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

The storage will require a OCI Key ID, key version Id, KMS Crypto endpoint, KMS management endpoint, OCI config file location, configuration profile as well as the name of the Secrets Manager configuration file which will be encrypted by OCI Vault and OCI session configuration shown below.

```python
from keeper_secrets_manager_storage_oracle_kms import OracleKeyValueStorage, OCISessionConfig
from keeper_secrets_manager_core import SecretsManager
config_file_location = "/home/<user>/.oci/config"
profile = "DEFAULT"
kms_crypto_endpoint = "https://<id>-crypto.kms.<region>.oraclecloud.com"
kms_management_endpoint = "https://<id>-management.kms.<region>.oraclecloud.com"
key_id = '<key_id>'
key_version_id = "<key_version_id>"
config_path = "<path to config json>"
one_time_token = "<Keeper One Time Token>"
oci_session_config = OCISessionConfig(config_file_location, profile, kms_crypto_endpoint, kms_management_endpoint)
storage = OracleKeyValueStorage(key_id=key_id, key_version=key_version_id, config_file_location=config_path, oci_session_config=oci_session_config,logger=None)
secrets_manager = SecretsManager(one_time_token,config=storage)
all_records = secrets_manager.get_secrets()
first_record = all_records[0]
print(first_record)
```

{% endtab %}

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

The storage will require a OCI Key ID, key version Id, KMS Crypto endpoint, KMS management endpoint, OCI config file location, configuration profile as well as the name of the Secrets Manager configuration file which will be encrypted by OCI Vault and OCI session configuration shown below.

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

public class Program
{
    private static async Task Main()
    {
        var ociConfigFileLocation = "<path_to_oci_config>";
        var profile = "DEFAULT";
        var kmsCryptoEndpoint = "https://<id>-crypto.kms.<region>.oraclecloud.com";
        var kmsManagementEndpoint = "https://<id>-management.kms.<region>.oraclecloud.com";
        var ociSessionConfig = new OciSessionConfig(ociConfigFileLocation, profile, kmsCryptoEndpoint, kmsManagementEndpoint);

        var path = "ksm_config.json";
        string keyId = "<oci_key_id>";
        string keyVersionId = "<oci_key_version_id>";

        var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.SetMinimumLevel(LogLevel.Debug);
            builder.AddConsole();
        });
        var logger = loggerFactory.CreateLogger<OracleKeyValueStorage>();
        var storage = new OracleKeyValueStorage(keyId, keyVersionId, path, ociSessionConfig, logger);

        var oneTimeToken = "<one_time_token>";
        SecretsManagerClient.InitializeStorage(storage, oneTimeToken);

        var options = new SecretsManagerOptions(storage);
        var records = await SecretsManagerClient.GetSecrets(options);
        records.Records.ToList().ForEach(record =>
            Console.WriteLine(record.RecordUid + " - " + record.Data.title));
    }
}
```

{% 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(keyID, keyVersion) will be used to encrypt the KSM config file with new Key and version. 
</strong>
String newKeyID = "&#x3C;new Key ID>";
String newKeyVersion = "&#x3C;New Key Version>";
OracleKeyValueStorage oracleKeyValueStorage = new OracleKeyValueStorage(configFileLocation, profile, oracleSessionConfig);
oracleKeyValueStorage.changeKey(newKeyID, newKeyVersion); // Change the key for encryption/decryption
</code></pre>

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// To change the OCI Vault key used for encryption, call the changeKey method on the OciKeyValueStorage instance.
const newKeyId = "ocid1.key.oc1.iad.<new_unique_id>";
const newKeyVersionId = "ocid1.keyversion.oc1.iad.<new_unique_id>";
const storage = await new OciKeyValueStorage(keyId, keyVersionId, configPath, ociSessionConfig).init();
await storage.changeKey(newKeyId, newKeyVersionId);
```

{% endtab %}

{% tab title="Python" %}

```python
   storage = OracleKeyValueStorage(key_id=key_id, key_version=key_version_id, config_file_location=config_path, oci_session_config=oci_session_config,logger=None)
    
    new_key_id = "<new key id>"
    new_key_version_id = "<new key version>"
    isChanged = storage.change_key(new_key_id, new_key_version_id)
    print(f"Key is changed: {isChanged}")
```

{% endtab %}

{% tab title=".Net" %}

```csharp
// To change the OCI Vault key used for encryption, call ChangeKeyAsync on the OracleKeyValueStorage instance.
var storage = new OracleKeyValueStorage(keyId, keyVersionId, path, ociSessionConfig, logger);
string newKeyId = "<new_oci_key_id>";
string newKeyVersionId = "<new_oci_key_version_id>";
await storage.ChangeKeyAsync(newKeyId, newKeyVersionId, null);
```

{% endtab %}
{% endtabs %}

### Decrypt Config

You can decrypt the configuration file to migrate to a different cloud provider or to retrieve your raw credentials. Pass `true` to save the decrypted configuration back to the file, or `false` to return the plaintext without modifying the file.

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

```java
OracleKeyValueStorage oracleKeyValueStorage = new OracleKeyValueStorage(configFileLocation, profile, oracleSessionConfig);
oracleKeyValueStorage.decryptConfig(false); // Set false as a parameter to extract only plaintext.
//OR 
oracleKeyValueStorage.decryptConfig(true); // Set true as a parameter to extract plaintext and save config as a plaintext.
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const storage = await new OciKeyValueStorage(keyId, keyVersionId, configPath, ociSessionConfig).init();

// Returns plaintext only (file stays encrypted)
const plaintext = await storage.decryptConfig(false);

// OR: returns plaintext and saves config as plaintext
const saved = await storage.decryptConfig(true);
```

{% endtab %}

{% tab title="Python" %}

```python
storage = OracleKeyValueStorage(key_id=key_id, key_version=key_version_id, config_file_location=config_path, oci_session_config=oci_session_config, logger=None)

# Returns plaintext only (file stays encrypted)
plaintext = storage.decrypt_config(False)
print(plaintext)

# OR: returns plaintext and saves config as plaintext
plaintext = storage.decrypt_config(True)
print(plaintext)
```

{% endtab %}

{% tab title=".Net" %}

```csharp
// To decrypt the config file and revert to plaintext, call DecryptConfigAsync on the OracleKeyValueStorage instance.
var conf = await storage.DecryptConfigAsync(false); // Returns plaintext only
Console.WriteLine(conf);
// OR
var conf = await storage.DecryptConfigAsync(true); // Returns plaintext and saves config as plaintext
Console.WriteLine(conf);
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
You're ready to use the KSM 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 %}
