agenixを利用して秘匿情報をdotfilesで管理する

管理者·

概要

nixosのdotfilesでしばし他人に見せたくない秘匿情報を管理したいケースがある。
方法はいくつかあるが、Flakeとの相性の良いagenixを利用して認証キー管理を選択するとよい。

agenixのフロー

開発時: plaintext → age暗号化 → .ageファイル(Gitにコミット)
起動時: .ageファイル → ホスト秘密鍵で復号 → /run/agenix/secret(tmpfs)

agenixはSSH鍵(ed25519/RSA)をそのまま暗号化鍵として使える。
NixOSホストは/etc/ssh/ssh_host_ed25519_keyをすでに持っているので、それで復号の材料とします。

以下のような流れになります

secrets.nix で「誰が読めるか」を公開鍵で宣言
↓ agenix CLIで暗号化(複数の受信者に向けて)
↓ 各ホストは自分の秘密鍵でのみ復号できる

構成

dotfiles/
├── flake.nix
├── secrets/
│   ├── secrets.nix        # 公開鍵と対象ファイルのマッピング
│   ├── github.age   # 暗号化済みシークレット
│   └── db-password.age
└── configuration.nix

今回はホスト名をnixosとします
先にflakeを改修してagenixを利用できるようにします。

flake.nix

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    agenix = {
      url = "github:ryantm/agenix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, agenix, ... }: {
    nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        agenix.nixosModules.default
      ];
    };

    # agenix CLIをdevShellで使えるようにする
    devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
      packages = [ agenix.packages.x86_64-linux.default ];
    };
  };
}

CLIからコマンドを打てるようにdevShellの設定も入れてください。

修正したら一度適用します
自身の環境ではHome Managerを利用しているので以下のようにします

nix run nixpkgs#home-manager -- switch --flake .#myHome

続いてsecrets/secrets.nixを作成します
PC上に存在するssh_host_ed25519_keyを確認します

cat /etc/ssh/ssh_host_ed25519_key.pub

存在しない場合は作成する必要があります。

OpenSSH設定を修正するためconfigration.nixを修正します
デフォルトだと以下のようになっているので

  # Enable the OpenSSH daemon.
  # services.openssh.enable = true;

以下のように有効化します

# configuration.nix
services.openssh = {
  enable = true;
  settings = {
    PermitRootLogin = "no";
    PasswordAuthentication = false;
  };
};

適用すると/etc/ssh/ssh_host_ed25519_keyが自動生成されます

sudo nixos-rebuild switch
cat /etc/ssh/ssh_host_ed25519_key.pub

内容が確認できたらsecrets/secrets.nixを修正

let
  # ホストの公開鍵(ssh-keyscan で取得)
  nixos = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...";

  all = [ nixos ];
in {
  "github.age".publicKeys = all;
}

もし複数のホストを利用したい場合は以下のように書きます

let
  nixos = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...";
  dev = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA...";

  all = [ nixos dev ];
in {
  "github-token.age".publicKeys = all;
  "db-password.age".publicKeys = [ nixos ];  # ホストのみ読める
  "wifi-password.age".publicKeys = all;
}

.ageファイルの作成

# devShellに入る
cd ~/dotfiles/secrets
nix develop
agenix -e github.age

エディタが開くので plaintext で入力して保存 → .age ファイルが生成される

[user]
  name = hoge
  email = example@devnix.jp

複数行の入力もOK AWS credentialsを例にします

agenix -e secrets/aws-credentials.age
# エディタで入力:
# [default]
# aws_access_key_id=AKIA...
# aws_secret_access_key=xxxx

.ageファイルはバイナリ暗号文なのでそのままGitにコミットして問題ありません。
secrets.nixも公開鍵しか含まないので同様です。

configuration.nixを改修し.ageを読み込みます

{ config, ... }:

{
  # シークレットの宣言
  age.secrets = {
    github = {
      file = ./secrets/github.age;
      owner = "nixos";       # アクセスできるユーザー
      group = "users";
      mode = "0400";
    };
  };
}

Home Managerに渡す方法

# home.nix
{ config, ... }:

{
  # セッション変数でシークレットパスを渡す
  home.sessionVariables = {
    GITHUB_FILE = config.age.secrets.github.path;
  };
}

Tips

運用する際のagenixコマンド

# シークレットの新規作成・編集
cd dotfiles
agenix -e secrets/github.age

# 受信者(公開鍵)を変えた後に再暗号化
# 公開キーを追加した場合でも利用します
agenix -r secrets/github.age
# 一括でやりたい場合
agenix -r

# 復号確認(デバッグ用)
agenix -d secrets/github.age

新たなPCで環境構築をしたいケース

新PC側で必要なもの
├── dotfiles リポジトリ(Gitから取得)
├── .age ファイル(リポジトリに含まれている)
└── 復号できる秘密鍵(← これをどう渡すかが問題)

ユーザー秘密鍵を外部メディアで移動を行う。

# 【旧PC】USBに秘密鍵をコピー
cp ~/.ssh/id_ed25519 /mnt/usb/

# 【新PC】NixOSインストール後
mkdir -p ~/.ssh
cp /mnt/usb/id_ed25519 ~/.ssh/
chmod 600 ~/.ssh/id_ed25519

# dotfiles取得
git clone git@github.com:hogehoge/dotfiles.git ~/dotfiles

# 【新PC】ホスト公開鍵を確認
cat /etc/ssh/ssh_host_ed25519_key.pub
# → ssh-ed25519 AAAAC3... (これをメモ)

# 【旧PC】secrets.nix に新PCのホスト鍵を追加
vim ~/dotfiles/secrets/secrets.nix

参考

シェア: