1 ポイント 投稿者 GN⁺ 2 시간 전 | 1件のコメント | WhatsAppで共有
  • NixOSでシークレットを Nix 設定、非公開 Git リポジトリ、git-crypt に平文で置くと、Nix store は誰でも読めるため、マシンにアクセスできる人がシークレットを読めてしまう
  • sops-nix.sops.yaml のルールと sops の編集フローでシークレットファイルを暗号化し、有効化時にホストの SSH キーで復号して /run/secrets/<name>tmpfs に平文を置く
  • agenixsecrets.nix でシークレットごとの受信者公開鍵を指定し、.age ファイルを /run/agenix/<name>tmpfs に復号するが、新しいホストの追加や鍵のローテーション時には再キーイングが必要になる
  • ファイルシステムにシークレットを直接置く方式は単一サーバーやノート PC では可能だが、builtins.readFile "/var/lib/myservice/token" のように評価時点で読むと値が Nix store に入ってしまうため避けるべき
  • 始めたばかりで独立したトークンが数個なら agenix のほうが手順が少なく、メールサーバーのように関連するシークレットが多いホストなら、複数の値を 1 ファイルにまとめられる sops-nix のほうが向いている

NixOSでシークレットを扱うときの基本的なリスク

  • NixOS におけるシークレット管理は、sops-nixagenix/ragenix、ファイルシステム活用、非公開 Git リポジトリ、git-crypt、Nix 設定に直接書く方式に分けられる
  • 非公開 Git リポジトリ、git-crypt、Nix 設定への直接記述は、マシンを共有していたり設定を公開する予定があるなら使ってはいけない
  • 公開された設定からシークレットが少なくとも 2 回漏えいしたことがあり、例は 12 に残っている

sops-nix

  • sops-nix は最初は設定が難しそうに感じるかもしれないが、ドキュメントが大きく改善され、sops が SSH キーによるシークレットの暗号化・復号を標準でサポートするようになったのは大きな改善点
  • ただし sops-nix はこの SSH キー対応ではまだ後れを取っており、sops-nix#779sops-nix#922 で関連作業が進んでいる
  • 利用フローは、.sops.yaml に暗号化・復号ルールを作成し、sops コマンドでシークレットファイルを編集する形
    • 例としては、secrets/*.yaml パスに対して age の受信者として SSH 公開鍵を指定する
    • sops secrets/shush.yaml を実行すると選択したエディタが開き、hello: sops のような YAML 値を書ける
    • エディタを終了すると値は ENC[AES256_GCM,...] の形で暗号化され、同じコマンドで再編集できる
  • NixOS 設定では sops-nix モジュールがほとんどの作業を処理する
    • defaultSopsFile = ./secrets/shush.yaml; でデフォルトのシークレットファイルを指定する
    • age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; でホスト SSH キーを指定する
    • secrets."hello"ownergroupmode を指定してファイル権限を設定する
  • 有効化時に sops-nix がホストの SSH キーでファイルを復号し、平文を /run/secrets/<name> に置く
    • このパスは tmpfs なので、シークレットがディスクに触れることはない
    • 値を必要とするサービスはそのパスを読めばよい
  • テンプレート 機能は、共有設定や他のユーザーが参照する設定で便利
    • サービス設定ファイルが平文と一部のシークレット値を同時に必要とする場合、ファイル全体を暗号化しなくてよい
    • たとえば SMTP_USER=isabel は平文のままにし、SMTP_PASSWORD=${config.sops.placeholder."mailserver/smtp_password"} のようにシークレットのプレースホルダーを入れられる

agenix

  • agenixsops-nix と異なり、secrets.nix でシークレットとアクセス可能な鍵を設定するため、より Nix らしい使い心地がある
  • secrets.nix ではユーザーとホストの SSH 公開鍵を束縛し、各 .age ファイルにどの公開鍵がアクセスできるかを指定する
    • たとえば "secret1.age".publicKeys = [ isabel host1 ];"secret2.age".publicKeys = [ isabel host2 ]; のように、シークレットごとに異なる受信者リストを持たせられる
  • シークレットファイルは agenix CLI で作成する必要がある
    • agenix -e secret1.age コマンドで secret1.age を作成したり、後で再編集したりできる
  • ホスト設定へ接続する方法は sops-nix と似ているが、各シークレットが別ファイルなので表面積はより小さい
    • age.secrets.secret1.file = ./secrets/secret1.age; でファイルを指定する
    • ownergroupmode で所有者と権限を指定する
  • 起動時にホストの SSH キーで各 .age ファイルを復号し、/run/agenix/<name> に置く
    • このパスも tmpfs 上にある
  • 最もよくつまずく部分は 再キーイング(rekeying)
    • 新しいホストを追加したり鍵を交換したりすると、secrets.nixpublicKeys リストが変わったすべてのシークレットを再暗号化しなければならない
    • agenix --rekey がこれを処理するが、既存の暗号文を読むために現在の受信者のうち少なくとも 1 つの秘密鍵が必要になる
    • 実際には、新しく追加するホストではなく、最も信頼しているマシンで再キーイングを行うことになる

ファイルシステムだけを使う方式

  • ファイルシステムにシークレットを直接置く方式には、設定だけではマシンを完全に記述できなくなるというコストがある
  • 再インストール時には、すべてのファイルを正しい場所と所有権で再配置しなければならない
    • 深夜 2 時にサーバーを復旧するような場面では、復旧作業にとって大きな災難になりうる
  • 避けるべきパターンは builtins.readFile "/var/lib/myservice/token" のような形
    • この方式は評価時点でファイルを読み、その内容を Nix store に含めてしまう
    • Nix store は誰でも読めるため、最初に警告した失敗パターンとまったく同じになる
  • 代わりに、サービスには値そのものではなくパスを渡すべき
  • 単一サーバーやノート PC では問題ないこともあるが、フリート運用だったり、設定だけでゼロから再構築したい環境なら sops-nixagenix のほうが適している
  • マシンごとに本当にリポジトリへ入れてはいけない値が 1 つか 2 つだけなら問題ないが、あとでそれを再投入しなければならない責任は将来の自分に残る

sops-nix と agenix の比較

  • sops-nix を選ぶ主な理由は、できるだけ多くのデータを 1 つのファイルにまとめられる点
    • メールサーバーのように関連シークレットが多い場合、agenix のように 5 個前後のファイルへ分けるのではなく、1 ファイルにより多くのシークレットを入れられる
    • 強力なツールとして継続利用に向いており、メールサーバーのようにシークレットが非常に多いホストではまず選択肢に入る
  • agenixシンプルさ が強み
    • 学ぶべき YAML スキーマがない
    • 同期が必要な .sops.yaml がない
    • secrets.nix はただの Nix なので、ホストやユーザーで使っていた let ... in 束縛を鍵にもそのまま使える
    • 思考モデルは「シークレット 1 つ、ファイル 1 つ、受信者リスト 1 つ」で、アクセス制御の方式とうまく噛み合う
    • 可動部分が最も少ない部類でありながら、ホストごとの鍵アクセス制御を提供するため、NixOS マシンのシークレット管理を初めて尋ねる人に勧めやすい選択肢になっている
  • どちらのツールも問題を解決でき、現時点での差はほとんど 使い勝手 に近い
    • 始めたばかりで、複数サービスが関連シークレットのまとまりを必要とするなら sops-nix のほうがより拡張しやすい
    • 始めたばかりで、ほとんどが独立したトークン数個だけなら agenix のほうが少ない手順で目的に到達できる
    • 最初のシークレットツールを選ぶなら、まず agenix で流れに慣れ、「シークレット 1 つにつきファイル 1 つ」という方式の不便さを実際に感じたときに sops-nix へ移るのがよい
  • 耐量子性に関する内容は修正済み
    • agesops は耐量子セキュア暗号化キーをサポートしている
    • age#578 がクローズされ、v1.3.0 がリリースされた
    • age キーを作るときに -pq を含めればよく、例は age-keygen -pq -o key.txt

1件のコメント

 
GN⁺ 2 시간 전
Lobste.rs のコメント
  • sops-nix と agenix が復号済みのシークレットをディスクに保存しないという説明は見たが、実際にどんな利点があるのか気になる
    暗号化されたシークレットとその鍵の両方がディスク上にあるのではないか? それともどちらか一方が TPM のような場所に保存されるのだろうか?
    Nix を使い始めたばかりで、小規模なセルフホスティング環境では単純なので scp でファイルシステムに入れる方法を使っている
    少し調べると SSH 秘密鍵を TPM で保護できるようで、VM でも可能なのか気になっていたが、vTPM のサポートがあり得ると分かって自分で答えを見つけた形になった
    • 自分のサーバーでは sops-nix を使っていて、自分の 脅威モデル には十分で、うまく動いていると思う。今は SSH 秘密鍵を TPM に保存する方法が気になっている
      サーバー側には NixOps のアクセス手段もある。Colmena のやり方を見ればよい: https://colmena.cli.rs/0.4/features/keys.html
      要するに、シークレットを持つ信頼済みマシンがリモートサーバーへそれをプッシュする構成だ。今 scp でやっていることに近いが、その過程をより Nix らしく動かしている
    • 好きな言い回しを出す時が来た。「ケースバイケース!」 ここでのシークレット管理は二つの問題を同時に扱っている。ディスク上のシークレットファイルを守ることと、システムをビルドするのに使う設定内のシークレットを守ることだ。結局それらの値は どこかには存在していなければならない からである
      ここ数晩かけて自分のシステム flake に agenix 系を再設定したばかりなので、agenix についてだけ話せる。興味がある人向けには agenix-rekey を選んだ。シークレットを入れた .yml ファイルを置く必要がなく、すでにしているようにシークレットをすべて Nix の中で設定できるからだ
      暗号化されたシークレットは Nix store にあり、Nix store の他のものと同様に全体で読み取り可能である。そのシークレットを開く SSH 秘密鍵は通常、実際の SSH サーバーの秘密鍵であり、必要なら そうしないこともできる。シークレットはアクティベーション時、だいたい起動時に復号されて /run/agenix/<user> に置かれる
      secrix というツールはさらに進んで、シークレットを systemd サービスに結び付け、そのサービスをシークレットを必要とするサービスにさらに結び付ける。つまりそのサービスが動作している間だけシークレットが復号される。ただ実際には、NixOS ユーザーがサービスを頻繁に起動停止することはあまりないので、多くの場合はずっと実行中という意味になりがちだ。ユーザー作成のようなシステムアクティベーション用シークレットには向いているかもしれない
      agenix-rekey は rekey をそれほど面倒でなくし、secrets.nix の代わりに flake 出力で置き換えてくれる。鍵の片側の半分として YubiKey 分割 ID を使う。rekey はその鍵ともう片側の半分で認証してシークレットを復号し、その後サーバーの SSH 公開鍵で再び鍵を掛ける工程だ。公開鍵はシステムインストール時に生成され、自分は nixos-anywhere--copy-host-keys を使って、インストールクロージャで生成された鍵を取得している。暗号化されたシークレットはリポジトリ内に置くが、信頼済みビルダーだけがアクセスできる別のサブモジュールに置いている
      参考までに vTPM はたいていハードウェアベースではなく、多くのプロバイダーは TPM を提供していても大半は TPM v2 ではなく TPM v1.2 しか提供していない。自分のプロバイダーである BinaryLane もそうだ。セキュリティ層が一つ増えるのは確かだが、本物の TPM のような魔法の HSM ではなく、プロバイダーやホストノードの侵害から守ってくれるわけでもない。本物の HSM ベース vTPM を許可するには、プロバイダー側にとってはかなり高コストになりそうで、AWS は AWS 価格でそれを提供しているのだと思う
    • 自分は agenix + agenix-rekey + age-plugin-1p を使っている
      マスター鍵は 1Password の中にあるので、ノートPCのディスクにどんな認証情報も置かずに、どのサーバーのパスワードでも編集・閲覧・rekey できる
      実行時に鍵アクセスが必要なサーバーには権限を与えられる。agenix-rekey にそのサーバーがどの鍵を見られるかを知らせて agenix rekey を実行すると、そのサーバーが復号できる暗号化鍵バージョンが Nix store に記録される。そのサーバーの SSH 秘密鍵はそのサーバー上にのみ存在し、決して外へ出ない。agenix-rekey が rekey に必要とするのは公開鍵だけだ
      したがってシークレットが漏れるのは、自分の 1Password アカウントが侵害された場合か、そのシークレットを使うサーバーが侵害された場合である
    • Agenix では基本的に、暗号化されたシークレットを /etc/ssh/ssh_host_ed25519_key で復号し、/run/agenix.d にマウントされた ramfs に置く
      なのでその通り。暗号化された内容、暗号化鍵、復号済みの内容のすべてにファイルシステムからアクセス可能である
    • こうすると NixOS 設定全体 を公開で共有することもできる。そうする人は多くないが、Nix の約束の半分は他の人も自分のシステム問題を一緒にデバッグできることにあると感じている
  • agenix と agenix-rekey を使ってみようと思ってはいた。多くの人が言う痛点をかなり減らしてくれそうだが、まだ試してはいない
    https://github.com/oddlama/agenix-rekey
  • agenix で認証情報を管理していたが、結局は単にファイルシステムに置く方式へ移った。そちらの方が単純で、再インストールも自分にとってはめったにないからだ
    そのうえ長期に維持される認証情報も減ってきている。長期認証情報のコピー から離れて、ハードウェアベースの認証情報へ移行しつつあり、それを直接使うか、短命な認証情報と交換する方向へ進んでいる