シェルスクリプトでパスワードを暗号化して保持する

背景

先日バックアップのスクリプトを書いていたときにバックアップ先サーバのログイン情報の置き方に困ったので、平文で置かなくても良いやりかたを探したところ、下記のページがヒットしました。 tkuchiki.hatenablog.com

(暗号化には全然詳しくないんですが)なんかこいつ弱そうなのでもっとちゃんとしたやり方をするべきなんですが、暗号化でバイナリじゃなくて文字列が出て来るところがシェルスクリプト的に大変扱いやすいので、平文で置いておくよりはマシだろうということで採用しました。

暗号化・復号化

リンク先にあった通りなんですが下記のようにして暗号化、復号化ができます。

# 暗号化
echo "$plain_password" | openssl enc -e -des -base64 -k "$pass_phrase"

# 復号化
echo "$encrypted_password" | openssl enc -d -des -base64 -k "$pass_phrase"

パスフレーズをどうするかという話

実際にシェルスクリプトを作って運用するときにはパスフレーズを何にするかが重要です。ジョブ管理サーバからスクリプトを転送して実行するような場合を考えて、

  • スクリプトが実行されるサーバに固有の情報で、
  • 簡単に変わることがなく、
  • 外部から読み取ることができない

という3つを条件として考えます。sshか何かでサーバに入られたらそもそも仕方がないので、とりあえずこれでいいんじゃないでしょうか。

最初に思いついたのがMACアドレスなんですが、同じセグメントに侵入できていれば見えちゃうのでボツでした。。
ホスト名は結構いい線いっていると思うんですが、簡単すぎる。いろいろ調べてたらdmidecodeというコマンドに行き着きました。

kanjuku-tomato.blogspot.jp

system-uuidというのは使えそうな感じなので、これとdmidecodeから取れる他の値やホスト名とかを組み合わせたら、そこそこ強力なパスフレーズになるのではないでしょうか。 とりあえず現状は以下のようにしています。

#!/bin/bash
encrypt() {
  echo "$1" | openssl enc -e -des -base64 -k "$(hostname)$(dmidecode -s system-uuid)"
}

decrypt() {
  echo "$1" | openssl enc -d -des -base64 -k "$(hostname)$(dmidecode -s system-uuid)"
}

これで、(脆弱性を突かれない限り)スクリプトを実行したいサーバ以外の場所では見えない形でパスワードを書くことができるはずです。まあ今回の私の場合は公開鍵認証でsftpとかrsyncを使うべき案件っていう気がしてますが。

ただ、暗号の強度がどの程度のものかよく分からないのが不安です。詳しい方いたら教えてもらえると嬉しいです。

おまけ

そもそも、rsync+sshでパスワード入力が必要になるっていうところから調査を始めたのですが、対話の自動化にはsshpassを使いました。

sshpassを使ってパスワード指定のSSH接続を行ってみる(パスワード指定自動ログイン) | レンタルサーバー・自宅サーバー設定・構築のヒント

これがあればexpectを使ってごちゃごちゃやる必要はないかもしれません。
とりあえず以下の使い方ではちゃんと動きました。

sshpass -p $password ssh user@host 'echo "$(hostname) is up"'

sshpass -p $password rsync /local/directory/ user@host:/remote/directory/

sshpass -p $password sftp user@host << EOF
put /path/to/local/file
EOF