Capistrano(カピストラーノ)で sudo が使えない問題

CapistranoのGetting Startedを行なっていて、sudo が利用できない問題に直面しました。

実行環境

Capisranoを実行するサーバ

OS CentOS6
OpenSSH OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010
Ruby ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]
rubygems 1.3.7
Capistrano 2.9.0
net-scp 1.0.4
net-sftp 2.0.5
net-ssh 2.2.1
net-ssh-gateway 1.1.0
highline 1.6.2

デプロイ対象サーバ(IP を 192.168.100.200 とします。)

OS CentOS6
OpenSSH OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010
Ruby ruby 1.8.7 (2011-06-30 patchlevel 352) [i686-linux]
rubygems 1.3.7

再現

% cap invoke COMMAND="df -h" HOSTS=hoge@192.168.100.200 SUDO=1
  * executing `invoke'
  * executing "sudo -p 'sudo password: ' df -h"
    servers: ["192.168.100.200"]
    [hoge@192.168.100.200] executing command
*** [err :: hoge@192.168.100.200] sudo
*** [err :: hoge@192.168.100.200] :
*** [err :: hoge@192.168.100.200] no tty present and no askpass program specified
*** [err :: hoge@192.168.100.200] 
    command finished in 53ms
failed: "sh -c 'sudo -p '\\''sudo password: '\\'' df -h'" on hoge@192.168.100.200

SUDO=1 を外せば実行可能です。

% cap invoke COMMAND="df -h" HOSTS=hoge@192.168.100.200
  * executing `invoke'
  * executing "df -h"
    servers: ["192.168.100.200"]
    [hoge@192.168.100.200] executing command
 ** [out :: hoge@192.168.100.200] Filesystem            Size  Used Avail Use% マウント位置
 ** [out :: hoge@192.168.100.200] /dev/mapper/vg_testbudgearycontrol-lv_root
 ** [out :: hoge@192.168.100.200] 50G  3.3G   44G   8% /
 ** [out :: hoge@192.168.100.200] tmpfs                 2.0G     0  2.0G   0% /dev/shm
 ** [out :: hoge@192.168.100.200] /dev/sda1             485M   33M  427M   8% /boot
 ** [out :: hoge@192.168.100.200] /dev/mapper/vg_testbudgearycontrol-lv_home
 ** [out :: hoge@192.168.100.200] 92G  1.5G   86G   2% /home
    command finished in 48ms

つまり、下記もできないということ。仮想端末が割り当てられないようだ。

% ssh hoge@192.168.100.200 'sudo df -h'
sudo: no tty present and no askpass program specified

解決方法1 : 仮想端末が割り当てられていないので ssh -t をつける

普通のshell

ssh の -t オプションは強制的に仮想端末を割り当てる。下記は、実行結果。sudo をつけて実行が可能。

ssh
% ssh -t hoge@192.168.100.200 'sudo df -h'
[sudo] password for hoge: 
Sorry, try again.
[sudo] password for hoge: 
Filesystem            Size  Used Avail Use% マウント位置
/dev/mapper/vg_testbudgearycontrol-lv_root
                       50G  3.3G   44G   8% /
tmpfs                 2.0G     0  2.0G   0% /dev/shm
/dev/sda1             485M   33M  427M   8% /boot
/dev/mapper/vg_testbudgearycontrol-lv_home
                       92G  1.5G   86G   2% /home
Connection to 192.168.100.200 closed.
capistrano

まず、default_run_options[:pty]=true が書かれた capfile を用意します。

default_run_options[:pty]=true

capfileを指定して実行します。

% cap -f capfile invoke COMMAND="df -h" HOSTS=hoge@192.168.100.200 SUDO=1
  * executing `invoke'
  * executing "sudo -p 'sudo password: ' df -h"
    servers: ["192.168.100.200"]
    [admin@192.168.100.200] executing command
 ** [out :: hoge@192.168.100.200] Filesystem            Size  Used Avail Use% マウント位置
 ** [out :: hoge@192.168.100.200] /dev/mapper/vg_testbudgearycontrol-lv_root
 ** [out :: hoge@192.168.100.200] 50G  3.4G   44G   8% /
 ** [out :: hoge@192.168.100.200] tmpfs                 2.0G     0  2.0G   0% /dev/shm
 ** [out :: hoge@192.168.100.200] /dev/sda1             485M   33M  427M   8% /boot
 ** [out :: hoge@192.168.100.200] /dev/mapper/vg_testbudgearycontrol-lv_home
 ** [out :: hoge@192.168.100.200] 92G  1.9G   85G   3% /home
    command finished in 70ms

解決方法2 : Defaults visiblepw

sshd に Defaults visiblepw を設定すれば 仮想端末なしでも sudo が許可されます。デプロイされる側のサーバで visudo して、下記のように加えて、ssh を再起動します。

#
# Disable "ssh hostname sudo <cmd>", because it will show the password in clear.
#         You have to run "ssh -t hostname sudo <cmd>".
#
# Defaults    requiretty
Defaults visiblepw

上記のところに パスワードが見えるので ssh -t 使ってくださいと書いてありますけども・・・。

ssh
% ssh hoge@192.168.100.200 'sudo df -h'
[sudo] password for hoge: xxxxxxx            ##←パスワード丸みえ
Filesystem            Size  Used Avail Use% マウント位置
/dev/mapper/vg_testbudgearycontrol-lv_root
                       50G  3.3G   44G   8% /
tmpfs                 2.0G     0  2.0G   0% /dev/shm
/dev/sda1             485M   33M  427M   8% /boot
/dev/mapper/vg_testbudgearycontrol-lv_home
                       92G  1.5G   86G   2% /home
capistrano

Capistranoの場合は、パスワードは見えませんね・・。

% cap invoke COMMAND="df -h" HOSTS=hoge@192.168.100.200 SUDO=1  
  * executing `invoke'
  * executing "sudo -p 'sudo password: ' df -h"
    servers: ["192.168.100.200"]
    [hoge@192.168.100.200] executing command
Password: 
 ** [out :: hoge@192.168.100.200] Filesystem            Size  Used Avail Use% マウント位置
 ** [out :: hoge@192.168.100.200] /dev/mapper/vg_testbudgearycontrol-lv_root
 ** [out :: hoge@192.168.100.200] 50G  3.3G   44G   8% /
 ** [out :: hoge@192.168.100.200] tmpfs                 2.0G     0  2.0G   0% /dev/shm
 ** [out :: hoge@192.168.100.200] /dev/sda1             485M   33M  427M   8% /boot
 ** [out :: hoge@192.168.100.200] /dev/mapper/vg_testbudgearycontrol-lv_home
 ** [out :: hoge@192.168.100.200] 92G  1.5G   86G   2% /home
    command finished in 4008ms

おまけ1 : sudoで特定のコマンドをパスワードなしで実行できるようにする

例えば、visudo で下記のように設定して、sshd を restart ます。

%wheel        ALL=(ALL)       NOPASSWD: /bin/df

上記だと、/bin/df コマンドは wheelグループユーザに所属していれば パスワードなしで sudo 実行できます。sudo で実行したいコマンドがたくさんある場合は不向きですね。

おまけ2 : sudo 時の path

visudo で設定を見ると Defaults secure_path というのがあります。これは、sudo 時に下記のパスが設定されますが、例えば、gem コマンドが /usr/local/bin にあった場合は、sudo 時に gem コマンドが使えないということになってしまいます。そのため、Default secure_pathに pathを加えることで対応します。

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin