アプリの取引用の鍵とシークレットをサーバーのディスクに置かない

erpc worker は、アプリの取引用の鍵とシークレットを 1Password、キーチェーン、または暗号化したキーストアに保管し、メモリの中でアプリに渡します。サーバーのディスクには置きません。
このページは、プレリリースの ERPC CLI v0.1.0-rc.4 について説明しています。

取引用の鍵がアプリに届くまで

ウォレットを持つアプリは、起動時にパイプで鍵を受け取ります。wallet.json も .env もなく、サーバーにコピーもありません。erpc は、鍵を暗号化せずにディスクへ書くことはありません。鍵を入れるファイルは 1 つだけで、それは自分のマシンにあるキーストアのファイルです。パスフレーズのもとで暗号化されています。
  • 保管場所: erpc worker key new は、erpc login がセッションを 1Password に置いていれば 1Password に、そうでなければキーチェーンに、それもなければキーストアに鍵を作ります。erpc.toml には、鍵の参照と公開鍵が記録されます。
  • サーバーの上: erpc worker のエージェントは、鍵をメモリの中だけに持ちます。自身をダンプできない状態にしてメモリをロックし、ファイルディスクリプタで鍵をアプリに渡します。アプリは読んだ後に鍵を消去します。
  • 再起動の後、ワーカーはロックされた状態で戻ります。erpc worker start が鍵をもう一度送るまで、アプリは動きません。エージェントが失敗したり強制終了されたりした場合も、systemd が再び起動し、同じようにロックされた状態で戻ります。
  • パッケージの更新でワーカーは再起動しません。 deploy は needrestart に、ワーカーのユニットに手を出さないよう設定します。自動モードではワーカーのユニットを後回しにし、ターミナルで聞かれたときの既定の答えは「いいえ」です。そのため、無人のセキュリティ更新でアプリが再起動することはありません。この設定を書けなかったときは、デプロイはそのことを伝えて先へ進み、ワーカーはこの保護なしで動きます。
取引用の鍵を指すのは [wallet] だけで、ほかからは指しません。erpc がこの鍵を読むのは、ターミナルにいる人のためだけです。AI のツールのためにも、1Password のサービスアカウントでも読みません。[wallet] の参照を指す [secrets] の行や、.wallet で終わる keychain: または keystore: のアカウントは受け付けません。キーストアでは、鍵として保管したエントリはシークレットとしては開きません。1Password と、別の名前のキーチェーンのアカウントでは、鍵であることを示す印がありません。[wallet] のない erpc.toml がそうした項目を [secrets] の下で指すと、その項目はシークレットとして読まれます。

値の保管場所を選ぶ

1Password は必須ではありません。erpc worker key new と erpc worker secret put は、--store で指定しない限り(--store 1password --vault <id>、--store keychain、--store keystore)、受け取った値を次のうち最初に当てはまる場所に保管します。
  1. 1Password。erpc login がセッションをそこに置いているとき、または --vault を付けたとき。
  2. OS のキーチェーン。再起動の後も値を保てる環境のとき。macOS、Windows、ログインしたセッションでデスクトップのキーリングがある Linux です。
  3. erpc のキーストア。そうしたキーリングのない Linux マシンのとき。ヘッドレスのサーバー、WSL、SSH でのログインです。このようなマシンで --store keychain を付けると受け付けません。
キーチェーンやキーストアに置いた鍵は、そのマシン 1 台にしかなく、コピーも同期もありません。ほかのマシンは keychain: や keystore: の参照を読めません。
マシンをなくしたり消去したりすると、ウォレットも失われます。ウォレットに置く額は少なくするか、1Password を使ってください。1Password なら、保管庫にログインしたどのマシンからでも読めます。1Password には erpc login --store 1password-desktop でログインするか、デスクトップアプリのない環境では op signin を使います。
1Password のサービスアカウントにアプリのシークレットを置くことはできますが、erpc はサービスアカウントで取引用の鍵を読みません。1Password では、読み出しのたびにアプリに承認の確認が出ることがあり、その間 erpc はスピナーを表示します。

シークレットを保管する

API トークンや RPC キーのようなシークレットも同じように保管しますが、アプリにはパイプではなく環境変数として届きます。erpc worker secret put <NAME> が値を保管し、erpc.toml の [secrets] には参照だけが入ります。
bash
erpc worker secret put API_TOKEN --generate          # the bot's own API token, made for you and shown to nobody
erpc worker secret put ERPC_API_KEY --from-account   # the account's RPC key, read from your account (or SOLANA_RPC_ENDPOINT in [vars])
  • --generate は値を作ります。ランダムな 32 バイトを、16 進数 64 文字で表したものです。
  • --from-account は、アカウントの RPC キーのうち、共有 RPC が受け入れた最初のキーを保管します。キーはプライマリーキーから順に、1 つにつき 1 回の getHealth で試し、応答を 8 秒待ちます。401 か 403 が返ったキーは受け入れられなかったものとして次を試し、RPC が受け入れたキーだけを保管します。保管したのがアカウントのプライマリーキーか別のキーかを表示します(--json では account_key)。
  • どちらの値も表示しません。--json でも同じです。キーストアを初めて使うとき、またはロックされているときは、ターミナルにいる人が要ります。
  • キーはこのマシンから試すので、サーバーのアドレスに限ったキーは、サーバーでは使えてもここでは受け入れられません。すべてのキーが受け入れられなかったとき、--from-account は何も保管しません。使いたいキーを手で保管してください。入力は画面に出さずに打つか、パイプで渡します。RPC に問い合わせられなかったときも何も保管せず、erpc.toml は元のままです。同じコマンドをもう一度実行してください。
キーを手で保管するには、次のようにします。
bash
erpc worker secret put ERPC_API_KEY        # asks for the value, unseen
  • --replace は、すでに設定されている名前に新しい値を保管します。erpc worker secret list は、シークレットの設定を名前と保管場所で一覧にします。
  • データの回線が渡す設定(GRPC_ENDPOINT、SHREDS_ENDPOINT、SOLANA_SEND_RPC_ENDPOINT)はシークレットではありません。--grpc、--shreds、--unlimited が設定します。
[secrets] や [wallet] の参照は、次のどれかです。
参照値のある場所
op://<vault-id>/<item-id>/<field>1Password。保管庫と項目の ID で指します
keychain:<service>/<account>値を保管したマシンの OS のキーチェーン
keystore:<service>/<account>値を保管したマシンの erpc のキーストア

キーストアで値を暗号化して保管する

キーストアは ~/.erpc/keystore のディレクトリです(ERPC_HOME が設定されていれば、その下の keystore)。Linux と macOS では、ディレクトリは 0700、ファイルは 0600 になります。Windows では、erpc は独自の権限を設定しません。
  • master.json には、ランダムな 32 バイトのマスターキーが入っています。マスターキーは、パスフレーズから PBKDF2-HMAC-SHA256(600,000 回)で作った鍵のもとで封じられています。各エントリは 1 つの値を持ち、エントリごとの鍵のもとで ChaCha20-Poly1305 で封じられています。
  • パスフレーズ: キーストアを使う最初の key new か secret put で決めます。ターミナルで 2 回入力し、12 文字以上にします。erpc がパスフレーズを受け取るのは、入力が画面に出ないこのプロンプトからだけで、引数・環境変数・パイプからは受け取りません。
  • Linux でのロック解除: パスフレーズでキーストアを一度開くと、ロック解除はカーネルの永続キーリングに、メモリの中で保たれます。保たれるのは、マシンが再起動するか、キーリングが使われないまま有効期限(システムが別に定めていなければ 3 日)を迎えるか、erpc worker secret lock を実行するまでです。erpc worker secret unlock は先にパスフレーズを聞き、いつまで解除されているかを伝えます。自分のログインを持たずに始めたシェル(- なしの su、sudo -E)では、ロック解除は保たれず、コマンドごとにパスフレーズを聞きます。
  • ターミナルに人がいないとき、キーストアが要るコマンドは、ロック解除が保たれていればそれを使い、なければ erpc worker secret unlock を示して失敗します。ロックが解除されたキーストアが渡すのはシークレットで、取引用の鍵は渡しません。
  • macOS と Windows では(--store keystore)、ロック解除は保たれません。キーストアが要るコマンドは、そのたびにパスフレーズを 1 回聞くので、ターミナルが要ります。

キーストアが守るもの、守らないもの

  • keystore ディレクトリをバックアップし、パスフレーズを覚えておいてください。 erpc はどちらも復旧できず、両方がそろわなければ、キーストアの中身は失われます。
  • キーストアのファイルとパスフレーズを持つ人は、鍵を持つことになります。PBKDF2 は推測を 1 回ごとに遅くしますが、推測しやすいパスフレーズを安全にするわけではありません。
  • キーストアのロックが解除されている間は、自分として動くどのプログラムも、カーネルのキーリングからマスターキーを読み(自分のキーリングを持たないセッションのプログラムも、そのキーリングをつなぎ込めます)、鍵のエントリも含めて、すべてのエントリを開けます。erpc 自身の決まり([wallet] が指す鍵は、ターミナルにいる人のためだけに読み、AI のツールのためには読まない。キーストアに保管した鍵は、シークレットとしては開かない)は、erpc がすることです。自分として動くほかのプログラムを縛るものではありません。使い終わったら erpc worker secret lock を実行してください。
  • エントリの名前は隠されず、エントリの大きさから値の長さが分かります。
  • 書き換えられたファイルは開きません。同じエントリの古いコピーを元の場所に戻したものは開きます。
  • erpc worker secret rm は、シークレットのキーストアのエントリを、erpc.toml のその行と一緒に削除します(アプリのほかの設定が同じエントリを指している場合を除きます)。1Password やキーチェーンにある値はそのまま残します。ディスクを消去するわけではなく、バックアップの中のコピーも残ります。
  • erpc は、取引用の鍵のエントリを削除することも上書きすることもありません。鍵を替えるには、資金を移してから、そのファイルと [wallet] を自分で削除してください。
  • キーストアとキーチェーンでは、大文字・小文字を問わず WALLET という名前の設定は作れません。--store 1password ならその名前を使えます。

取引用の鍵を扱う

コマンドすること
erpc worker key new取引用の鍵を作り、入金先の公開鍵を表示します
erpc worker key import <FILE>鍵ファイルを 1Password、キーチェーン、またはキーストアに移し、ファイルの消去を提案します
erpc worker key show鍵の公開鍵と保管場所を表示します
erpc worker key balanceアプリ自身の RPC の設定を通して、鍵の残高を表示します
erpc worker key send --to <ADDRESS> --sol <N>ターミナルで「はい」と答えた後、送金 1 件にメモリの中で署名します。--all は手数料を除いた全額を送ります
送金が届いたかどうか分からないまま erpc が終わったときは、もう一度送る前にその署名を調べてください。2 回目の送信は、2 件目の送金になります。