Jenkinsfile からなんかしらのコマンドを sudo で実行させたいときがあります。
そういうときに設定やJenkinsfileをどう書けばいいのか、数パターンあるのでそれをまとめてみます。
ユーザjenkinsの設定
まずはそもそもユーザ jenkins がsudoできるように設定が必要です。
下記のコマンドでまずユーザjenkins のパスワードを設定します。
パスワードは任意のパスワードでOKです。
$ sudo passwd jenkins
つぎに jenkins を sudo できるグループに追加します。Ubuntuのときは下記でOKです。
他のディストリビューションについてはググってみてください。
$ sudo usermod -aG sudo jenkins
ここまで来たら jenkins で sudo できるはずです。下記のように jenkins にスイッチして whoami してみてください。
root と返ってくるはずです。
$ su jenkins $ sudo whoami root $ exit
ここまでは下記のどの方法をするにしもて必要な作業です。
パスワード無しでsudoできるようにする
ユーザ jenkins ではパスワードなしでsudoできるようにしてしまう方法です。
力強すぎるのであまりおすすめはしませんが、まずは紹介します。
sudoの設定を変更する下記のコマンドを実行します。
$ sudo visudo
すべてのコマンドをパスワード無しで実行するには下記のように記述します。
Defaults:jenkins !requiretty jenkins ALL=(ALL) NOPASSWD:ALL
全部のコマンドは必要ない場合は必要なコマンドだけパスワードなしにもできます。
下記の例ではコマンド /path/to/command だけパスワードなしにする設定です。
詳細は「sudoers NOPASSWD」でググると色々できてます。
Defaults:jenkins !requiretty jenkins ALL=(ALL) NOPASSWD: /path/to/command
expectコマンドを使う
対話的コマンドを自動化するツールに expectがあります。対話的なコマンドを自動化できるすぐれものです。ベースがTcl なので結構とっつきにくいです。
かなり難解ですが、下記のページが基本的な情報です。
https://linuxjm.osdn.jp/html/expect/man1/expect.1.html
Jenkinsfile にかくときはシェバンを /usr/bin/expect にすればOKです。下記の例はsudoするときの例でdす。
spawn がプロセス実行、expect がコマンドからのレス待ち、sendがコマンドへの入力です。下記のコードを見ればなんとなくわかるかと思います。
最後のexpectはプロンプトの「$」が表示されるのを待っています。
withCredentials([usernamePassword(credentialsId: 'user_jenkins', passwordVariable: 'jenkins_password', usernameVariable: 'jenkins_username')]) { sh """\ |#!/usr/bin/expect -f |spawn sudo bash -c \"rm -rf *\" |expect -re "password for $jenkins_username" |send -- "$jenkins_password\\r" |expect "\$" """.stripMargin()}
askpassを使う
これが一番おすすめです。askpass については下記のサイトの紹介されていました。
パスワードを標準出力に吐くスクリプトを作って、環境変数SUDO_ASKPASS にそのスクリプトのパスを設定すればOKです。
sudo するときに -A をつけます。
jenkinsfile の例
Jenkinsで書くと下記のようになります。
パスワードを吐くスクリプトをワークスペースにおいてしまうと、ブラウザからアクセスできてしまうので WORKSPACE_TMP を利用します。
withCredentials([usernamePassword(credentialsId: 'user_jenkins', passwordVariable: 'jenkins_password', usernameVariable: 'jenkins_username')]) { script { // パスワードを標準出力に吐き出すスクリプト作成 // sudo には -A オプションが必要 // WORKSPACEの下にスクリプトを置くと、そのスクリプトをブラウザから参照できてしまうので // WORKSPECE_TMP を利用している sh "mkdir -p $env.WORKSPACE_TMP" String sudoAskpass = sh(returnStdout: true, returnStatus: false, script: "mktemp --tmpdir=${env.WORKSPACE_TMP}/ ${BUILD_TAG}.XXXXXXXXXX").trim() sh """\ |#!/bin/bash -eu |echo -e '#!/bin/bash\\necho $jenkins_password' > $sudoAskpass |chmod u+x $sudoAskpass |export SUDO_ASKPASS=$sudoAskpass |sudo -A whoami |""".stripMargin() // もう一度sudoを使うにはexportが必要 sh """\ |#!/bin/bash -eu |export SUDO_ASKPASS=$sudoAskpass |sudo -A whoami |""".stripMargin() } } }
まとめ
Jenkinsfile からsudo する方法を説明しました。expect か askpass を使うのがいいかなと思います!
コメント