結論
- sops のファイルは、値の暗号文を 1 つだけ持つ。受け取り手 (age の公開鍵) ごとの封筒と MAC は、同じファイルの
sopsメタデータに入る .sops.yamlが効くのは新規の暗号化だけ。既存ファイルの受け取り手はsops updatekeysを実行するまで変わらない- 暗号化されるのは値とコメントで、キー名は平文で残る。MAC は既定で、暗号化していない値も覆う
- 復号鍵は 1 か所を選んで読むのではない。環境変数と
~/.config/sops/age/keys.txtなど、見つかった鍵を全部足して試す - 復号した平文は
exec-env/exec-fileで子プロセスへ渡せる。リポジトリに平文は残らないが、direnv_loadは一時ファイルを経由し、同じユーザーのプロセスからは読める
以下は sops 3.13.3 / age v1.3.2 / direnv 2.37.1 で確かめた。
ソースの参照先は github.com/getsops/sops/v3@v3.13.3。
前提: 値はデータ鍵で 1 回だけ暗号化し、データ鍵を人数分の封筒に入れる

sops はファイルを新しく暗号化するときにランダムなデータ鍵を 1 つ作り、値をそのデータ鍵で AES-256-GCM 暗号化する。
データ鍵は受け取り手それぞれの公開鍵で暗号化し (封筒)、ファイル末尾のメタデータに recipient (公開鍵) と enc (封筒) の組で並べる。
復号する側は、自分の秘密鍵で開けられる封筒を探してデータ鍵を取り出し、値を復号する。
データ鍵はファイルごとに 1 つで、sops edit で保存しても作り直さない。
編集の前後で封筒 (enc) は変わらず、触っていない値の暗号文も 1 文字も変わらなかった。変わるのは書き換えた値の暗号文だけ。
データ鍵を作り直すのは sops rotate だけ (
後述
)。
age-keygen -o a.key
age-keygen -o b.key
A=$(age-keygen -y a.key)
B=$(age-keygen -y b.key)
printf 'PASSWORD=hunter2\n' > s.enc.env
sops encrypt -a "$A,$B" -i s.enc.env
cat s.enc.envPASSWORD=ENC[AES256_GCM,data:Vks5HxadNw==,iv:...,tag:...,type:str]
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\n...
sops_age__list_0__map_recipient=age1pxaj...
sops_age__list_1__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\n...
sops_age__list_1__map_recipient=age1arqf...
sops_lastmodified=2026-10-06T04:32:02Z
sops_mac=ENC[AES256_GCM,data:...]
sops_unencrypted_suffix=_unencrypted
sops_version=3.13.3受け取り手が 2 人でも、PASSWORD の暗号文は 1 つしか無い。人数分あるのは封筒の行だけ。
値を人数分暗号化する方式だと、受け取り手の増減のたびに全部の値を暗号化し直すことになる。
データ鍵を挟むと、増減で書き換わるのは封筒だけで済む (
後述の updatekeys
)。
age は秘密鍵 1 つにつき公開鍵 1 つで、age-keygen -y は何度実行しても同じ公開鍵を返す。
.sops.yaml に並べるのは、別々の人やマシンの公開鍵。
# .sops.yaml
creation_rules:
- path_regex: \.enc\.(ya?ml|json|env)$
age: age1aaa...,age1bbb... # YAML の配列でも書ける暗号化は公開鍵だけでできるので、.sops.yaml は git に入れてよい。秘密鍵は入れない。
- PITFALL: dotenv で
export PASSWORD=...と書くと、=の左全体がキー名になる。暗号化後もexport PASSWORD=ENC[...]のままで、sops exec-envで渡る変数名もexport PASSWORDになり、アプリから読めない。dotenv にはexportを付けない
コメントも暗号化され、キー名だけが平文で残る

sops が暗号化するのは値だけではない。YAML のコメントも type:comment の暗号文になる。
コメントに秘密が書かれている可能性を前提にした挙動。
printf '# API token for the service\ntoken: secret\nlisten: 127.0.0.1:8080 # bind addr\n' > config.yaml
sops encrypt -a "$A" config.yaml#ENC[AES256_GCM,data:x7Mk/PHw...,iv:...,tag:...,type:comment]
token: ENC[AES256_GCM,data:4SLk0cnn...,iv:...,tag:...,type:str]
listen: ENC[AES256_GCM,data:oIqX9nP4...,iv:...,tag:...,type:str] #ENC[AES256_GCM,data:5kyT5n5M...,type:comment]
sops:
age:
- recipient: age1pxaj...
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
...行頭のコメントも行末のコメントも暗号化される。平文で残るのはキー名と構造だけ。
- PITFALL: 「値だけ暗号化されるから注釈は読める」と考えて
config.example.yamlのような雛形を消すと、項目の説明が誰にも読めなくなる。注釈付きの雛形は平文で別に残す
MAC は暗号化していない値も覆う

--encrypted-regex / --unencrypted-regex (.sops.yaml では encrypted_regex / unencrypted_regex) で、暗号化するキーを絞れる。
暗号化しなかった値も、既定ではファイル全体の MAC の計算に入る。
sops を通さずに平文の値を書き換えると、次に sops で開いたときに MAC の不一致で止まる。
# .sops.yaml: 書き忘れたキーが暗号化される側に倒れる向きで書く
creation_rules:
- path_regex: config\.enc\.yaml$
unencrypted_regex: ^listen$
age: age1...printf 'listen: 127.0.0.1:8080\ntoken: dummy\n' > config.enc.yaml
sops encrypt -i config.enc.yaml # listen は平文、token は ENC[...]
sed -i 's/8080/9090/' config.enc.yaml
sops decrypt config.enc.yaml
# => MAC mismatch. File has ..., computed ... (rc=51).sops.yaml のルールに mac_only_encrypted: true を足すと、MAC は暗号化した値だけに掛かり、同じ書き換えでは止まらない。
旧来の sops -e --mac-only-encrypted でも同じ指定になる。
sops encrypt サブコマンドにはこのフラグが無く、flag provided but not defined: -mac-only-encrypted で失敗する。
キー名の書き換えは、MAC より手前で止まる。
sops は値を暗号化するとき、キーのパス (token: など) を AES-GCM の付加データに入れている (sops.go の strings.Join(path, ":"))。
| sops を通さずに変えた箇所 | 結果 |
|---|---|
平文の値 (listen の値) | MAC mismatch (rc=51)。mac_only_encrypted: true なら通る |
暗号化した値のキー名 (token => tok) | cipher: message authentication failed (rc=25) |
平文のキー名 (listen => port) | unencrypted_regex から外れて暗号文として読まれ、Input string 127.0.0.1:8080 does not match sops' data format (rc=25) |
編集は常に sops edit config.enc.yaml で行う。
- PITFALL: 本当に危ないのは MAC の不一致ではない。
encrypted_regex方式で新しい秘密のキーを正規表現に足し忘れ、平文のまま commit すること。MAC の不一致は起動時に落ちるだけで、漏れはしない - PITFALL: 暗号化したファイルを元の設定ファイル名のまま置くと、アプリが
ENC[...]の文字列をそのまま値として読む - PITFALL: yamllint や yamlfmt を sops の出力に通すと、
#ENC[...]のコメントや長い暗号文の行に直せない指摘が出て、整形は出力を書き換える。トップレベルのsops:とmac: ENC[の有無で判定して対象から外す
拡張子で形式が決まり、binary 扱いは 2 回目の暗号化を止めない

sops が構造を理解する形式は YAML / JSON / dotenv / INI / binary の 5 つ (--input-type の help)。
--input-type を付けなければ、拡張子で決まる。
| 拡張子 | 形式 | 暗号化後 |
|---|---|---|
.yaml .yml | YAML | キーは平文、値が ENC[...] |
.json | JSON | 同上 |
.env | dotenv | 同上 |
.ini | INI | 同上 |
それ以外 (.txt .toml .pass など) | binary | {"data": "ENC[...]", "sops": {...}} の JSON に包む |
構造を持つ形式は、トップレベルに sops (dotenv なら sops_ で始まるキー) があると暗号化を断る。
binary 扱いのファイルは中身を 1 つの値として扱うので、暗号化済みの JSON をもう一度包む。
printf 'PASS=hunter2\n' > s.enc.env
sops encrypt -a "$A" -i s.enc.env # rc=0
sops encrypt -a "$A" -i s.enc.env # rc=203
# The file you have provided contains a top-level entry called 'sops', or for
# flat file formats top-level entries starting with 'sops_'. ...
printf 'hunter2\n' > s.pass
sops encrypt -a "$A" -i s.pass # rc=0, 1021 バイト
sops encrypt -a "$A" -i s.pass # rc=0, 2373 バイト (二重に暗号化された)暗号化済みかどうかは sops filestatus で確かめられる。ただし binary 扱いの平文には {"encrypted":false} を返さず、エラーになる。
sops filestatus s.enc.env => {"encrypted":true}
sops filestatus plain.env => {"encrypted":false}
sops filestatus s.pass => {"encrypted":true}
sops filestatus plain.pass => rc=1 cannot check file status: ... Could not unmarshal input data"encrypted":true が出たときだけ飛ばす形にすれば、どの形式でも二重にならない。
encrypt_once() {
if sops filestatus "$1" 2>/dev/null | grep -q '"encrypted":true'; then
echo "skip: $1" >&2
return 0
fi
sops encrypt -i "$1"
}- PITFALL: 二重になったファイルは 2 回復号すれば戻るが、見た目は 1 回分と同じ JSON なので気付きにくい。パスワード 1 つだけを置くファイルでも、
.enc.envのような構造を持つ形式にしておけば rc=203 の安全弁が効く - PITFALL:
.tomlも binary 扱い。TOML のままではキーごとの暗号化はできず、ファイル全体が 1 つの暗号文になる
path_regex は鍵を選ぶだけで、対象ファイルは自分で渡す

.sops.yaml を書いても、当てはまるファイルが自動で暗号化されるわけではない。
sops encrypt が扱うのは引数で渡した 1 ファイルだけ。
path_regex は「渡されたファイルにどの creation_rules (= どの鍵) を使うか」を選ぶためにある。
# .sops.yaml
creation_rules:
- path_regex: ^sub/.*\.enc\.yaml$
age: age1...$ sops encrypt < sub/x.enc.yaml
Error: must specify --filename-override when reading from stdin
$ (cd sub && sops encrypt x.enc.yaml) # rc=0
$ sops encrypt other.yaml
error loading config: no matching creation rules found
$ sops encrypt -a "$A" other.yaml
error loading config: no matching creation rules found
$ sops encrypt -i sub/x.enc.yaml sub/y.enc.yaml
level=warning msg="More than one positional argument provided. Only the first one will be used!"
# rc=0。y.enc.yaml は平文のまま照合は .sops.yaml のある場所からの相対パスで行われる。sub/ の中で x.enc.yaml と渡しても sub/x.enc.yaml として当たる。
ファイルを 2 つ渡すと、警告を出して先頭だけを暗号化し、終了コードは 0 になる。
まとめて暗号化するなら、列挙は呼び出し側でやる。
fd -e enc.yaml -x sops encrypt -i {}- PITFALL: どの
creation_rulesにも当たらないファイルは暗号化できない。-aで鍵を直接渡しても、.sops.yamlがある場所ではno matching creation rules foundで失敗するので回避にならない
鍵の追加と削除は updatekeys、外した鍵には rotate も要る

暗号化済みのファイルは、自分のメタデータに記録した受け取り手を使う。
.sops.yaml が読まれるのは新規に暗号化するときだけ。sops --help にも次のとおりある。
The -p, -k, –gcp-kms, –hckms, –hc-vault-transit, and –azure-kv flags are only used to encrypt new documents. Editing or decrypting existing documents can be done with “sops file” or “sops decrypt file” respectively. The KMS and PGP keys listed in the encrypted documents are used then.
.sops.yaml の age を A だけから A, B の 2 つに変えた後の、recipient の数は次のとおり。
| 操作 | recipient |
|---|---|
| 新しく暗号化したファイル | 2 |
| 既存のファイル | 1 のまま |
既存のファイルを sops edit で保存 | 1 のまま |
既存のファイルに sops updatekeys -y | 2 |
updatekeys は .sops.yaml の creation_rules に合わせて封筒を足し引きする。
実行する人は、今の鍵で復号できる必要がある。
age-keygen -y key.txt # 秘密鍵から公開鍵を出して .sops.yaml に足す
sops updatekeys -y secrets.enc.yaml
git ls-files -z '*.enc.yaml' | xargs -0 -n1 sops updatekeys -yupdatekeys はデータ鍵を作り直さない。前後で値の暗号文 (token: の行) は 1 文字も変わらなかった。
sops rotate -i はデータ鍵を作り直すので、値の暗号文も変わる。
- PITFALL: 鍵を外すときは
updatekeysだけでは足りない。外した鍵の持ち主は過去にデータ鍵を取り出せていて、そのデータ鍵はupdatekeys後も同じまま使われる。sops rotate -i <file>でデータ鍵を作り直し、必要なら秘密の値そのものも変える
復号鍵は 1 か所から選ぶのではなく、見つかった全部を試す

sops 3.13.3 が age の秘密鍵を探す場所は次のとおり (age/keysource.go)。
| 出どころ | 中身 |
|---|---|
SOPS_AGE_KEY | 秘密鍵の文字列そのもの |
SOPS_AGE_KEY_FILE | 鍵ファイルのパス |
SOPS_AGE_KEY_CMD | 鍵を stdout に出すコマンド |
SOPS_AGE_SSH_PRIVATE_KEY_FILE | SSH 秘密鍵のパス |
SOPS_AGE_SSH_PRIVATE_KEY_CMD | SSH 秘密鍵を出すコマンド |
~/.ssh/id_ed25519 と ~/.ssh/id_rsa | あれば読む |
$XDG_CONFIG_HOME/sops/age/keys.txt (既定は ~/.config/sops/age/keys.txt) | あれば読む |
loadIdentities はこれらを順に見て、見つかった鍵を全部 1 つのリストに足す。
どれか 1 つが設定されていれば他を読まない、という作りではない。
keys.txt は、環境変数で鍵を指定していても、ファイルがあれば必ず読まれる。
鍵 A で暗号化したファイルを、無関係な鍵 C と組み合わせて開いた結果は次のとおり。
| 設定 | 結果 |
|---|---|
SOPS_AGE_KEY_FILE=c.key だけ | 失敗 |
SOPS_AGE_KEY_FILE=c.key + keys.txt に A | 成功 |
SOPS_AGE_KEY="$(cat c.key)" + keys.txt に A | 成功 |
SOPS_AGE_KEY_FILE=c.key + SOPS_AGE_KEY_CMD="cat a.key" | 成功 |
どの鍵でも開けないときは、探した場所がエラー文に並ぶ。
Failed to get the data key required to decrypt the SOPS file.
Group 0: FAILED
age1pxaj...: FAILED
- | failed to create reader for decrypting sops data key with
| age: no identity matched any of the recipients. Did not find
| keys in locations 'SOPS_AGE_SSH_PRIVATE_KEY_FILE',
| 'SOPS_AGE_SSH_PRIVATE_KEY_CMD', ...
Recovery failed because no master key was able to decrypt the file. In
order for SOPS to recover the file, at least one key has to be successful,
but none were.SOPS_AGE_KEY_CMD のコマンドには、環境変数 SOPS_AGE_RECIPIENT に開けようとしている封筒の公開鍵が入る。
暗号化側の宛先は -a か SOPS_AGE_RECIPIENTS で渡す。
.envrc でディレクトリごとに SOPS_AGE_KEY_FILE を切り替えても、keys.txt の鍵は常に候補に入る。
「このディレクトリでは別の鍵でしか開けない」を作りたいなら、keys.txt を置かない。
- PITFALL:
.envrcに秘密鍵本体 (SOPS_AGE_KEY=AGE-SECRET-KEY-1...) を書かない。パスかコマンドで渡す。環境変数はそのシェルの子プロセスにしか届かないので、systemd や cron から呼ぶ sops には届かない
鍵を平文ファイルから外しても、同じユーザーのプロセスは防げない
既定の keys.txt は平文。暗号化ファイルで秘密を管理して得られるのは、「平文の秘密が鍵ファイル 1 か所に集まる」ことまで。
鍵ファイルそのものを守る口は、sops 3.13.3 のソースで次のものが確かめられる。
SOPS_AGE_KEY_CMD: コマンドの出力を鍵として読む。キーリングなどの外部の秘密管理から都度取り出せるAGE-PLUGIN-...形式の identity: age プラグイン (TPM や YubiKey) の鍵を読める- パスフレーズ付きの SSH 鍵は、
SOPS_AGE_SSH_PRIVATE_KEY_CMD経由では読めない (is password protected, which is unsupportedのエラーになる)
どの方式でも、復号に要る権限はユーザー権限そのもの。
同じユーザーで動くプロセスは、ユーザーと同じ手段で鍵を使える。
復号した値を環境変数に載せると、同じユーザーのプロセスから /proc/<pid>/environ で読める。
DUMMY_TOKEN=dummy123 sleep 20 &
tr '\0' '\n' < /proc/$!/environ | grep DUMMY_TOKEN
# => DUMMY_TOKEN=dummy123方式ごとに防げる範囲が違う。
| 方式 | 鍵の置き方 | 防げる | 防げない |
|---|---|---|---|
keys.txt | 平文 | なし | ファイルを読めるプロセス、盗難、バックアップからの流出 |
SOPS_AGE_KEY_CMD='secret-tool lookup ...' | キーリング。ディスクの平文が消える | 盗難、バックアップや dotfiles からの流出 | ログイン中の同じユーザーのプロセス |
SOPS_AGE_KEY_CMD='age -d keys.txt.age' | パスフレーズで暗号化 | 上に加え、無断の復号 | 入力の盗み見 |
age-plugin-yubikey (touch policy always) | ハードウェアへの参照だけ | 鍵の持ち出し、タッチなしの復号 | タッチした瞬間の復号 |
| LUKS | 平文のまま | 電源 OFF 時の盗難 | 起動中のすべて |
- PITFALL: ハードウェアに紐づく鍵はなくすと全ファイルが復号できなくなる。先にオフラインで保管する age 鍵を
.sops.yamlに 2 人目の受け取り手として足し、sops updatekeysしておく - PITFALL: ハードウェア鍵は direnv の自動読み込みと相性が悪い。必要なときだけ
sops exec-env <file> '<cmd>'で復号する運用になる
exec-env と direnv_load で、平文の .env をリポジトリに置かずに読み込む

sops exec-env <file> 'direnv dump' を direnv_load に渡すと、暗号化した dotenv を環境変数として読み込める。
コミットするのは暗号化したファイルだけで済む。
# ~/.config/direnv/direnvrc
use_sops() {
local f
for f in "${@:-secrets.enc.env}"; do
watch_file "$f" # 暗号ファイルを編集したら再読込
direnv_load sops exec-env "$f" 'direnv dump'
done
}sops encrypt -i secrets.enc.env # 既存の .env をリネームして暗号化
echo 'use sops' > .envrc && direnv allow
sops edit secrets.enc.env # 以後の編集環境は 3 段で受け渡される。
sops exec-envが復号した値を環境変数に積み、/bin/sh -c 'direnv dump'を起動するdirenv dumpがその環境をシリアライズするdirenv_loadがそれを受け取り、direnv の管理する環境へ取り込む
空白・$・" を含む値も崩れない。
ただし、平文がディスクを一切通らないわけではない。
direnv 2.37.1 の direnv_load は、mktemp -dt direnv.XXXXXX で一時ディレクトリを作り、dump をその中の output に書かせる。
続けて direnv apply_dump が出したシェルスクリプトを同じディレクトリの script に書き、source してから rm -rf で消す。
# direnv stdlib の direnv_load (抜粋)
temp_dir=$(mktemp -dt direnv.XXXXXX)
output_file="$temp_dir/output"
script_file="$temp_dir/script"
DIRENV_DUMP_FILE_PATH="$output_file" "$@" &&
"$direnv" apply_dump "$output_file" >"$script_file" &&
source "$script_file"
rm -rf "$temp_dir"ダミーの値で確かめると、dump は $TMPDIR 配下に書かれ、apply_dump で平文の export 文に戻る。
TMPDIR=$PWD/t bash -c '
eval "$(direnv stdlib)"
direnv_load env FOO="hello world" sh -c "direnv dump; cp \"\$DIRENV_DUMP_FILE_PATH\" ./copy"
echo "FOO=$FOO"'
# => FOO=hello world
ls -A t # 読み込み後は何も残らない
head -c 16 copy # => eJykWMmuq8x2fpUr (圧縮して base64 にした dump)
direnv apply_dump copy | grep -o "export FOO=[^;]*"
# => export FOO=$'hello world'リポジトリのディレクトリに平文は残らない。一方で読み込みの間だけ、$TMPDIR (多くの環境で /tmp) に平文の script が置かれる。
direnv の外 (zsh の起動時など) では、eval "$(sops exec-env "$f" 'direnv dump zsh')" で同じことができる。
- PITFALL:
set -a; source <(sops decrypt file)は値に空白があると壊れる。dotenv の出力は値をクォートしないので、GREETING=hello worldはworld: command not foundになる - PITFALL:
sops edit <存在しないファイル>は、.sops.yamlのルールで暗号化した新規ファイルを作る。平文の雛形を先に作る必要はない - PITFALL: シェル起動時に読むと、起動のたびに復号が 1 回走る (約 10ms)。起動を速くするための出力キャッシュに載せると、平文がキャッシュに残る
exec-file は FIFO で渡し、中身は 1 回しか読めない

sops exec-file enc.yaml 'cmd {}' は、復号した中身をファイルのパスとしてコマンドへ渡す。
既定で使うのは通常ファイルではなく名前付きパイプ (FIFO)。FIFO は | にファイルシステム上の名前を付けたもので、中身を持たず、サイズは常に 0。
cmd/sops/subcommand/exec/exec.go の流れは次のとおり。
os.MkdirTemp("", ".sops")で$TMPDIRの下に一時ディレクトリを作る- その中に権限 0600 の FIFO (
tmp-file) を作る - 書き込み用の goroutine が FIFO を開き、平文を 1 回書いて閉じる
- コマンドの
{}を FIFO のパスに置き換え、/bin/sh -cで起動して終了を待つ - 終了後に
os.RemoveAllで一時ディレクトリごと消す
書き手は 1 回しか書かないので、2 回目に FIFO を開いた読み手には書き手がいない。
$ sops exec-file c.enc.yaml 'f={}; ls -la "$f"; cat "$f"; timeout 2 cat "$f"; echo "exit=$?"'
prw------- 1 user user 0 ... /tmp/.../.sops3771322336/tmp-file
listen: 127.0.0.1:8080
token: secret123
exit=124 # 2 回目の cat は返ってこない起動時に設定を 1 回だけ読むアプリなら、変更せずに暗号化した設定を渡せる。
nohup sops exec-file config.enc.yaml './app -config {}' >app.log 2>&1 &- PITFALL: 設定を 2 回読むアプリや、再読み込みするアプリでは 2 回目が止まる。その場合は
--no-fifoで通常ファイルにする。平文は、コマンドが終わるまで$TMPDIRの一時ディレクトリに置かれる - PITFALL: アプリより先に、同じユーザーの別プロセスが FIFO を開くと中身を取られる
- PITFALL:
exec-fileはコマンドの終了まで親として待つ。アプリを kill すると sops も終わり、一時ディレクトリは消される
まとめ
| 場面 | 挙動 | 対策 |
|---|---|---|
| 受け取り手を複数にする | 値の暗号文は 1 つ。封筒が人数分付く | .sops.yaml に各人の公開鍵を並べる。秘密鍵は git に入れない |
dotenv の export K=v | キー名が export K になる | export を付けない |
| YAML のコメント | 行頭も行末も暗号化される | 注釈付きの雛形は平文で別に残す |
| 平文の値を sops 外で編集 | 既定は MAC mismatch | sops edit で編集する。不要なら mac_only_encrypted: true |
| 暗号化した値のキー名を変える | message authentication failed | キー名も sops edit で変える |
| 部分暗号化の書き方 | encrypted_regex は足し忘れが平文で残る | unencrypted_regex で公開してよいキーを列挙する |
.txt .toml .pass | binary 扱いで二重に暗号化できる | 構造を持つ形式にするか、filestatus で "encrypted":true を確かめる |
.sops.yaml の path_regex | 鍵を選ぶだけ。2 ファイル目は警告だけで無視 | fd -x などで 1 ファイルずつ渡す |
.sops.yaml の鍵を変える | 既存ファイルの封筒は変わらない | sops updatekeys -y |
| 鍵を外す | データ鍵は変わらない | updatekeys の後に sops rotate -i |
| 復号鍵の指定 | 見つかった鍵が全部候補になる。keys.txt は常に読まれる | 鍵を分けたいなら keys.txt を置かない |
| 鍵ファイルの保護 | 同じユーザーのプロセスは防げない | 脅威に合わせて KEY_CMD かプラグインを選ぶ |
direnv_load | $TMPDIR に一時ファイルを置いてから消す | リポジトリには平文を置かない、までが守れる範囲と考える |
exec-file | FIFO は 1 回しか読めない | 2 回読むアプリは --no-fifo |