All pages
Powered by GitBook
1 of 1

Oracle Key Vault Encryption

Protect Secrets Manager connection details with Oracle Key Vault

Keeper Secrets Manager integrates with Oracle Key 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 Oracle 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

Prerequisites

  • Support the Java/Kotlin Secrets Manager SDK.

  • Required Oracle packages: oci-java-sdk-keymanagement, oci-java-sdk-common and oci-java-sdk-common-httpclient-jersey.

  • OCI Key needs ENCRYPT and DECRYPT permissions.

  • Supports the JavaScript Secrets Manager SDK

  • Requires the oci-keymanagement package from OCI SDK.

  • OCI KMS Key needs ENCRYPT and DECRYPT permissions.

  • Supports the Python Secrets Manager SDK

  • Requires oci package

  • User credentials to be used will need to have key vault permissions

  • Supports the .Net Secrets Manager SDK.

  • Requires OCI.DotNetSDK.Keymanagement.

  • Requires Encrypt and Decrypt permissions.

  • Supports the GoLang Secrets Manager SDK

  • Requires the oci-keymanagement package from OCI SDK.

  • OCI KMS Key needs ENCRYPT and DECRYPT permissions.

Setup

1. Install Module

Setting up project using Gradle or Maven

Gradle

repositories {
  mavenCentral()
}

dependencies {
  implementation("com.keepersecurity.secrets-manager:oracle:1.0.0")
  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")
}

Maven

<!-- 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-core</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>
   	

The Secrets Manager Oracle Key Vault module can be installed using npm

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

The Secrets Manager OCI KSM module can be installed using pip

pip3 install keeper-secrets-manager-storage

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

pip3 install oci

The Secrets Manager oracle KSM module can be installed using dotnet nuget package manager.

dotnet add package Keeper.SecretsManager.OracleKeyManagement

The Secrets Manager oracle KSM module Integration can be installed using

go get github.com/keeper-security/secrets-manager-go/integrations/oracle

2. Configure Oracle KV Connection

Ensure that you have an Oracle Key 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)

See the Oracle documentation for more information on setting up an Oracle Keys:

https://docs.oracle.com/en-us/iaas/Content/API/Concepts/sdkconfig.htm

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

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

3. Add Oracle Key Vault Storage to Your Code

Once Oracle connection has been configured, You can fetch the Key to encrypt / decrypt KSM configuration using integration and you need to tell the Secrets Manager SDK to utilize the KMS as storage.

Using Oracle Key Vault Integration

Once setup, the Secrets Manager Oracle Key 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

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.

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 Oracle KV 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());
		}
	}
}

To do this, use OracleKeyValueStorage as your Secrets Manager storage in the SecretsManager constructor.

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

import { OCISessionConfig, OciKeyValueStorage } from "@keeper-security/secrets-manager-oracle-kv";
    const getKeeperRecordsOCI = async () => {
        const oracleConfigFileLocation = "/home/...../.oci/config";
        const oracleProfile = "DEFAULT";
        const kmsCryptoEndpoint = "https://<>-crypto.kms.<location>.oraclecloud.com";
        const kmsManagementEndpoint = "https://<>-management.kms.<location>.oraclecloud.com";
        const ociSessionConfig = await new OCISessionConfig(oracleConfigFileLocation, oracleProfile, kmsCryptoEndpoint,kmsManagementEndpoint);
        const logLevel = LoggerLogLevelOptions.info;
        let config_path = "<Keeper config File Path>";
        const oneTimeToken = "<one time token>";
        const keyId = 'ocid1.key.oc1.iad.<>.<>';
        const keyVersionId = "ocid1.keyversion.oc1.iad.<>.<>";
        const storage = await new OciKeyValueStorage(keyId, keyVersionId, config_path, ociSessionConfig,logLevel).init();
        await initializeStorage(storage, oneTimeToken);
        const { records } = await getSecrets({ storage: storage });
        console.log(records);
        const firstRecord = records[0];
        const firstRecordPassword = firstRecord.data.fields.find((x: { type: string; }) => x.type === 'bankAccount');
        console.log(firstRecordPassword.value[0]);
    };
    console.log("start");
    getKeeperRecordsOCI();

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, oracle config file location, configuration profile as well as the name of the Secrets Manager configuration file which will be encrypted by Oracle KMS and OCI session configuration shown below.

from keeper_secrets_manager_storage.storage_oci_key_management import  OracleKeyValueStorage,OCISessionConfig
from keeper_secrets_manager_core import SecretsManager
config_file_location = "/home/<user>/.oci/config"
profile = "DEFAULT"
kms_crypto_endpoint = "https://<kmsendpoint>.oraclecloud.com"
kms_mgmt_endpoint = "https://<kmsendpoint>.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_mgmt_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)

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, oracle config file location, configuration profile as well as the name of the Secrets Manager configuration file which will be encrypted by Oracle KMS and OCI session configuration shown below.

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

public class Program
{
	private static async Task getOneIndividualSecret()
	{
	   Console.WriteLine("execution started");
            bool changeKey = false;
            bool decryptConfiguration = false;
            var OCIConfigFileLocation = "location";
            var profile = "DEFAULT";
            var kmsCryptoEndpoint = "crypto_endpoint";
            var kmsManagementEndpoint = "management_endpoint";
            var ociSessionConfig1 = new OciSessionConfig(OCIConfigFileLocation, profile, kmsCryptoEndpoint, kmsManagementEndpoint); 
            var path = "oci_ksm_conf_test.json";
            string keyId1 = "key1";
            string keyId2 = "key2";
            string keyVersionId1 = "key1version";
            string keyVersionId2 = "key2version";
            
            var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.SetMinimumLevel(LogLevel.Debug);
                builder.AddConsole();
            });
            var logger = loggerFactory.CreateLogger<OracleKeyValueStorage>();
            var oracle_storage = new OracleKeyValueStorage(keyId2,keyVersionId2,path,ociSessionConfig1,logger );
            
            var dotnet_access_token = "<accesstoken>";
            SecretsManagerClient.InitializeStorage(oracle_storage, dotnet_access_token);
            if (changeKey)
            {
                oracle_storage.ChangeKeyAsync(keyId1,keyVersionId1,null).Wait();
            }
            if (decryptConfiguration)
            {
                var conf = await oracle_storage.DecryptConfigAsync(true);
                Console.WriteLine(conf);
            }
            var options = new SecretsManagerOptions(oracle_storage);
            var records_1 = await SecretsManagerClient.GetSecrets(options);
            records_1.Records.ToList().ForEach(record => Console.WriteLine(record.RecordUid + " - " + record.Data.title));
	}

	static async Task Main()
	{
		await getOneIndividualSecret();
	}
}

To do this, use NewOracleKeyValueStorage as your Secrets Manager storage in the SecretsManager constructor.

The NewOracleKeyVaultStorage requires the following parameters to encrypt the KSM configuration using Oracle Vault:

ksmConfigFileName : The file name of KSM configuration.

keyConfig : Provide oracle key credentials KeyID and KeyVersionID.

oracleConfig : Provide oracle credentials VaultManagementEndpoint, VaultCryptoEndpoint.

By default, the oci-keymanagement library will use the default OCI configuration file (~/.oci/config).

package main

import (
	"encoding/json"
	"fmt"

	"github.com/keeper-security/secrets-manager-go/core"
	oraclekv "github.com/keeper-security/secrets-manager-go/integrations/oracle"
)

func main() {
	decryptConfig := true
	changeKey := true
	ksmConfigFile := ""
	oneTimeToken := "oneTimeToken"
	keyConfig := &oraclekv.KeyConfig{
		KeyID:        "ocid1.key.oc1.<>.<>.<>",
		KeyVersionID: "ocid1.keyversion.oc1.<>.<>.<>.<>",
	}
	oracleConfig := &oraclekv.OracleConfig{
		VaultManagementEndpoint: "https://<>-management.kms.<>.oraclecloud.com",
		VaultCryptoEndpoint:     "https://<>-crypto.kms.<>.oraclecloud.com",
		Profile:                 "",
		ProfileConfigPath:       "",
	}
	cfg := oraclekv.NewOracleKeyVaultStorage(ksmConfigFile, keyConfig, oracleConfig)
	secrets_manager := core.NewSecretsManager(
		&core.ClientOptions{
			Token:  oneTimeToken,
			Config: cfg,
		},
	)
	secrets, err := secrets_manager.GetSecrets([]string{})
	if err != nil {
		// do something
		fmt.Printf("Error: %s\n", err)
	} else {
		for _, secret := range secrets {
			fmt.Printf("Recieved secret: %s\n", secret.Title())
		}
	}

}

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

//The method changeKey(keyID, keyVersion) will be used to encrypt the KSM config file with new Key and version. 

String newKeyID = "<new Key ID>";
String newKeyVersion = "<New Key Version>";
OracleKeyValueStorage oracleKeyValueStorage = new OracleKeyValueStorage(configFileLocation, profile, oracleSessionConfig);
oracleKeyValueStorage.changeKey(newKeyID, newKeyVersion); // Change the key for encryption/decryption
// To change the Oracle KMS key used for encryption, you can call the `changeKey` method on the `OciKeyValueStorage` instance.
const storage = await new OciKeyValueStorage(keyId, keyVersionId, configPath, ociSessionConfig).init();
await storage.changeKey(keyId2, keyVersionId2);
   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("Key is changed " + isChanged)
// To change the Oracle KMS key used for encryption, you can call the `ChangeKeyAsync` method on the `OracleKeyValueStorage` instance.
// using Microsoft.Extensions.Logging;

     var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder.SetMinimumLevel(LogLevel.Debug);
                builder.AddConsole();
            });
    var logger = loggerFactory.CreateLogger<OracleKeyValueStorage>();
    var oracle_storage = new OracleKeyValueStorage(keyId2,keyVersionId2,path,ociSessionConfig1,logger );
// If you want to change the key not oracle config, then pass nil in place of oracle config.
		updatedKeyConfig := &oraclekv.KeyConfig{
			KeyID:        "ocid1.key.oc1.<>.<>.<>",
			KeyVersionID: "ocid1.keyversion.oc1.<>.<>.<>.<>",
		}
	isChanged, err := cfg.ChangeKey(updatedKeyConfig, nil)

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.

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.
 const storage = await new OciKeyValueStorage(keyId, keyVersionId, config_path, ociSessionConfig).init();
 await storage.decryptConfig(true); // Saves to file
 const decryptedConfig = await storage.decryptConfig(true); // returns the decrypted config
 storage = OracleKeyValueStorage(key_id=key_id, key_version=key_version_id, config_file_location=config_path, oci_session_config=oci_session_config,logger=None)
 storage.decrypt_config(True)
//To decrypt the config file and save it again in plaintext, you can call the `DecryptConfigAsync` method on the `OracleKeyValueStorage` instance.
 var conf = await oracle_storage.DecryptConfigAsync(true);
 Console.WriteLine(conf);   
cfg := oraclekv.NewOracleKeyVaultStorage(ksmConfigFile, keyConfig, oracleConfig)
	secrets_manager := core.NewSecretsManager(
		&core.ClientOptions{
			Token:  oneTimeToken,
			Config: cfg,
		},
	)
// Pass true if you want to save decryptconfig in ksm config file, else pass false.
decryptedConfig, err := cfg.DecryptConfig(true) 

You're ready to use the KSM integration 👍

Check out the KSM SDKs documentation for more examples and functionality