homelab notes ポート開放できない家の自宅サーバー

秘密情報が作業ログに残ったときにやったこと

設定ファイルを丸ごと表示させたら、暗号化キーが作業ログに平文で出た。 交換したが、その前にそのキーが実際に何を守っていたかを数えたのが良かった。

まず影響範囲を数える

慌てて交換すると、そのキーで暗号化されていたデータが読めなくなる。 先に「何が入っているか」を確認する。

$ sqlite3 db.sqlite "select count(*) from integration;"        0
$ sqlite3 db.sqlite "select count(*) from integrationSecret;"  0
$ sqlite3 db.sqlite "select count(*) from apiKey;"             0
$ sqlite3 db.sqlite "select count(*) from widget_secret;"      0

全部 0 だった。そのキーは空の金庫の鍵だったので、 交換によるデータ消失は起きない、と判断できた。

ログインパスワードは別物か確認する

キーを替えるとログインできなくなるのでは、と心配になる。形式を見れば分かる。

$ sqlite3 db.sqlite "select substr(password,1,4), length(password) from user;"
$2b$|60

$2b$ で長さ60なら bcrypt ハッシュ。 暗号化ではなくハッシュなので、暗号化キーとは無関係。 交換しても同じパスワードでログインできると確信できる。

新しいキーをログに出さずに作る

生成した鍵をシェルに出すと、今度はシェル履歴に残る。 コンテナの中で生成して、そのまま書き込むと外に出ない。

docker run --rm -v portainer_data:/d alpine sh -c '
  F=/d/compose/4/docker-compose.yml
  K=$(od -An -tx1 -N32 /dev/urandom | tr -d " \n")   # 64桁の16進
  [ ${#K} -eq 64 ] || { echo "生成失敗"; exit 1; }
  cp "$F" "$F.pre-rotate"
  sed -i -E "s|(SECRET_ENCRYPTION_KEY=).*|\1$K|" "$F"
'

openssl が無くても /dev/urandomod で作れる。 追加パッケージが要らないぶん確実。

古いキーの痕跡を消す

バックアップファイルにも残っている。交換後の旧キーは無効なので、 残しておく理由がない。

for f in "$F".bak-* "$F".pre-rotate-*; do
  sed -i -E "s|(SECRET_ENCRYPTION_KEY=).*|\1<rotated-out>|" "$f"
done

消し残しの確認まで含めて手順にする。

for f in /d/compose/4/*; do
  printf "%-45s " "$(basename $f)"
  grep -qE "SECRET_ENCRYPTION_KEY=[0-9a-f]{64}" "$f" && echo "鍵あり" || echo "鍵なし"
done
本体だけ「鍵あり」(新しいほう)で、残りが全部「鍵なし」になれば完了。 なお、交換前に取ったバックアップの中には旧キーが残るが、 リポジトリ自体が暗号化されていて、かつ旧キーは既に無効なので放置してよい。 世代整理でいずれ消える。

そもそも出さない

根本的にはこれ。設定ファイルを表示するときは伏せ字を通す。

$ cat docker-compose.yml | sed -E 's/(KEY=|TOKEN=|PASSWORD=).*/\1<伏字>/'

コマンドの出力も同じ。docker inspectEnv は 環境変数を全部出すので、そのまま貼ると事故る。

$ docker inspect <name> --format '{{range .Config.Env}}{{println .}}{{end}}' \
    | sed -E 's/(SECRET[A-Z_]*=).*/\1<伏字>/'

認証キーをコマンド引数に書かない

別の話だが同じ種類の事故。VPN の認証キーを引数で渡すと シェル履歴と ps の出力に残る。ファイルに置いて読ませる。

install -m 600 /dev/null config/authkey
cat > config/authkey    # ここに貼り付けて Ctrl-D

なお、鍵を失効させても、既に登録済みのデバイスは動き続ける。 失効は「これ以上新しいデバイスを作れなくする」だけ。安心して失効させてよい。