記事一覧に戻る

Linuxサーバにパスワードレスで接続する方法

はじめに

私はこのWebサイトの更新を行う際、手動でサーバにSSHコマンドで接続し、gitコマンドやらnpmコマンドを打ってリリース作業を行っていました。

毎回決まったコマンドを打っているので、「何とか自動化できないかなぁ」と長らく思っていました。しかしSSHでログインする際、サーバのユーザ名とパスワードの入力を求められるため、自動化ができずにいました。

しかしちょっと調べてみると、SSHキー(公開鍵と秘密鍵のペア)を生成してサーバに登録しておくことで、パスワードレスで接続が可能なことが分かりました。GitHubをリモート・リポジトリに指定する際、SSHキーの登録が必須になっていると思いますが、その方式と同じですね。

私もこの方式で、リリース作業の自動化(スクリプト化)が無事できました!

ということで、今回はSSHキーの生成方法から、パスワード無しでサーバに接続する方法について解説します。なお、Linuxにあまり慣れていない方を想定した内容になっていますので、ご了承ください。

なお、秘密鍵や公開鍵の仕組み自体については、この記事では触れません。

環境

サーバ

私のサーバのOSやバージョンです。

NAME="Ubuntu"
VERSION="20.04.4 LTS (Focal Fossa)"

パスワード方式であれSSHキー方式であれ、SSHで接続することに変わりはありません。そのため、サーバのSSH用のポート(22)が許可されていることが前提となります。

もしまだ許可されていない場合、以下のコマンドで許可できます。

sudo ufw allow 22

また、サーバはLinux系であることを前提にしています。WindowsサーバでもSSH接続は出来ると思いますが、手順は異なりますので本記事では対象外です。

ローカル端末

接続元となる端末をここではローカル端末と呼ばせてもらいます。

私のローカル端末情報です。

NAME="Debian GNU/Linux"
VERSION="11 (bullseye)"

この記事用にchromebookのLinux仮想環境を使っています。WindowsであればWSL2(Windows Subsystem for Linux2)なら大丈夫ですし、Windows 10 (ビルド 1809 以降) であればpowershellでも大丈夫です。

ただし、この記事ではローカル端末もLinuxを前提に記述します。powershellの場合、細かい部分は異なる可能性がありますので、ご了承ください。

powershellでは、昔はSSHキーの生成がサポートされていなかったようなので、バージョン等の詳細はMicorosoft社のOpenSSH for Windows の概要をご確認ください。

SSHで普通に繋げる場合(要パスワード)

SSHキーを使ったパスワードレスのログインの前に、SSHコマンドで手動で繋げる場合の手順を確認してみます。

ローカル端末がLinux系であればWindowsであれ、以下のコマンドで接続させると思います。

ssh username@hostname

usernameはサーバのログイン先のユーザ名で、hostnameはサーバのホスト名(もしくはIPアドレス)です。

上記のコマンドを打つと、以下のようにユーザ名とパスワードが求められます。ユーザ名やIPはボカしてあります。

ssh my-username@160.xx.xx.xxx
my-username@160.xx.xx.xxx's password:

ここでパスワードを入力すれば無事ログインできます。サーバのメンテナンス等を手動で行う場合はこれで十分かと思いますが、パスワードを手動で入力する必要があるため、リリース作業のような定型の処理を自動化するには向きません。

パスワード無しでサーバに接続し、決まった処理を自動化するには、後述するSSHキーを使った認証方式がベターです。

SSHキーで接続する場合

SSHキーでサーバに接続させるためには、以下の作業を事前に行う必要があります。

  1. ローカル端末でSSHキー(公開鍵、秘密鍵のペア)を生成
  2. 公開鍵をサーバに登録

ローカル端末でSSHキーを生成

キーの生成は全てローカル端末(接続元の端末)側の操作になります。サーバ側で実行しないようにご注意ください。

1. 保存先のフォルダを確認

キーを生成する前に、保存先となるフォルダが存在するか確認をします。

保存先は、通常はホームディレクトリ直下の.sshフォルダに格納します。なのでこのフォルダが存在するかまず確認します。

# ホームディレクトに移動
cd ~
# 非表示フォルダも含めて表示
ls -a

非表示フォルダなので、ls -aのオプションを付けています。

.sshフォルダがあればOKです。SSHキーを生成したことがなくても、パスワード方式でSSHで接続したことがある場合、既にフォルダは自動で作成されていると思います。

無い場合、以下のコマンドで作っておきましょう。

mkdir .ssh

2. SSHキーを生成

ssh-keygenコマンドを使って公開鍵と秘密鍵のペアを生成します。

ここで、暗号化のアルゴリズムを指定できます。強度等、様々な種類がありますが、ここではRSAを利用します。明示的に指定をしなかった場合、デフォルトでRSAが使われますが、バージョンによっては異なるかもしれません。

GithubへのSSHキー登録では、よりモダンなed25519がドキュメント上に記載されていますが、特段セキュリティに関して強い要求が無いのであれば、RSAで問題ないと思います。とはいえ、セキュリティに関連する部分ではあるので、拘りがある場合は適宜調べていただければと思います。

暗号化のアルゴリズムに深く踏み込んでしまうと脱線していまいますので、ここでは割愛し、RSA方式で生成します。

以下のコマンドで生成します。

ssh-keygen -t rsa -f ~/.ssh/id_rsa_chromebook

-fオプションで、保存先と鍵名を指定しています。このオプションを省略しても、次に保存先を聞かれます。

鍵の名前は、id_rsa_chromebookにしています。指定しなかった場合、鍵名はid_rsaになるかと思います。複数キーを作成する場合もあると思うので、後でわかる名前にしておきましょう。

次に、鍵に対するパスワードの設定を求められます。パスワードレスで接続させたいので、ここは何も入力せずエンターを押します。

Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase): 

確認用に再度同じパスワードの入力を求められます。同じく何も入力せず、エンターを押します。

Enter same passphrase again:

キーが正常に生成されたとメッセージが表示されます。他にもfingerprintやrandomart等の複雑な文字列や記号の羅列が表示されますが、特段メモらなくて大丈夫です。

Your identification has been saved in /home/my-username/.ssh/id_rsa_chromebook
Your public key has been saved in /home/my-username/.ssh/id_rsa_chromebook.pub
The key fingerprint is:
SHA256:y*************************************** my-username@penguin
The key's randomart image is:
+---[RSA 3072]----+
||
+----[SHA256]-----+

.sshフォルダの中身を確認すると、公開鍵と秘密鍵が生成されていることが確認できます。

> ls ~/.ssh
id_rsa_chromebook  id_rsa_chromebook.pub

id_rsa_chromebook秘密鍵id_rsa_chromebook.pub公開鍵となります。役割が異なるため、混同しないように注意しましょう。

これでキー生成は完了です!

公開鍵をサーバに登録

上記で生成した、公開鍵(id_rsa_chromebook.pub)をサーバに登録します。間違って秘密鍵を登録しないようにしてください。

サーバの登録先について

登録先は、サーバ側のホームディレクトリ直下の~/.ssh/authorized_keysファイルです。このファイルに、公開鍵を書き込みます。もちろん、複数のキーの登録も可能です。

ちなみに、上で生成した公開鍵を登録する前のauthorized_keysファイルは、私の場合は以下の内容になってます。別端末で生成した公開鍵が、既に1件登録されています。キーの値は伏せてあります。

> cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3N*******

登録方法

手動での登録も可能ですが、ローカル端末の鍵をサーバ側の.ssh/authorized_keysに自動で登録してくれるコマンド(ssh-copy-id)があります。今回はこれを使います。

このコマンドを使えば、サーバ側の登録先のファイルが存在しない場合、自動で作成してくれます。ローカル端末の操作だけで登録が完結するので便利です。

ローカル端末で以下のコマンドを実行します。usernameはサーバのユーザ名、hostnameはサーバのホスト名(もしくはIPアドレス)です。

ssh-copy-id -i ~/.ssh/id_rsa_chromebook.pub username@hostname

-iオプションで、登録する公開鍵を指定しています。このオプションを省略した場合は、ローカルの公開鍵(.pubで終わるファイル)が全て登録されるようです。不要な鍵が残っていた場合も登録されるので、複数まとめて登録したい場合を除き、基本は鍵名を指定したほうが良いかと思います。

いきなり本登録するのが怖い場合、dry-run(登録される内容が確認できる。本登録はされない。)することも出来ます。以下のように-nオプションをつけるだけです。

ssh-copy-id -n -i ~/.ssh/id_rsa_chromebook.pub username@hostname

まずはdry-runで試してみます。はじめて接続するサーバの場合、以下のような確認メッセージが出る場合があります。yesと入力してエンターします。

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/my-username/.ssh/id_rsa_chromebook.pub"
The authenticity of host '160.16.84.146 (160.16.84.146)' can't be established.
ECDSA key fingerprint is SHA256:JVi******************.
Are you sure you want to continue connecting (yes/no/[fingerprint])? 

すると、登録対象となるキーの値が表示されます。dry-runなので登録自体はされません。

usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
=-=-=-=-=-=-=-=
Would have added the following key(s):

ssh-rsa 
AAAB3***********************

表示された値はさきほど生成されたid_rsa_chromebook.pubと同じ内容なのでOKです。このまま、ssh-copy-id -i ~/.ssh/id_rsa_chromebook.pub username@hostnameで登録をします。

/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/my-username/.ssh/id_rsa_chromebook.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
username@160.xx.xx.xxx's password: 

接続先のユーザのパスワードが求められるため、入力します。

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'username@160.xx.xx.xxx'"
and check to make sure that only the key(s) you wanted were added.

1つのキーが登録されたとメッセージが表示されました。これで完了です。

試しに、登録先となるサーバ側の~/.ssh/authorized_keysの中身を確認してみると、ちゃんと登録されていることが確認できます。私の場合、もともと1つ登録されていたので、2つ目として登録されています。

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDOSTQID9wELU0j*******************************************
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDo3BSMKv4kJC5q*******************************************

接続して確認してみる

それでは、ローカル端末からパスワードなしでサーバにSSH接続できるか確認してみます。

以下のように、-iオプションで秘密鍵を指定してSSHコマンドを打ちます。ローカル端末で実行します。なお、指定する鍵は公開鍵でなく秘密鍵なのでご注意ください。

くどいですが、usernameとホスト名(もしくはIPアドレス)は実際の接続先に書き換えてください。

ssh -i ~/.ssh/id_rsa_chromebook username@160.xx.xx.xxx

無事パスワードを入力しなくても接続されました!

login-successful

鍵の指定について

-iオプションで秘密鍵を指定すればパスワード登録なしで接続が可能になりました。しかし、指定を省くと従来同様にパスワードを求められる場合もあります。

鍵の指定を省略させるためには、ssh-addというコマンドでSSHの認証エージェントに鍵を登録する必要があるのですが、今回は割愛させていただきます。

自動化の例

例えば、サーバに接続し、サーバ上でbashコマンドを実行したいとします。しかし、残念ながら、直感的に以下のようにスクリプトを書いても想定通りに動きません。

#!/bin/bash
ssh -i ~/.ssh/id_rsa_chromebook crypto@160.16.84.146
# ローカルで実行される、、、
ls -l ~/fitbit

sshコマンドでサーバに接続されるものの、lsコマンドはローカル端末で実行されてしまいます。

サーバ側で処理を実行させる方法は少しがクセがあるので、例と言うほどではありませんが、使い方のパターンをいくつか紹介したいと思います。

サーバでbashコマンドを実行

サーバでbashコマンドを実行するには、以下のように記述します。私のサーバのホームディレクトリにある、fitbitフォルダの中身を表示するだけのスクリプトです。

#!/bin/bash
ssh -i ~/.ssh/id_rsa_chromebook crypto@160.16.84.146 'ls -l ~/fitbit'

SSHコマンドに、直接サーバ側で実行されるbashコマンドを記述しています。実際に実行してみると、ちゃんとサーバ側のfibitフォルダにあるファイルの一覧が表示されました。

total 132
-rw-rw-r-- 1 crypto crypto  2353 Apr  9  2023 README.md
drwxrwxr-x 2 crypto crypto  4096 Sep  6 23:00 __pycache__
-rw-rw-r-- 1 crypto crypto  7835 Apr  9  2023 api.py
-rw-r--r-- 1 crypto crypto   718 Dec 30 23:00 conf.json
-rw-rw-r-- 1 crypto crypto   355 Apr  9  2023 consts.py
-rw-rw-r-- 1 crypto crypto  5085 Sep  5 23:27 graph.py
-rw-rw-r-- 1 crypto crypto  4091 Sep  5 23:27 main.py
drwxrwxr-x 4 crypto crypto  4096 Apr  9  2023 pytweet
-rw-rw-r-- 1 crypto crypto 87078 Dec 30 23:00 tweet.png
-rw-r--r-- 1 crypto crypto   400 Mar 20  2023 twitter_conf.json

サーバにあるスクリプトを実行

今度はサーバにおいてあるbashスクリプトを実行する例です。ローカル端末から、サーバの~/test/hello.shを実行してみます。なお、実行されるスクリプトはコンソールにhello,world!を出力するだけです。

以下のように、sshコマンドに実行するスクリプトのパスを渡します。理屈的には1つ目の例と同じです。

ssh -i ~/.ssh/id_rsa_chromebook crypto@160.16.84.146 '~/test/hello.sh'

実行すると、ちゃんと指定のスクリプトが動きました。

hello,world!

localのスクリプトをサーバで実行

ローカルにあるbashスクリプトをサーバで実行することも可能です。

私もこの方式でこのサイトのデプロイ作業を自動化しています。ローカル端末側でもbashスクリプトが動く環境がないと厳しいかもしれませんが、サーバにスクリプトのファイルを置かなくても済むので便利です。

以下のように記述します。

ssh -i ~/.ssh/id_rsa_chromebook crypto@160.16.84.146 'bash -s' < local.sh

こちらも、原理は他の例と同じです。SSHコマンドに、ローカルにあるbashスクリプト(local.sh)のファイルの中身を、bashコマンドとして渡しています。

なお、今回のlocal.shの中身は以下のとおりです。

#!/bin/bash
cd test
ls -l

サーバにあるtestディレクトリにcdし、ファイルの一覧を表示しています。

コマンドを打つと、ちゃんとファイルの一覧が表示されました。

total 4
-rwxrwxr-x 1 crypto crypto 29 Dec 31 20:17 hello.sh

ssh-copy-idが無い場合

公開鍵をサーバに登録で、ssh-copy-idコマンドが使えない場合の手順を記載します。大体のLinuxなら利用できると思いますが、軽量なバージョンだったりすると使えない場合もあるかと思います。私自身、手動での登録は行ったことがないので試せていませんが、念のため記載します。

サーバ側の~/.ssh/authorized_keysに生成した公開鍵の値を書き込めば大丈夫です。なので、.sshフォルダを作成し、authorized_keysの空ファイルを作成し、鍵の値をコピペすればOKです。

以下のコマンドで一発で登録できます。DigitalOceanのサイトからの引用です。

cat ~/.ssh/your-public-key.pub | ssh username@remote-host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

your-public-key.pubusernameremote-hostは実際のものに書き換えてください。

複雑に見えますが、公開鍵の値をサーバの登録先のファイルに追加しているだけです。実行するとユーザ名とパスワードの入力が求められるはずなので、入力してください。

最後に

SSHキーを生成し、サーバにパスワードなしで接続する方法を解説しました。

普段何気なく使っていたsshコマンドですが、奥が深いですね!ssh-addのような、今回紹介できなかったコマンド等は、私も実際に試す機会が出てきたら別途記載したいと思います。

それでは、今年も良い一年お世話になりました。良いお年を(^^)V。おそらくギリギリ2023年中にアップロードできていると思います、、、!

参考

記事一覧に戻る