Ansibleでlinux初期ログイン時のパスワード変更をする
[追記] 新しい記事を書きました -> https://blog.kefiwild.com/posts/ansible_initial_ip_password_change/
例えばubuntuで最初にログインするとき、以下のように初期パスワードの変更を求められることがあります。
ラズパイにubuntu 20.04を入れて、初期ユーザとして存在するubuntuユーザでログインしようとしたらこうなります。
WARNING: Your password has expired.
You must change your password now and login again!
Changing password for ubuntu.
Current password:
新たにラズパイにubuntuを入れる等の機会は個人的にはそこそこあります。
Ansibleでこういったラズパイの初期設定をしようとした際に、初期パスワード変更部分でいくつかハマったので書きます。
まずplaybook
だいたいこんな感じになりました
|
|
参考: https://github.com/ansible/ansible/issues/1619#issuecomment-445846522
初期パスワード変更が必要かどうかを判定する
初期パスワード変更が必要な状況でAnsibleで接続しようとすると、パスワード変更プロンプトに阻まれて接続失敗となります。
fatal: [test]: UNREACHABLE! => {
"changed": false,
"msg": "Failed to create temporary directory.In some cases, you may have been able to authenticate and did not have permissions on the target directory. Consider changing the remote tmp path in ansible.cfg to a path rooted in \"/tmp\", for more error information use -vvv. Failed command was: ( umask 77 && mkdir -p \"` echo ~/.ansible/tmp `\"&& mkdir \"` echo ~/.ansible/tmp/ansible-tmp-1635680250.522707-851912-228594635714524 `\" && echo ansible-tmp-1635680250.522707-851912-228594635714524=\"` echo ~/.ansible/tmp/ansible-tmp-1635680250.522707-851912-228594635714524 `\" ), exited with result 1",
"skip_reason": "Host test is unreachable",
"unreachable": true
}
上記のような接続失敗の場合、Ansibleでのタスク結果は unreachable
となります(注意: failed
でない)。
そこで初期パスワード変更の要否判定として、pingモジュールを使っています。
|
|
pingの結果がunreachableならば初期パスワードが必要と判断することにし、ignore_unreachable
でエラーを無視することで後続のタスクにつなげます。
また、task実行前にgather_factsが走ってしまいそこで失敗してしまうため、gather_facts
をfalseにする必要があります。
expectモジュールを使ってパスワード変更プロンプトに対応する
expectモジュール を使うことで、プロンプトへの入力を自動化できます。
そのままではunreachableのためタスク実行できないため、delegate_to: 127.0.0.1
で、ローカルからsshコマンドを実行します。
|
|
パスワード変更後にreset_connectionする
結論から書くと、上記expectモジュールでパスワード変更を行った後に(順序は関係ないかも)、 metaモジュール で reset_connection
する必要がありました。
|
|
reset_connection
しないと、以下のようにパスワード変更直後のssh接続を行うタスクで unreachable
となります。
fatal: [test]: UNREACHABLE! => {
"changed": false,
"msg": "Failed to create temporary directory.In some cases, you may have been able to authenticate and did not have permissions on the target directory. Consider changing the remote tmp path in ansible.cfg to a path rooted in \"/tmp\", for more error information use -vvv. Failed command was: ( umask 77 && mkdir -p \"` echo ~/.ansible/tmp `\"&& mkdir \"` echo ~/.ansible/tmp/ansible-tmp-1635679566.8478498-610282-252614244168586 `\" && echo ansible-tmp-1635679566.8478498-610282-252614244168586=\"` echo ~/.ansible/tmp/ansible-tmp-1635679566.8478498-610282-252614244168586 `\" ), exited with result 1",
"unreachable": true
}
とてもハマりました。
このあたりの仕組みはちゃんと分かってないですが、パスワード変更から即座に次のタスクを実行しようとすると、以前の接続が再利用されるような感じ?
初期パスワード変更の状況を再現する
初期パスワード変更のplaybookを書いて試したものの失敗 -> イメージを焼き直してリトライ を何回かやったんですが、結構ハマっちゃったので、初期パスワード変更の状況を再現する方法を調べました。
passwd --expire
でユーザパスワードをexpireさせることで、次回ログイン時にパスワード変更プロンプトが出るようになるようです。
$ passwd ubuntu
$ passwd --expire ubuntu
$ chage --list ubuntu
おわりに
playbookは github にあります
あくまで自分が使うためだけを目的にしてるので、もろもろ雑です