Snowflake Summitで発表されたExternal Network Accessを使用し、Slack通知をしてみた
(Zennに初投稿です)
6月に行われたSnowflake Summit@Las Vegasで紹介されたExternal Network Access(プレビュー)機能を使用し、個人用Slackチャネルに通知してみました。
背景
運用時に何かしらのエラーが発生した際、それらをSlackに通知する方は多いのではないのでしょうか。従来のSnowflakeでは、外部関数やLambdaなどを通じて、Slackに通知していたのではないかと思います。しかし、今回、発表されたExternal Network Accessを使用することで外部関数やLambdaなどを設定することなく、よりシンプルにSlack通知機能を実装することが可能となりました。
External Network Accessとは?
External Network Accessとは、UDFやStored Procedure(SPROC)からSlack、OpenAI、 Googleなどの特定の外部ネットワークに対して、セキュアにアクセスできる機能となっております。ドキュメントからの抜粋ではありますが、機能に関して、このように記述しております。
- Write UDF and procedure handlers that access external locations.
- Allow or block access to locations on a network external to Snowflake.
- Use secrets that represent stored credentials, rather than using literal values, within handler code to authenticate with external network locations.
- Specify which secrets are allowed for use with external network locations.
こちらの機能を使用し、Python UDFから私の個人用Slackチャネルに通知してみたいと思います。なお、制限事項としてPython/Java UDFでのみ、使用することが可能です。
コード全体
まず先にコードを、以下の通り、載せておきます。
-- 1. Network Ruleの作成
CREATE OR REPLACE NETWORK RULE slack_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('slack.com');
--2. Secretの作成
CREATE OR REPLACE SECRET slack_token
TYPE = GENERIC_STRING
SECRET_STRING = '<your-access-token>';
-- 3. External Access Integrationの作成
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION slack_apis_access
ALLOWED_NETWORK_RULES = (slack_rule)
ALLOWED_AUTHENTICATION_SECRETS = (slack_token)
ENABLED = true;
--4. Slack通知するPython UDFの作成
CREATE OR REPLACE FUNCTION post_to_slack(channel varchar ,message varchar)
RETURNS variant
LANGUAGE python
RUNTIME_VERSION = 3.8
HANDLER = 'main'
EXTERNAL_ACCESS_INTEGRATIONS = (slack_apis_access)
PACKAGES = ('requests')
SECRETS = ('cred' = slack_token)
AS
$$
import _snowflake
import requests
import json
def main(p_channel ,p_message):
api_key = _snowflake.get_generic_secret_string('cred')
url = 'https://slack.com/api/chat.postMessage'
v_headers = {{"Authorization": "Bearer "+ api_key}}
v_data_json = {{
'channel': p_channel
,'text': p_message
}}
response = requests.post(url ,headers=v_headers ,json = v_data_json)
return response.json()
$$;
--5. テスト
SELECT
'<your-channel-id>' as channel
,'TEST!!!' as message
,post_to_slack(channel ,message) as slack_notify
作成手順
Slack通知を設定するための手順を示します。
0. SlackのAccess Tokenを用意する
こちらの記事を参考しながら、Slackのアクセストークンを発行します。また、私の場合、今回のテストは自分のDMに送るため、自ユーザのuser_idも取得しています。(こちらは任意です)
1. Network Ruleの作成
アクセスの許可/制限したい外部ネットワークに関する情報を設定するのが、このNetwork Ruleオブジェクトになります。。このオブジェクトにおけるオプションを、下記の通り、説明します。
-
MODE
ではIGRESS or EGRESSを指定 -
TYPE
ではHOST_PORT、IPV4、AWSVPCEID、AZURELINKIDの4つのいずれかをを指定 -
VALUE_LIST
では、TYPEに連動して具体的なホスト名やIPアドレスを指定する。今回はslackに通知するため、slack.com
を指定している。
-- 1. Network Ruleの作成
CREATE OR REPLACE NETWORK RULE slack_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('slack.com');
2. Secretの作成
各種サービスにアクセス時に必要なCredentials情報を含むのが、このSecretオブジェクトとなります。このSecretオブジェクト自体はGAされた既存の機能であります。こちらを機能の一部を拡張してります。
-
TYPE
に記載しているGENERIC_STRING
を指定。 -
SECRET_STRING
にはAPIキーやアクセストークンなどを指定する。今回は0.で取得したSlackのアクセストークンを指定している。
--2. Secretの作成
CREATE OR REPLACE SECRET slack_token
TYPE = GENERIC_STRING
SECRET_STRING = '<your-access-token>';
3. External Access Integrationの作成
Integrationという言葉の通り、Network RuleとSecretの2つのオブジェクトを統合するのが、External Access Integrationオブジェクトとなります。コードの通り、オプションのALLOWED_NETWORK_RULES
やALLOWED_AUTHENTICATION_SECRETS
に1.と2.で作成した各オブジェクトを指定しています。なお、ドキュメント内に、External Access Integrationの取り扱いに関するセキュリティ上の注意点がございますので、ご利用になる場合は注意してください。
External Access Networkは外部リソースに情報流出させることができる機能となりますので、適切な権限管理を徹底して頂ければと思います。
-- 3. External Access Integrationの作成
CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION slack_apis_access
ALLOWED_NETWORK_RULES = (slack_rule)
ALLOWED_AUTHENTICATION_SECRETS = (slack_token)
ENABLED = true;
4. Python UDFの作成
UDFのオプションについて説明します。通常UDFに下記2つオプションを追加で指定しています。
-
external_access_integrations
で3.で作成したslack_apis_access
-
secret
で2.で作成したslack_token
これらオプションの指定により、当該UDFが外部ネットワークにアクセスが可能となります。
UDFのコンテンツについて説明します。1番最初のimportにある通り、_snowflake
を指定することで、Secret Access関連のメソッドを使用することができます。次にget_generic_secret_string
を使用し、3.で設定したSlackのAccess Tokenを取得します。なお、get_generic_secret_string
以外に3つメソッドがございます。(2023/7現在)
- get_oauth_access_token(oauth_secret_name)
- get_secret_type(secret_name)
- get_username_password(username_password_secret_name)
SlackのWeb APIの仕様に従い、ヘッダーとデータの情報を設定した上でAPIにPostする流れとなっております。(詳細はコード参照)
--4. Slack通知するPython UDFの作成
CREATE OR REPLACE FUNCTION post_to_slack(channel varchar ,message varchar)
RETURNS variant
LANGUAGE python
RUNTIME_VERSION = 3.8
HANDLER = 'main'
EXTERNAL_ACCESS_INTEGRATIONS = (slack_apis_access)
PACKAGES = ('requests')
SECRETS = ('cred' = slack_token)
AS
$$
import _snowflake
import requests
import json
def main(p_channel ,p_message):
api_key = _snowflake.get_generic_secret_string('cred')
url = 'https://slack.com/api/chat.postMessage'
v_headers = {{"Authorization": "Bearer "+ api_key}}
v_data_json = {{
'channel': p_channel
,'text': p_message
}}
response = requests.post(url ,headers=v_headers ,json = v_data_json)
return response.json()
$$;
5. テスト
下記の通り、通知するチャネルIDとテキストメッセージを指定し、UDFを実行しています。
SELECT
'<your-channel-id>' as channel
,'TEST!!!' as message
,post_to_slack(channel ,message) as slack_notify
添付のようにメッセージが届いたら成功です。
まとめ
本記事では、Summitで発表されたExternal Network Accessを使用し、Slack通知をする手順を示しました。数行のSQLコードでSlack通知機能をシンプルに実装できるように、従来とは比較にならないほど簡単になったのではないかと思います。個人的には、今後はアラート機能と新たに出てきたトリガータスク機能と併用することで、エラー発生、検知、通知までの一連の動作をSnowflake内でイベントドリブンで実装することが可能になると考えています。また、外部ネットワークの候補先として、Slack以外にもGoogleやOpen AIなど様々なユースケースで利用が考えられ、今後もこちらの機能は重宝しそうだと思います。(セキュリティには気をつけましょう)
Discussion
Traceback (most recent call last): File "_udf_code.py", line 8, in main TypeError: unhashable type: 'dict'
エラーでした。
下記修正したらうまくいきました。記事ありがとうございました。