このチュートリアルでは、Cloudflare AI Gateway と Zero Trust を使い、AI エージェント向けの実用的で安全なウェブサイトラッパーを作成します。Cloudflare Zero Trust の管理者は、Cloudflare Access でラッパーへのアクセスを保護できます。加えて、Gateway ポリシー でユーザーと AI エージェントのやり取りを制御できます。たとえば Browser Isolation で隔離ブラウザー上で AI エージェントを実行する、Data Loss Prevention プロファイルで機密データの共有を防ぐ、社内ガイドラインに反する回答を避けるためのコンテンツスキャン、などです。特定の AI プロバイダー(ChatGPT Enterprise など)のエンタープライズプランがある場合、AI エージェントラッパーはテナント制御を適用する手段にもなります。
このチュートリアルでは、AI エージェントの例として ChatGPT を使います。
次を用意してください。
- Cloudflare Zero Trust 組織。
- 使う AI プロバイダーの API キー。ChatGPT なら OpenAI API キー ↗ など。
まず、AI アプリを制御する AI gateway を作成します。
-
Cloudflare ダッシュボード ↗ で AI Gateway ページを開きます。
AI Gateway を開く ↗ -
Create Gateway を選択します。
-
ゲートウェイに名前を付けます。
-
Create を選択します。
-
ゲートウェイの希望するオプションを設定します。
-
AI プロバイダーを接続 し、AI gateway 経由で選んだ AI エージェントへクエリをプロキシします。
-
(任意)Authenticated Gateway を有効にします。Authenticated Gateway は、リクエストヘッダー
cf-aig-authorizationのトークンを必須にし、AI gateway を安全に呼び出せるようにします。- AI > AI Gateway を開きます。
- AI gateway を選び、Settings を開きます。
- Authenticated Gateway をオンにし、Confirm を選びます。
- Create authentication token を選び、Create an AI Gateway authentication token を選択します。
- トークンを設定し、トークン値をコピーします。Worker を作成するとき、AI gateway の呼び出しでこのトークンを渡します。
詳細は AI Gateway の始め方 を参照してください。
Guardrails は AI Gateway の組み込みセキュリティ機能です。選んだカテゴリに基づき、プロンプトと応答の安全でないコンテンツや不適切なコンテンツを Cloudflare が識別します。
-
Cloudflare ダッシュボードで AI Gateway ページを開きます。
AI Gateway を開く ↗ -
AI gateway を選びます。
-
Guardrails を開きます。
-
Guardrails をオンにします。
-
Change を選び、プロンプトと応答の両方でフィルタするカテゴリを設定します。
Worker を作るには、Wrangler でローカルに作るか、ダッシュボード ↗ でリモートに作るかを選びます。
-
ターミナルで Cloudflare アカウントにログインします。
wrangler login -
プロジェクトをローカルで初期化します。
mkdir ai-agent-wrapper cd ai-agent-wrapper wrangler init -
Wrangler 設定ファイルを作成します。
name = "ai-agent-wrapper" main = "src/index.js" compatibility_date = "2023-10-30" [vars] # Add any environment variables here -
AI プロバイダーの API キーを シークレット として追加します。
wrangler secret put <OPENAI_API_KEY>
これで、Wrangler が作成した index.js ファイルを使って Worker を作れます。
-
Cloudflare ダッシュボードで Workers & Pages ページを開きます。
Workers & Pages を開く ↗ -
Create を選択します。
-
Workers で Hello world テンプレートを選びます。
-
Worker に名前を付け、Deploy を選択します。
-
Worker を選び、Settings タブを開きます。
-
Variables and Secrets を開き、Add を選択します。
-
種類に Secret を選び、シークレット名(例:
OPENAI_API_KEY)を付け、Value に AI プロバイダーの API キーを入力します。
Worker ページで Edit code を選び、オンラインコードエディターで Worker を作れます。
次は、AI Gateway 配下の AI プロバイダーとやり取りできる簡単なフロントエンドを提供する、スターター Worker の例です。この例では AI プロバイダーとして OpenAI を使います。
export default {
async fetch(request, env) {
if (request.url.endsWith("/api/chat")) {
if (request.method === "POST") {
try {
const { messages } = await request.json();
const response = await fetch(
"https://gateway.ai.cloudflare.com/v1/$ACCOUNT_ID/$GATEWAY_ID/openai/chat/completions",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${env.OPENAI_API_KEY}`,
},
body: JSON.stringify({
model: "gpt-4o-mini",
messages: messages,
}),
},
);
if (!response.ok) {
throw new Error(`AI Gateway Error: ${response.status}`);
}
const result = await response.json();
return new Response(
JSON.stringify({
response: result.choices[0].message.content,
}),
{
headers: { "Content-Type": "application/json" },
},
);
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: { "Content-Type": "application/json" },
});
}
}
return new Response("Method not allowed", { status: 405 });
}
return new Response(HTML, {
headers: { "Content-Type": "text/html" },
});
},
};
const HTML = `<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ChatGPT Wrapper</title>
<style>
:root {
--background-color: #1a1a1a;
--chat-background: #2d2d2d;
--text-color: #ffffff;
--input-border: #404040;
--message-ai-background: #404040;
--message-ai-text: #ffffff;
}
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 20px;
background: var(--background-color);
display: flex;
flex-direction: column;
align-items: center;
gap: 20px;
color: var(--text-color);
}
.chat-container {
width: 100%;
max-width: 800px;
background: var(--chat-background);
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
height: 80vh;
display: flex;
flex-direction: column;
}
.chat-header {
padding: 15px 20px;
border-bottom: 1px solid var(--input-border);
background: var(--chat-background);
border-radius: 10px 10px 0 0;
text-align: center;
}
.chat-messages {
flex-grow: 1;
overflow-y: auto;
padding: 20px;
}
.message {
margin-bottom: 20px;
padding: 10px 15px;
border-radius: 10px;
max-width: 80%;
}
.user-message {
background: #007AFF;
color: white;
margin-left: auto;
}
.ai-message {
background: var(--message-ai-background);
color: var(--message-ai-text);
}
.input-container {
padding: 20px;
border-top: 1px solid var(--input-border);
display: flex;
gap: 10px;
}
input {
flex-grow: 1;
padding: 10px;
border: 1px solid var(--input-border);
border-radius: 5px;
font-size: 16px;
background: var(--chat-background);
color: var(--text-color);
}
button {
padding: 10px 20px;
background: #007AFF;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:disabled {
background: #ccc;
}
.error {
color: red;
padding: 10px;
text-align: center;
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">
<h2>AI Assistant</h2>
</div>
<div class="chat-messages" id="messages"></div>
<div class="input-container">
<input type="text" id="userInput" placeholder="Type your message..." />
<button onclick="sendMessage()" id="sendButton">Send</button>
</div>
</div>
<script>
let messages = [];
const messagesDiv = document.getElementById('messages');
const userInput = document.getElementById('userInput');
const sendButton = document.getElementById('sendButton');
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
async function sendMessage() {
const content = userInput.value.trim();
if (!content) return;
userInput.disabled = true;
sendButton.disabled = true;
messages.push({ role: 'user', content });
appendMessage('user', content);
userInput.value = '';
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages
})
});
if (!response.ok) {
throw new Error('API request failed');
}
const result = await response.json();
const aiMessage = result.response;
messages.push({ role: 'assistant', content: aiMessage });
appendMessage('ai', aiMessage);
} catch (error) {
appendMessage('ai', 'Sorry, there was an error processing your request.');
console.error('Error:', error);
}
userInput.disabled = false;
sendButton.disabled = false;
userInput.focus();
}
function appendMessage(role, content) {
const messageDiv = document.createElement('div');
messageDiv.className = 'message ' + role + '-message';
messageDiv.textContent = content;
messagesDiv.appendChild(messageDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
</script>
</body>
</html>`;AI Gateway エンドポイントのアカウント ID とゲートウェイ ID は置き換えてください。Workers の 環境変数 または シークレット として追加できます。AI gateway 作成時に Authenticated Gateway を使った場合は、トークンもシークレットとして追加し、cf-aig-authorization ヘッダーで AI gateway に渡してください。
Worker のコードが完成したら、Cloudflare Access で制御できるホスト名で Worker に到達できるようにします。
Wrangler 設定ファイルを編集し、カスタムホスト名だけで Worker にアクセスできるように次の情報を追加します。
name = "ai-agent-wrapper"
main = "src/index.js"
compatibility_date = "2023-10-30"
workers_dev = false
+# Replace with your custom domain
+routes = [
+ { pattern = "<YOUR_CUSTOM_DOMAIN>", custom_domain = true }
+]
[vars]
# Add any environment variables hereWorker を公開するには wrangler deploy を実行します。
Cloudflare ダッシュボードの コードエディター でリモート作成した場合は、Deploy を選んでデプロイできます。
カスタムホスト名からのみ Worker にアクセスできるようにするには:
-
Cloudflare ダッシュボードで Workers & Pages ページを開きます。
Workers & Pages を開く ↗ -
Worker を選びます。
-
Settings を開きます。
-
Domains & Routes で Add を選択します。
-
Custom domain を選びます。
-
希望するカスタムドメイン名を入力します。
-
Add domain を選択します。
これで Worker は到達可能なパブリックホスト名の背後にあります。workers.dev と Preview URLs の両方をオフにし、カスタムドメインだけでアクセスできるようにしてください。
信頼できるユーザーだけが AI エージェントラッパーにアクセスできるようにするには:
- Cloudflare ダッシュボード ↗ で Zero Trust > Access controls > Applications を開きます。
- Create new application を選択します。
- Self-hosted and private を選択します。
- Add public hostname を選び、Worker に設定したカスタムドメインを入力します。
- Worker 向けに Access アプリケーションを設定 します。
- アプリケーションに接続できるユーザーを制御する Access ポリシー を追加します。
これで、Access ポリシーに一致したユーザーだけが AI ラッパーにアクセスできます。
許可していない公開 AI エージェントへのアクセスは、Gateway の HTTP ポリシー でブロックできます。
-
Cloudflare ダッシュボード ↗ で Zero Trust > Traffic policies > Firewall policies > HTTP を開きます。
-
Add a policy を選択します。
-
次のポリシーを追加します。
Selector Operator Value Action Content Categories in Artificial Intelligence Block -
Create policy を選択します。
これで、管理対象エンドポイントから公開 AI エージェントへアクセスできなくなります。
あるいは、カスタムブロックメッセージ、リダイレクト、または AI エージェントラッパーへ誘導する ユーザー通知 を表示して、公開 AI エージェントの利用を防げます。
AI エージェントラッパーへのアクセスを制御できるようになったので、Data Loss Prevention(DLP)や Clientless Web Isolation などの追加のセキュリティ手段で、AI エージェントと共有するデータを保護・制御できます。
Data Loss Prevention(DLP) を使い、ユーザーが AI エージェントへ機密データを送らないようにできます。
-
Cloudflare ダッシュボード ↗ で Zero Trust > Data loss prevention > Profiles を開きます。
-
適用したい DLP プロファイル が正しく設定されていることを確認します。
-
ラッパーのホスト名に DLP プロファイルを適用する HTTP ポリシーを追加します。例:
Selector Operator Value Logic Action Host is ai-wrapper.example.comAnd Block DLP Profile in AI DLP profile -
Create policy を選択します。
DLP ポリシーの作成について詳しくは、HTTP トラフィックをスキャンする を参照してください。
ラッパーをセルフホスト Access アプリケーションとして公開したので、Access ポリシー を作成してアプリケーションに設定し、ユーザー向けの 隔離セッション で実行できます。
- Cloudflare One ↗ で Browser isolation > Browser isolation settings を開きます。
- Allow users to open a remote browser without the device client をオンにします。
- Access controls > Policies を開きます。
- Add a policy を選択します。
- Action を Allow にします。
- Add rules で、アプリケーションを隔離する対象を定義する ID ルールを追加します。
- Additional settings (optional) で Isolate application をオンにします。
Access ポリシーを作成したら、ラッパーに紐づけます。
- Access controls > Applications を開きます。
- ラッパーアプリケーションを選び、Configure を選択します。
- Policies で Select existing policies を選択します。
- 先に作成した Access ポリシーを選びます。
- Confirm を選び、Save を選択します。
Clientless Web Isolation のトラフィックには Gateway HTTP ポリシーが適用されるため、設定した DLP プロファイルは隔離セッションにも適用されます。
Access アプリケーションの隔離について詳しくは、セルフホストアプリケーションを隔離する を参照してください。
AI エージェントへのアクセス保護に Cloudflare を採用すると、可視性と設定の柔軟さが向上します。
Zero Trust はすべての Access イベント と DLP 検出 を記録します。加えて、AI Gateway はユーザープロンプト、モデル応答、トークン使用量、コストの 可視性 を提供します。
ログは Logpush で外部プロバイダーへエクスポートできます。
ラッパーを 別の AI プロバイダー に切り替えたり、複数の AI プロバイダーから選べるようにしたりできます。Workers AI で Cloudflare のグローバルネットワーク上で直接動く AI モデルも含められます。これにより、ユーザー体験や既存のアクセス制御に影響を与えずに、AI 利用コストを管理したり、新しいモデルを採用したりできます。