# Harness CIプラグイン

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FNJsoKtG8Uf0Tm9M4MXcl%2Fkeeper%2Bharness.png?alt=media&#x26;token=0ac51e07-5eec-4bfc-bdd4-57657e94917c" alt=""><figcaption></figcaption></figure>

### 機能

* Harness CIパイプライン内でKeeperボルトからシークレットを取得
* Harness CIパイプラインのビルド引数としてシークレット認証情報を設定
* Keeperボルトからセキュアファイルをコピー
* プラグインURL: <https://plugins.drone.io/plugins/keeper-plugin>

{% hint style="info" %}
Keeperシークレットマネージャーの機能一覧は [概要](https://docs.keeper.io/jp/keeperpam/secrets-manager/overview) をご参照ください。
{% endhint %}

### 要件

#### Keeperシークレットマネージャーの要件

| 要件          | 説明                                                                                                                                                |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| KSMアクセス     | Keeperシークレットマネージャーの有効なサブスクリプションが必要です ([クイックスタートガイド](https://docs.keeper.io/jp/keeperpam/secrets-manager/quick-start-guide))                       |
| アドオン有効化     | Keeperアカウントでシークレットマネージャーアドオンが有効になっていること                                                                                                           |
| ロール所属       | シークレットマネージャー適用ポリシーが有効なロールのメンバーであること                                                                                                               |
| KSMアプリケーション | シークレットが共有された[Keeperシークレットマネージャー](https://docs.keeper.io/jp/keeperpam/secrets-manager/about/terminology)アプリケーションが構成済みであること                         |
| KSM構成       | 初期化済みの[構成](https://docs.keeper.io/jp/keeperpam/secrets-manager/about/secrets-manager-configuration) (Base64トークン、ワンタイムアクセストークン、またはJSON構成ファイルのいずれか) |

#### Harness CIの要件

* 有効なHarness[アカウント](https://app.harness.io/auth/#/signin)があること
* [Harness CI](https://developer.harness.io/docs/continuous-integration/use-ci/prep-ci-pipeline-components/)のパイプラインが設定されていること
* Harness CIの[シークレット管理](https://developer.harness.io/docs/platform/secrets/add-use-text-secrets/)を理解していること
* [Keeperプラグイン](https://plugins.drone.io/plugins/keeper-plugin)がインストールされていること

### 構成の種類

プラグインは3つの認証方式をサポートします。セキュリティ要件に合わせて選択します。

| 種類                   | Harnessのシークレット種別 | 用途              |
| -------------------- | ---------------- | --------------- |
| ワンタイムアクセストークン (OTAT) | テキストシークレット       | 使い捨て、最高のセキュリティ  |
| Base64トークン           | テキストシークレット       | 再利用可、標準的なセキュリティ |
| JSON構成ファイル           | ファイルシークレット       | 完全な構成、再利用可      |

### セットアップ手順

#### 手順1. Keeperボルトの構成

1. Keeperボルトに[共有フォルダ](https://docs.keeper.io/enterprise-guide/sharing/folders)を作成します。
2. 共有フォルダ内にシークレットを含む[レコードを作成](https://docs.keeper.io/enterprise-guide/creating-vault-records)します。
3. シークレットマネージャーの[アプリケーション](https://docs.keeper.io/jp/keeperpam/quick-start-guide#create-a-secrets-manager-application)を作成します。
4. 希望する認証情報の種類を生成します。
   * ワンタイムアクセストークン ([OTAT](https://docs.keeper.io/jp/keeperpam/secrets-manager/about/one-time-token))
   * Base64[トークンまたはJSON](https://docs.keeper.io/jp/keeperpam/about/secrets-manager-configuration#creating-a-secrets-manager-configuration)構成

#### 手順2. Harness CIのシークレット作成

次の画面に移動します。**\[Project] → \[Project Setup] → \[Secrets] → \[+ New Secret]**

**オプションA: ワンタイムアクセストークン (テキストシークレット)**

1. **\[+ New Secret → Text]** をクリックします。
2. 次のとおり設定します。
   * **\[Secret Name]:** `keeper_otat_secret`
   * **\[Secret Value]:** トークンを貼り付けます (例: `US:xxxxx...`)
   * **\[Scope]:** **\[Project]** (推奨)
3. **\[Save]** をクリックします。

{% hint style="info" %}
ワンタイムアクセストークンは1回限りの利用です。パイプライン実行ごとに新しいトークンを生成してください。
{% endhint %}

**オプションB: Base64トークン (テキストシークレット)**

1. **\[+ New Secret → Text]** をクリックします。
2. 次のとおり設定します。
   * **\[Secret Name]:** `keeper_base64_secret`
   * **\[Secret Value]:** Base64エンコードされたトークンを貼り付けます。
   * **\[Scope]:** **\[Project]** (推奨)
3. **\[Save]** をクリックします。

{% hint style="info" %}
Base64文字列に改行や空白が入らないようにしてください。
{% endhint %}

**オプションC：JSON構成ファイル (ファイルシークレット)**

1. **\[+ New Secret] → \[File]** をクリックします。
2. 次のとおり設定します。
   * **\[Secret Name]:** `keeper_ksm_config_file`
   * **\[Upload File]:** KSMのJSON構成ファイルを選択します。
   * **\[Scope]:** **\[Project]** (推奨)
3. **\[Save]** をクリックします。

想定されるJSONの構造は次のとおりです。

```json
{
  "hostname": "keepersecurity.com",
  "clientId": "your-client-id",
  "privateKey": "your-private-key"
}
```

#### 手順3. パイプラインでの参照

シークレットは次の構文で参照します。

```yaml
settings:
  ksm_config: <+secrets.getValue("your_secret_identifier_name")>
```

### クイックスタート

#### パイプラインの例

```yaml
pipeline:
  name: harness_keeper_plugin
  identifier: harness_keeper_plugin
  projectIdentifier: default_project
  orgIdentifier: default
  stages:
    - stage:
        name: HkpCI
        identifier: HkpCI
        type: CI
        spec:
          cloneCodebase: false
          platform:
            os: Linux
            arch: Amd64
          runtime:
            type: Cloud
            spec: {}
          execution:
            steps:
              - step:
                  type: Plugin
                  name: Fetch_Keeper_Secrets
                  identifier: Fetch_Keeper_Secrets
                  spec:
                    image: keeper/harness-plugin:latest
                    settings:
                      ksm_config: <+secrets.getValue("keeper_base64_secret")>
                      secrets: |
                        RECORD_UID/field/password > PASSWORD
                        RECORD_UID/field/login > USERNAME
              - step:
                  type: Run
                  name: Use_Secrets
                  identifier: Use_Secrets
                  spec:
                    image: alpine:3.20
                    shell: Sh
                    command: |
                      if [ -f /harness/secrets/USERNAME ] && [ -f /harness/secrets/PASSWORD ]; then
                        USERNAME=$(cat /harness/secrets/USERNAME)
                        PASSWORD=$(cat /harness/secrets/PASSWORD)
                        echo "Username: $USERNAME"
                        echo "Password retrieved successfully"
                      else
                        echo "Error: Secret files not found"
                        exit 1
                      fi
```

{% hint style="info" %}
`RECORD_UID` はKeeperボルトの実際のレコードUIDに置き換えてください。
{% endhint %}

パイプライン実行が完了すると、シークレットを出力する手順のログで内容を確認できます。

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FaggGT7TJmTqYDSEMMqYp%2Fimage.png?alt=media&#x26;token=f269170e-e348-4b1e-8e44-226fda09c6b1" alt=""><figcaption></figcaption></figure>

### シークレットの設定

#### Keeper表記法の構文

`secrets` 入力は、取得するシークレットを指定するためにKeeper表記法を用います。

```yaml
settings:
  secrets: |
    RECORD_UID/field/password > PASSWORD
    RECORD_UID/field/login > USERNAME
    RECORD_UID/custom_field/apiKey > API_KEY
    RECORD_UID/file/certificate.crt > CERT_FILE
```

#### 表記の形式

```
<record_uid>/<selector>/<field_name> > <destination_name>
```

<table><thead><tr><th width="290.93359375">要素</th><th>説明</th></tr></thead><tbody><tr><td><code>record_uid</code></td><td>Keeperレコードの識別子</td></tr><tr><td><code>selector</code></td><td>データの種類です。<code>field</code>、<code>custom_field</code>、<code>file</code> のいずれか</td></tr><tr><td><code>field_name</code></td><td>取得するフィールドまたはファイルの名前</td></tr><tr><td><code>destination_name</code></td><td><code>/harness/secrets/</code> 内の出力ファイル名</td></tr></tbody></table>

#### セレクターの種類

<table><thead><tr><th width="174.6640625">セレクター</th><th width="272.37890625">説明</th><th>出力先</th></tr></thead><tbody><tr><td><code>field</code></td><td>標準のレコードフィールド (ログイン、パスワードなど)</td><td><code>/harness/secrets/&#x3C;destination></code></td></tr><tr><td><code>custom_field</code></td><td>レコードに定義されたカスタムフィールド</td><td><code>/harness/secrets/&#x3C;destination></code></td></tr><tr><td><code>file</code></td><td>ファイル添付</td><td><code>/harness/secrets/&#x3C;destination></code></td></tr></tbody></table>

#### 例

```yaml
secrets: |
  # Standard fields
  abc123/field/password > DB_PASSWORD
  abc123/field/login > DB_USERNAME
  
  # Custom fields
  xyz789/custom_field/apiKey > API_KEY
  xyz789/custom_field/endpoint > API_ENDPOINT
  
  # File attachments
  def456/file/server.crt > SERVER_CERT
  def456/file/server.key > SERVER_KEY
```

{% hint style="info" %}
配列やキーと値のペアなど複雑な値については、[Keeper表記法](https://docs.keeper.io/jp/keeperpam/secrets-manager/about/keeper-notation)の述語 (Predicates) のドキュメントをご参照ください。
{% endhint %}

### ローカルDockerランナーの構成

Harness Cloudではなく `runtime: type: docker` ([ローカルランナー](https://developer.harness.io/docs/continuous-integration/use-ci/set-up-build-infrastructure/define-a-docker-build-infrastructure/)) を使う場合、ローカル上のパイプライン間で[データ](https://developer.harness.io/docs/continuous-integration/use-ci/caching-ci-data/share-ci-data-across-steps-and-stages/#share-data-between-steps-in-a-stage)を共有するには[共有パス](https://developer.harness.io/docs/continuous-integration/use-ci/prep-ci-pipeline-components/#shared-paths)を設定する必要があります。

```yaml
spec:
  cloneCodebase: false
  platform:
    os: Linux
    arch: Amd64
  runtime:
    type: docker
    spec: {}
  sharedPaths:
    - /harness
  execution:
    steps:
      # ... your steps
```

{% hint style="info" %}
Harness Cloudでは `/harness` が自動的に共有されます。ローカルDockerでは `sharedPaths` を明示的に設定する必要があります。
{% endhint %}

### セキュリティのベストプラクティス

<table><thead><tr><th width="316.59765625">項目</th><th>説明</th></tr></thead><tbody><tr><td>ワンタイムアクセストークンの利用</td><td>可能な限りパイプライン実行ごとに新しいトークンを生成します</td></tr><tr><td>シークレットファイルの削除</td><td>パイプラインの手順で利用後にシークレットファイルを削除します</td></tr><tr><td>適切なスコープ</td><td>より広いアクセスが不要な限りプロジェクトレベルのスコープを使います</td></tr><tr><td>アクセスの制限</td><td>パイプラインを編集できるユーザーを制限します (編集者はシークレットを読み取れる可能性があります)</td></tr></tbody></table>

#### シークレットのマスキング (ログからの隠蔽)

Harness CIはコンソールに出力されたシークレットをログ上で自動的にマスキングします。ただし次の点に注意してください。

* 隠されるのは出力ログのみです
* パイプライン編集者がシークレットを取り出せる可能性があります
* 常に最小権限の原則に従ってください

### トラブルシューティング

#### よくある問題

| 現象                        | 原因                       | 対処                                                     |
| ------------------------- | ------------------------ | ------------------------------------------------------ |
| `KSM config is required`  | シークレットが見つからない、または式が誤っている | シークレット名が完全一致しているか確認します (大文字・小文字を区別)                    |
| `Missing required fields` | JSON構成が不完全               | JSONに `hostname`、`clientId`、`privateKey` が含まれることを確認します |
| 式が解決されない                  | シークレットのスコープが一致しない        | シークレットのスコープがパイプラインのスコープと一致しているか確認します                   |
| トークンはすでに使用済み              | ワンタイムトークンは1回限り           | 実行ごとに新しいOTATを生成します                                     |

#### 事象: クラウドでは動くがローカルで失敗する

**症状:** `Fetch_Keeper_Secrets` は成功しますが、次の手順で `/harness/secrets/` の読み取りに失敗します

**原因と対処**

1. **シークレット名の不一致**
   * プラグインは `> USERNAME` および `> PASSWORD` に書き込みます
   * Run手順では `/harness/secrets/USERNAME` および `/harness/secrets/PASSWORD` を参照する必要があります
2. **ワークスペースが共有されていない**
   * ステージのspecに `sharedPaths: /harness` を追加します (ローカルDockerランナーの構成を参照)

#### デバッグ: プラグイン出力の確認

プラグインの直後にデバッグ用の手順を追加します。

```yaml
- step:
    type: Run
    name: Debug_Secrets
    spec:
      image: alpine:3.20
      shell: Sh
      command: |
        echo "Contents of /harness/secrets:"
        ls -la /harness/secrets/ || echo "Directory not found"
```

ファイルが表示されない場合は次を確認してください。

* プラグインの設定 (シークレット名)
* ワークスペースの共有 (ローカルランナー向け)
* `ksm_config` の設定 (`PLUGIN_KSM_CONFIG` へのマッピング)
