ssh-agent起動チェック

はじめに

ssh-agentが起動しているのに重複して起動するのは無駄なので、ssh-agentか起動しているなら起動せず、起動していないなら起動する。
また、agentにすでに鍵を渡しているなら何もせず、鍵を渡していないなら渡すというものを作ってみる。

ぁ、使うシェルはzshです。他のシェルでどうやるかはわかりません。

コードの前にやりたいこと

コマンドを実行したとき、正常に終了したら 0 ,なにかエラーがあれば、それ以外の数字が返却値として返ってきます。
この返り値を利用します。終了時の返り値を使うなんて、今回のこれを考えてみないと、きっと自分では思いつかなかったと思う。
その返り値、今回はssh-add -l コマンドの返り値を利用します。
0 → ssh-agent起動済み 鍵もagentに渡している
1 → ssh-agent起動済み 鍵は渡されていない
2 → ssh-agent未起動 鍵も渡されていない
となります。
なので、スクリプトにやらせるのは、
2 → ssh-agent起動、さらにssh-add
1 → ssh-add
0 → なにもしない

実際にコマンドを実行して、返り値が変るか試してみた。
赤で表示されているのがエラーになっている部分(返り値)

コードをぺたっと


ssh-add -l >& /dev/null
if $? -eq 2 ; then
eval `ssh-agent -s`
fi
ssh-add -l >& /dev/null
if $? -eq 1 ; then
ssh-add ~/.ssh/id*~*.pub
fi

説明

1,5行目は、出力なしで、ssh-add -l コマンドを実行しています。出力なしでも返り値はもちろん残ります。
2行目 ifの条件判断のところですが、$?が前回実行したコマンドの返却値です。-eq は数値として両隣を比較し、同じだったときに真を返します。
3行目 ssh-agentの起動をしている部分です。
4,8行目 if文の終わりです。Rubyだとendみたいな…Cだと {} の閉じ括弧に当たる部分
6行目 2行目とほぼ同じです。比較している数字が違うだけ。
7行目 ssh-agentに鍵を渡している部分。~/.ssh/にある秘密鍵すべてをごそっとssh-agentに渡しています。
後半の~*.pubは公開鍵をssh-agentに渡してしまわないため(extended_glob?が有効じゃないといけないかも)

ubuntudでfirefox4へ移行したときのメモ

ubuntufirefox4をダウンロードしてきてからメニューバーにあるアイコンをクリックしてfirefox4を起動できるようにするまでにやったことをメモしておく。
# 主に自分向けのメモになるかもしれない。

最初に

firefoxのダウンロード先は~/Downloadsとして進めますが、Linuxの伝統?流儀?的には多分こんなところにおいておくべきではないはず。なので、必要な人は~/Downloadsの部分の場所を変えて、記述も読み替えてください。
# わかってないけど,/usr/local/libとかに置くのがいいのかな…?

本題(?

まずダウンロードしてきたら、圧縮されたものになっているはずなので展開


$ tar zxvf firefox-4.0.tar.bz2
…あれ…エラーでてる。
とよく見たらbzじゃなくてbz2…これに必要なオプション覚えてないんよねー…と言うことで

$ man tar
で調べると、 j らしいので、オプションを変えて実行

$ tar jxvf firefox-4.0.tar.bz2
で、だーーーーっと出力。展開されてるOKOKヽ(・ω・。)ノ
展開したら、実行権限のついたfirefoxってファイルがある。
# 同じく実行権限の着いたfirefox-binってファイルがあるけど、こっちはなにかわかんない

さて、次はPATHの通ったところ?にfirefoxの実行ファイルを置く…になるのかな。
で、実際には移動させないでシンボリックリンクを使う。
シンボリックリンクは単純にWindowsのリンクみたいな物…と思っておけばいいのかな。
# シンボリックリンクとハードリンクってのがあるけど、今回は気にしない。この場合使用するのはシンボリックリンクであってる。…はず…
シンボリックリンクを作るにはlnコマンドで、sオプション。
sオプションがシンボリックリンクを作りますよって意味。
あと、/usr/binはroot権限下のディレクトリなので、root権限が必要。なのでプロンプト表示は#にしてみました。コメントじゃないんだよ!(`・ω・´)


# ln -s ~/Downloads/firefox/firefox /usr/bin
…ってやるはずなんやけど、
なぜかすでに、今回展開したfirefoxファイルへのリンクが貼ってあった…
で、問題なのがそのリンクの名前が「firefox-4」となっていること。
メニューバーのブラウザアイコンをクリックしたときに呼び出されるのは、/usr/bin/abrowser のリンク先のようなので…こいつを変更しないといけない。
多分、abrowserのリンク先を変更する方法は2つあって、

  1. lnコマンドを使う
  2. メニューバーのブラウザアイコンのプロパティに変更を加える。

1の方法なら、


# cd /usr/bin
# ln -sf firefox-4 abrowser
です。さらにオプションが増えてますが、fオプションは、既にabrowserがあっても、上書きしてね。って意味

2の方法なら、メニューバーのブラウザアイコンを右クリックして、プロパティを開く。
コマンドがfirefoxってなっているところを、firefox-4変更する。

このどちらかでできるはず。

と、いうことで、全然為にならない自分用のメモでしたヽ(・ω・。)ノ

scpでファイル(ディレクトリ)名補完

sftpで補完が効かないと言っていたところ、scpでならできると教えてもらった。
調べてみると、秘密鍵を使ってやればできる様子。

実際に補完が効いているところ


$ scp HOST1:
Desktop/ SCRIPT/ documents/ public_html/ tmp/

秘密鍵について

ssh接続で使える認証方法の1つで、通常(?)はID名とパスワードを入力してログインするが、
秘密鍵を使う方法では、事前に公開鍵と秘密鍵のペアを作成しておき、リモートホストとローカルホストの公開鍵と秘密鍵が一致したらログインできるというもの。
普通にIDとパスワードで認証する方式より、秘密鍵を使う認証方式の方がセキュリテイ的に安全なものらしい。

秘密鍵パスフレーズについて

秘密鍵を作成するときに、パスフレーズを設定することができる。
パスフレーズを設定すれば、秘密鍵を使う際にパスフレーズが要求され、パスフレーズが一致しなければ、秘密鍵を使うことができない。
万が一秘密鍵が誰かに盗まれてしまった場合、パスフレーズが設定されていれば、秘密鍵を使うことができず、悪用されない。なので、パスフレーズを付けておいたほうがいいとのこと。
(パスフレーズはパスワードと同じもの。# パスフレーズの方がセキュリティ的に高いらしいが…よくわかってない)

ところで…、ちょこっと問題がある。
scpコマンドを使ったことがあればわかると思うが、
リモートホストで認証されるタイミングはscpコマンドを実行後である。
が、scpで補完が聞いて欲しいのは実行後でなく、実行前(入力中)である。

今回の秘密鍵を使う方法で、この問題を解決する方法は2つ。

1つ目のパスフレーズを設定しないのが一番簡単ではある。
セキュリティを考えるとよろしくないが…

2つ目のssh-agentを使う方法では、秘密鍵パスフレーズが設定してあっても大丈夫。
ssh-agentは秘密鍵パスフレーズを、ssh-agentを終了するまで預かってくれる。
ssh接続やscp,sftpなどで認証が必要になるとssh-agentが代わりに認証作業を行なってくれるため、パスワード、パスフレーズなどを入力することなく接続ができる。
秘密鍵よりも必要な操作は増えるが、一旦ssh-agentを起動すると終了するまでは秘密鍵パスフレーズを設定しなかったときと同じように扱える。
なので、セキュリティが気になる環境だったり、気になる人はこちらを使うほうがいいかもしれない。

秘密鍵の作成

秘密鍵を作成してから、秘密鍵を利用してログインできるようにする手順は

  • 秘密鍵の作成
  • 接続先ホストへ公開鍵を渡し、authorized_keysに追加
  • 秘密鍵を利用してログイン

となる。
秘密鍵パスフレーズを設定し、ssh-agentを使う場合は

というのが、秘密鍵を利用してログインの前に入る。

さて、
秘密鍵の作成には、ssh-keygenコマンドを使用する。

RSA暗号方式を使う場合は

$ ssh-keygen -t rsa
DSA暗号方式を使う場合は
$ sshkeygen -t dsa
作る鍵にコメントを付けることもできる、RSAとDSAと両方のケースを示しておく。

$ ssh-keygen -t rsa -C "comment" # commentがコメント部分
$ ssh-keygen -t dsa -C "comment" # C は大文字
RSAとDSAの違いはよくわかっていないので気になる場合は調べてください。

以下、RSA暗号方式を使って進めます。


$ ssh-keygen -t rsa
Enter file in which to save the key (/home/user01/.ssh/id_dsa): # 作成する鍵の名前、保存する場所についての指定。 指定しなければ()内のものになる
Enter passphrase (empty for no passphrase): # パスフレーズなしで使う場合は、なにも入力せずEnter
Enter same passphrase again: # パスフレーズの確認で再度同じものを入力
鍵を保存する場所は~/.ssh/の下のままの方が良さそう。
ここだと特別設定なしで秘密鍵を見つけてくれる。
それ以外の場所にすると、使うときに自分で秘密鍵の在り処を指定しないといけなくなるはず。
パスフレーズを設定する場合は5文字以上でないといけない様子。
4文字だと短いって怒られました。

きちんと作成できれば、~/.sshに<指定した名前>のファイル(秘密鍵)と<指定した名前>.pub(公開鍵)ができているはずです。


$ cd ~/.ssh
$ ls
出来ていない場合は、作成すディレクトリの指定を間違えたとかで失敗していると思うので確認する。
公開鍵はscpの接続先ホストに置くものなので、置きに行く。

$ sftp HOST1 # ここでは一旦IDとパスワードの認証…
$ cd .ssh
$ put <指定した名前>.pub # 自分で作成した鍵の名前で読み替えて下さい(念の為)
次にsshで接続先ホストに再度接続する

$ ssh HOST1
$ cd .ssh
$ cat <指定した名前>.pub >> authorized_keys # 利用していい公開鍵のリストに作成した鍵を追加する

ssh-agentを使う

秘密鍵パスフレーズを設定しなかった場合はここを飛ばして、次のscpでの補完をやってみるのところまで進んでください。

ssh-agentを起動して、秘密鍵パスフレーズを渡してあげましょう


$ exec ssh-agent $SHELL
$ ssh-add ~/.ssh/<作成した秘密鍵>
Enter passphrase for /home/user01/.ssh/<作成した秘密鍵>: # 設定したパスフレーズ
これでssh-agentに鍵をパスフレーズを渡すことができた。

scpでの補完をやってみる

さて、実際に補完が効くか試してみる。
…その前にssh接続が出来るかどうか試してみる。もちろんIDやパスワード、パスフレーズが要求されず、ログインできれば成功。


$ ssh HOST1
出来ただろうか。
出来たなら次が本題scpで補完が効くか試してみよう。

$ scp HOST1:[tab] # [tab]の位置でタブキーを押す
使用しているシェルによっては2回タブキーを押す必要がある。(bashとか)
接続先ホストのホームディレクトリにあるファイルが補完対象として表示されれば成功。

これで補完を使いながら、別ホストのファイルを移動してくることができる。
さらに、もともとsftpを使っていたのなら


$ scp -r HOST1:<ディレクトリ> .
のように、-r オプションを付けることで、再帰的にディレクトリをコピー(指定したディレクトリの中身全部をコピー)できる。

ssh接続をちょこっと楽にする

~/.ssh/config がssh(クライアント側)の設定ファイル。
ここにオプションを書きこんでおけば、長いホスト名やユーザ名を入力する必要がなくなったりする。

ホスト名

名前解決ができない環境の場合、ssh接続するために、IPアドレスを指定しないといけない。
しかも、同じネットワーク内に複数の名前解決できないサーバがあった場合、
最後の部分しか違わないのに全部打ち込まないといけないことになる。
また、名前解決ができる場合でも、外部からだとホスト名だけでは接続できない。
となると、毎回毎回同じようなサーバの名前を打ち込まないといけない。
# C-r で履歴検索でいいというのもあるかもしれませんが
そこで書いておくと便利な設定はこれ


Host Foo
HostName 192.168.1.5

Host Hoge
HostName 192.168.1.8

Host Test
HostName test.co.jp

Hostは自分勝手に(?)付けたホストの名前で、この名前で接続先ホストにアクセスできる。
上のように書いておけば、
192.168.1.5にssh接続するには
ssh Foo
とすればいい。これで、ssh 192.168.1.5と同じ働きをする。

ユーザ名

ホストごとにユーザが違うこともある。
それぞれのホストごとに違うユーザ名を打ち込むのもまた面倒…
これも設定ファイルに書けば省略できるので書いてしまう。


Host Foo
HostName 192.168.1.5
User user1

Host Hoge
HostName 192.168.1.8
User gest

Host Test
HostName test.co.jp
User a-man

これもホスト名の時と同じで、

ssh Foo
を実行すれば、ssh user1@192.168.1.5 と同じ働きをする。

Userの設定をした後、別のユーザでログインするにはどうすればいいか、
~/.ssh/config の設定をする前のようにコマンドを打たないといけないかと思ったが、

ssh root@Foo
のようにすれば、別のユーザでもログインができた。

実行時に反映されるオプションや引数の優先度が
コマンドライン > ~/.ssh/config > /etc/ssh/ssh_config
の順になっているかららしい
/etc/ssh/ssh_configは全員に適応されるsshクライアントの設定ファイル


とりあえず自分で使っているのはこの程度。
他にも設定はいろいろあるようで、目的のホストまでに中間ホストを経由するとき、
設定ファイルに書いておけば、中間ホストへの接続を裏でやってくれるような設定もあるらしいが、
ちゃんと動いていないので今回書くのは見送り。

その他の設定や詳細については

man ssh_config
か、検索するなどしてください。

おまけ?

本題とたいして関係がないが、.sshディレクトリや、authorized_keys, 秘密鍵 のアクセス権は600になっていないといけない。
秘密鍵を初めて作るときに、存在しないなどの理由で.sshディレクトリや、authorized_keysを自分で作ることもあったが、最初このことを知らずデフォルトのアクセス権(644)のままにしていた。
デフォルトのままだと他の人が見ることができてしまい、よろしくないとのこと。
なので変更した。
.sshディレクトリは 700
その他,authorized_keysなどは600にしておく。


$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
確認↓

$ ls -Al | grep ssh
drwx------ 2 USER_A USER_A 4096 2011-03-08 19:27 .ssh

$ ls -l
-rw------- 1 USER_A USER_A 362 2011-03-08 19:28 authorized_keys

【追記】-------------------------------------------
.pubが中身なauthorized_keysは書き込みができなければ、他のユーザから見えても大丈夫。
なのでパーミッションは600でなく。644でOKです。

                                                                                                    • -

エラー:環境変数 LS_COLORS の値を解釈できません

タイトルのエラーに遭遇して、自己解決できたので、その時のことについてメモ。

zstyleでメニュー選択するスタイルを試しにコマンドライン上で有効にしてみた。
すると、zsh補完がカラー表示になっていたのに、白一色になってしまった。
.zshrcを確認してみても、カラー表示にする設定になっている…うーん…。

LS_COLORSを読み込んで補完対象を色表示するようになっているから、
LS_COLORSがおかしいのかと思い、 LS_COLORS がどうなっているのか調べた。
dircolorsコマンドでLS_COLORSが見れるようなので実行。


$ dircolors
LS_COLORS='rs=0:di=01;34:ln=01;36:hl=44;37:pi=40;33:so=01;35:do=01;35:(省略)*.xspf=00;36:';
export LS_COLORS
となっていた。 改行が無いので非常に長いが…。
この出力をもとに、LS_COLORSを上書きしてみた。

export LS_COLORS='rs=0:di=01;34:ln=01;36:hl=44;37:pi=40;33:so=01;35:(省略)*.xspf=00;36:';
これで色表示が治ったので、
zshに同じコマンドを書きこんで解決。

解決したものの……
試行錯誤の過程で、zsh補完のカラー表示が消えただけでなく、
普通にコマンドラインで打ったlsのカラー表示も白だけになってしまった原因がわからないこと。
あと、LS_COLORSを表示するコマンドがdircolorsなのに、
dircolorsの出力を環境変数として、登録しなおすとカラー表示が戻ったのか…

メソッドチェインで呼び出せるようにメソッドを作成してみる

以前コマンドプロンプト上で動くTwitterクライアントを作った。
それを他の人に見ても、分かりやすいコードになるようにつくり直してみている。
また、わからないながら、少しずつ調べながらオブジェクト指向っぽくかければなぁと。
#オブジェクト指向らしく書けてるかどうかは不明(・ω・`)…

メソッドチェインを使いたい、けど…

以前のコードでは、タイムライン取得と表示を1つのメソッド内に書いていたが、今回は分けることにした。
分けると、取得したタイムラインを、表示のメソッドに方になにかの方法で渡さないといけないわけで…。
ここで出来ればメソッドチェインの形で使えれば、見た目もすっきりするし、使いやすくていいかと思うのだけど……
メソッドチェインの形で使うためにどんなふうに書けばいいのかわからない!!

ちなみにメソッドチェインてこんなやつ↓


"ABC".downcase.reverse #=> "cba"
この例では、"abc".downcase #=> "abc" 大文字を小文字へ変換し、
"abc".reverse #=> "cba" で逆順に並び替え。


メソッドチェインにするためには、左側にある関数の返り値が右にある関数のメソッドが属するオブジェクトでないといけないはず…。

実際に取得したタイムラインはArrayオブジェクトなようなので、
Arrayオブジェクトに自分でメソッド追加が出来れば、メソッドチェインが作れるはず…

と、調べてみたところ、クラスにメソッドを追加することは普通にできるらしい…(・ω・`)
ということで、てきとーに書いてみた。

実際に書いたもの


# -*- coding: utf-8 -*-
require 'twitter'

# TL取得
class MyClass
def getHome
timeline = Twitter.home_timeline.reverse
end
end

# 既存クラスへメソッドを追加
class Array
def show
self.each do |tweet|
scl_name = tweet.user.screen_name
tw_text = tweet.text
puts "#{scl_name}:"
puts "#{tw_text}"
end
end
end

test = MyClass.new
test.getHome.show

一応試してみたが、他のコードを実行したとき、
Arrayにはshowメソッドはなかったので、クラスへのメソッド追加は追加したコードのみの効果だけの様子。

require 'twitter'のエラー(opensslがロードできない)と言われる

require 'twitter'したときに返ってくるのをコピペしたのが以下のもの


:29:in `require': no such file to load -- openssl (LoadError)
from :29:in `require'
from /usr/local/lib/ruby/gems/1.9.1/gems/simple_oauth-0.1.4/lib/simple_oauth.rb:3:in `'
from :29:in `require'
from :29:in `require'
from /usr/local/lib/ruby/gems/1.9.1/gems/twitter-1.1.2/lib/faraday/oauth.rb:2:in `'
from :29:in `require'
from :29:in `require'
from /usr/local/lib/ruby/gems/1.9.1/gems/twitter-1.1.2/lib/twitter/connection.rb:2:in `block in '
from /usr/local/lib/ruby/gems/1.9.1/gems/twitter-1.1.2/lib/twitter/connection.rb:2:in `each'
from /usr/local/lib/ruby/gems/1.9.1/gems/twitter-1.1.2/lib/twitter/connection.rb:2:in `'
from :29:in `require'
from :29:in `require'
from /usr/local/lib/ruby/gems/1.9.1/gems/twitter-1.1.2/lib/twitter/api.rb:1:in `'
from :29:in `require'
from :29:in `require'
from /usr/local/lib/ruby/gems/1.9.1/gems/twitter-1.1.2/lib/twitter.rb:3:in `'
from :33:in `require'
from :33:in `rescue in require'
from :29:in `require'
from twclient.rb:3:in `
'

opensslがロードできない…って言われてもどうしたらいいかわかんなかったので、aptitude install opensslしてみたり、似たようなパッケージをいれてみたりしてたけど解決しない。
英語のRubyのフォーラムで同じようなエラーに遭遇した人がいたらしい。
そこを見ていくとrubyをインストールしたときにDLしたソース(?)の場所で (./configure とか make とかしたところっぽい)


# cd ext/openssl/
# ruby extconf.rb
# make
# makeinstall
って言うのがあった。以前rubyをインストールしてもgemが動かなかったときにも ext/zlibの中のextconf.rbを実行してmake && make installして動くようになったことがあったので、これかと思って試してみた。
すると、twitterライブラリがrequireできた!
解決解決ヽ(・ω・。)ノ

別件になるけど、そういえば、require 'rubygems'っていらなくなったんですね。