greenlight proto をベースにした解説。
greenlightはLightning Network(LN)の運用を簡易化するためのサービスである。しかし、どこが自己ホスト(self host)で、どこに信頼を置く必要があるのかが分かりにくい。SchedulerはLNノードの管理やスケジューリング機能を担うが、これは非公開のコードで動作し、ユーザーはその内部を直接検証できない。一方、Signerはトランザクション署名を行う重要なコンポーネントであり、cln(Core Lightning)はLightning Networkの実装である。これらは公開リポジトリとして誰でも参照できる。
目的と結論
Greenlight では、Scheduler (Closed Source) が Node 管理の中心にあり、UserClient (with integrated Signer/HSM) が Self-Hosted 環境で秘密鍵を保持する構造をとる。結論として、UserClient 側が鍵操作を制御しつつ、Greenlight 側の Scheduler が Node (CLN) を起動・管理する。これにより、秘密鍵をローカルで保持したまま Node をリモートで稼働させる運用が可能となる。
全体構造
以下の図に示すように、UserClient (with integrated Signer/HSM) は自前の環境 (Self-Hosted) で動作する。一方、Scheduler は Greenlight が管理し、CLN (c-lightning+plugin) も Greenlight Hosted 環境で稼働する。UserClient は Scheduler に対して Manage API call を行い、Node に対する操作は Scheduler が CLN を経由して実行する。Signer/HSM は秘密鍵をローカルで保持し、署名要求のみを受け付ける。
(Self-Hosted) (Greenlight Hosted)
+-----------------------------------+ (Manage API call) +----------------------------+
| UserClient (with integrated | --------------------> | Scheduler (Closed Source) |
| Signer / HSM) | +-------------+--------------+
+-----------------------------------+ |
| (Node management)
| v
| +------------------------+
|-----------------------> |CLN (c-lightning+plugin)|
+-----------+------------+
ノード登録とスケジューリングフロー
チャレンジ発行 (GetChallenge)
- スコープ (REGISTER や RECOVER) と node_id を指定し、Scheduler に GetChallenge をコールする。
- Scheduler は一度きり有効な challenge を生成し、ChallengeResponse に含めて返す。
Register / Recover
- クライアントは challenge を秘密鍵で署名し、node_id、network、CSR などと共に送信する。
- Scheduler は署名検証後にノード所有権を確認し、mTLS のための device_cert と device_key を発行する。
- Register は新規発行、Recover は既存ノードの証明書再発行となる。
Schedule / GetNodeInfo
- クライアントは Schedule を呼び出し、ノード起動をリクエストする。
- Scheduler は CLN を割り当て、grpc_uri など接続情報を返す。
- すでに起動済みの場合、GetNodeInfo で接続情報を取得可能である。
接続・操作
- クライアントは取得した device_cert と device_key を用い、mTLS で CLN (node) に接続する。
- 支払いやチャネル操作などの RPC 呼び出しを行う。
- 署名が必要な場合、CLN は Signer (HSM) へ HsmRequest を送信し、秘密鍵を外部に渡さずに署名のみを実行する。
Signer フロー (HSMRequest / HsmService)
CLN は秘密鍵が必要なとき、Node Service の StreamHsmRequests を用いて外部サイナー (Signer/HSM) へ HsmRequest を通知する。Signer はローカルで署名を実施し、HsmResponse で返す。具体的な流れは以下の通りである。
- ノード (CLN) 側で署名が必要になる
- StreamHsmRequests によって署名リクエスト (HsmRequest) が Signer に飛ぶ
- Signer は秘密鍵で署名し、HsmResponse に署名データ (raw) を格納して返す
- CLN は署名済みトランザクションを使って on-chain 操作などを進行する
CLN との連携
Scheduler がスケジューリングリクエストを受けると、内部で以下を行う。
- Scheduler が起動要求を受理する。
- 該当する CLN インスタンスを確保し、node_id とネットワーク情報を対応付ける。
- 署名が必要な場面で、CLN は Node サービスを通じてサイナーに HsmRequest を送る。
- サイナーが HsmResponse で署名済みバイト列を返す。
- CLN は得られた署名を使ってトランザクションを送信する。
以下はノード登録と署名のやり取りを含むシーケンス図である。
sequenceDiagram participant Client as Client participant Scheduler as Scheduler participant Node as Node (CLN) participant Signer as Signer/HSM Client->>Scheduler: GetChallenge(scope=REGISTER, node_id) Scheduler-->>Client: ChallengeResponse(challenge) Client->>Scheduler: Register(署名付きchallenge, CSR...) Scheduler-->>Client: RegistrationResponse(device_cert, device_key) note over Client,Scheduler: 認証情報を取得後、<br>node_id単位で操作可能 Client->>Scheduler: Schedule(node_id) Scheduler-->>Node: CLNインスタンス起動 Scheduler-->>Client: NodeInfoResponse(grpc_uri) note over Scheduler,Node: ノードを起動済みなら<br>GetNodeInfoで取得 Client->>Node: (mTLS認証) PayRequest, FundChannel 等 Node-->>Signer: HsmRequest(署名要求) Signer-->>Node: HsmResponse(署名済みraw) note over Node: 署名済みTXをCLNが送信し、<br>ネットワークで処理を実行 Node-->>Client: 操作結果
mTLS と HSM の詳細
mTLS の目的と構造
mTLS (mutual TLS) は、Server・Client が互いに証明書を提示して正当性を認証し合う。Greenlight では初回アクセス時に “NOBODY” 証明書でレジストレーションを行い、Register/Recover 成功後にノード専用のデバイス証明書を取得する。この仕組みにより、誤ったクライアントが他人のノードを操作することを防げる。
sequenceDiagram participant Client(Nobody) as Client (TLS:Nobody) participant Scheduler as Scheduler Service participant Signer as Local Signer Client(Nobody)->>Scheduler: GetChallenge(scope=REGISTER, node_id) Scheduler-->>Client(Nobody): ChallengeResponse(challenge) note over Client(Nobody): 認証不要で呼べるのは<br>Register/Recover関連のみ Client(Nobody)->>Signer: challenge署名を依頼 Signer-->>Client(Nobody): 署名付きchallenge Client(Nobody)->>Scheduler: Register(署名付きchallenge, CSR) Scheduler-->>Client(Nobody): device_cert, device_key note over Client(Nobody): node専用 cert/keyを取得し<br>TlsConfig.identity()でアップグレード
HSM (Signer) の必要性
on-chain での送金やチャネル開閉において、秘密鍵署名が必須となる。CLN が秘密鍵を直接保有しないため、Signer/HSM が外部署名を行う設計で鍵を安全に守る。Scheduler はノードの起動やポリシー管理を行い、Signer は鍵管理アプリとして署名のみ担当する。
HSM サインフロー: CLN→Signer
sequenceDiagram participant Node(CLN) as Node (CLN) participant Signer as Local Signer(HSM) participant TLS as TlsConfig Node(CLN)->>Signer: HsmRequest(署名対象raw) Signer->>Signer: 内部ポリシーで確認し、秘密鍵で署名 Signer-->>Node(CLN): HsmResponse(署名済みraw) note over Node(CLN): 得られた署名でTXを作成し、<br>ネットワーク送信
Pairing の詳細
Pairingサービス (scheduler.proto)
Pairing (ペアリング) は新規デバイスがノード操作権限を取得するプロセスである。既存デバイスの承認を経て、新規デバイスに TLS 証明書が発行される。
- PairDevice: 新規デバイスは device_id, CSR, device_name, restrictions などを送信。
- GetPairingData: 既存デバイスが新規デバイスのペアリング情報を確認。
- ApprovePairing: 既存デバイスが最終承認し、サーバが新規デバイス向けに証明書を発行する。
sequenceDiagram participant NewDevice as New Device participant OldDevice as Old Device (signer) participant Scheduler as Scheduler participant SignerRequests as SignerRequestsStream NewDevice->>Scheduler: PairDevice(PairDeviceRequest) note over NewDevice,Scheduler: 新規デバイスがペアリング用セッションを作成 OldDevice->>Scheduler: GetPairingData(GetPairingDataRequest) Scheduler-->>OldDevice: GetPairingDataResponse(device_id, description, restrictions, ...) note over OldDevice: 実際にユーザが確認し、承認を判断 OldDevice->>Scheduler: ApprovePairing(ApprovePairingRequest) note over Scheduler: 承認内容を<br>SignerRequestsStreamへ通知 Scheduler-->>SignerRequests: SignerRequest(ApprovePairingRequest) SignerRequests-->>Scheduler: SignerResponse(承認成功または拒否) note over Scheduler: 承認完了後に<br>新規デバイスへTLS証明書を発行 Scheduler-->>NewDevice: PairDeviceResponse(device_cert, device_key, rune, creds) note over NewDevice: ノード操作権限を<br>新規デバイスで取得
まとめ
以上のとおり、UserClient (with integrated Signer/HSM) はセルフホストされ、ユーザが秘密鍵を常に制御する。一方、Scheduler (Closed Source) は Greenlight 側で稼働し、Node (CLN) の起動や管理を統括する。この構造により、秘密鍵保護とリモート運用を両立させつつ、ペアリング機能によってデバイス間で安全に権限を移管できる。