SSL証明書、秘密鍵、CSRなどを頻繁に扱います。私の仕事を自動化するいくつかの小さなbashスクリプトがあります。スクリプトの1つはopensslを使用して、SSL証明書の新しい秘密鍵とCSRを生成します。このスクリプトは実際には1行にエラーチェックを加えたものです。入力する時間を節約するためです。
#!/usr/bin/env bash
if [[ $# -ne 1 ]]; then
echo "Format: $0 hostname"
echo " e.g. $0 www.example.com"
exit 2
fi
openssl req -new -newkey rsa:2048 -nodes -keyout "$1.key" -out "$1.csr" \
-subj "/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1"
cat "$1.csr"
これはうまくいきました。しかし最近、SANにはますます多くの証明書が必要になり、次のようにスクリプトを修正しました。
#!/usr/bin/env bash
if [[ $# -eq 0 ]]; then
echo "Format: $0 hostname"
echo " e.g. $0 www.example.com [SAN1 SAN2 ...]"
exit 2
fi
SANS=""
if [[ $# -gt 1 ]]; then
SANS=""
for san in "${@:2}"; do
SANS="${SANS}DNS:${san}, "
done
SANS="-addext \"subjectAltName = ${SANS%,*}\""
fi
openssl req -new -newkey rsa:2048 -nodes -keyout "$1.key" -out "$1.csr" \
-subj "/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1" \
$SANS
cat "$1.csr"
これでスクリプトは機能しなくなりました。ただ作成してください。
req: Use -help for summary.
スクリプトの最後の部分を次のように修正しました。
CMD="openssl req -new -newkey rsa:2048 -nodes -keyout \"$1.key\" -out \"$1.csr\" \
-subj \"/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1\" \
$SANS"
echo $CMD
$CMD
これにより、コマンドを実行する前にコマンドを表示できます。コマンドが正確で、このコマンドをbashプロンプトにコピーして貼り付けると、正しい結果が得られます。もしそうなら、このコマンドがスクリプトで実行されたときに失敗するのはなぜですか?
答え1
問題はSANS
文字列である変数です。引用符なしで変数を使用します。これは、シェルが変数をスペースに分割することを意味します(そして、すべてのパーティションにファイル名のグロービングを適用します)。
保存する代わりに複数の個別文字列文字列は配列を使用します。
SANS=()
if [[ $# -gt 1 ]]; then
subjAltNames=("${@:2}")
IFS=,
SANS=(-addext "subjectAltName = ${subjAltNames[*]}")
fi
$#
1より大きい場合は、2つの要素と文字列を含む配列を提供し、その後にSANS
コマンドライン引数でカンマ区切りの文字列のリストが表示されます。カンマで区切られたリストはasを使用して別の配列から生成され、その要素を最初の文字と区切り文字で連結します(それであらかじめコンマに設定しました)。-addext
subjectAltNames =
subjAltNames
${subjAltNames[*]}
$IFS
IFS
後で個別に参照される要素のリストに適切にアクセスするには、SANS
次のようにします。"${SANS[@]}"
openssl req -new -newkey rsa:2048 -nodes -keyout "$1.key" -out "$1.csr" \
-subj "/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1" \
"${SANS[@]}"
配列が空の場合、SANS
パラメータリストの末尾に空のパラメータは提供されません。