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/241.0.2.0/231.0.8.0/211.0.32.0/191.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 argparseimport subprocessCHUNK_SIZE = 256# サポート対象の国の一覧# キー: 国コード / バリュー: ルールのプリフィックスCOUNTRIES = {'cn': 'block-china-','ru': 'block-russia-',}def main():"""メイン関数"""args = get_args()dry_run = args.dry_runcountry_code = args.country_codeaddresses = 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 = 0while True:start = n * CHUNK_SIZEstop = start + CHUNK_SIZEchunk_addresses = addresses[start:stop]if not chunk_addresses:breakname = '{}{}'.format(name_prefix, n)create_rule(name, chunk_addresses, dry_run=dry_run)n += 1def 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))returnreturn 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 addressesif __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 に置いたので興味のある方は参考にしてみてください。