パスワードストア利用時の「トークン更新漏れに ご注意!!」という話

## はじめに

ロボットが業務システムにログインする時のアカウント情報、その管理どうしてますか？

- ロボットに組み込んでしまう。
- 外部ファイルに記述し、実行時に読み込むようにしている。
- パスワードマネージャーで管理し、API等により実行時に認証情報を取得する。
- Kapplets を使って、実行の都度入力する。
- その他

など、用途や状況により様々でしょう。

BizRobo! もエンタープライズ利用の場合には CyberArk などサードパーティ製品と連携させてアカウントを管理する方法もありますが、多くの場合は BizRobo! 内蔵の `パスワードストア` を利用しているのではないでしょうか。

今回は経験の浅いメンバーから時々質問を受ける `パスワードストア` の「特徴」と「手間」について整理しようと思います。

:::note
本記事は、BizRobo! v11.3.0.2 の利用を前提に解説します。
:::

## パスワードストアとは

マニュアルによると
> パスワード ストアは、機密情報を開示せずにさまざまなシステムへのアクセス権を付与するように設計されたパスワード リポジトリです。

とあります。

言い換えると「**ロボット開発者が一切パスワードを知らなくても、ロボットが実行時に認証情報を取得してターゲットシステムにログインするための仕組み**」ですね。

パスワードを開発者に知らせる必要がないので、開発者がパスワードを管理する必要もなければ、知らない情報を漏洩することもない。セキュアな仕組みです。

`パスワードストア` はレポジトリ機能として Management Console（以降、MC）に実装されており、`パスワード` と `パスワード アクセス` という情報の組み合わせで構成されています。

#### パスワード
管理する対象・アカウントの情報
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/f5a3bcff-0774-24df-64d4-86ce4379dcfa.png)
- 「プロジェクト」ごとに管理されます
- ターゲットシステムへログインするためのアカウント情報（ユーザー名とパスワード）を登録します

#### パスワードアクセス
認証のための情報（誰にアクセスを許可するかを管理）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/d7681d85-b6e7-6580-dbd9-ec15d1b765e8.png)
成りすましを防ぎ、許可された特定のユーザ（正規の手続きを踏んで本番環境へ登録されたロボット）にだけパスワード情報を貸与するため、MCへ登録されたロボット[^1]の `リソースアクセストークン` をキー情報として登録します。

[^1]: 稼働単位のグループ（ベーシックエンジンロボットを中心に、そこに含まれるロボット、スニペットのグループ）

#### アクセストークン算出の範囲
`リソース アクセス トークン` は、MC に登録されたに `ベーシックエンジンロボット`、`ロボット`、`スニペット` の一式を解析して算出された文字列で、それらの状態が少しでも変化すると発行されるトークンの値も変わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/ac8814f2-37d0-288e-97b8-68044669256a.png)
ロボットの動作を定義する一塊のファイル群を対象としてトークンの計算を行います。

この特徴により **「正規の手続きを踏まず無許可でMCに登録されたロボット」や「不正に改変されたロボット」ではパスワード情報を取得することができず**、ロボットを用いた不正ログインを防ぐ仕組みになっています。

:::note warn
セキュリティ上の理由から `パスワードストア` を利用するロボットでは、MCへ登録するたびにロボットのアクセストークンを取得し、`パスワードアクセストークン`として設定する必要があります。
:::

## `パスワードアクセストークン` の更新漏れに注意するケース

これまで見てきたように、**ロボットの動作を定義する一塊のファイル群**に変更があった場合には、ロボットの`リソースアクセストークン` も更新されます。

`リソースアクセストークン` の取得は `ベーシックエンジンロボット` に対して行いますが、`ロボット` や `スニペット` に変更があった場合でも、それを参照している `ベーシックエンジンロボット` のトークンは変更になります。

つまり、以下の様に**共通部品**として複数の `ベーシックエンジンロボット` から参照される `ロボット` や `スニペット` を編集した場合、`パスワードストア` を利用している参照元 `ベーシックエンジンロボット` は全てトークンを取得しなおしてパスワードアクセスを更新する必要があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/5b501248-5b92-5804-6d31-5e38a47ea674.png)
とはいえ影響範囲は「プロジェクト」なので それほど大量になることも混乱することもないですが、見落としが無いよう注意が必要です。

## 見落としを防ぐための一つの工夫

残念ながら v11.3 現在の MC には `参照先ロボット` や `使用されるスニペット` をキーワードにしたフィルタ機能がないので、`リソースアクセストークン` を再取得すべき `ベーシックエンジンロボット` の一覧を目視以外で確認する方法がないです。

ということでトリッキーではあるものの、トークン再取得リストを出力するコードを用意してみました。

```javascript:影響があるベーシックエンジン ロボットの抽出 [produced with ChatGPT]
const targetRobot = "%編集したロボット名%";

// class="rl2robotsReferenced" のタグのinnerTextにtargetRobotが含まれている行を抽出
const rows = Array.from(document.querySelectorAll('tr.ng-star-inserted')).filter(row => {
  const rl2robotsReferencedCell = row.querySelector('td.rl2robotsReferenced');
  return rl2robotsReferencedCell && rl2robotsReferencedCell.innerText.includes(targetRobot);
});

// 結果を格納する配列
const results = [];

// 抽出した行から class="folder" タグと class="name" タグのInnerTextを抽出
rows.forEach(row => {
  const folderCell = row.querySelector('td.folder');
  const nameCell = row.querySelector('td.name');
  if (folderCell && nameCell) {
    const folder = folderCell.innerText.trim();
    const name = nameCell.innerText.trim();
    results.push({ folder, name });
  }
});

// 結果をJSON形式で表示
console.log(results);
```
Chromeにて動作確認済み。
以下の様に、MCのレポジトリ ページ上で Chrome Developer Tool を開き、Consoleに上記のコードを貼り付けてEnterキーを押します。実行前に `%編集したロボット名%` の編集は忘れずに。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/ff9eac27-ee9e-6cbe-a9d7-30275a52defe.png)
ページを跨いでの抽出はできないので、「ページごとのアイテム」は 100 にセットしておくことをお勧めします。

## まとめ

仕組みと必要性を知っていれば意識せずとも確認するので見落としも少ないのですが、単なる手順として覚えていると抜けるものですね。