Google Cloud Platform で特定の国からのアクセスをブロックする方法
Google Cloud Platform で特定の国からのアクセスをブロックする方法についてです。
直接国を指定してブロックする方法は用意されていないので、 まずブロックしたい国の IP アドレスの範囲を特定してから、それらをファイアウォール機能で全件ブロックする というアプローチを採ることになります。
Google Cloud Platform (以下 GCP )のファイアウォール機能は 1 つのルールにつき最大 256 件の IP アドレスの範囲を指定できるので、およそ ブロックすべき IP アドレスの範囲の数 ÷ 256 [個]
のルールを作成すれば OK です。
たとえば 1,000 個の IP 範囲のある国をブロックしたい場合は 1,000 ÷ 4 ≒ 3.9 なので、ルールを 4 つ作ればすべてカバーできます。
手作業で行う場合は、 GCP のコンソールから VPC network → Firewall に進み「 Create Firewall Rule 」をクリックしてファイアウォールルールを 1 件ずつ作成していきます。
本記事作成時点でそのルール作成画面に設けられている主なフィールドは次のとおりです(インタフェースを日本語にしている方は日本語に読み替えてください)。
- Name
- Description
- Logs
- Network
- Priority
- Direction of traffic
- Action on match
- Targets
- Target tags
- Source filter
- Source IP ranges
- Second source filter
- Protocols and ports
- Enforcement
それぞれの意味合いはおおよそ以下のとおりです。
名前 | 説明 |
---|---|
Name | ルール名。アルファベットの小文字・数字・ハイフンが使えます。 |
Description | 説明。機能には影響がありません。 |
Logs | ログを有効にするかどうか。デフォルトは Off 。 |
Network | 対象のネットワーク。 |
Priority | 適用優先度。数字が低いものが優先される。デフォルトは 1000 。 |
Direction of traffic | アクセスの方向。 Ingress は外からのアクセス、 Egress は内から外へのアクセス。デフォルトは Ingress 。 |
Action on match | ルールにマッチしたときに許可するかブロックするか。デフォルトは Allow 。 |
Targets | ルールを適用する対象インスタンス。 |
Target tags | ルールを適用する対象タグ。 Targets で Specified target tags を選んだときに使える。 |
Source filter | アクセス元のフィルタ。 |
Source IP ranges | アクセス元の IP 範囲。 Source filter で IP ranges を選んだときに使える。 |
Second source filter | 2 つめのアクセス元フィルタ。 |
Protocols and ports | ルールを適用するプロトコルとポート。 |
Enforcement | ルールを有効にするかどうか。デフォルトは Enabled 。 |
細かな設定方法は、公式のドキュメントを読むか、ブログで紹介している人がいるのでそれらを参考にしてください。
件数が少ない場合は手作業でもよいですが、数が多くなる場合は gcloud
コマンドでまとめて追加した方がかんたんで確実です。
今回は試しに中国をブロックしてみましょう。
最初にその国の IP アドレスの範囲を特定する必要があります。 これは ipv4.fetus.jp で公開されているものをお借りするのがかんたんです。
# 中国の IP アドレスの範囲の一覧をダウンロードする
curl -O https://ipv4.fetus.jp/cn.txt
ファイル cn.txt
の中身は次のようになっています。
#
# [cn] 中華人民共和国 (China)
# https://ipv4.fetus.jp/cn.txt
# 出力日時: ...
#
1.0.1.0/24
1.0.2.0/23
1.0.8.0/21
1.0.32.0/19
1.1.0.0/24
...
このデータとファイアウォールルールを作成する gcloud
のサブコマンド gloud compute firewall-rules create
を使ってルールを作成していきます。
gcloud compute firewall-rules create
コマンドは次のような形で使用します:
gcloud compute firewall-rules create [NAME] \
--action=DENY \
--rules=ALL \
--direction=INGRESS \
--priority=10 \
--no-enable-logging \
--source-ranges=[RANGES]
これを実行し無事に処理が成功すると、 [RANGES]
で指定した IP アドレスからのアクセスをブロックするファイアウォールルールが作成されます。
名前は [NAME]
で指定したものになります。
その他のオプションの意味合いは次のとおりです。
オプション | 意味合い |
---|---|
--action=DENY |
ルールにマッチしたときに行う処理。 ALLOW または DENY 。 |
--rules=ALL |
ルールを適用するプロトコルとポート。 ALL とするとすべてが対象になる。 |
--direction=INGRESS |
アクセスの方向。 INGRESS または EGRESS 。 INGRESS が外部から内部への、 EGRESS が内部から外部へのアクセスを表す。別名として IN OUT も用意されている。 |
--priority=10 |
優先度。 0 から 65535 までの整数。数字が低いほど優先度が高い。デフォルトは 1000 。 |
--no-enable-logging |
ロギングを無効にする。 |
--source-ranges=[RANGES] |
対象の IP アドレスのリスト。 , 区切りで複数指定可。 |
[NAME]
と [RANGES]
には実際の名前と IP アドレスの範囲を入れます。
ひとつのルールで指定できる IP アドレスの範囲は最大 256 件なので、たとえば範囲の数が 6,000 個ある場合は 20 個強のルールを作成する必要があります。 これを手作業でやるのは大変なので、次のようなスクリプトを書きます。
gcp_block_country.py
:
"""
Google Cloud Platform で特定の国からのアクセスをブロックする
ルールを作成するためのスクリプト
"""
import argparse
import subprocess
CHUNK_SIZE = 256
# サポート対象の国の一覧
# キー: 国コード / バリュー: ルールのプリフィックス
COUNTRIES = {
'cn': 'block-china-',
'ru': 'block-russia-',
}
def main():
"""メイン関数"""
args = get_args()
dry_run = args.dry_run
country_code = args.country_code
addresses = get_addresses(country_code)
name_prefix = COUNTRIES[country_code]
create_rules(name_prefix, addresses, dry_run=dry_run)
def get_args():
"""コマンドライン引数を取得する"""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--dry-run', action='store_true', help='ドライラン')
parser.add_argument('--country-code', required=True, help='国コード')
return parser.parse_args()
def create_rules(name_prefix, addresses, *, dry_run):
"""ファイヤウォールルールを複数件まとめて作成する"""
n = 0
while True:
start = n * CHUNK_SIZE
stop = start + CHUNK_SIZE
chunk_addresses = addresses[start:stop]
if not chunk_addresses:
break
name = '{}{}'.format(name_prefix, n)
create_rule(name, chunk_addresses, dry_run=dry_run)
n += 1
def create_rule(name, addresses, *, dry_run):
"""ファイヤウォールルールを 1 件作成する"""
args = [
'gcloud',
'compute',
'firewall-rules',
'create',
name,
'--action=DENY',
'--rules=ALL',
'--direction=INGRESS',
'--priority=10',
'--no-enable-logging',
'--source-ranges={}'.format(','.join(addresses)),
]
if dry_run:
print('Run:', ' '.join(args))
return
return subprocess.run(args, check=True)
def get_addresses(country_code):
"""アドレス一覧を取得する"""
def is_valid(line):
return line.strip() and not line.startswith('#')
with open('./{}.txt'.format(country_code)) as f:
addresses = [l.strip() for l in f.readlines() if is_valid(l)]
return addresses
if __name__ == '__main__':
main()
実行します。
最初は --dry-run
オプションを付けてどのようなコマンドが走るのかを確認します。
python gcp_block_country.py --country-code cn --dry-run
問題がなさそうであれば --dry-run
を外して実行します。
python gcp_block_country.py --country-code cn
コマンドを実行して少し待つと block-china-0
block-china-1
……というルールが作成されることが確認できます。
確認はブラウザで GCP の console の VPC network → Firewall を開くか gcloud
コマンドを使うとよいでしょう。
次のコマンドを使用すればどんなファイアウォールルールが登録されているかを確認できます。
gcloud compute firewall-rules list
以上です。
今回は中国を対象にしましたが、他の国でも同様のやり方で制限することができます。 コードを GitHub に置いたので興味のある方は参考にしてみてください。