NetBoxは、デバイスやVMの情報に暗号化されたSecret情報を持たせることができるので、例えばログイン用のアカウント情報などもNetBoxに登録しておくことができます。
このSecretはbase64でエンコードされるだけのもの、、ではなく、256ビットのAES共通鍵で暗号化されて保存されます。(ドキュメントより)
The plaintext value of a secret is encrypted to a ciphertext immediately prior to storage within the database using a 256-bit AES master key
鍵作成
鍵形式は以下。
Supported Key Format
Public key formats supported
- PKCS#1 RSAPublicKey* (PEM header: BEGIN RSA PUBLIC KEY)
- X.509 SubjectPublicKeyInfo** (PEM header: BEGIN PUBLIC KEY)
- OpenSSH line format is not supported.
Private key formats supported (unencrypted) - PKCS#1 RSAPrivateKey* (PEM header: BEGIN RSA PRIVATE KEY) - PKCS#8 PrivateKeyInfo (PEM header: BEGIN PRIVATE KEY)
https://netbox.readthedocs.io/en/stable/core-functionality/secrets/#supported-key-format
PKCS#1形式のRSAキーペアを用意するのが簡単でopenssl genrsa
で作れる、、、と思ったけど、NetBoxのUIでもキーペアが作成できます。
鍵の作成は画面一番右上ユーザーメニューの[Profile]から。
User Profile画面のサイドメニューの[User Key]で鍵管理の画面になります。
初回アクセス時はまだ登録された鍵情報がないため、[Create User Key]押下し、鍵の作成を行います。
別途作成したキーペアの公開鍵の内容をテキストフィールドに入力するか、[Generate a New Key Pair]押下してここでキーペアを作成します。
今回はここでキーペアを作成してみます。
[Generate a New Key Pair]押下するとキーペアが作成され、その情報が表示されます。
ここで表示された秘密鍵はこの画面を閉じると再表示はできない(NetBox上には残らない)ので、テキストの内容を手元にコピーし、netbox_private.key
などのファイル名で保存しておきます。
保存したら[I have saved my new private key]押下。
すると元の鍵管理画面に戻って作成された公開鍵情報が表示された状態になるので[Save]を押下。
これで鍵情報が登録されました。
Secretの暗号化は共通鍵で暗号化されると書かれてたのに何でRSA公開鍵作るのかというと、暗号化・復号に使うAES共通鍵を、ここで作ったRSAキーペアの公開鍵で暗号化したものがNetBox上に保存され、Secret情報の暗号化・復号にはRSAキーペアの秘密鍵で復号したAES共通鍵を使用するみたい。(ドキュメントを読む限り、そうなる)
webの画面で作成されたキーペアは見た感じ2048ビット長になる模様(NetBox v2.10.4時点)。
web画面でSecretの作成
Secret Roleの作成
Secretを作成するにはその準備としてSecret Roleを作成しておく必要があります。 (Secretの必須パラメタにSecret Roleがある)
Secret Roleの作成は、メニューの[Secrets] -> [Secret Roles]から。
Secret Roleには、暗号化するSecretが何の情報なのかメタ情報的な名称を付けてやるとよさげ。 例えば「login credentials」など。
Secretの作成
VM情報を開くとダッシュボードに「Secrets」のパートの[+ Add secret]を押下。
Secretの作成画面になるので、Secret Roleを選択しデータを入力、[Create]押下。
そうすると、現在のNetBoxのweb操作のためのセッション情報に秘密鍵が保持されてない場合、秘密鍵を要求されるので、ここにキーペア作成時に保存した秘密鍵のテキストデータを入力し[Request session key]を押下します。
秘密鍵を入力するとセッション情報として保持されたという通知がブラウザのダイアログで表示されるので[OK]押下。
で、これで秘密鍵を使用可能になったので、[Create]押下してSecretの登録を再開します。
このとき、秘密鍵がセッション情報に登録されているので、[Unlock]を押下すると内容を確認できます。(内容はダミーですw)
RESTでSecretの参照
RESTの仕様は例によってNetBoxのweb画面下部の「{} API」で見れるswaggerから。
secretsのセクションにエンドポイント一覧があるのでそこで確認できます。
登録したSecretの情報を取得するには、/secrets/secrets/{id}/
を使用します。(IDはwebで見たときのURLで確認)
[zaki@cloud-dev netbox-key]$ curl -X GET http://192.168.0.19:28080/api/secrets/secrets/1/ -H "Accept: application/json; indent=4" -H "Authorization: Token ${NETBOX_TOKEN}" { "id": 1, "url": "http://192.168.0.19:28080/api/secrets/secrets/1/", "assigned_object_type": "virtualization.virtualmachine", "assigned_object_id": 6, "assigned_object": { "id": 6, "url": "http://192.168.0.19:28080/api/virtualization/virtual-machines/6/", "name": "client-dev" }, "role": { "id": 1, "url": "http://192.168.0.19:28080/api/secrets/secret-roles/1/", "name": "login credentials", "slug": "login-credentials" }, "name": "zaki", "plaintext": null, "hash": "pbkdf2_sha256$1000$jA10MuGv10l3$K586baQvjZQCl10idEA0WbeuWwHqotrOuG0Oz/7pAzQ=", "tags": [], "custom_fields": {}, "created": "2021-04-01", "last_updated": "2021-04-01T22:32:14.236537Z" }
ただし、普通にやってもデータが入っているplaintext
のところは(暗号化データを復号できずに)null
となっている。
この値を取得するには、webの画面でセッションとして秘密鍵情報を登録したのと同じように、RESTで秘密鍵を送信してセッションキーを発行しておく必要があります。
[zaki@cloud-dev netbox-key]$ ls -F gen_by_openssl/ netbox_register_private.key
カレントディレクトリに秘密鍵を保存したnetbox_register_private.key
ファイルがある場合、--data-urlencode
と@
でファイル指定して以下のRESTでセッションキーを取得します。
[zaki@cloud-dev netbox-key]$ curl -X POST -H "Authorization: Token ${NETBOX_TOKEN}" -H "Accept: application/json; indent=4" --data-urlencode "private_key@netbox_register_private.key" http://192.168.0.19:28080/api/secrets/get-session-key/ { "session_key": "8zJfic3TpR/WcJhDtuIWChZQrdkuJeIsfVI3JmDmqhc=" }
これでセッションキーを取得できたので、X-Session-Key
ヘッダにこの値を追加して再度SecretのAPIを叩く。
[zaki@cloud-dev netbox-key]$ curl -X GET http://192.168.0.19:28080/api/secrets/secrets/1/ -H "Accept: application/json; indent=4" -H "Authorization: Token ${NETBOX_TOKEN}" -H "X-Session-Key: 8zJfic3TpR/WcJhDtuIWChZQrdkuJeIsfVI3JmDmqhc=" { "id": 1, "url": "http://192.168.0.19:28080/api/secrets/secrets/1/", "assigned_object_type": "virtualization.virtualmachine", "assigned_object_id": 6, "assigned_object": { "id": 6, "url": "http://192.168.0.19:28080/api/virtualization/virtual-machines/6/", "name": "client-dev" }, "role": { "id": 1, "url": "http://192.168.0.19:28080/api/secrets/secret-roles/1/", "name": "login credentials", "slug": "login-credentials" }, "name": "zaki", "plaintext": "curry_tabetai", "hash": "pbkdf2_sha256$1000$jA10MuGv10l3$K586baQvjZQCl10idEA0WbeuWwHqotrOuG0Oz/7pAzQ=", "tags": [], "custom_fields": {}, "created": "2021-04-01", "last_updated": "2021-04-01T22:32:14.236537Z" }
無事に"plaintext": "curry_tabetai"
という値を取得できました。
ちなみにAnsibleのlookup pluginを使う場合はkey_file
に秘密鍵ファイルのパスを指定すれば、セッション処理は自動でやってくれるので楽です。(あとでまとめる)
curl
のオプションはこの辺も参照。
qiita.com
環境
Docker版NetBox (v2.10.4)で確認。