Webサーバー運用を行っている限り直面するのが、様々なセキュリティ対策を講じる必要があるということです。
このセキュリティ対策は俗に言う「イタチごっこ」でもあり、正解がいつまでも見えず常に学んでいく必要のある領域でもあります。
現在まで、多くの状況で使われている VPN(Virtual Private Network)の技術は運用面においても外すことの出来ないものです。
また、Webサーバーの管理以外でも遠隔での操作が必要な現場へVPN接続環境を構築することで、様々なメリットがあり、特に IPSec は無くてはならなかったものです。
ここに来て昨今、話題でも有る WireGuard について、実証を踏まえた構築を行ってみましたので記事にいたします。
WireGuardとは?
WireGuard ® は、最先端の暗号化技術を採用した、極めてシンプルでありながら高速でモダンな VPN です。大きな問題を避けながら、IPsec よりも高速、シンプル、軽量、便利になることを目指しています。OpenVPN よりも大幅に高性能になることを目指しています。WireGuard は、組み込みインターフェイスやスーパー コンピューターで実行できる汎用 VPN として設計されており、さまざまな状況に適しています。当初は Linux カーネル向けにリリースされましたが、現在はクロスプラットフォーム (Windows、macOS、BSD、iOS、Android) で幅広く導入できます。現在、開発が進められていますが、すでに業界で最も安全で、最も使いやすく、最もシンプルな VPN ソリューションとみなされているかもしれません。
公式ロゴマークは蛇かと思いきやカワウソとのこと。

A realistic illustration of an otter standing on a rock near a riverbank, looking alert and curious. The otter has sleek, wet fur, small rounded ears…
ChatGPT へ質問してみました
WireGuardは、2018年に最初にリリースされました。
開発者はJason A. Donenfeldで、WireGuardは最初にLinuxカーネルモジュールとして登場しました。
その後、WireGuardはそのシンプルさとセキュリティ性により、VPNソリューションとして広く使用されるようになり、2019年にはLinuxカーネルに統合されました。
WireGuardは、設定がシンプルで、高速なパフォーマンスと強力な暗号化を提供することから、OpenVPNやIPsecの代替として注目されています。
比較的新しい技術であることが伺えますが、これは試してみる価値が十分にあると思い、実証してみました。
WireGuardでやりたいこと
Webサーバーの運用には欠かせない、SSH接続が有ります。(SFTPも同義です)
多くの環境は、その対策が必要なサーバー以外はほぼ開放状態としていることも多いでしょう。(インターネットからは何処からでもSSH接続できる状態)
この状態はあまり良くないことは承知していましたが、SSH認証鍵の設定を必須にしている状態では、特に緊急で問題であると感じることは少ないのが現実かと思います。
しかし、auth.log を確認していると不正アクセスが予想以上に有ることで、サーバー負荷の上昇や、ログの不必要な肥大化などへ対処すべき懸念点があることが分かってきます。
下記のスクリプトで、とあるWebサーバーの auth.log の状態を確認してみましたが、その様子がすぐ把握できます。
auth_summary.sh (debian 11.11 / auth.log のフォーマットに準じて適宜$番号設定)
#!/bin/bash
# 引数からログファイルを取得(デフォルト値を指定)
LOG_FILE="${1:-/var/log/auth.log}"
# ファイルが存在するか確認
if [ ! -f "$LOG_FILE" ]; then
echo "Error: Log file '$LOG_FILE' not found."
exit 1
fi
echo "=== サマリー ==="
echo "失敗したログイン試行の総数:"
grep "Invalid user" $LOG_FILE | wc -l
echo "成功したログイン試行の総数:"
grep "Accepted publickey" $LOG_FILE | wc -l
echo "失敗したログイン試行の発生元IP (上位20件):"
grep "Invalid user" $LOG_FILE | awk '{if ($8 == "from") print "(no name)", $9; else print $8, $10}' | sort | uniq -c | sort -nr | head -n 20
#grep "Invalid user" $LOG_FILE | awk '{print $0, "(Line:", $1, ")"}'
echo "成功したログイン試行の発生元IP (上位10件):"
grep "Accepted publickey" $LOG_FILE | awk '{print $9, $11}' | sort | uniq -c | sort -nr | head -n 10

この様にして、数日程度で数万件もの失敗したログインがあるわけです。(成功したログインは私のものです)
一般的に、ブルートフォース攻撃(Brute Force Attack)と呼ばれているものですが、どのWebサーバーのインスタンスでも同様なことが起きています。
ログインユーザーの名前を見る限りでは、ubuntu, user, admin, test など良くあるユーザー名でのアタックです。
当方の運用サーバーではこの様なユーザーを作成していないため、そもそも認証が成立することがないのですが、「ピンポンダッシュ」をされているようで、非常に気持ち悪いといった状態でもあるわけです。
サーバーによってはドメイン名からユーザーを推測している事も汲み取れるログの記録が有ったりするので、攻撃する側の必死さも伝わってきます。(プログラムでクロールしているだけなんでしょうけれど、頑張っておられる様子が見れたりします)
過去に実際に自宅の「ピンポンダッシュ」をされた経験がありますが、その犯人は友人であった、といった笑い話はさておき、これらの攻撃は基本的に相手を知ることは困難です。
IPアドレスから辿り、サーバーの在処を知ったところでファイアーウォールで個別対応する以外は特に対処のしようがないのが現実でしょう。
また、ファイアーウォールでの個別設定などは労力がかかる上に、どんどんと異なるIPアドレスから攻撃が有るためあまり効率的ではない対策になってしまいがち。海外のサブネットごと排除することは出来ても、時間経過と共に運用が大変なことになってきます。
fail2ban 等のツールを導入するのも得策かもしれません。
そうなると、これらの攻撃を根本から排除するために、特定の環境以外からのSSH接続を遮断することが最善策になってくるかと思います。玄関の呼び鈴を付けない、といった感じでしょうか。
そもそも、SSH接続はGCPの認証で行うのみにすれば良いという話しにもなりますが、顧客側でサーバー側にSFTP接続をしたい、などの要求に答えるのには少々現実的ではないかもしれません。
利便性を考えると、SSH接続を開放しておきたいという事もありますが、昨今のサイバー攻撃事情を考慮すると厳密に対応しておいた方が良さそうなため、下記を実施することにしました。
1つ目は、SSH接続を遮断することを目的とします。
また、これに対して、多くのWebサーバー運用で用いているWordPressですが、管理画面が意外にも厄介者です。
2つ目は、WordPress管理画面への侵入を防ぐ、という事も目的とします。
GCPにWireGuardインスタンスを立ち上げる
Compute Engine からVMインスタンスを立ち上げます。
ディストリビューションは何が良いかは好みの部分もありますが、今回はイメージから、ファミリー:ubuntu-pro-2204-lts を選択して、インスタンスを作成します。
インスタンス作成後は、通常通りにログインし、WireGuardをインストールして設定していきます。
この辺りの設定方法は、Gemini や ChatGPT に聞いてみるのもオススメです。様々な記事があるのでここでの掲載は割愛いたします。
WireGuardの設定
私は下記の設定を施しました。
端末側(Mac)
WireGuardアプリをインストールします。
アプリは、Windows、macOS、Android、iOSなど様々なOSに対応しています。
https://www.wireguard.com/install
アプリを使わず、brew でもインストール可能ですが、GUIの方が便利です。
Mac の場合は、brew でインストールしたものと、アプリでは別領域で管理されるようで、アプリを使うと、wg コマンドは連動しておらず別々になるようです。
インストール後に、WireGuardを立ち上げ、「設定が空のトンネルを追加⋯」をクリックします。

新規の公開鍵と秘密鍵が自動生成され、下図の様な画面で表示されます。

ここから、端末側の設定を追加で記述していきます。

画面上部に表示されている「公開鍵」はインスタンス側の[Peer] PublicKey に設定します。
[Interface]
PrivateKey | 自動生成されたものをそのまま使います。 |
Address | 端末側に割り当てるIPアドレス。 /32 サブネットとして自動的に1つになります。 インスタンス側の[Peer] AllowedIPs に合わせるようにします。 |
DNS | 8.8.8.8 や、1.1.1.1 の信頼性のあるDNSを指定します。 指定せずとも接続後にインターネットに出られる場合には必要ないかもしれません。 |
[Peer]
PublicKey | インスタンス側の公開鍵(server_public.key) |
AllowedIPs | すべての通信をインスタンス側を経由させたい場合、0.0.0.0/0 を設定。GCPのVPCサブネットのみにしたい場合は、10.146.0.0/0 などにします。 |
Endpoint | インスタンス側の外部IPアドレス、とポート番号51820を設定します。(51820はWireGuardの初期設定) |
PersistentKeepalive | 25秒を設定。 25秒ごとに接続を維持するために送信されるパケットの間隔を設定します。 |
PresharedKey | (必要に応じて) |
上記のように設定して保存します。
インスタンス側(GCP)
wg0.conf
# WireGuard VPN 内部の IP
[Interface]
PrivateKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # server_private.key
Address = 10.146.0.2/20
ListenPort = 51820
# 端末側(Mac)の設定
[Peer]
PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 端末1の公開鍵
AllowedIPs = 10.146.0.21/32 # 端末のIP
AllowedIPs = 10.146.0.0/20 # サブネット全体を許可
[Peer]
PublicKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # 端末2の公開鍵
AllowedIPs = 10.146.0.22/32 # 端末のIP
AllowedIPs = 10.146.0.0/20 # サブネット全体を許可
今度は、インスタンス側の [Interface] は、WireGuardの受け口になる方です。
コマンドで生成した sever_privatre.key の中身と、Address、ListenPort を設定します。
[Peer] を複数定義することで複数端末からの接続を受け入れられるよう設定を追加することが出来ます。ここで少々ハマったのは、[Interface] Address インスタンス側のIPアドレスの割当を何にするかです。
GCPでは通常、東京リージョン asia-northeast1 のサブネットが 10.146.0.0/20 です。
そうすると、10.146.0.1 がデフォルトゲートウェイとなり、それ以降にVPCサブネット内に既にあるインスタンスの内部IPアドレスがエフェメラルで割り当てられていくため、被らないように。。。と考えがちですが、この [Interface] Address は言ってみれば WireGuard の管理下になるため、何でも良いようです。
wg-quick up で起動するとき、自動的にルートを構成してくれます。
AllowedIPs の解釈で少々手間取りましたが、考え方としては、端末側に割り当てる一つのIPを定義し、許可範囲を追加で設定してあげる、といった感じでOKなようです。カンマ区切りでもOKです。この辺りは少し追い込みが必要そうです。
そして、Endpoint で設定することも出来るようですが、基本的に設定する必要はないようです。
始め、固定観念として端末側のプロバイダに割り当てられたサブネットの指定が必要かも、など勝手な想像が邪魔をしていましたが、その必要は全くありません。IPSec 同様ですが、端末側は固定IPアドレスの環境でなくても、基本的に接続は成立します。
その他の設定
端末側のアプリで「有効化」したときの状態が「有効」と即座に変わりますが、ハンドシェイクが成功していない場合には、実際の接続は行われていません。(この辺りは少々勘違いしやすいかも)

GCPのWireGuardインスタンスのファイアーウォールに、udp:51820 のみ許可としておきます。
また、PING応答(icmp)も遮断しておきます。
ファイアーウォールに始めからある default-allow-ssh は基本的に全てのインスタンスにSSH接続を許可しているファイアーウォール設定ですが、ここから絞るために、対象インスタンスの外部IPアドレスから(または、10.146.0.0/20 VPCサブネットから)のみを追加することで、SSH接続をこの経路でのみ許可することにします。
今回は設定していませんが、PresharedKey(事前共有鍵)の設定も行えるようです。より強固にしたい場合には設定したほうが良さそうです。
その他、ネットワークの転送設定などが必要ですが、それらを適宜設定をしてルーティングします。
言うまでもなく、インスタンススペックは Peer の接続数などに応じて強化していくことが出来ます。数名程度での接続であれば、e2-small 等でも十分に使えそうです。
SSH接続を遮断する
WireGuardの接続が確立することで、各インスタンスへのSSH接続の経路を絞り、1つ目の目的である「SSH接続を遮断する」事ができたわけですが、どうもVPCサブネット内で内部IPアドレス同士で他のインスタンスへの転送がうまく完成しません。
これは、WireGuardインスタンスでの設定に影響しているようで、wg-quick で up させた際にルートを自動登録しており他の インスタンス (10.146.0.xx など) へのパケットも WireGuard を経由する設定になってしまう事が原因?のようです。
内部IPアドレス同士での通信ついては必須の対応ではないため、追々探ってみることにします。
後に分かりましたが、PostUp, PostDown を定義することで、これらは抜けられそうです。
参考 https://pc.watch.impress.co.jp/docs/column/ubuntu/1606110.html
WordPress管理画面への侵入を防ぐ
WordPress管理画面へのアクセスは、WireGuardインスタンスを経由することで許容するようにします。
この対応は比較的単純なもので、Nginx の ”location wp-admin” へ allowディレクティブとしてWireGuardインスタンスのIPアドレスを設定します。
意外にもBasic認証を取り入れることで多段で侵入を防げますが、そもそもアクセスをブロックしてしまう方が良いでしょう。
あとは、顧客側での運用において利便性が悪い場合にはBasic認証のみで、出来ることならWireGuardアクセスで管理するようにしたいところです。
WireGuard に感動したところ
IPSec と比べても接続確立までが高速な様子でしたが、VPNの新しいプロトコルだけあるといった印象です。
WireGuardはLinuxカーネルに統合されているため、単体プロセスとして存在しているわけではなく ps コマンドでも見ることが出来ません。
また、外部からのアクセスといった視点で、nmap コマンドでポートスキャンを実施してみました。
STATE は open|filtered の判断も正常に応答されず、SERVICE も unknown となるため、実質的に検知が難しいようです。
これが意味するところは、インスタンス側で WireGuard が動作していることが外部から判断されにくい、といったことになりますので、新たなる攻撃を受けないために、とても優れた仕組みだなと感動しました。
ちなみに、IPSec では、udp:500 での応答にしっかり open と返答が有るため、VPN接続できるんだなと外部から容易に察知されてしまいます。
様々な事が考えられている WireGuard VPN ですが、シンプルでありながら奥が深そうな気配を感じています。
WireGuard アクセスの提供
自社内、および顧客へ WireGuardアクセスを提供することで、より強固な運用環境の構築が行えるでしょう。
この運用に関する固定料金は、基本的にGCPインスタンスの運用費のみです。
場合によっては、固定IPアドレスの外部サービスを契約するよりもお安く済んでしまう可能性は大いにあります。
運用費としての人件費はかかってきてしまうもののGCPの運用に関して、より万全なセキュリティ対策を講じていることを提示できることから、高額な費用をかけずに安心を得られ、それを顧客にも提供できるでしょう。
たとえWebサーバー一台でも侵入された際の被害は予想を遥かに上回るものになります。
仮に、コンテンツが消えてしまうことよりも、その規模によっては顧客情報の漏洩等が極めてパンチの大きい事態になってくるはずです。
あまり意識されない部分としてあるのが、WordPressでのお問い合わせフォーム、および商材等への申し込みフォームから来た履歴です。これらは、簡易的なプラグインでもご丁寧にWebサーバーへ記録を残しています。Webサーバー上にこれらの顧客情報が保存されていることは、ある意味危険な状態であるとも言えます。
オープンソースであるWordPressの運用で十分なメリットを活かせているものの、この様な部分で対策を施さずにデメリットの方を傍受してしまうのは避けたいところでもありますね。
あとは、VPCネットワークの構成を組んでいき、各プロジェクトごとの疎通を行うことでより良いGCP運用環境が目指せそうです。
最後にチラッと
カメラネタ
最近ネットニュースでチラ見した、Leica LUX グリップ、が少しばかりか気になっています。
https://leica-camera.com/ja-JP/mobile/lux-grip
iPhone 16に搭載された、カメラコントロールボタンは数えるほどしか押していないのに、何故か気になってしまいます。
さすがライカさんです 📸
記事の内容が古くなっているものもあり、適宜アップデートされる場合がございます。