はじめに
自宅ルータとして RTX1210 買ったんですけどね。AWS 接続機能持ってるんですよ。
でも、AWS と自宅の間で VPN 張るのって VPN ゲートウェイ建てなきゃいけないからカネ掛かるじゃ無いですか。
ざっくり 5000円強/月くらい。企業だと安いんですけど個人だとめっちゃ高い。
いや、カネないから Lightsail 使ってるのに本末転倒じゃないですか。
じゃあどうするかって考えた時に、自宅のグローバル IP アドレスから TCP 全許可しちゃえ、って思いついちゃったんですよ。
でも、普通の自宅は固定グローバル IP アドレスじゃないよね。
じゃあ自分のグローバル IP アドレスをリアルタイムに許可しちゃえば良いんだ!(よくない)
・・・ってことで実装を考えたところ、AWS CLI の「aws lightsail put-instance-public-ports」を使えば良いことが分かりましたが、日本語文献や参考例があんまり無い。
なので試して成功した内容を掲載します。
前提
実行環境
・自宅に AWS CLI が利用できる Linux があるものとします。Windows でも多分出来ます。
・DDNS 運用は今回は説明しません ( 「$ curl ifconfig.me 」とかで調べられるのでは )
開放する対象
⚫︎IPv6 は無効化しています
⚫︎以下の TCP ポートはパブリック開放します
・HTTP
・HTTPS
⚫︎以下の TCP ポートを自宅のグローバル IP アドレスのみに制限します
・TCP 0-65535 (※このような全許可はよくない)
⚫︎以下のポートは自宅と AWS Web コンソールからのみ許可します
・SSH
TCP のみ対象にしている理由は攻撃者が IP アドレスの偽装をした場合に 3-way ハンドシェイクの確立が出来ないため偽装が難しいと考えるためです。
UDP / ICMP は攻撃者が偽装できるため攻撃や IP spoofing の対象となるから開放しません。
ただし、SYN Flood 攻撃に対して脆弱というリスクが存在します。(まぁ今日び OS で多少対策されてるけど。)
AWS CLI を使った穴あけ
コマンド
aws lightsail put-instance-public-ports --cli-input-json file:///DIR/YOUR_FILE.json
open-instance-public-ports というサブコマンドもありましたが、今回は自宅のグローバル IP アドレスのみを許可したいのと、不要な以前のアドレスは自動で削除したいので決め打ちとなる put-instance-public-ports にします。
これは PUT した JSON の通りに設定し、JSON 記載されていないルールは全て削除されます。
うーん、Infrastructure as Code…
で、このドキュメントがすんげー分かりづらいので日本語で書こうと思った訳です。
JSON 例
get-instance-public-ports の結果を元に json を作成します。
{
"portInfos": [
{
"fromPort": 80,
"toPort": 80,
"protocol": "tcp",
"cidrs": [
"0.0.0.0/0"
],
"cidrListAliases": [
]
},
{
"fromPort": 443,
"toPort": 443,
"protocol": "tcp",
"cidrs": [
"0.0.0.0/0"
],
"cidrListAliases": [
]
},
{
"fromPort": 22,
"toPort": 22,
"protocol": "tcp",
"cidrs": [
],
"cidrListAliases": [
"lightsail-connect"
]
},
{
"fromPort": 0,
"toPort": 65535,
"protocol": "tcp",
"cidrs": [
"<自宅の IP アドレス>/32"
],
"cidrListAliases": [
]
}
],
"instanceName": "<Lightsail インスタンス名>"
}
lightsail-connect は Web ブラウザから SSH に繋がるようにするための指定。
別に要らないけど念のため。。
Lightsail の firewall を制御する JSON では、特定のポートを開ける場合は fromPort と toPort を同じ値にします。
<自宅の IP アドレス> と <Lightsail インスタンス名> を修正してすれば Lightsail のファイアウォールが設定されます。すごい!
例えば「 “MY_ADDRESS/32″」とか「”MY_INSTANCE“」みたいなプレースホルダにしておいて、
sed "s/MY_ADDRESS/IPアドレス/" | sed "s/MY_INSTANCE/インスタンス名/" > input.json
みたいにしちゃえば、テンプレート化も出来ちゃうわけだ。もっとすごい!
実行結果
{
"operation": {
"status": "Succeeded",
"resourceType": "Instance",
"isTerminal": true,
"operationDetails": "lightsail-connect,80/tcp,443/tcp,22/tcp(lightsail-connect),0-65535/tcp(自分のIPアドレス
/32)",
"statusChangedAt": 1703256137.069,
"location": {
"availabilityZone": "ap-northeast-1a",
"regionName": "ap-northeast-1"
},
"operationType": "PutInstancePublicPorts",
"resourceName": "自分のインスタンス名",
"id": "14f844d7-bae7-d4b8-78c2-b7302ef44a06", #←捏造
"createdAt": 1703256137.069
}
}
変更前
変化が分かるように HTTP/HTTPS 以外を削除してみました。
変更後
バッチリ「すべての TCP」が自宅からのみに制限されています。
(一応送信元 IP アドレスは隠している)
おわりに
当たり前ですけど、あなたが このページに記載している内容を実行して何らかの不利益を被ったとしても、私は一切の責任を取りません。
この例では全開放しちゃいましたけど、使うサービスが決まってるなら個々にポート設定した方が当然ながら安全ですね。なのでこの記事公開後にjson を修正して使用ポートのみに絞る設定にしました。
グローバル IP アドレスが変わったら DNS レコードを変更する自動 DDNS を運用しているので、この処理に今回のファイアウォール設定を行う処理を組み込むことで全自動化できました。
これで Lightsail に Prometheus みたいな監視エージェント入れて、家の監視サーバからポーリングする・・・みたいな遊び方ができるようになりましたね!
ところで英語の公式ドキュメントが非常に分かりづらかった為この記事を書いたんですが、
以下の re:Post で非常に分かりやすく日本語解説されてました。
「既存の Lightsail ファイアウォールルールを別の Lightsail インスタンスにコピーするにはどうすればよいですか?」
ちくしょう!