# Google Cloud Key Management Encryption

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2F6mxHlHnrBXD2jVhRoqvF%2Fksm-Google%20Cloud.jpg?alt=media&#x26;token=620bd9e5-f05a-40e4-aeaa-712da3223699" alt=""><figcaption></figcaption></figure>

Keeper Secrets Manager integrates with Google Cloud Key Management 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 Google Cloud Key Management.
* 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

To configure Google Cloud Key Management with Keeper Security, you need a service account key file (`.json`).\
Key structure that is supported by this integration is `projects/<project_name>/locations/<location_name>/keyRings/<key_ring_name>/cryptoKeys/<key_name>/cryptoKeyVersions/<key_version>`

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

* Support the Java/Kotlin Secrets Manager SDK.
* Required GCP package `google-cloud-kms`
* GCP KMS key needs `ENCRYPT` and `DECRYPT` 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)
* `@google-cloud/kms` is bundled — no separate install required.
* GCP KMS key needs the following IAM permissions on the service account:
  * Cloud KMS CryptoKey Encrypter
  * Cloud KMS CryptoKey Decrypter
  * Cloud KMS CryptoKey Public Key Viewer (required for asymmetric keys)
    {% 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 `google-cloud-kms` package
* GCP KMS key needs `ENCRYPT` and `DECRYPT` 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 [Google.Apis.CloudKMS.v1](https://www.nuget.org/packages/Google.Apis.CloudKMS.v1)
* GCP KMS key needs `ENCRYPT` and `DECRYPT` permissions.
  {% endtab %}
  {% endtabs %}

## Setup

### 1. Install Module

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

**Gradle**

```java
repositories {
  mavenCentral()
}

dependencies {
	implementation("com.keepersecurity.secrets-manager:core:17.0.0")
	implementation("com.keepersecurity.secrets-manager:gcp:1.0.0")
	implementation ("com.google.cloud:google-cloud-kms:2.62.0")
	implementation ("com.google.auth:google-auth-library-oauth2-http:1.33.1") 
	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:1.0.2.4")
}
```

**Maven**

```xml
<!-- KMS-core -->
<dependency>
	<groupId>com.keepersecurity.secrets-manager</groupId>
	<artifactId>core</artifactId>
	<version>[17.0.0,)</version>
</dependency>
<dependency>
	<groupId>com.keepersecurity.secrets-manager</groupId>
	<artifactId>gcp</artifactId>
	<version>1.0.0</version>
</dependency>
<!-- gcp-kms -->
<dependency>
	<groupId>com.google.cloud</groupId>
	<artifactId>google-cloud-kms</artifactId>
	<version>2.62.0</version>
</dependency>
<!-- gcp auth -->
<dependency>
	<groupId>com.google.auth</groupId>
	<artifactId>google-auth-library-oauth2-http</artifactId>
	<version>1.33.1</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>
<!-- logback-classic -->
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-classic</artifactId>
	<version>1.2.6</version>
	<scope>compile</scope>
</dependency>
<!-- logback-core -->
<dependency>
	<groupId>ch.qos.logback</groupId>
	<artifactId>logback-core</artifactId>
	<version>1.2.6</version>
	<scope>compile</scope>
</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 Google Cloud Key Management module can be installed using npm

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

{% endtab %}

{% tab title="Python" %}
The Secrets Manager Google Cloud Key Management module can be installed using pip

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

{% endtab %}

{% tab title=".Net" %}
The Secrets Manager Google Cloud Key Management module can be installed using dotnet nuget package manager.

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

{% endtab %}
{% endtabs %}

### 2. Configure **GCP KMS** Connection

To enable secure authentication with Google Cloud Platform (GCP), generate a Service Account key in JSON format. This credential file will serve as the authentication mechanism for interacting with GCP services programmatically.

{% hint style="info" %}
See the Google documentation for more information on generating keys:

<https://cloud.google.com/iam/docs/keys-create-delete>
{% endhint %}

### 3. Add GCP KMS Storage to Your Code

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

## Using **GCP KMS Integration**

Once set up, the Secrets Manager GCP KMS integration supports all Secrets Manager SDK functionality. Your code will need to be able to access the GCP KMS 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 `GcpKeyValueStorage` instance and use this in `SecretManagerOptions` constructor.

The `GcpKeyValueStorage` will require the name of the Secrets Manager configuration file , gcp credential file and key details of Cloud Key Management.

```java
import java.security.Security;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import static com.keepersecurity.secretsManager.core.SecretsManager.initializeStorage;
import com.keepersecurity.secretsmanager.gcp.GcpKeyValueStorage;
import com.keepersecurity.secretsmanager.gcp.GcpSessionConfig;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
public class Test {
	public static void main(String args[]){
	    String oneTimeToken = "One_Time_Token";
	    String projectId = "projectId";
	    String location = "cloud_region";
	    String keyRing = "key_ring_name";
	    String keyId = "key_id";
	    String keyVersion = "key_version";
	    String configFileLocation = "client_config_test.json";
	    String credentialFileLocation = "<path_with_name_of_gcp_cred_file.json>";
	    Security.addProvider(new BouncyCastleFipsProvider());
		try{
				GcpSessionConfig sessionConfig = new GcpSessionConfig(projectId, location, keyRing, keyId, keyVersion, credentialFileLocation);
				GcpKeyValueStorage storage = new GcpKeyValueStorage(configFileLocation, sessionConfig);
				initializeStorage(storage, oneTimeToken);
				SecretsManagerOptions options = new SecretsManagerOptions(storage);	
		}catch (Exception e) {
				  System.out.println(e.getMessage());
		}
	}
}
```

{% endtab %}

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

The storage will require an `keyConfig` , `gcpsessionConfig`(generated by `GCPKSMClient`) , and the name of the `Secrets Manager configuration file` which will be encrypted by GCP Cloud Key Management.

```javascript
import { getSecrets, initializeStorage } from "@keeper-security/secrets-manager-core";
import { GCPKeyValueStorage, GCPKeyConfig, GCPKSMClient, LoggerLogLevelOptions } from "@keeper-security/secrets-manager-gcp";

const getKeeperRecordsGCP = async () => {
    const gcpCredFile = "<path_to_gcp_credentials.json>";
    const keyConfig = new GCPKeyConfig("<key_version_resource_url>");
    const gcpSessionConfig = new GCPKSMClient().createClientFromCredentialsFile(gcpCredFile);
    const configPath = "<path_to_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 encrypted config file
    const oneTimeToken = "<one_time_token>";

    const storage = await new GCPKeyValueStorage(configPath, keyConfig, gcpSessionConfig, 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]);
};
getKeeperRecordsGCP();
```

{% endtab %}

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

The storage will require `gcp_key_config` (generated by `GCPConfig` ), `gcp_session_config` object (generated by `GCPKMSClientConfig` ) and the name of the `Secrets Manager configuration file` which will be encrypted by GCP Cloud Key Management.

```python
from keeper_secrets_manager_storage_gcp_kms import GCPKeyConfig, GCPKeyValueStorage, GCPKMSClientConfig
from keeper_secrets_manager_core import SecretsManager

# Example key: projects/<project>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key_name>/cryptoKeyVersions/<version>
gcp_key_config = GCPKeyConfig("<key_resource_uri>")

gcp_cred_file_location_with_name = "<path_with_name_of_gcp_cred_file.json>"
gcp_session_config = GCPKMSClientConfig().create_client_from_credentials_file(gcp_cred_file_location_with_name)

config_path = "ksm_config.json"
one_time_token = "<one_time_token>"

storage = GCPKeyValueStorage(config_path, gcp_key_config, gcp_session_config)
secrets_manager = SecretsManager(token=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 `GCPKeyValueStorage` as your Secrets Manager storage in the `SecretsManager` constructor.

The storage will require an `keyConfig` (generated by `GCPKeyConfig` ), `gcpSessionConfig` object (generated by `GCPKMSClient` ), and the name of the `Secrets Manager configuration file` which will be encrypted by GCP Cloud Key Management.

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

public class Program {
    private static async Task Main() {
        string keyResourceName = "<key_version_resource_url>";
        string gcpConfigFilePath = "<path_to_gcp_credentials.json>";
        var keyConfig = new GCPKeyConfig(keyResourceName);
        var gcpSessionConfig = new GCPKMSClient().CreateClientFromCredentialsFile(gcpConfigFilePath);
        var ksmConfigPath = "ksm_config.json";
        var oneTimeToken = "<one_time_token>";
        var loggerFactory = LoggerFactory.Create(builder => {
            builder.SetMinimumLevel(LogLevel.Debug);
            builder.AddConsole();
        });
        var logger = loggerFactory.CreateLogger<GCPKeyValueStorage>();
        var gcp_storage = new GCPKeyValueStorage(keyConfig, gcpSessionConfig, ksmConfigPath, logger);
        SecretsManagerClient.InitializeStorage(gcp_storage, oneTimeToken);
    }
}
```

{% endtab %}
{% endtabs %}

## **Using Application Default Credentials**

{% tabs %}
{% tab title="JavaScript" %}
If you have configured credentials via `gcloud auth application-default login`, the `GOOGLE_APPLICATION_CREDENTIALS` environment variable, or are running on a GCP compute instance with a service account attached, you can omit the credentials file entirely.

```javascript
import { getSecrets, initializeStorage } from "@keeper-security/secrets-manager-core";
import { GCPKeyValueStorage, GCPKeyConfig, GCPKSMClient, LoggerLogLevelOptions } from "@keeper-security/secrets-manager-gcp";

const getKeeperRecordsGCP = async () => {
    // No credentials file needed — uses Application Default Credentials automatically
    const gcpSessionConfig = new GCPKSMClient();
    const keyConfig = new GCPKeyConfig("<key_version_resource_url>");
    const configPath = "<path_to_client-config.json>";
    const logLevel = LoggerLogLevelOptions.info;

    const oneTimeToken = "<one_time_token>";

    const storage = await new GCPKeyValueStorage(configPath, keyConfig, gcpSessionConfig, 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]);
};
getKeeperRecordsGCP();
```

Alternatively, you can pass the service account email and private key directly without a file:

```javascript
const gcpSessionConfig = new GCPKSMClient().createClientUsingCredentials(
    "<service_account_email>",
    "<private_key>"
);
```

{% 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" %}

```java
GcpKeyValueStorage storage = new GcpKeyValueStorage(configFileLocation, sessionConfig);
String newKeyID = "<new_key_id>";
boolean isChanged = storage.changeKey(newKeyID);
System.out.println("Key Changed: " + isChanged);
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// To change the GCP KMS key used for encryption, call the changeKey method on the GCPKeyValueStorage instance.
const newKeyConfig = new GCPKeyConfig("<new_key_version_resource_url>");
const storage = await new GCPKeyValueStorage(configPath, keyConfig, gcpSessionConfig).init();
await storage.changeKey(newKeyConfig);
```

{% endtab %}

{% tab title="Python" %}

```python
new_key_config = GCPKeyConfig("<new_key_resource_uri>")
storage = GCPKeyValueStorage(config_path, gcp_key_config, gcp_session_config)
is_changed = storage.change_key(new_key_config)
print("Key is changed:", is_changed)
```

{% endtab %}

{% tab title=".Net" %}

```csharp
// To change the GCP KMS key used for encryption, call ChangeKeyAsync on the GCPKeyValueStorage instance.
var gcp_storage = new GCPKeyValueStorage(keyConfig, gcpSessionConfig, path, logger);
bool isChanged = await gcp_storage.ChangeKeyAsync(newKeyConfig);
Console.WriteLine(isChanged);
```

{% 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
GcpKeyValueStorage storage = new GcpKeyValueStorage(configFileLocation, sessionConfig);
storage.decryptConfig(false); // Set false as a parameter to extract only plaintext.
//OR 
storage.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 GCPKeyValueStorage(configPath,keyConfig,gcpSessionConfig).init();
await storage.decryptConfig(true); // Set true as a parameter to extract plaintext and save config as a plaintext.
 // OR 
await storage.decryptConfig(false);  // Set false as a parameter to extract only plaintext.
```

{% endtab %}

{% tab title="Python" %}

```python
storage = GCPKeyValueStorage(config_path, gcp_key_config, gcp_session_config)

# Extract only plaintext
plaintext = storage.decrypt_config(False)
print(plaintext)

# OR extract plaintext and save 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 GCPKeyValueStorage instance.
var gcp_storage = new GCPKeyValueStorage(keyConfig, gcpSessionConfig, path, logger);
var conf = await gcp_storage.DecryptConfigAsync(false); // Returns plaintext only
Console.WriteLine(conf);
// OR
var conf = await gcp_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 %}
