🐷

External Network Access:GitActionの動的IPを取得し、Network Policy を都度更新する

がく@ちゅらデータです。
秋はどこにいってしまったのでしょうか・・・・

さて、先日、沖縄SnowVillageにて下記のようなLTをさせていただきました。

https://zenn.dev/churadata/articles/a12cae787d0fc5

で、

https://zenn.dev/churadata/articles/a553092387708b

として、Slack通知(デコ版)ってのを作って、ふぅ〜これで完成じゃ・・・と思っていました。

でもね、External Network Access、もっとできることがあると思うんですよ

その中で、仕事してて
「Snowflakeのセキュリティ対策として、GitActionからのアクセスもアクセス制限をIPでかけたい」
って話が上がりました

GitのIPってのは、比較的よく変更されるそうです。
なんかいい方法ない? って相談を受けて・・・・・・

あ!External Network Accessを使えば、比較的簡単に実装できるんでね?
外部API叩いて、Network Policyを作れば・・・・・・GitActionからアクセスする都度、動的にNetwork Policyを設定でできれば・・・・

※ただ、GitAction都度動かすのはちとつらいので、毎日一回Taskで動かすとかするのが、セキュリティ的にも妥協点ぁなと

で、作ってみました!

作ってみた

Network Rule

まず、network ruleを作ります

-- https://api.github.com/meta

CREATE OR REPLACE NETWORK RULE github_meta_network_rule
  MODE = EGRESS
  TYPE = HOST_PORT
  VALUE_LIST = ('api.github.com');

Snowflake Secret

今回のURL https://api.github.com/meta は、APIキーなどないので
secretは必要なし

external access integrationを作ります

CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION github_meta_access_integration
  ALLOWED_NETWORK_RULES = (github_meta_network_rule)
  ENABLED = true;

ストアドを作る

  • Snowpark(Python)でストアドを作る
  • gitのAPIからJSONでIPリストを取得する
  • network policyを作る

って機能を実装します
※ただ、今回のはエラーハンドリングとか全然してないので、プロトタイプと捉えてくれれば
※改善したら教えて下さいね!!!!

CREATE OR REPLACE PROCEDURE get_github_meta()
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = 3.10
HANDLER = 'main'
EXTERNAL_ACCESS_INTEGRATIONS = (github_meta_access_integration)
PACKAGES = ('snowflake-snowpark-python', 'requests')
EXECUTE AS CALLER
AS
$$
import snowflake.snowpark as snowpark
import json
import requests
import _snowflake
from datetime import date

def main(session): 
    # Retrieve the Webhook URL from the SECRET object
    github_meta_url = "https://api.github.com/meta"

    headers = {"content-type": "application/json"}
    response = requests.get(github_meta_url,headers = {"content-type": "application/json"})
    if response.status_code != 200:
        raise ValueError(
            'Request to slack returned an error %s, the response is:\n%s'
            % (response.status_code, response.text)
        )
    data = response.json()
    actions = data["actions"]

    ip_list_str = ",".join([f"'{s}'"for s in actions if ":" not in s])
    create_network_policy = f"CREATE OR REPLACE NETWORK POLICY network_policy_git_action ALLOWED_IP_LIST=({ip_list_str});"

    session.sql(create_network_policy).collect()
    return create_network_policy
    
$$; 

use role accountadmin;
call get_github_meta();

show network policies;
describe network policy NETWORK_POLICY_GIT_ACTION;

これを、GitActionからアクセスされるサービスアカウント?的なのに

ALTER USER GIT_ACTION_USER SET NETWORK_POLICY = NETWORK_POLICY_GIT_ACTION;

な感じで設定しておく。
新しく更新する際

call get_github_meta();

で、やれば最新のをユーザにアタッチすることができたはず

ちゅらデータ株式会社

Discussion