# Google Cloud Key Managementでの暗号化

<figure><img src="https://859776093-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPL6k1aGsLiFiiJ3Y7zCl%2Fuploads%2FHNfEDB7MeJxgMJcECpUF%2Fimage.png?alt=media&#x26;token=c28dd990-6933-4496-b4bc-1a5311f216b6" alt=""><figcaption></figcaption></figure>

KeeperシークレットマネージャーはGoogle Cloud Key Managementと連携し、Keeperシークレットマネージャーの構成ファイルを暗号化できるようにします。この連携により、マシン上の接続情報を保護しながら、すべてのシークレット認証情報に対するKeeperのゼロ知識暗号化の利点を活用できます。

## 機能

* Google Cloud Key Managementを使って、Keeperシークレットマネージャーの構成ファイルを暗号化および復号化します。
* シークレットマネージャーの接続情報への不正アクセスを防止します。
* 保護のためにコードに加える変更は最小限で済みます。すべてのKeeperシークレットマネージャーSDK機能で動作します。

## 要件

* Keeper SecurityとGoogle Cloud Key Managementを連携するには、`.json`で終わるサービスアカウントキーが必要です。
* この連携でサポートされるキーの構造は以下の形式です。\
  `projects/<project_name>/locations/<location_name>/keyRings/<key_ring_name>/cryptoKeys/<key_name>/cryptoKeyVersions/<key_version>`

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

* Java/Kotlin用シークレットマネージャーSDKに対応
* GCPパッケージ`google-cloud-kms`が必要
* GCP CKMキーに`ENCRYPT`および`DECRYPT`の権限が必要
  {% endtab %}

{% tab title="JavaScript" %}

* JavaScript用シークレットマネージャーSDKに対応
* GCPパッケージ`@google-cloud/kms`が必要
* GCP CKMキーに`ENCRYPT`および`DECRYPT`の権限が必要
  {% endtab %}

{% tab title="Python" %}

* Python用シークレットマネージャーSDKに対応
* GCPパッケージ`google-cloud-kms`が必要
* GCP CKMキーに`ENCRYPT`および`DECRYPT`の権限が必要
  {% endtab %}

{% tab title=".Net" %}

* .NET用シークレットマネージャーSDKに対応
* GCPパッケージ`Google.Apis.CloudKMS.v1`が必要
* GCP CKMキーに`ENCRYPT`および`DECRYPT`の権限が必要
  {% endtab %}

{% tab title="GoLang" %}

* GoLang用シークレットマネージャーSDKに対応
* GCP SDKから[kms/apiv1](https://pkg.go.dev/cloud.google.com/go/kms/apiv1)、[kmspb](https://pkg.go.dev/cloud.google.com/go/kms/apiv1/kmspb)、[core](https://pkg.go.dev/github.com/keeper-security/secrets-manager-go/core)、[kms](https://pkg.go.dev/cloud.google.com/go/kms)の各パッケージが必要
* GCP CKMキーに`ENCRYPT`および`DECRYPT`の権限が必要
  {% endtab %}
  {% endtabs %}

## セットアップ

### 1. モジュールのインストール

{% tabs %}
{% tab title="Java" %}
GradleまたはMavenを使用してプロジェクトをセットアップ

**Gradle**

```
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-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>
<!-- 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" %}
npmを使用してシークレットマネージャーとGoogle Cloud Key Managementモジュール統合をインストールします。

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

{% endtab %}

{% tab title="Python" %}
シークレットマネージャーGoogle Cloud Key Managementモジュールは、pipを使用してインストールできます。

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

{% endtab %}

{% tab title=".Net" %}
シークレットマネージャーのGoogle Cloud Key Managementモジュールは、.NETのNuGetパッケージマネージャーを使用してインストールできます。

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

{% endtab %}

{% tab title="GoLang" %}
シークレットマネージャーのGoogle Cloud Key Managementモジュール統合は、以下を使用してインストールできます。

```bash
go get github.com/keeper-security/secrets-manager-go/integrations/gcp
```

{% endtab %}
{% endtabs %}

### 2. Google CKM接続を構成

Google Cloud Platform (GCP) で安全に認証を行うには、JSON形式のサービスアカウントキーを作成します。この認証情報ファイルは、GCPのサービスとプログラム経由でやり取りする際の認証手段として使用されます。

{% hint style="info" %}
キーの生成の詳細については、[Googleのドキュメント](https://cloud.google.com/iam/docs/keys-create-delete)をご参照ください。
{% endhint %}

### 3. コードにGCPキーボルトストレージを追加

GCP接続の設定が完了したら、統合機能を使ってKSM構成を暗号化および復号化するためのキーを取得できます。また、シークレットマネージャーSDKに、KMSをストレージとして使用するよう指示する必要があります。

## GCPキーボルト統合の使用

セットアップが完了すると、シークレットマネージャーのGCPキー・ボールト統合は、シークレットマネージャーSDKのすべての機能に対応します。KSM構成ファイルを暗号化・復号化するには、コードからGCPのCKMキーへアクセスできる必要があります。

#### 指定した接続認証情報の使用

{% tabs %}
{% tab title="Java" %}
この操作を行うには、`GcpKeyValueStorage`インスタンスを作成し、それを`SecretManagerOptions`のコンストラクタに渡します。

`GcpKeyValueStorage`には、シークレットマネージャーの構成ファイル名、GCP認証情報ファイル、および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" %}
この操作を行うには、`SecretsManager`のコンストラクタで`GCPKeyValueStorage`をシークレットマネージャーのストレージとして使用します。

このストレージには、`keyConfig`、`GCPKSMClient`によって生成される`gcpsessionConfig`、およびGCP Cloud Key Managementで暗号化されるシークレットマネージャー構成ファイル名が必要です。

```javascript
 import {GCPKeyValueStorage,GCPKeyConfig,GCPKSMClient,LoggerLogLevelOptions} from "@keeper-security/secrets-manager-gcp";
    const getKeeperRecordsGCP = async () => {
        const gcpCredFile = "<path_with_name_of_gcp_cred_file.json>"
        const keyConfig2  = new GCPKeyConfig("<key_version_resource_url_1>");
        const keyConfig = new GCPKeyConfig("key_version_resource_url_2");
        const gcpSessionConfig = new GCPKSMClient().createClientFromCredentialsFile(gcpCredFile)
        let config_path = "<path to client-config.json>"
        let logLevel = LoggerLogLevelOptions.debug;
        const oneTimeToken = "<one_time_token>";
        const storage = await new GCPKeyValueStorage(config_path, keyConfig, gcpSessionConfig, 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")
    getKeeperRecordsGCP()

```

{% endtab %}

{% tab title="Python" %}
この操作を行うには、`SecretsManager`のコンストラクタで`GCPKeyValueStorage`をシークレットマネージャーのストレージとして使用します。

このストレージには、`GCPConfig`によって生成される`gcp_key_config`、`GCPKMSClientConfig`によって生成される`gcp_session_config`オブジェクト、GCP Cloud Key Managementによって暗号化されるシークレットマネージャー構成ファイルの名前が必要です。

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

# キーの例: projects/<project>/locations/<location>/keyRings/<keyring>/cryptoKeys/<key_name>/cryptoKeyVersions/<version>
gcp_key_config_1 = GCPKeyConfig("<key_resource_uri_1>")
gcp_key_config_2 = GCPKeyConfig("<key_resource_uri_2>")

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_1, 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" %}
この操作を行うには、`SecretsManager`のコンストラクタで`GCPKeyValueStorage`をシークレットマネージャーのストレージとして使用します。

このストレージには、`GCPKeyConfig`によって生成される`keyConfig`、`GCPKMSClient`によって生成される`gcpSessionConfig`オブジェクト、そして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 getOneIndividualSecret() {
     Console.WriteLine("execution started");
     string key1ResourceName = "<KEY1ResourceURL>";
     string key2ResourceName = "<Key2ResourceURL>";
     string gcpConfigFilePath = "<GCP config file path with name>";
     var keyConfig = new GCPKeyConfig(key1ResourceName);
     var gcpSessionConfig = new GCPKMSClient().CreateClientFromCredentialsFile(gcpConfigFilePath);
     var ksmConfigPath = "ksm_config.json";
     var dotnet_access_token = "[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, dotnet_access_token);
   }
   static async Task Main() {
     await getOneIndividualSecret();
   }
 }
```

{% endtab %}

{% tab title="Go" %}
この操作を行うには、`NewSecretsManager`で`NewGCPKeyVaultStorage`をシークレットマネージャーのストレージとして使用します。

`NewGCPKeyVaultStorage`は、GCP Cloud Key Management を使用してKSM構成を暗号化するために、以下のパラメータを必要とします。

* `ksmConfigFileName`: KSM構成ファイルのファイル名
* `keyResourceName`: Google Cloud Key Management の [`keyResourceName`](https://cloud.google.com/kms/docs/resource-hierarchy#retrieve_resource_id) を指定
* `credentialFileWithPath`: GCP認証情報ファイルのパスとファイル名を指定

```go
package main
import (
	"encoding/json"
	"fmt"
	"github.com/keeper-security/secrets-manager-go/core"
	gcpkv "github.com/keeper-security/secrets-manager-go/integrations/gcp"
)
func main() {
	credentialFileWithPath := "<Location of credential file ending with .json>"
	keyResourceName := "<Key_Resource_Name>"
	ksmConfigFileName := "ksmConfig.json"
	oneTimeToken := "<One_Time_Access_Token>"
	cfg := gcpkv.NewGCPKeyVaultStorage(ksmConfigFileName, keyResourceName, credentialFileWithPath)
	client_options := &core.ClientOptions{
		Token:  oneTimeToken,
		Config: cfg,
	}
	fmt.Printf("Client ID Value: %s", cfg.Get(core.KEY_CLIENT_ID))
	secrets_manager := core.NewSecretsManager(client_options)
	secrets, err := secrets_manager.GetSecrets([]string{})
	if err != nil {
		// do something
		fmt.Printf("Error while fetching secrets: %v\n", err)
	}
	for _, record := range secrets {
		fmt.Printf("Records: %v\n", record)
	}
}
```

{% endtab %}
{% endtabs %}

## 追加オプション

### キーの変更

KSM構成の暗号化に使用するキーは変更可能です。以下の例では、そのキーを使用するために必要なコードを示しています。

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

<pre class="language-bash"><code class="lang-bash"><strong>//The method changeKey(keyID) will be used to encrypt the KSM config file with new Key and version. 
</strong>GcpKeyValueStorage storage = new GcpKeyValueStorage(configFileLocation, sessionConfig);
String newKeyID = "&#x3C;new Key ID>";
boolean isChanged = storage.changeKey(keyId);
System.out.println("Key Changed: "+isChanged); // 暗号化および復号に使用するキーを変更します。
</code></pre>

{% endtab %}

{% tab title="JavaScript" %}

<pre class="language-bash"><code class="lang-bash"><strong>// 暗号化に使用するGCP Cloud Key Managementのキーを変更するには、OciKeyValueStorage インスタンスで changeKey メソッドを呼び出します。
</strong>const storage = await new GCPKeyValueStorage(configPath,keyConfig,gcpSessionConfig).init();
await storage.changeKey(keyConfig2);
</code></pre>

{% endtab %}

{% tab title="Python" %}

```python
storage = GCPKeyValueStorage(config_path, gcp_key_config_1, gcp_session_config)
is_changed = storage.change_key(gcp_key_config_2)
print("Key is changed:", is_changed)
```

{% endtab %}

{% tab title=".Net" %}

```bash
// 暗号化に使用するGoogle Cloud Key Managementのキーを変更するには、
// GCPKeyValueStorage インスタンスで ChangeKeyAsync メソッドを呼び出します。
// ※ロギング機能を使用する場合は Microsoft.Extensions.Logging の参照が必要です。
var gcp_storage = new GCPKeyValueStorage(keyConfig2, gcpSessionConfig, path,logger);
bool isChanged = gcp_storage.ChangeKeyAsync(keyConfig1).Wait();
Console.WriteLine(isChanged)
```

{% endtab %}

{% tab title="GoLang" %}

<pre><code>// GCP構成を変更せずにキーだけを変更したい場合は、Oracle構成の代わりに nil を渡してください。
cfg := gcpkv.NewGCPKeyVaultStorage(ksmConfigFileName, keyResourceName, credentialFileWithPath)
<strong>updatedResourceName := "&#x3C;Updated Key Resource Name>"
</strong>isChanged, err := cfg.ChangeKey(updatedResourceName, "")
	if err != nil {
		// do something
	}
fmt.Printf("Key changed: %v\n", isChanged)
</code></pre>

{% endtab %}
{% endtabs %}

### 構成を復号化する

現在の実装を別のクラウドに移行する場合や、生の認証情報を取り出したい場合は、構成ファイルを復号化できます。この関数はブール値を受け取り、`true`に設定すると復号された構成をファイルに保存し、`false`の場合は復号された構成を返すだけになります。

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

```java
GcpKeyValueStorage storage = new GcpKeyValueStorage(configFileLocation, sessionConfig);
storage.decryptConfig(false); // 平文のみを抽出するには、パラメーターに false を指定します。
//または 
storage.decryptConfig(true); // 平文を抽出し、構成ファイルを平文として保存するには、パラメーターに true を指定します。
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const storage = await new GCPKeyValueStorage(configPath,keyConfig,gcpSessionConfig).init();
await storage.decryptConfig(true); // 平文を抽出して構成ファイルを平文として保存するには、パラメーターに true を指定します。
// または
await storage.decryptConfig(false);  // 平文のみを抽出するには、false を指定します。
```

{% endtab %}

{% tab title="Python" %}

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

# 平文のみ抽出
plaintext = storage.decrypt_config(False)
print(plaintext)

# 平文を抽出して構成ファイルを平文として保存
plaintext = storage.decrypt_config(True)
print(plaintext)
```

{% endtab %}

{% tab title=".Net" %}

```bash
# 構成ファイルを復号して平文として再保存するには、OracleKeyValueStorage インスタンスで DecryptConfigAsync メソッドを呼び出します。
var gcp_storage = new GCPKeyValueStorage(keyConfig2, gcpSessionConfig, path,logger);
var conf = await gcp_storage.DecryptConfigAsync(false); # 平文のみを抽出するには、パラメーターに false を指定します。
Console.WriteLine(conf);
# または
var conf = await gcp_storage.DecryptConfigAsync(true); # 平文を抽出し、構成ファイルを平文として保存するには、パラメーターに true を指定します。
```

{% endtab %}

{% tab title="GoLang" %}

<pre class="language-go"><code class="lang-go">cfg := gcpkv.NewGCPKeyVaultStorage(ksmConfigFileName, keyResourceName, credentialFileWithPath)
<strong>plainText, err := cfg.DecryptConfig(false)
</strong>if err != nil {
	// 適切な処理を実行
	fmt.Printf("Error while decrypting config: %v", err)
}  
plainText, err := cfg.DecryptConfig(true) // 平文を抽出し、構成ファイルを平文として保存するには、パラメーターに true を指定します。
	// 適切な処理を実行
	fmt.Printf("Error while decrypting config: %v", err)
}  
</code></pre>

{% endtab %}
{% endtabs %}

{% hint style="success" %}
KSM統合機能を使用する準備ができました。
{% endhint %}

{% hint style="info" %}
その他の例と機能については、[KSM SDKのドキュメント](https://docs.keeper.io/keeperpam/secrets-manager/developer-sdk-library)をご参照ください。
{% endhint %}
