MENU

Azure-API-Management APIゲートウェイ経由でVSC拡張 Claude Code・Codex・Continueを接続する

APIMゲートウェイ経由でClaude Code・Codex・Continueを接続する

社内のAzure API Management(APIM)や企業向けLLMゲートウェイを経由してAIコーディングツールを使いたいとき、「どの設定ファイルをどう書けばいいか」が意外とわかりにくい。Claude Code、OpenAI Codex、Continue.devはそれぞれ要求するAPI形式が異なるため、同じゲートウェイでも設定方法が変わってくる。

この記事では、APIゲートウェイとの疎通確認から始まり、3つのツールそれぞれの設定方法までを順番に説明する。


目次

Azure API Managementとは

そもそも Azure API Management(APIM)は何をするものか、を最初に整理しておく。

APIMはMicrosoftが提供するAPIゲートウェイサービスだ。クライアントからのリクエストを直接バックエンドのAIモデルに届けるのではなく、その間に入って認証・流量制御・ルーティングを担う

[クライアント(Claude Code等)]
  ↓
[Azure API Management]  ← ここで subscription key 検証・quota管理・routing
  ↓
[バックエンドモデル(Azure OpenAI / Anthropic互換等)]

企業がAPIMを挟む理由は主に以下だ。

  • APIキーの一元管理: 開発者ごとに個別のsubscription keyを発行し、バックエンドのキーを直接渡さなくて済む
  • Quota / Rate Limiting: ユーザーやProductごとにトークン消費・リクエスト数を制限できる
  • ルーティング: 1つのAPIMホストの下に複数のバックエンド(Anthropic互換・OpenAI互換等)を束ねられる
  • Policy: ヘッダ変換・キャッシュ・ログ記録などをAPIM側で管理できる

今回のように「社内APIMを経由してAIツールを使う」という構成では、APIMがキーの入り口になる。バックエンドモデルへの直接アクセスは開発者には渡されず、APIMのsubscription keyだけが配布される。


前提と全体像

今回扱う構成は以下のようなものだ。

[Claude Code / Codex / Continue]
  ↓ 環境変数 / 設定ファイル
[Azure API Management(APIM)または社内LLMゲートウェイ]
  ├─ /anthropic-compatible/v1/messages  ← Claude Code用
  └─ /openai/v1/responses               ← Codex用
  ↓
[バックエンドモデル]

ひとつ理解しておくべき重要な事実がある。Claude Code・Codex・Continueは要求するAPI形式が異なるため、同じゲートウェイホストを使っていても、ツールごとに別のエンドポイントルートが必要になる。

ツール要求API形式設定ファイル
Claude CodeAnthropic Messages API~/.claude/settings.json
OpenAI CodexOpenAI Responses API~/.codex/config.toml
Continue.devOpenAI Chat Completions互換(推奨)~/.continue/config.yaml

「同じゲートウェイだから同じ設定で動くはず」という思い込みが、最初のつまずきになりやすい。


Step 1: ゲートウェイへの疎通確認

ツールの設定を触る前に、まずcurlでゲートウェイに直接疎通できるか確認する。この段階で問題を切り分けておくと、後の作業がかなり楽になる。

GETではなくPOSTで叩く

Anthropic Messages APIの /v1/messages はPOSTエンドポイントだ。最初にGETで叩くと404が返ってくるが、これはAPIが存在しないのではなく、メソッドが違うだけのことが多い。

$env:APIM_KEY = "<your-key>"
curl.exe -v `
  -X POST "https://<apim-host>/<base-path>/v1/messages" `
  -H "Content-Type: application/json" `
  -H "anthropic-version: 2023-06-01" `
  -H "x-api-key: $env:APIM_KEY" `
  --json '{
    "model": "<model-name>",
    "max_tokens": 64,
    "messages": [{ "role": "user", "content": "Say hello" }]
  }'

認証ヘッダ名の確認方法

APIMで401が返ってきたとき、どのヘッダ名が必要かを探すには WWW-Authenticate レスポンスヘッダを見る。これはあまり知られていないが、APIMはこのヘッダに正しいキー名を明示してくれる。

HTTP/1.1 401 Access Denied
WWW-Authenticate: AzureApiManagementKey realm="...", name="x-api-key", type="header"

name="x-api-key" がそれだ。APIMのsubscription keyヘッダ名は既定では Ocp-Apim-Subscription-Key だが、API単位で変更できる。上の例では x-api-key に変更されている。ドキュメントを読んで既定値を送っても通らないのはこのためだ。

さらに注意が必要なのは、同じAPIMホストでもAPIルートごとにヘッダ名が異なる場合がある点だ。たとえば実際の検証では以下のような違いがあった。

APIルート認証ヘッダ名
Anthropic互換(Claude Code用)x-api-key
Azure OpenAI Responses互換(Codex用)api-key

どちらのルートを叩くかによって送るヘッダ名が変わる。疎通確認は必ずルートごとに行うこと。

レスポンスコード別の対処

HTTPステータス意味対処
200全て通過次のステップへ
401認証失敗WWW-Authenticate のヘッダ名を確認
403 Access DeniedProductへの紐付けがない等APIM Product / Subscription の設定を確認
403 Quota Exceededクォータ超過(設定ミスではない)Retry-After ヘッダの秒数待ってリトライ
404パスが存在しないAPIM側のAPI route・operationを確認
400リクエスト不正JSONの形式・model名・BOM問題を確認
400 DeploymentNotFoundmodel名がバックエンドと不一致APIMに登録されているdeployment名を確認
502/500バックエンドエラーAPIMのtrace機能で確認

403 Quota Exceeded認証や設定の失敗ではない。APIMのquota policyによってリクエスト上限に達した状態で、しばらく待てば解消する。Retry-After ヘッダに待機秒数が入っている。Codexは再接続を複数回試みるため、curl単発より消費が早い点に注意。

DeploymentNotFound は認証は通っているがリクエストbodyの model フィールドがバックエンドに登録されたdeployment名と一致していない場合に返る。モデル名の形式(gpt-5gpt-5.2gpt-5.2-codex 等)はAPIMの設定次第なので、管理者に確認するか curl で候補を総当たりする。

PowerShell 5.1 のBOM問題

Windows PowerShell 5.1 では Set-Content がBOM付きUTF-8で書き出す。JSONの先頭が { ではなく不可視の EF BB BF になり、バックエンドが unexpected character at char 0 で400を返す。

回避策は以下の通り。

[System.IO.File]::WriteAllText(
  "$PWD\body.json",
  $jsonString,
  [System.Text.UTF8Encoding]::new($false)  # $false = BOMなし
)

PowerShell 7(pwsh)を使っている場合はデフォルトでBOMなしUTF-8になるため、この問題は発生しない。



以降はCase A〜Cで構成されている。 使うツールに対応するCaseだけを参照すればよい。すべてを順番に実施する必要はない。


Case A: Claude Codeの設定

Claude Code をAPIM経由で使う設定。curlで200が確認できたら、以下のパラメータを渡す。

設定ファイルの場所

用途パス
CLI・VS Code拡張共通%USERPROFILE%\.claude\settings.json
VS Code拡張が読まない場合%APPDATA%\Code\User\settings.json

settings.json の書き方

{
  "env": {
    "ANTHROPIC_API_KEY": "dummy",
    "ANTHROPIC_BASE_URL": "https://<apim-host>/<base-path>",
    "ANTHROPIC_MODEL": "<model-name>",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "<model-name>",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "<model-name>",
    "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1",
    "DISABLE_PROMPT_CACHING": "1"
  }
}

ANTHROPIC_API_KEY"dummy" を入れているのは、値が空だとClaude CodeがAPIキー未設定として起動を止めてしまうためだ。実際の認証はゲートウェイのカスタムヘッダが担う。

認証ヘッダは環境変数で管理する

ANTHROPIC_CUSTOM_HEADERS にAPIキーの値が入るため、settings.jsonには書かない。Windowsのユーザー環境変数として設定する。

[Environment]::SetEnvironmentVariable(
  "ANTHROPIC_CUSTOM_HEADERS",
  "x-api-key: <your-key>",
  "User"
)

BASE_URLに /v1/messages を含めない

ここは間違えやすい。Claude Codeは内部で /v1/messages を付加するため、BASE_URLに含めると二重パスになる。

# 正しい
ANTHROPIC_BASE_URL = "https://<apim-host>/anthropicxapi"

# 誤り(/anthropicxapi/v1/messages/v1/messages になる)
ANTHROPIC_BASE_URL = "https://<apim-host>/anthropicxapi/v1/messages"

VS Code拡張版について

VS Code拡張版は ~/.claude/settings.jsonenv を読まず、Anthropicログインを要求してくるという報告がある(GitHub issue #11784)。この場合は %APPDATA%\Code\User\settings.jsonclaudeCode.environmentVariables に同じ変数を設定することで回避できる場合がある。

Microsoft Foundryを使う環境であれば、CLAUDE_CODE_USE_FOUNDRY=1 を使う公式手順の方が安定する。

動作確認

claude -p "Say hello"

Case B: OpenAI Codexの設定

OpenAI Codex をAPIM経由で使う設定。CodexはClaude Codeとは別物で、Anthropic Messages APIを解釈できない。APIM側にOpenAI Responses API互換のエンドポイントルートが別途必要になる。

設定ファイルの場所

%USERPROFILE%\.codex\config.toml

config.toml の書き方

Codexには認証ヘッダの渡し方が2種類ある。用途に応じて使い分ける。

パターンA: http_headers(シェル展開が使える環境)

model = "<model-name>"
model_provider = "apim"
model_reasoning_effort = "medium"

[model_providers.apim]

name = “APIM OpenAI Compatible” base_url = “https://<apim-host>/<openai-path>/v1” wire_api = “responses” http_headers = { “api-key” = “${APIM_KEY}” }

${APIM_KEY} はCodexがシェル経由で環境変数展開する。CLIで直接起動する場合に使う。

パターンB: env_http_headers(VS Code拡張など、シェル展開が使えない環境)

[model_providers.apim]
env_http_headers = { "api-key" = "APIM_KEY" }

重要: env_http_headers の値には $ なし・クォートなしの環境変数名そのものを書く。ランタイムがプロセスの環境変数から参照して展開する。"${APIM_KEY}""$APIM_KEY" と書くと展開されず文字列がそのまま送られるため注意。

いくつかの注意点がある。

base_url/v1 を含める: CodexはBASE_URLに /v1 を含めることを前提としている。Claude Codeとは逆の挙動なので混同しやすい。

wire_api = "responses" の適用条件: CodexはデフォルトでOpenAI Responses API(/v1/responses)を使う。APIMのバックエンドがResponses APIに対応していない場合は404や400が返る。バックエンドがChat Completions APIのみ対応している場合は wire_api = "openai" を試す。Azure OpenAI ServiceのResponses API対応状況はバージョンによって異なる。

環境変数の設定

$env:APIM_KEY = "<your-key>"

Codex IDE extensionのprofilesについて

Codex CLIは config.toml に複数の [model_providers.*] を定義してプロファイルを切り替えられる。しかしCodex IDE extension(VS Code拡張)は現時点でprofilesに対応していない。拡張はtop-levelの設定(modelmodel_provider)を固定で読む。

複数環境を切り替えたい場合は、config.toml ごと差し替えるスクリプト方式を使う(後述)。


Case C: Continue.devの設定

Continue.dev をAPIM経由で使う設定。Continueは3つの中で最も設定の自由度が高い。複数のモデルを1つのconfig.yamlに並べてUIで切り替えられるため、「社内APIMモデルとローカルOllamaを混在させる」といった構成が作りやすい。

設定ファイルの場所

%USERPROFILE%\.continue\config.yaml

config.yaml の書き方(APIM + Ollama混在)

name: Mixed Config
version: 1.0.0
schema: v1

models:
  - name: APIM GPT Chat
    provider: openai
    model: <model-name>
    apiBase: https://<apim-host>/<openai-path>
    apiKey: ${env:APIM_KEY}          # Continue内部の認証フロー用(providerが参照)
    requestOptions:
      headers:
        api-key: ${env:APIM_KEY}     # APIMへの実際のHTTPヘッダとして付与
      query:
        api-version: 2025-03-01-preview
    roles:
      - chat
      - edit
      - apply

  - name: Local Ollama Autocomplete
    provider: ollama
    model: qwen2.5-coder:7b
    apiBase: http://<ollama-host>:11434/
    roles:
      - autocomplete

apiKeyrequestOptions.headers の両方にキーを書く理由:apiKey はContinueの内部認証フローでproviderが参照する値であり、requestOptions.headers はAPIMへのHTTPリクエストに実際に追加されるヘッダだ。APIMのsubscription keyは後者のヘッダ名(api-key 等)で送る必要があるため、両方の設定が必要になる。

${env:VARNAME} 構文について

config.yaml で ${env:APIM_KEY} と書くと、ContinueがそのOS環境変数の値に展開してくれる。PowerShellの $env:APIM_KEY とは別物で、config.yaml 内の専用構文だ。

# これが Continue の環境変数参照構文
apiKey: ${env:APIM_KEY}

# PowerShell変数(config.yamlには書かない)
$env:APIM_KEY = "..."

APIキーをconfig.yamlにハードコードしたくない場合は、事前にOS環境変数として設定しておいてこの構文で参照する。ユーザー永続環境変数として設定する場合は以下。

[Environment]::SetEnvironmentVariable("APIM_KEY", "<your-key>", "User")

Responses APIのみのエンドポイントについて

APIMがResponses API専用のエンドポイントしか持っていない場合、ContinueがそのAPIを直接扱えるかはバージョン依存になる。Chat Completions互換のルートをAPIM側に用意しておく方が、Continueとの相性は確実によくなる。


VS Code拡張固有のコツ

ターミナルのCLIで動いても、VS Code拡張では別の話になることが多い。それぞれ注意点がある。

Case A: Claude Code拡張

~/.claude/settings.jsonenv は拡張では読まれないことがある

CLIは ~/.claude/settings.jsonenv ブロックを参照するが、VS Code拡張は拡張自身の設定ファイルを見に行く場合がある。その場合は %APPDATA%\Code\User\settings.jsonclaudeCode.environmentVariables を追加する。

"claudeCode.environmentVariables": [
  { "name": "ANTHROPIC_API_KEY",              "value": "dummy" },
  { "name": "ANTHROPIC_BASE_URL",             "value": "https://<apim-host>/<base-path>" },
  { "name": "ANTHROPIC_CUSTOM_HEADERS",       "value": "x-api-key: <your-key>" },
  { "name": "ANTHROPIC_MODEL",                "value": "<model-name>" },
  { "name": "ANTHROPIC_DEFAULT_OPUS_MODEL",   "value": "<model-name>" },
  { "name": "ANTHROPIC_DEFAULT_SONNET_MODEL", "value": "<model-name>" },
  { "name": "CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS", "value": "1" },
  { "name": "DISABLE_PROMPT_CACHING",         "value": "1" }
]

設定後は VS Code を完全に再起動する

設定ファイルを保存しただけでは拡張に反映されないことがある。VS Codeをいったん終了して起動し直す。

VS Codeターミナルの環境変数と settings.json の env は別物

VS Codeターミナル内で $env:ANTHROPIC_BASE_URL が見えていても、それはそのPowerShellプロセスの変数であり、~/.claude/settings.jsonenv とは異なる。CLIが通るのに拡張だけ失敗する場合はここを疑う。なお、Windowsのユーザー環境変数として登録済みの変数([Environment]::SetEnvironmentVariable(..., "User") で設定したもの)はVS Code拡張プロセスでも参照できる。確認コマンド:

Get-ChildItem Env:ANTHROPIC* | Format-Table -AutoSize

Case B: Codex拡張

profilesは使えない → top-levelに直書きする

Codex CLIはprofilesで接続先を切り替えられるが、VS Code拡張はprofilesに対応していない。拡張は ~/.codex/config.toml のtop-levelにある modelmodel_provider を固定で読む。複数環境を切り替えたい場合は config.toml ファイルごと差し替える方式にする。

# 拡張向けにtop-levelに置く(profilesブロックは拡張では無視される)
model = "gpt-5.2"
model_provider = "apim"

[model_providers.apim]

base_url = “https://<apim-host>/<openai-path>” wire_api = “responses” query_params = { “api-version” = “2025-03-01-preview” } env_http_headers = { “api-key” = “APIM_KEY” } request_max_retries = 1

拡張のモデルドロップダウンを触らない

拡張UIのモデル選択ドロップダウンに表示される GPT-5.5GPT-5.4 などはAPIMのdeployment名と一致しない可能性が高い。config.tomlで指定したモデルが使われるよう、ドロップダウンは変更しない。

gpt-5-codex は拡張で使わない(gpt-5.2 推奨)

2026年5月時点の挙動として、gpt-5-codex を拡張で使うと image_generation ツールが自動的に混入してクラッシュすることがある。CLI(codex exec)では gpt-5.2-codex が安定しているが、VS Code拡張では gpt-5.2gpt-5 の方が安全。APIまたはCLIのバージョンアップにより変わる可能性がある。

MCPサーバーを最小化する

Codex拡張の初期動作確認中は、MCPサーバーを最小限にする。不要なMCPがあるとタイムアウトやクォータ消費が増える。

# 確認が取れるまでコメントアウト推奨
# [mcp_servers.drawio]
# command = "npx"
# args = ["-y", "@drawio/mcp"]

request_max_retries = 1 でクォータ消費を抑える

Codexはデフォルトで複数回リトライする。APIMのquota policyにかかりやすい環境では request_max_retries = 1 を設定しておくと安全。

web_search = "disabled" で不要なAPI呼び出しを止める

web_search = "disabled"

[features].web_search = false は旧形式で非推奨。top-levelまたはprofile配下に上記の形式で置く。


設定のまとめ

3ツールの違いをまとめると以下のようになる。

項目Claude CodeCodex CLICodex拡張Continue.dev
設定ファイル~/.claude/settings.json~/.codex/config.toml~/.codex/config.toml(top-level)~/.continue/config.yaml
API形式Anthropic MessagesOpenAI ResponsesOpenAI ResponsesChat Completions互換
BASE_URLに /v1含めない含める含めるproviderによる
認証ヘッダ設定ANTHROPIC_CUSTOM_HEADERS 環境変数http_headers${VAR} 展開)env_http_headers(変数名を値に)requestOptions.headers
複数モデル管理config.jsonコピー方式CLIはprofiles対応ありprofiles非対応(top-level固定)config.yamlに並べてUI選択

セキュリティ上の注意

APIキーをコマンド引数やチャットに貼らない。APIMのログやチャット履歴にそのまま残る。ターミナルで確認する際は環境変数経由で渡す。また curl.exe -v はリクエストヘッダ(キー含む)をターミナルに平文出力するため、そのターミナルのスクリーンショットや出力を共有しないこと。

# NG: キーが直接残る
curl.exe -H "x-api-key: abc123def456..."

# OK: 環境変数経由
$env:APIM_KEY = "<key>"
curl.exe -H "x-api-key: $env:APIM_KEY"

もしキーがログに出てしまった場合は、即座にAPIM側でローテーションする。

settings.jsonやconfig.tomlをGit管理ディレクトリに置かない。キーを含む設定ファイルが誤ってリポジトリに入るリスクを避けるため、ホームディレクトリ(~/)に置くのが基本だ。特に claudeCode.environmentVariables にキー値を直書きした場合、その settings.json をGit管理すると即座にキーが漏洩する。キーは [Environment]::SetEnvironmentVariable でOS環境変数に登録する方が安全。

動作確認コマンド

# Claude Code CLI
claude -p "Say hello"

# Codex CLI(CLIバージョン)
codex "say hello in one sentence"

# Continue.dev: VS Code上のContinueパネルからチャット欄に "Say hello" と送信して応答を確認

まとめ

社内APIゲートウェイ経由でAIコーディングツールを動かすとき、つまずきやすいポイントを粒度別に整理する。

大きな前提として押さえておくこと:

  • APIMは認証・quota管理・ルーティングを担うゲートウェイ。バックエンドへの直接アクセスは渡されず、subscription keyだけが窓口になる
  • Claude Code・Codex・ContinueはAPI形式が異なる。同じAPIMホストでも、ツールごとに別のエンドポイントルートが必要になる

細かく気にしないといけないポイント:

  1. 認証ヘッダ名はAPIルートごとに違う — 401が出たら WWW-Authenticatename= を読む。同一ホストでも Claude Code用とCodex用でヘッダ名が違うことがある
  2. ANTHROPIC_BASE_URL には /v1/messages を含めない — Claude Code が内部で付加するため二重パスになる。Codex の base_url は逆に /v1 を含める必要がある
  3. 403 Quota Exceeded は設定ミスではない — APIキーや認証の問題ではなくquota超過。Retry-After の秒数だけ待つ
  4. DeploymentNotFound はmodel名の問題 — 認証は通っているが body の model フィールドがAPIMのdeployment名と一致していない
  5. Continueの ${env:VAR} はOS環境変数を参照するconfig.yaml専用構文 — PowerShellの $env: とは別物
  6. Codex IDE extensionはprofiles非対応 — CLIではprofileで切り替えられるが、VS Code拡張はtop-levelの設定を固定で読む

curlで疎通確認(Step 1)を先に行い、その後は使うツールのCase(A/B/C)だけを参照する。複数ツールを検証する場合は Claude Code → Codex → Continue の順で進めると問題の切り分けがしやすい。


よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次