2021.07.22   2021.08.30

【Linux】suのパスワード入力を自動化するあれこれ

Linux    

シェルスクリプトを作成していると、rootで実行したいコマンドがよく出てきます。

rootに自動スイッチする方法は色々あり、状況によって使い分けたくなります。

本記事ではその助けになるように、suのパスワード入力を自動化するあれこれをまとめたものです。

コマンド検証環境: CentOS8

結論

・root権限コマンドの実行が少数でよく、sudoが使用できる場合
 → echo 'パスワード' | sudo -S コマンド を使う

・root権限コマンドの実行が少数でよく、sudoが使用できない場合
 → ヒアドキュメントを使う

・root権限コマンドを大量に実行する必要がある場合
 →expectコマンドを使う

 以降ではそれぞれの方法について解説します。

sudoを使う

sudoが使用できるコマンドであればecho 'パスワード' | sudo -S コマンドでコマンドの実行を自動化できます。

メリットはrootのパスワードを使用する必要がなく、現在ログインしているユーザーのパスワードを記述すれば良いことです。つまりrootのパスワードをどこにも書かなくて良いのです。

デメリットはコマンド実行が単発になることです。

下記例ではhogeユーザー(一般ユーザー)でログインしており、そのパスワードがhogehogeとしています。この例ではtomcatに対してsystemctlコマンドを実行します。

コマンド実行例
echo 'hogehoge'  | sudo -S systemctl --no-pager status tomcat


パスワードを暗号化する

上記の方法だと、平文のパスワードをベタ書きしないといけないのでパスワードを暗号化します。(※この方法は管理するファイルが2つ増えます)

事前準備としてコンソールでopensslコマンドを実行し、2048ビットのRSA秘密鍵と暗号化したパスワードを保存するファイルを作成します。

暗号化するパスワードはhogehogeとします。

openssl genrsa -out password.key 2048
echo 'hogehoge' | openssl rsautl -encrypt -inkey password.key > password.txt
ls
# password.key    password.txt

それぞれ秘密鍵がpassword.key、パスワード保存ファイルがpassword.txtとなります。

あとはスクリプトにパスワード復号コマンドを記述すればパスワードのベタ書きを回避できます。

#!/bin/bash

PASSWROD=openssl rsautl -decrypt -inkey password.key -in password.txt
echo $PASSWROD  | sudo -S systemctl --no-pager status tomcat

ヒアドキュメントを使う

sudo が使えないコマンドについてはヒアドキュメントを使用するとroot権限コマンドの実行を自動化できます。

メリットはrootのパスワードさえ分かれば、だいたいどこの環境でも使用できる点です。
デメリットはどこかのファイルにrootのパスワードを書く必要があるところです。

rootユーザーのパスワードをhogerootとした時、ヒアドキュメントの記述は次のようになります。 
この例ではtomcatに対してsystemctlコマンドを実行しています。

su -c 'systemctl --no-pager status tomcat' << EOF
hogeroot
EOF


パスワードを暗号化する

sudoパターンと同じ方法でパスワードを暗号化します。

事前準備としてコンソールでopensslコマンドを実行し、2048ビットのRSA秘密鍵と暗号化したパスワードを保存するファイルを作成します。

暗号化するパスワードはhogerootとします。

openssl genrsa -out password.key 2048
echo 'hogeroot' | openssl rsautl -encrypt -inkey password.key > password_r.txt
ls
# password.key    password_r.txt

それぞれ秘密鍵がpassword.key、パスワード保存ファイルがpassword_r.txtとなります。

あとはスクリプトにパスワード復号コマンドを記述すればパスワードのベタ書きを回避できます。

#!/bin/bash

PASSWROD=openssl rsautl -decrypt -inkey password.key -in password_r.txt

su -c 'systemctl --no-pager status tomcat' << EOF
$PASSWROD
EOF

expectを使う

特権コマンドを同時に複数実行したい場合はexpectコマンドを使用します。

su以外にも対話式コマンドの自動実行が行えるので非常に便利なコマンドです。

しかし、expectコマンドはCentOSにデフォルトでインストールされていないのと(※)、若干あつかいに慣れが必要なのが欠点と言えます。

※ 著者の経験上での話で、特にエビデンスはありません。間違っていたらすみません。


expectコマンドのインストール

次のコマンドを実行すると、expectコマンドをインストールできます。

expectのインストール(centos7)
yum install expect
expectのインストール(centos8)
dnf install expect


expectでrootに自動ログインする

次のスクリプト記述例のsend右側パスワード(ここではhogeroot)を実際のパスワードに書き換えれば、rootユーザーに自動スイッチすることができます。
ここでは、rootユーザーで実行したいコマンドをsystemctlとしています。

【シェルスクリプト】expectでrootユーザーにスイッチ
#!/bin/bash
# test.sh

expect -c "
set timeout 1
spawn env LANG=C su
expect \"Password:\"
send \"hogeroot\n\"
"
echo ""

# rootユーザーで実行いたいコマンドを記述していく
systemctl --no-pager status tomcat
systemctl --no-pager status postgresql
exit 0
実行結果
[hoge@centos8 ~]$ ./test.sh
spawn env LANG=C su
Password: 
● tomcat.service - Apache Tomcat application server.
   Loaded: loaded (/usr/lib/systemd/system/tomcat.service; disabled; vendor preset: disabled)
   Active: active (running) since Thu 2021-07-22 11:40:44 JST; 6h ago
# 中略
● postgresql.service - PostgreSQL database server
   Loaded: loaded (/usr/lib/systemd/system/postgresql.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
# 以下略

注意点としては、シェルスクリプトではなくコマンドラインでexpectコマンドを実行する場合は最後の行にinteractを記述する必要があります。
逆にシェルスクリプトでinteractを記述するとうまく動作しなくなります。

interactは現プロセスの制御をexpectからユーザーに返す処理です。

【コマンドライン】expectでrootユーザーにスイッチ
expect -c "
set timeout 1
spawn env LANG=C su
expect \"Password:\"
send \"hogeroot\n\"
interact   # この処理を追加
"

あと、これは余談ですが、このコマンドは次のように一行で書くこともできます。

expect -c "set timeout 1 ; spawn env LANG=C su ; expect \"Password:\" ; send \"hogeroot\n\" ; interact"


パスワードを暗号化する

sudoパターンと同じ方法でパスワードを暗号化します。

事前準備としてコンソールでopensslコマンドを実行し、2048ビットのRSA秘密鍵と暗号化したパスワードを保存するファイルを作成します。

暗号化するパスワードはhogerootとします。

openssl genrsa -out password.key 2048
echo 'hogeroot' | openssl rsautl -encrypt -inkey password.key> password_r.txt
ls
# password.key    password_r.txt

それぞれ秘密鍵がpassword.key、パスワード保存ファイルがpassword_r.txtとなります。

あとはスクリプトにパスワード復号コマンドを記述すればパスワードのベタ書きを回避できます。

#!/bin/bash

#追加
PASSWROD=openssl rsautl -decrypt -inkey password.key -in password.txt

expect -c "
set timeout 1
spawn env LANG=C su
expect \"Password:\"
# 変更
send $PASSWROD\"\n\" 
"
echo ""
systemctl --no-pager status tomcat
systemctl --no-pager status postgresql
exit 0


expectの書式解説

expectコマンドの書式は次のようになっています。

書式
expect -c "
set timeout [expectのタイムアウト時間]
spawn [実行したいコマンド]
expect [コマンドの返答]
send [コマンドへの回答]
"

spawn に入力待ちを行うコマンド(env LANG=C su)を設定します。
expect に入力待ち時に表示される文字列(Password:)を設定します。
send に入力する文字列(rootのパスワード)と改行文字を設定します。

timeoutはexpectの処理をタイムアウトする時間です。

先ほどの例で言うと、rootユーザーでスクリプトを実行した際にはexpectで期待する文字列Password:が返ってこないので10秒の受付待ち(デフォルト設定)が発生してしまいます。

それを防ぐためにtimeoutを1としていました。

env LANG=C コマンドコマンドで実行した文字列をcentOSのデフォルト言語(英語)に変換するコマンドです。

こうすることでプロンプトに返ってくる文字列をPassword:に統一しています。
これは言語設定によってPassword:が日本語で表示されてしまうためその対策となります。

コメント
現在コメントはありません。
コメントする
コメント入力

名前 (※ 必須)

メールアドレス (※ 必須 画面には表示されません)

送信