Skip to content

Instantly share code, notes, and snippets.

@kauplan
Created September 28, 2018 10:03
Show Gist options
  • Save kauplan/4ade9e5bd8a5d94d8d36a46507bfa5da to your computer and use it in GitHub Desktop.
Save kauplan/4ade9e5bd8a5d94d8d36a46507bfa5da to your computer and use it in GitHub Desktop.
技術書典5 か-01 カウプラン機関「シェルスクリプトでサーバ設定を自動化する本」サンプルコード #1
#!/bin/sh
##
## @(#) opensslコマンドでファイルを暗号化/復号する。
## パスワードはパスワードファイルから自動的に読み込む。
##
## 事前準備:
## $ vi ~/.pass # パスワードファイルを作成
## $ sudo chown ~/.pass # 所有者を root に変更
## $ sudo chmod 600 ~/.pass # root のみアクセス可能に変更
## $ export PASSWORD_FILE=~/.pass # 環境変数に設定
##
## 使い方:
## $ crypt -h # ヘルプを表示
## $ crypt -e file1 file2... # ファイルを暗号化
## $ crypt -d file1.encrypted ... # ファイルを復号
##
set -e # スクリプトにエラーがあれば終了
set -u # 未定義の変数があればエラーにする
## openssl コマンドのオプションを指定
## (OpenSSL 1.1 との互換性のため、-md sha256 をつける)
OPENSSL_OPTION="-aes-256-cbc -salt -md sha256"
## quietモード(空ならコマンドを表示)
quiet_mode=''
## エラーメッセージを出力して終了
abort () {
command=`basename $0`
echo "Error ($command): $1" >&2
exit 1
}
## コマンドを表示してから実行する
run () {
[ -z "$quiet_mode" ] && echo "$ $1" >&2
eval $1
}
## ヘルプメッセージを表示
print_help () {
cat <<HERE
Usage:
$ crypt -h # show help
$ crypt -e file1 file2... # encrypt
$ crypt -d file1.encrypted ... # decrypt
How to prepare password file:
$ vi ~/.pass # create password file
$ sudo chown ~/.pass # root user owns password file
$ sudo chmod 600 ~/.pass # readable only by root user
$ export PASSWORD_FILE=~/.pass # export as environment variable
HERE
}
## コマンドオプションを検証
validate_command_options () {
local argc=$1 h=$2 e=$3 d=$4
if [ -n "$h" ]; then
print_help
exit 0
fi
if [ -z "$e" -a -z "$d" ]; then
abort "'-e' (encrypt) or '-d' (decrypt) required."
fi
if [ -n "$e" -a -n "$d" ]; then
abort "'-e' (encrypt) and '-e' (decrypt) are exclusive."
fi
if [ $argc -eq 0 ]; then
[ -n "$e" ] && abort "-e: plain file required."
[ -n "$d" ] && abort "-d: encrypted file required."
fi
}
## パスワードファイルをチェック
check_password_file () {
## 環境変数 $PASSWORD_FILE に指定したファイルをチェック
local f=${PASSWORD_FILE:-''}
[ -n "$f" ] || abort '$PASSWORD_FILE should be set.'
[ -f "$f" ] || abort "$f: password file not found."
## パスワードファイルは root ユーザのみアクセス可能であるべし
## (つまり一般ユーザが読み出し可能ならエラー)
if cat $f >/dev/null 2>&1; then # TODO: より正確に検査
abort "$f: should be accessable only by root user."
fi
}
## メイン処理
main () {
## 引数が何もないか、または '--help' なら、ヘルプメッセージを表示
if [ $# -eq 0 -o ${1:-''} = '--help' ]; then
print_help
exit 0
fi
## コマンドオプションを解析
local opt h='' e='' d='' q=''
while getopts 'hedq' opt; do
case $opt in
h) h='Y' ;; # show help
e) e='Y' ;; # encrypt action
d) d='Y' ;; # decrypt action
q) q='Y' ;; # quiet mode
\?) exit 1;;
esac
done
## コマンドオプションをチェック
shift `expr $OPTIND - 1`
validate_command_options $# "$h" "$e" "$d"
quiet_mode=$q
## パスワードファイルからパスワードを読み込み、環境変数に設定
check_password_file # パスワードファイルをチェック
PASSWORD=`sudo cat $PASSWORD_FILE`
export PASSWORD
## ファイルを暗号化または復号する
local ext='encrypted' # 暗号化ファイルの拡張子
local openssl_opt="$OPENSSL_OPTION -pass env:PASSWORD"
if [ -n "$e" ]; then # 暗号化 (encrypt)
for x in $@; do
[ "${x%.$ext}" = "${x}" ] || abort "$x: already encrypted."
run "openssl enc -e $openssl_opt < $x > $x.$ext"
done
elif [ -n "$d" ]; then # 復号 (decrypt)
for x in $@; do
[ "${x%.$ext}" != "${x}" ] || abort "$x: not encrypted."
run "openssl enc -d $openssl_opt < $x > ${x%.$ext}"
run "chmod 600 ${x%.$ext}" # 他人によるアクセスを防ぐ
done
else
abort "(internal error) unreachable"
fi
}
main $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment