VPS公開後のSSH・UFW・Docker設定をまとめて確認するCLI「vps-check」を作った(Ubuntu)
AIを使うことで、個人でもWebアプリをかなり簡単に作れるようになりました。
自分もAIを使いながらWebアプリを作り、VPS上でDockerやNginxを使って公開しています。
一方で、アプリそのものを作るより難しいと感じたのが、
「VPS側の設定、本当にこれで大丈夫なのか?」
という部分でした。
そこで今回、VPSのよくある公開設定を確認するCLIツール vps-check を作りました。
GitHub:
現在は v0.1.0 です。
なぜ作ったのか
きっかけの1つはDockerのポート公開でした。
Docker Composeで、
ports:
- "4001:4001"
のように指定すると、ホスト側の全インターフェースにbindされる場合があります。
一方、Nginxからローカルでアクセスするだけなら、
ports:
- "127.0.0.1:4001:4001"
のようにloopbackへbindする方法もあります。
Webアプリ自体はAIを使って比較的簡単に作れても、
- Dockerのポート
- PostgreSQLなどのDB
- SSH
- Firewall
- HTTPS
- Nginx
といったインフラ側の設定は、別途理解する必要があります。
毎回コマンドを調べながら確認するのも面倒だったため、
「VPS上で実行するだけで、まず確認すべき項目を一覧にできないか」
と考えたのが vps-check の始まりです。
vps-checkで確認しているもの
v0.1.0では、次のような項目を確認します。
- 外部インターフェースで待ち受けているポート
- PostgreSQL / MySQL / Redis / MongoDBなどの待受け
- Dockerの公開ポート
- SSH PasswordAuthentication
- SSH root login
- UFW
- NginxなどのWebサーバー
- unattended-upgrades
設定を変更する機能はありません。
read-onlyの確認ツールとして作っています。
実行例
VPS Check v0.1.0
OS: Ubuntu 22.04
[INFO] Service is listening on all interfaces
Port: 443
Protocols: IPv4, IPv6
Addresses: 0.0.0.0, ::
[PASS] No common datastore is listening on all interfaces
[PASS] No Docker ports bound to all interfaces detected
[PASS] SSH password authentication is disabled
[PASS] SSH root login is disabled
[PASS] UFW host firewall is active
[INFO] Nginx detected
[PASS] Automatic security updates are scheduled
sudoなしでも実行できます。
権限が不足して正確に確認できない項目は、無理にPASSやWARNを出さず、
[SKIP] SSH password authentication could not be checked
のように表示します。
必要であれば、
sudo vps-check
で追加のチェックができます。
作ってみて分かったこと
実装そのものより、実際のUbuntu VPSで試してから修正した部分がいくつもありました。
1. 0.0.0.0 だから「インターネット公開済み」とは限らない
最初は、
0.0.0.0:5432
のような状態を見つけたら、
「外部公開されています」
と警告することも考えました。
しかし、これは正確ではありません。
ホスト側で全インターフェースにbindされていても、
- UFW
- VPS事業者側Firewall
- NAT
- その他のネットワーク設定
によって、インターネットから到達できない場合があります。
そのため vps-check では、
「all interfacesで待ち受けている」
という事実と、
「インターネットからアクセス可能」
という状態を分けています。
例えば、
This service may be externally reachable depending
on firewall and network configuration.
のような表現にしています。
2. 22 / 80 / 443を全部WARNにすると分かりにくい
最初の実機テストでは、
- SSH : 22
- HTTP : 80
- HTTPS : 443
がすべてWARNになっていました。
しかし、公開Webサーバーでは、これらが外部インターフェースで待ち受けていること自体は珍しくありません。
そこで、単純なlistenポート一覧はINFO扱いに変更しました。
危険性については、
- DB
- Docker
- SSH設定
など、それぞれ専用のチェックで判定するようにしています。
3. IPv4 / IPv6が二重表示された
実VPSでは、
0.0.0.0:443
:::443
の両方が取得されました。
そのまま表示すると同じ443番ポートが2件出てしまうため、
Port: 443
Protocols: IPv4, IPv6
Addresses: 0.0.0.0, ::
のように1件へまとめました。
4. 127.0.0.53%lo でloopback判定に失敗した
Ubuntu実機で特に面白かったのがこれです。
ss の結果に、
127.0.0.53%lo
というアドレスが出てきました。
これはloopbackですが、%lo が付いていたため、最初の実装では通常のlocal IPとして分類していました。
そこでIP分類時だけzone suffixを取り除き、
127.0.0.53
として判定するように修正しました。
表示上のEvidenceには元の、
127.0.0.53%lo
を残しています。
また、
fe80::1%eth0
のようなIPv6 link-localまでloopback扱いしないようにしています。
このあたりはWindows上のunit testだけでは気付かず、実VPSで動かしたことで見つかりました。
JSON出力も用意した
通常表示以外に、
vps-check --json
も用意しています。
例えば、
{
"id": "SSH-001",
"status": "pass",
"title": "SSH password authentication is disabled",
"evidence": "PasswordAuthentication no"
}
のような形式です。
将来的に別ツールやAIから結果を利用する可能性も考え、最初から人間向け表示と機械向け出力を分けました。
CIとReleaseもGitHub Actionsで自動化
push / Pull Request時にはGitHub Actionsで、
go test ./...
go vet ./...
go build ./...
を実行しています。
v* タグをpushすると、
- Linux amd64
- Linux arm64
- SHA256SUMS
を生成し、GitHub Releaseへ自動で添付します。
v0.1.0もこのworkflowで公開しました。
v0.1ではやらないこと
最初から大きなセキュリティツールを目指すと完成しなくなりそうだったので、かなり範囲を絞っています。
v0.1では、
- 自動修正
- CVEスキャン
- マルウェアスキャン
- CIS Benchmark完全対応
- クラウド事業者APIとの連携
- SaaS
- AI API
- セキュリティスコア
などは実装していません。
また、PASSが出たからといって、
「このVPSは安全」
という意味でもありません。
あくまで、個人開発者が最初に確認しやすい項目をチェックするためのツールです。
今後
v0.2候補としては、
- pending package updates
- pending security updates
-
/var/run/reboot-requiredによる再起動要求
などを考えています。
ただ、まずは機能を増やすより、
実際に第三者が使ってくれるか
を見たいと思っています。
IssueやFeature Requestも歓迎です。
GitHub: