Finatext Tech Blog
✨

Snowflake REST API で SSL CertVerificationError が出て沼った話

に公開

こんにちは、ナウキャストで LLM エンジニアをしている Ryotaro です。

Snowflake の Cortex Analyst を REST API 経由で叩こうとしたら、なぜか SSL エラーで怒られて結構ハマりました。snowflake-connector 経由だと普通に動くのに、requests で直接叩くとダメ。なんで?

結論から言うと、アカウント名に _ が入っていると SSL 証明書のホスト名検証で弾かれるというオチでした。_ を - に変えるだけで解決します。

ただ、なんで snowflake-connector だと動くのかが気になって GitHub のソースコードまで追ってみたので、その調査結果も共有します。

まず何が起きたか

Snowflake の Cortex Analyst を使おうと思って REST API を叩いたら、こんなエラーが出ました。

以下は REST API 経由で叩いているコードです。

import requests
import snowflake.connector

# 接続の作成
session = snowflake.connector.connect(
    user="TEST",
    password="********",
    account="TEST_ACCOUNT",
    warehouse="TEST_WH",
    role="TEST_ROLE",
)

# Cortex Analyst向けの設定変数
DATABASE = "TEST_DB"
SCHEMA = "TEST_SCHEMA"
VIEW_NAME = "TEST_VIEW"
API_ENDPOINT = "api/v2/cortex/analyst/message"

# Cortex Analystへの問い合わせ
request_body = {
    "messages": [{"role": "user", "content": "Hello, world!"}],
    "semantic_view": f"@{DATABASE}.{SCHEMA}.{VIEW_NAME}",
}
resp = requests.post(
    url=f"https://{session.host}/{API_ENDPOINT}",
    json=request_body,
    headers={
        "Authorization": f'Snowflake Token="{session.rest.token}"',
        "Content-Type": "application/json",
    }
)

print(resp.json())

エラー内容

Max retries exceeded with url: /api/v2/cortex/analyst/message (Caused by SSLError(SSLCertVerificationError(1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'test_account.snowflakecomputing.com'. (\_ssl.c:1010)")))

不思議なのは、snowflake-connector を使って SQL を実行する場合は普通に動くことです。

import snowflake.connector

conn = snowflake.connector.connect(
    user="TEST",
    password="********",
    account="TEST_ACCOUNT",
    warehouse="TEST_WH",
    role="TEST_ROLE",
)

with conn.cursor() as cursor:
    cursor.execute("SELECT * from TEST_TABLE")
    rows = cursor.fetchall()
    print(rows)
# こちらは正常に実行できます。
[{'1': 1}]

原因を調べてみた

hostname mismatch / certificate is not valid というエラーメッセージから、TLS 証明書のホスト名検証で弾かれてるっぽいです。

調べてみると、RFC1123 では DNS ホスト名に使える文字として英数字とハイフンのみが許可されていて、アンダースコア(_)は使えないようです。Snowflake のアカウント名には _ を含められるんですが、それがホスト名の一部になると RFC1123 非準拠になってしまうことが原因です。

SSL/TLS 証明書には SAN (Subject Alternative Name) という拡張フィールドに、その証明書が有効なホスト名のリストが記載されています。そして Snowflake の SSL 証明書には test-account.snowflakecomputing.com(ハイフン版)は含まれてるけど、test_account.snowflakecomputing.com(アンダースコア版)は含まれてない。だからエラーになるわけです。

なぜ REST API だとダメなのか?

今回使ってたアカウント名が TEST_ACCOUNT だったんですが、これに含まれる _ がそのままホスト名に入って test_account.snowflakecomputing.com という URL になっていたことが原因でした。

エラーが発生する流れ

Snowflake はこの問題を認識しており、URL のハイフンバージョンを作成することで解決しています。なので、test-account.snowflakecomputing.com だと正常に接続できます。

アカウント名でアンダースコアがサポートされていないシナリオ/機能の場合は、アンダースコアの代わりにハイフンを使用します。

https://docs.snowflake.com/en/user-guide/admin-account-identifier#specifying-the-account-name-when-connecting-to-snowflake

対処法

対処は簡単で、URL のアカウント名に _ が含まれる場合は - に変換してあげるだけです。今回だと TEST_ACCOUNT を TEST-ACCOUNT にして、URL が test-account.snowflakecomputing.com になるようにします。

実装例: ヘルパー関数

以下のようなヘルパー関数を用意すると便利です:

def normalize_snowflake_host(host: str) -> str:
    """
    Snowflake のホスト名のアンダースコアをハイフンに変換する

    Args:
        host: Snowflake のホスト名 (例: test_account.snowflakecomputing.com)

    Returns:
        正規化されたホスト名 (例: test-account.snowflakecomputing.com)
    """
    return host.replace("_", "-")

# 使用例
import requests
import snowflake.connector

# Snowflake 接続の作成
session = snowflake.connector.connect(
    user="TEST",
    password="********",
    account="TEST_ACCOUNT",
    warehouse="TEST_WH",
    role="TEST_ROLE",
)

# Cortex Analyst向けの設定変数
DATABASE = "TEST_DB"
SCHEMA = "TEST_SCHEMA"
VIEW_NAME = "TEST_VIEW"
API_ENDPOINT = "api/v2/cortex/analyst/message"

# ホスト名を正規化(アンダースコア→ハイフン)
normalized_host = normalize_snowflake_host(session.host)

# Cortex Analystへの問い合わせ
request_body = {
    "messages": [{"role": "user", "content": "Hello, world!"}],
    "semantic_view": f"@{DATABASE}.{SCHEMA}.{VIEW_NAME}",
}

resp = requests.post(
    url=f"https://{normalized_host}/{API_ENDPOINT}",  # 正規化されたホストを使用
    json=request_body,
    headers={
        "Authorization": f'Snowflake Token="{session.rest.token}"',
        "Content-Type": "application/json",
    }
)

print(resp.json())

根本的な対処

より根本的な対処としては、アカウント作成時にアンダースコアを含めないようにすることです。RFC1123 準拠のホスト名を使用することで、このような問題を未然に防ぐことができます。

なぜ snowflake-connector だとうまくいくのか?

気になったので GitHub のソースコードを読んでみました。

vendored ライブラリを使っている

snowflake-connector-python は、標準の requests や urllib3 をそのまま使わず、独自にカスタマイズした "vendored" バージョンを内包していました。src/snowflake/connector/vendored/ というディレクトリに配置されていて、Snowflake の要件に合わせて改変されています。

https://github.com/snowflakedb/snowflake-connector-python/tree/main/src/snowflake/connector/vendored

pyOpenSSL のホスト名検証を独自実装に置き換えている

vendored 版の urllib3/util/ssl_.py を読むと、pyOpenSSL を使う場合に check_hostname=False を設定して、独自のホスト名検証実装を使ってました。

コード内のコメントにはこう書いてあります:

"We always set 'check_hostname=False' for pyOpenSSL so we rely on our own 'ssl.match_hostname()' implementation"

標準の厳格なホスト名検証を回避して、Snowflake 独自のロジックで検証しているようです。

加えて、requests/adapters.py では assert_same_host=False を設定していて、urllib3 レイヤーでのホスト名マッチングも緩和されています。ssl_wrap_socket.py では SSL ソケットを独自にラップして OCSP/CRL 検証なんかもカスタマイズしていました。

関連する GitHub Issue

Issue 探してたら、同じ問題で困ってる人がいました。GitHub Issue #1839 (SNOW-996175) で RFC1123 準拠の課題 として議論されてます。

https://github.com/snowflakedb/snowflake-connector-python/issues/1839

Issue の中で報告者はこう言っています:

"While Snowflake support says, _ is interchangeable with -, this is being not supported by Snowflake connector."

Snowflake のサポートは「アンダースコアとハイフンは互換性がある」と答えてるらしいんですが、snowflake-connector 側での自動変換機能はまだ実装されてないんですね。

ちなみに PR #739 では過去に「ハイフン → アンダースコア」の変換が削除された履歴もありました。

https://github.com/snowflakedb/snowflake-connector-python/pull/739

結局なんで動くのか

要するに、snowflake-connector は requests/urllib3 をそのまま使わず、自前でカスタマイズしたものを使っていました。その中で pyOpenSSL のホスト名検証を独自実装に置き換えているため、標準の requests みたいに厳密なホスト名チェックで弾かれない、というわけです。

ただ、SSL 検証自体を無効化しているわけではなく、検証ロジックを独自実装に置き換えているだけです。

まとめ

Snowflake REST API を直接叩くときに SSL エラーが出たら、まずアカウント名に _ が入ってないか確認してみてください。入ってたら - に置換すれば大体解決します。

snowflake-connector が内部でどう処理してるかまで調べてみましたが、vendored ライブラリ使って独自のホスト名検証ロジック実装してたり。ライブラリの内部実装を追うのは勉強になりますね。

とても小さな tips ですが、同じところでハマった人の参考になれば。

2025 年 1 月の BCR-1875(Behavior Change Release)により、DUO MFA + PrivateLink という構成でも同様の問題が発生することが判明しました。

BCR-1875 では、Snowflake の多要素認証(MFA)が従来の「Duo Prompt」から「Duo Universal Prompt」へ移行されました。この変更により、アカウント名にアンダースコアが含まれていて、かつ PrivateLink を使用している場合、追加の DNS 設定が必要になります。

影響を受ける構成

  • アカウント名にアンダースコア(_)が含まれる
  • PrivateLink を使用している
  • DUO MFA を使用している

必要な対処

ハイフン版の DNS エントリを追加する必要があります。必要な FQDN は、SYSTEM$GET_PRIVATELINK_CONFIG 関数の privatelink-dashed-urls-for-duo パラメータを使って取得できます。

SELECT SYSTEM$GET_PRIVATELINK_CONFIG();

返却される JSON の privatelink-dashed-urls-for-duo キーに、ハイフン変換後の FQDN リストが含まれています。例えば、アカウント名が account_dev、組織名が myorg の場合、以下のような FQDN が返されます。

myorg-account-dev.privatelink.snowflakecomputing.com
app-myorg-account-dev.privatelink.snowflakecomputing.com

これらの FQDN に対して DNS エントリを追加することで、PrivateLink 環境でも正常に接続できるようになります。詳細は SYSTEM$GET_PRIVATELINK_CONFIG のドキュメント を参照してください。

PrivateLink 環境での設定についてより詳しく知りたい方は、弊社メンバーが書いた以下の記事も参考にしてください。

https://zenn.dev/finatext/articles/snowflake-privatelink-pit-traps

参考リンク

追記: Snowflake Managed MCP Server でも同様の警告

2025 年 11 月 4 日に GA された Snowflake Managed MCP Server の公式ドキュメントでも、同様の警告が記載されています。

"When you configure hostnames for MCP server connections, use hyphens (-) instead of underscores (_). MCP servers have connection issues with hostnames containing underscores."

— Build MCP servers in Snowflake | Snowflake Documentation

これは REST API での SSL エラーと同じ根本原因(RFC1123 非準拠のホスト名)によるものです。Snowflake の複数のコンポーネント(REST API、PrivateLink、MCP Server)で共通して発生する問題として認識しておくと良いかもです。

参考

Snowflake ドキュメント

GitHub Issues & Pull Requests

RFC 仕様

関連記事

We are Hiring!

この件についてもっと詳しく知りたい、議論したい、はたまたナウキャストという会社に興味を持ったという方は、カジュアル面談フォームから連絡ください。

https://herp.careers/v1/finatexthd/vZWzSlI_B-qk

Finatext Tech Blog
Finatext Tech Blog

Discussion