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