BLOGサブスレッドの日常

2016.04.05

EC2へのSSH接続を簡単にしたい! (1)「いつもの設定」を記憶させる

mzsm

株式会社サブスレッドのみずしま a.k.a mzsm(@mzsm_j)です。こんにちは。

弊社では現在、ほとんどの案件でAWSを利用しています。
そして案件ごとに本番、受入(テスト)、開発といったような環境が必要だったり、さらに本番環境は冗長性のために2台必要だったりということがあるので、弊社で管理しているEC2インスタンスはざっと数十台はあるでしょうか。

EC2インスタンス上で作業を行うにはSSHで接続する必要があります。
個人で1台だけ借りてるくらいなら別になんてことないのですが、弊社のように管理しているインスタンスが多くなってくると、「どの案件のどのサーバがどのIPアドレスなのか」とか、「どのサーバにはどの鍵を使えばいいのか」とか、いろいろと面倒くさくなってくるのです。
というか実際に今すでに面倒くさい。

というわけで、これから数回に分けて、そのあたりの改善方法を書いていきたいと思っています。

前提条件

ローカルマシンはMac OS X Yosemite以降を利用しているものとします。
Windowsについては今回対象外です。

EC2インスタンス作成時のAMIはAmazon Linux AMI 2016.03.0 (HVM), SSD Volume Type (ami-f80e0596)を使用しているものとします。

この記事内で記述しているIPアドレス・ホスト名は例示用IPアドレス(RFC5737)を利用した架空のものです。

まずはおさらい

作成したばかりのEC2インスタンスに初めてSSH接続する場合、およそこんな感じのコマンドを実行することになります。

$ ssh -i ~/.ssh/hogehoge.pem ec2-user@ec2-203-0-113-64.ap-northeast-1.compute.amazonaws.com

-iは接続に使用するキーペアの秘密鍵を指定しています。
EC2インスタンスを作成するとき、そのインスタンスへのSSH接続に利用するデフォルトのキーペアを指定する項目があるので、そのとき指定したキーペアの秘密鍵を指定します。
なお、この秘密鍵ファイルのパーミッションが600か400でない場合、エラーになって接続に失敗します。たまにこれを忘れてパニクってます。

また、Amazon Linuxのデフォルトユーザーはec2-userなので、リモートユーザー名(@の前)にはこれを指定しています。

もちろんこの状態から、新しく別のユーザーを作成したり、自分がいつも使っているキーペアの公開鍵を~/.ssh/authorized_keysに追記して-iオプションを指定しなくて良いようにしたりすることもありますが、基本はこんな感じです。

ちなみに、このホスト名のec2-xxx-xxx-xxx-xxxの部分にあたる数字はそのままパブリックIPアドレスと対応しているので、前述のコマンドは次のように書き換えることもできます。

$ ssh -i ~/.ssh/hogehoge.pem ec2-user@203.0.113.64

インスタンス数が増えると…

ここからは「営業改善プロジェクト」という架空の案件をユースケースとして考えていきます。

この案件では、本番環境に2台、受入環境に2台、開発環境に1台、合計5台のEC2インスタンスを立ち上げることになりました。

※接続に利用する秘密鍵ファイルはeigyo-kaizen.pem(全サーバ共通)
※その秘密鍵ファイルはローカルマシンの~/.sshディレクトリ内に置いてある
※リモートユーザー名はデフォルトのec2-user(全サーバ共通)
※ローカルマシンのユーザー名はusernameである
※5台のホスト名は次のとおり

  • 本番環境
    • ec2-203-0-113-23.ap-northeast-1.compute.amazonaws.com
    • ec2-203-0-113-205.ap-northeast-1.compute.amazonaws.com
  • 受入環境
    • ec2-203-0-113-10.ap-northeast-1.compute.amazonaws.com
    • ec2-203-0-113-179.ap-northeast-1.compute.amazonaws.com
  • 開発環境
    • ec2-203-0-113-200.ap-northeast-1.compute.amazonaws.com

さて、この開発環境に接続するときは次のコマンドを実行することになります。

$ ssh -i ~/.ssh/eigyo-kaizen.pem ec2-user@ec2-203-0-113-200.ap-northeast-1.compute.amazonaws.com

一方、本番環境の2つめのサーバに接続するときは…

$ ssh -i ~/.ssh/eigyo-kaizen.pem ec2-user@ec2-203-0-113-205.ap-northeast-1.compute.amazonaws.com

わかりにくい!!
数字が1文字違うだけやないかい!!

以前接続したサーバに接続しようとシェルのhistoryを見ていてec2-203-0-113-200.~と出てきたとして、そのホスト名のインスタンスが開発環境なのか本番環境なのか、さらにこれ以外にも複数の案件があるとすればどの案件のインスタンスかまで含めて、すぐに思い出せるでしょうか。僕は無理です。

これだけでも十分面倒なわけですが、さらには

  • 別クライアントの案件なので別のキーペアを利用している
  • ログインユーザー名を変更している
  • セキュリティ対策のため、SSH待受ポートを変更している

…など、いろんな事情でサーバごとに指定すべきオプションが違うこともありえます。

こんなややこしいことを覚えていられるほど記憶力がいい人なんてそうそういません。
AWSコンソールにログインすれば各インスタンスのホスト名や、デフォルトのキーペア(のファイル名を)確認できますが、毎回それをするのも面倒です。

というわけで、このような情報は設定としてマシンに記憶させ、さらに人間にわかりやすい名前で接続できるようにしてしまいましょう。

SSH接続の設定を保存する

~/.sshディレクトリ内のconfigという名前のファイルに、SSH接続時のさまざまな設定を書くことができます。
その名前のファイルが存在しない場合は、勝手に作ってOKです。

このファイル内に次のような設定を書き込みます。

Host eigyo-kaizen-prod-1
    HostName       ec2-203-0-113-23.ap-northeast-1.compute.amazonaws.com

Host eigyo-kaizen-prod-2
    HostName       ec2-203-0-113-205.ap-northeast-1.compute.amazonaws.com

Host eigyo-kaizen-test-1
    HostName       ec2-203-0-113-10.ap-northeast-1.compute.amazonaws.com

Host eigyo-kaizen-test-2
    HostName       ec2-203-0-113-179.ap-northeast-1.compute.amazonaws.com

Host eigyo-kaizen-dev-1
    HostName       ec2-203-0-113-200.ap-northeast-1.compute.amazonaws.com

Host eigyo-kaizen-*
    IdentityFile   /Users/username/.ssh/eigyo-kaizen.pem
    User           ec2-user

この設定を書き込むと、次のコマンドで各インスタンスに接続できるようになります。

(開発環境)
$ ssh eigyo-kaizen-dev-1
(本番環境2つめ)
$ ssh eigyo-kaizen-prod-2

~/.ssh/configを設定する前と比べると、鍵設定とユーザー名が省略され、ホスト名が短くなってスッキリしました。

どの案件のどの環境のサーバに接続しようとしているのか人間にわかりやすいホスト名となったので、過去に接続していたサーバをhistoryから探すのもやりやすくなりますね。

また、シェルとしてzshを使っている場合は設定を読み取って自動的に補完が効くようになるので、ホスト名うろ覚えであっても簡単に入力できます。
bashの場合はbash-completionパッケージを入れることで同様のことができるようです。他のシェルの場合は知りません。

% ssh ei
(↓タブキーを入力)
% ssh eigyo-kaizen-
(↓さらにタブキーを入力)
% ssh eigyo-kaizen-
eigyo-kaizen-dev-1   eigyo-kaizen-prod-1  eigyo-kaizen-prod-2  eigyo-kaizen-test-1  eigyo-kaizen-test-2
(pを入力)
% ssh eigyo-kaizen-p
(↓タブキーを入力)
% ssh eigyo-kaizen-prod-
(↓さらにタブキーを入力)
% ssh eigyo-kaizen-prod-
eigyo-kaizen-prod-1  eigyo-kaizen-prod-2

設定ファイルに何を書いている?

最初に同じような記述が繰り返されていますが、ここではホスト名に対して人間にわかりやすい別名を付けています。
これを5つのインスタンスぶんすべて設定しています。

Host [わかりやすい名前(SSH接続時に入力する名前)]
    HostName [実際に接続するホスト名(またはIPアドレスでも可)]

今回は、[案件名(eigyo-kaizen)]-[環境名]-[環境ごと連番]というフォーマットで名前を付けました。
このように階層的な名前構造にしておくと、先述の入力補完がいい感じになるため都合が良いです。
これ以外にも、AZ名を入れたり、複数リージョンにインスタンスを立てているならリージョン名を入れたり、webやmail,dbなどサーバの役割を示す言葉を入れたり、必要に応じてわかりやすい名前を付けるとよいでしょう。

最後の部分では、ここまでの5つのインスタンスに共通の設定をまとめて書いています。

Host eigyo-kaizen-*
    IdentityFile   [使用する秘密鍵ファイルパス]
    User           [ログインユーザー名]

Hostの一部をワイルドカード(*)にし、その条件に当てはまる全てのホストに対して同じ設定が効くようにしています。

先述のとおり階層的な名前構造にしてあるため、案件名の後にワイルドカードを入れる(eigyo-kaizen-*)とすることで、この案件に関する全てのインスタンスに対して同じ設定を指定できます。
もしも本番環境だけ特別に指定したい設定がある場合は、eigyo-kaizen-prod-*とすればよいでしょう。

なお、秘密鍵のファイルパスはここではフルパスで記述しています。
これは~/.ssh/から始まるパス表記では上手く動かなかったためです。

この次はどうする?

これでまずは、人間にとってわかりやすい名前で、さらに各サーバごとのオプションを気にすることなく、SSH接続ができるようになりました。

今回は基礎知識的な話がほとんどで、さらに言えば別にEC2に限った話ではありませんでした。

EC2に特化した話になるのはここからです。

実はEC2インスタンスはけっこう簡単にホスト名・IPアドレスが変わります(※Elastic IPを指定していない場合)。
(さすがにサーバ起動中にいきなりIPアドレスが変わるということはありませんし、rebootコマンドで再起動しても変更されませんが)

IPアドレスが変更されるのは、サーバをいったん停止させてから起動しなおしたときです。
インスタンスのスケールアップ・ダウンを行うときもこの条件に該当するので、めったにない話ではありません。

しかしそのたびに新しいホスト名を調べて~/.ssh/configを書き換えないといけないのはなかなか面倒です。

それならばプログラムで~/.ssh/configを自動的に書き換えることができれば楽なのでは…?

…というわけで、次回に続きます。

(今回は初回なので気合が入って長くなってしまいましたが、次回からはもうちょっと短くなる模様です)

この記事を書いた人

mzsm