概要
僕が管理しているマストドンサーバ Abyss.fun は、最低限のサーバ侵入検知として、 /var/log/auth.log
を監視し、ログイン状況などをリアルタイムで見れるようにしています。
で、ご覧の通りの状況です。
一応ポートは変えてはいるんですが、数分に1度、総当りで攻撃を食らってますね。
そもそもこんなありがちユーザ名でログインできるようにはしてないし、公開鍵認証のみにしているので入れるはず無いんですが、溢れるログの濁流を見るだけでうんざりしますね。
なので、今回は cloudflared (ArgoTunnel)(最近はCloudFlare Zero Trustとも) を利用して、自システム⇔Cloudflare 間のトンネルを張り、CloudFlareのCDNを経由して通信できる環境を構築します。
ちなみに、 SSHのログインだけでなく、HTTP/HTTPSの通信にも対応 しているため(たしか有償プランだとそれ以外のポートやUDPにも対応したはず)、ポートを開放することなくシンプルなWebサーバを公開することができます。 もちろん NAT越え の用途にも使えます。
※なお、この記事を書き始めてからQiitaに別の方が書いた実績があるのを見つけてしまい。別に書かなくてもいいかな、なんてやさぐれてしまいそうになりましたが、補足とかいろいろあるし書き始めちゃったからもうとりあえず書いちゃえ!って気持ちでノリと勢いで書くことにしました。後悔はしていない。
Cloudflaredを使ってブラウザで任意のサーバーにSSHする - Qiita
1. サーバにcloudflaredをインストールする
公式のドキュメントに沿ってやれば行けるんですがね……書くことが大事
Via the command line · Cloudflare Zero Trust docs
まずはcloudflaredのダウンロードページにアクセス。
Downloads · Cloudflare Zero Trust docs
パッケージのダウンロードをしてインストールします。
※以降の手順ではrootユーザにて操作します。
# Debian系の場合
curl -OL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
dpkg -i cloudflared-linux-amd64.deb
# RedHat系の場合
curl -OL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm
rpm -ivh cloudflared-linux-x86_64.rpm
なお、パッケージマネージャにリポジトリを登録して、 apt upgrade
や yum update
などで他のパッケージと一緒にアップデート出来るようにもできます。
そのリポジトリ登録手順へのリンクがダウンロードページ内の「Cloudflare Package Repository」の先にあります。
ただ、cloudflared独自のパッケージアップデート方法が実装されていてこっちのほうが便利だったり、コンフィグファイルの扱いが若干違ったりするので、パッケージマネージャは経由しないほうが便利だったりします。
2. cloudflaredのログイン
cloudflaredを利用するには CloudFlareのアカウントを持っている 必要があります。当然ですが。
アカウント作成手順は省略します。
これによりcloudflaredを使って、自サーバ側からCloudFlareのサービスを利用することが出来るようになります。AWS CLIとかGitHub CLIとかみたいな、*aaSサービスにありがちな操作ですね。
また、 CloudFlareに登録されているドメインがある ことも必要です。
Cloudflare Registrarからドメインを購入してもいいですし、以下の記事のように他のレジストラからネームサーバの移管だけするのでも大丈夫です。
[ドメインを Route 53 から Cloudflare に移管する]
ドメインを登録する手順についても省略します。
ここからまたサーバに入って操作を行います。
$ cloudflared tunnel login
Please open the following URL and log in with your Cloudflare account:
https://dash.cloudflare.com/argotunnel?aud=&callback=https%3A%2F%2Flogin.cloudflareaccess.org%2F************
Leave cloudflared running to download the cert automatically.
cloudflared tunnel login
コマンドを入力するとURLが表示されるので、ブラウザからそのURLにアクセスします。
利用したいドメインを選択します。
Successの表示が出たらターミナルに戻ります。
2023-08-11T07:33:30Z INF Waiting for login...
2023-08-11T07:34:22Z INF Waiting for login...
You have successfully logged in.
If you wish to copy your credentials to a server, they have been saved to:
/root/.cloudflared/cert.pem
$ ls -l /root/.cloudflared/cert.pem
-rw------- 1 ubuntu ubuntu 1926 Aug 11 16:34 /root/.cloudflared/cert.pem
これでメッセージに表示された通り、CloudFlareと通信するために使われる証明書ファイルが作成されました。
以降は cloudflared tunnel ~
コマンドを使って操作をします。
3. トンネルを作成する
ここからは淡々とトンネルを作成していきます。
# トンネルを作る
cloudflared tunnel create <TunnelName>
# これで /root/.cloudflared にトンネルの情報(<TunnelID>.json)が作られる
ls -l /root/.cloudflared/*.json
# 作成したトンネルの確認
cloudflared tunnel info <TunnelName or TunnelID>
<TunnelName>
は任意のわかりやすい名前をつけましょう。
名前はシステム単位がいいです。例えば僕はさくらのVPSの石狩リージョンにサーバをまとめているので、Ishikari-serversとつけておきました。
4. トンネルにDNSルート情報を登録
そもそも話になりますが、cloudflaredを使ってCloudFlare CDN経由でアクセスする際、 IPアドレスの直打ちではなく、登録したドメインのサブドメインを利用 してアクセスすることになります。
例えば server01.example.com
というドメインとサーバを紐づけておくことで、sshする際にドメイン名でのみアクセスすることができます。
コレが地味にcloudflaredを使うもう一つのメリットなんですが、冒頭で紹介したような総当たり攻撃を仕掛けてくる攻撃者というのは、 適当なグローバルIPアドレスに対してログイン試行を繰り返す わけです。
cloudflaredを使うとドメイン名でしかアクセスができなくなりますので、 パターンが無限に存在するドメインに対してログイン試行をするわけにも行かず 、必然的にsshに対する攻撃を回避することが出来るというわけです。
※そもそもCloudFlareアカウントによる認証も含まれるわけなので、まずはそちらで接続ユーザを制限できるわけですが。
cloudflared tunnel route dns <TunnelID> <domain>
<TunnelID>
は先程トンネルを作成した時に表示されたID、 <domain>
はssh接続する時に利用するドメインを指定します。
ここでCloudFlareのダッシュボードからDNSレコードを見ると、対象ドメインにCNAMEとTunnelIDが登録されるのが確認できます。
先程登録したドメインのCNAMEレコードが登録されました。
これでCloudFlare側でもDNSレコードとトンネルの紐づけができました。
なお、CloudFlare Zero Trustのダッシュボードからもこちらの設定が確認できます。
こちらで cloudflared tunnel
コマンドで操作した内容(作成したトンネルとかDNSルート情報とか)を確認することができます。
無料で利用することはできますが、CloudFlareのDNSサービスとは別サービスとなっていますので、今回は解説を省略します。
また、今回はDNSルート情報を登録する手順を説明しましたがIPアドレスを登録することもできます。大抵の場合では利用することがないと思いますので、こういう方法もあるんだなぁ。程度に紹介しておきます。
# IPアドレス(GIP?)で登録することも出来るが、殆どいらないんじゃないかと
cloudflared tunnel route ip add <TunnelID> <IPaddress>
5. configファイルを作成する
DNSルート情報を作成したので、次はサーバ側で「どのドメインでアクセスしてきたらどのIPアドレス/ポートに振り分けるか」を設定してあげます。
ここはさくっとコンフィグ記述例だけ紹介します。
---
tunnel: <TunnelID>
credentials-file: /root/.cloudflared/<TunnelID>.json
ingress:
- hostname: www.example.com
service: http://127.0.0.1:80
- hostname: server01.example.com
service: ssh://127.0.0.1:22
- hostname: server02.example.com
service: ssh://192.168.0.2:22
- service: http_status:404
<TunnelID>
はトンネルを作成した時に表示されたIDを指定します。
また、ingress配下の設定では以下の順で処理が行われます。
-
www.example.com
へのアクセスがあった場合はトンネルを張っている 自サーバのWebサービス に誘導します。 -
server01.example.com
へのアクセスがあった場合はトンネルを張っている 自サーバのsshサービス に誘導します。 -
server02.example.com
へのアクセスがあった場合は server02サーバのsshサービス に誘導します。 - どれにも該当しないドメインにアクセスがあった場合は HTTP/404エラー を返します。
このように、 ドメインによってHTTP通信とSSH通信を分けたり、他のサーバにフォワーディングしたり することができます。
この辺がcloudflaredのほんとに優秀だなぁって思うところですよね。複数ドメインの通信を処理してくれて、しかも基本無料で利用できるなんて。
もうCloudFlareには足を向けて寝られないです。データセンタ含めるとどこ向いて寝ることもできません。立ったままで寝ましょう(嘘)
6. cloudflaredサービスの作成と起動
あとはサーバを立ち上げたら自動でトンネル接続するようにsystemdサービスを登録してやります。
cloudflared service install
これを実行すると、 /etc/systemd/system/
配下に以下のファイルが生成されます。
-
cloudflared.service
: cloudflared本体を自動起動する -
cloudflared-update.service
: cloudflaredをアップデートする -
cloudflared-update.timer
:cloudflared-update.service
を日時で実行する
なお、最初のインストール手順でパッケージマネージャを利用した場合、 cloudflared update
コマンドが動きません。なので、自動で更新するためのsystemdサービス cloudflared-update.service
が動きません。
これを回避するには --no-update-service
オプションを追加します。アップデート関連のsystemdサービスはインストールされなくなります。
ここまででsystemdの状態を確認すると、サービスが起動しているはずです。
# systemctl status cloudflared
● cloudflared.service - cloudflared
Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2023-08-11 19:06:59 JST; 26min ago
Main PID: 3887090 (cloudflared)
Tasks: 19 (limit: 76736)
Memory: 16.0M
CPU: 5.003s
CGroup: /system.slice/cloudflared.service
└─3887090 /usr/local/bin/cloudflared --no-autoupdate --config /usr/local/etc/cloudflared/config.yml tunnel run
...
Aug 11 19:03:43 server01 cloudflared[3886133]: 2023-08-11T10:03:43Z INF Registered tunnel connection connIndex=0 connection=333a90ab-57c1-4d4f-9881-047e2ef6d456 event=0 ip=198.41.200.193 location=KIX protocol=quic
Aug 11 19:03:43 server01 cloudflared[3886133]: 2023-08-11T10:03:43Z INF Registered tunnel connection connIndex=1 connection=47f7a272-2508-45ab-aac2-a78d93895920 event=0 ip=198.41.192.107 location=NRT protocol=quic
Aug 11 19:03:44 server01 cloudflared[3886133]: 2023-08-11T10:03:44Z INF Registered tunnel connection connIndex=2 connection=cf84e920-13fd-4c18-9d92-ba8bae08fadd event=0 ip=198.41.200.113 location=KIX protocol=quic
Aug 11 19:03:45 server01 cloudflared[3886133]: 2023-08-11T10:03:45Z INF Registered tunnel connection connIndex=3 connection=70e29c68-847c-4278-9a49-ffbf3de3ea52 event=0 ip=198.41.192.227 location=NRT protocol=quic
ここで確認すべきは、ログの最後に INF Registered tunnel connection
の行が4行あることです。
これらがCloudFlareのデータセンタと接続されているトンネルです。
つまりは、一つの接続に4経路の冗長化がされているというわけです。
これは別のコマンドからも確認できます。
# cloudflared tunnel info <TunnelID>
NAME: <TunnelName>
ID: <TunnelID>
CREATED: 2023-08-11 06:17:25.524388 +0000 UTC
CONNECTOR ID CREATED ARCHITECTURE VERSION ORIGIN IP EDGE
<ConnectorID> 2023-08-11T10:06:58Z linux_amd64 2023.7.3 <HostIP> 2xKIX, 2xNRT
この表示のEDGEの部分が増えていると思います。
NRTが確か成田で関東リージョン、KIXがどこだか忘れたけど関西リージョンで、それぞれ2経路の合計4経路となってます。
この辺がcloudflaredのほんとに優秀だなぁって思うところですよね。接続性を維持するために4経路も冗長化してくれて、しかも基本無料で利用できるなんて。
もうCloudFlareには足を向けて寝られないです。データセンタ含めるとどこ向いて寝ることもできません。地球の裏側にもある可能性を考えて逆立ちで寝ましょう(大嘘)
なお、サービスを再起動する際は、セッションがクラウド側に残るみたいです。なので起動する前にセッションをクリアするのがいいでしょう。
systemctl stop cloudflared.service
cloudflared tunnel cleanup <TunnelID>
systemctl start cloudflared.service
7. クライアント側の設定と接続
ここからようやくクライアント側の設定です。長かった。
作業想定はWSLですが、同様の手順でWindows(PowerShell)でもできます。
まず、クライアント側にも同じcloudflaredのパッケージをインストールし、ログインします。
つまり、 1. サーバにcloudflaredをインストールする と 2. cloudflaredのログイン を実施しましょう。
これは書かなくてもいいですよね。面倒なので。
次に、ssh接続時にcloudflaredを利用する設定を入れます。
$ cloudflared access ssh-config --hostname server01.example.com
Add to your /home/wdsadm/.ssh/config:
Host server01.example.com
ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
この Host ~
以降の2行を ~/.ssh/config
内に追記します。
ちなみに、このままだとホストごとにいちいちコンフィグを書かないといけないので、Host *.example.com
のようにまとめてしまってもいいと思います。
で、ここまで設定したら普通にsshしたらつながると思います。
ssh server01.example.com -l username
つながった!
あとはよしなに
とりあえずcloudflaredを利用するところまで設定しました。
あとは公開鍵認証の設定を入れたり、sshdのListenAddressを127.0.0.1のみにしたりしてやれば、外部にポートを公開していない状態でのアクセスが可能となります。
無料の割に高機能で安定感のあるcloudflaredです。みなさんのご家庭のサーバにもぜひともcloudflaredを導入してみてください!