Cloudflare Secrets Store徹底検証!Workersのシークレット管理を一元化

はじめに
◆Cloudflare公式ドキュメント:https://developers.cloudflare.com/secrets-store/
◆Cloudflare公式ブログ:https://blog.cloudflare.com/secrets-store-beta/
従来、各Cloudflare Workersごとに使用できるSecret機能はありました。
ただ同じ内容のSecretを使用する場合には、各Cloudflare Workersごとで同じ内容のSecretを作成するしかありませんでしたが、Secrets Storeを使用することで一元管理ができるようになります。
※既存のSecret

秘匿情報のため、アクセスできるアカウントに対して権限の指定もできます。
そしてsecret自体はCloudflareに保存される前に暗号化してから保存する仕様になっており、また暗号に使用した鍵も頻繁に更新される仕様になっているためセキュリティも高いです。
Cloudflare公式ドキュメントによると、Secrets Storeは現在、Cloudflare Workersと互換性があるのですが、今後、他の製品との統合も追加される予定とのことです。
Secrets Storeの動作検証
Secrets Storeの設定画面
以下のメニュー一覧の中に新規で追加されています。

Secrets Storeについて
現在のオープンベータでは、Storeは一つしか使用できない制限がかかっています。
wranglerコマンドのドキュメントを確認しますと、Storeの作成や削除などのコマンドが載ってましたので、GAになった際には複数のSecrets Storeが管理できることになりそうです。
◆wranglerドキュメント:https://developers.cloudflare.com/workers/wrangler/commands/#secrets-store-store
Secret作成(GUI)
※現在のオープンベータでは、アカウントごとに20個までSecretの登録が可能となってます。
まずはCloudflare画面から作成を行ってみます。

下記が作成の画面になります。
現状、権限の範囲は「Workers」のみ選択ができます。

下記のように問題なく作成ができました。

Secret作成(wrangler)
wranglerコマンドから作成も可能です。
(ストアIDはCloudflareのSecrets Storeの画面から確認可能です。)
$ npx wrangler secrets-store secret create ストアID --name test-secret-01 --scopes workers --remote
Enter a secret value: … ******
Creating secret... (Name: test-secret-01, Value: REDACTED, Scopes: workers, Comment: undefined)
Select an account › XXXXXX
Created secret! (ID: XXXXXXXXXXXXXXXX)
┌────────────────┬──────────────────────────────────┬─────────────────────────────┬────┐
│ Name │ ID │ StoreID │ Comment │ Scopes │ Status │ Created │ Modified │
├────────────────┼──────────────────────────────────┼─────────────────────────────┼────┤
│ test-secret-01 │ XXXXXXXXXXXXXX │ XXXXXXXXXXXXXX │ │ workers │ pending │ 2025/5/19 7:58:10 │ 2025/5/19 7:58:10 │
└────────────────┴──────────────────────────────────┴─────────────────────────────┴────┘
私の環境だと、上記コマンドだとpermissionエラーが出てしまいました。
wranglerで再ログインを実行したら問題なく動作しましたので、もしpermissionエラーが出ましたら再ログインしてみてください。
$ npx wrangler login
$ npx wrangler whoami
wranglerコマンドで下記のようにアップデート、削除、コピーなども可能ですのでプログラム的に対応させることもできます。
◆Cloudflareドキュメント:https://developers.cloudflare.com/workers/wrangler/commands/#secrets-store-secret
●コマンド例
・list
$ npx wrangler secrets-store secret list ストアID --remote
・update
$ npx wrangler secrets-store secret update ストアID --secret-id シークレットID --scopes workers --comment duplicate-test --remote
・duplicate(copy)
$ npx wrangler secrets-store secret duplicate ストアID --secret-id シークレットID --name test-secret2 --scopes workers --comment duplicate-test --remote
・get
$ npx wrangler secrets-store secret get ストアID --secret-id シークレットID --remote
・delete
$ npx wrangler secrets-store secret delete ストアID --secret-id シークレットID --remote
Cloudflare Workers連携
Cloudflare WorkersからCloudflareのAPIを実行して値を取得して表示してみます。
今回のAPIはAccount IDとAPI Tokenが必要なので、Secrets Storeに両方とも入れておき、2つのWorkersから同じsecretが使えることを確認してみます。
◆実行するAPI:https://developers.cloudflare.com/api/resources/workers/subresources/scripts/methods/list/
※Cloudflare Workersのlistを取得するAPI

API Tokenの作成
まずはCloudflare Workersの読み取り権限をもったAPI Tokenを作成します。


Workersの読み取り権限だけが必要なのでカスタムトークンで作成します。

下記のように権限を指定しました。

概要を確認して問題なければ作成をします。

発行されたTokenは忘れずに保存しておきましょう。

作成したAPI Tokenの権限で問題なく情報が取得できるかcurlで確認をしておきます。
※アカウントIDはCloudflareの画面から確認できます。
$ curl https://api.cloudflare.com/client/v4/accounts/アカウントID/workers/scripts
-H "Content-Type: application/json"
-H "Authorization: Bearer 作成したAPIトークン"
{
"result": [
{
...
],
"success": true,
"errors": [],
"messages": []
}
Secrets Storeに登録
Secrets StoreにアカウントIDと作成したAPIトークンを登録します。
$ npx wrangler secrets-store secret create ストアID --name test-secrets-store-api-token --scopes workers --remote
...
Enter a secret value: … ****************************************
Creating secret... (Name: test-secrets-store-api-token, Value: REDACTED, Scopes: workers, Comment: undefined)
Created secret! (ID: eef802e1d92349288c767fc3fd285a4e)
...
$ npx wrangler secrets-store secret create ストアID --name test-secrets-store-account-id --scopes workers --remote
...
Enter a secret value: … ********************************
Creating secret... (Name: test-secrets-store-account-id, Value: REDACTED, Scopes: workers, Comment: undefined)
Created secret! (ID: cd2a27f66f1744219ca416ee2232762c)
...
問題なく作成できているか確認します。
$ npx wrangler secrets-store secret list ストアID --remote
...
Listing secrets... (store-id: XXXXXXXXXXX, page: 1, per-page: 10)
┌───────────────────────────────┬──────────────────────────────────┬─────────┬─────────┬─────────┬───────────────────┬───────────────────┐
│ Name │ ID │ Comment │ Scopes │ Status │ Created │ Modified │
├───────────────────────────────┼──────────────────────────────────┼─────────┼─────────┼─────────┼───────────────────┼───────────────────┤
│ test-secret-01 │ XXXXXXXXXXX │ │ workers │ active │ 2025/5/19 7:58:10 │ 2025/5/19 7:58:11 │
├───────────────────────────────┼──────────────────────────────────┼─────────┼─────────┼─────────┼───────────────────┼───────────────────┤
│ test-secrets-store-api-token │ XXXXXXXXXXX │ │ workers │ active │ 2025/5/19 8:56:01 │ 2025/5/19 8:56:07 │
├───────────────────────────────┼──────────────────────────────────┼─────────┼─────────┼─────────┼───────────────────┼───────────────────┤
│ test-secrets-store-account-id │ XXXXXXXXXXX │ │ workers │ active │ 2025/5/19 8:56:42 │ 2025/5/19 8:56:47 │
└───────────────────────────────┴──────────────────────────────────┴─────────┴─────────┴─────────┴───────────────────┴───────────────────┘
Workers作成
2つのCloudflare Workersを作成します。
$ npm create cloudflare@latest -- test-secret-store-01
...
What would you like to start with?
│ category Hello World example
│
├ Which template would you like to use?
│ type Worker only
│
├ Which language do you want to use?
│ lang TypeScript
...
$ npm create cloudflare@latest -- test-secret-store-02
...
What would you like to start with?
│ category Hello World example
│
├ Which template would you like to use?
│ type Worker only
│
├ Which language do you want to use?
│ lang TypeScript
...
先ほど作成したsecretをbindするように、test-secret-store-01、test-secret-store-02共にwrangler.jsoncを編集します。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "test-secret-store-01",
"main": "src/index.ts",
"compatibility_date": "2025-05-17",
"observability": {
"enabled": true
},
"secrets_store_secrets": [
{
"binding": "ACCOUNT_ID",
"store_id": "XXXXXXXXXXX",
"secret_name": "test-secrets-store-account-id"
},
{
"binding": "API_TOKEN",
"store_id": "XXXXXXXXXXX",
"secret_name": "test-secrets-store-api-token"
}
]
}
`src/index.ts`にCloudflareのAPIからCloudflare Workersの一覧を取得するコードを書きます。
認証情報はSecrets Storeから取得させるようにしています。
こちらもtest-secret-store-01、test-secret-store-02共に編集します。
export interface Env {
ACCOUNT_ID: String;
API_TOKEN: String;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const accountID = await env.ACCOUNT_ID.get();
const apiToken = await env.API_TOKEN.get();
const resp = await fetch(`https://api.cloudflare.com/client/v4/accounts/${accountID}/workers/scripts`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiToken}`,
},
});
if (!resp.ok) {
const text = await resp.text();
console.error('Fetch error:', text);
return new Response('Failed to fetch data', { status: resp.status });
}
const data = await resp.json();
return new Response(JSON.stringify(data), {
headers: { 'Content-Type': 'application/json' },
});
},
};
私のIDEの環境だと下記エラーが出ましたが、そのまま気にせずデプロイをしてしまって大丈夫でした。

Cloudflare WorkersのコードができましたのでCloudflareにデプロイします。
$ npx wrangler deploy
Cloudflareの画面からデプロイされているか確認します。
この段階でSecrets Storeが使われてることも確認できます。

検証なので「*.workers.dev」ドメインで「test-secret-store-01」のCloudflare Workersにアクセスしてみます。
curl https://test-secret-store-01.xxx.workers.dev | jq .
{
"result": [
{
...
],
"success": true,
"errors": [],
"messages": []
}
登録されているCloudflare Workersの一覧が取得できました。
また「test-secret-store-02」のCloudflare Workersにも同じようにアクセスしてみて同じ結果が取得できることを確認します。
curl https://test-secret-store-02.xxx.workers.dev | jq .
{
"result": [
{
...
],
"success": true,
"errors": [],
"messages": []
}
これで「test-secret-store-01」、「test-secret-store-02」にて同じsecretが適用されてることが確認できました。
各Cloudflare Workersごとにsecretを配置しなくてよいので管理がしやすくなりました。
ローカルでのSecrets Storeの使い方
ローカルで開発する際にはSecrets Storeがないので開発が面倒だなと思っていたのですが、ローカルでもSecrets Storeでsecretが作成できるようになってました。
シンプルに作成コマンドの「--remote」を外してあげれば、ローカルのSecrets Storeにsecretが登録できます。
※create、 delete、 listも問題なく動作しました。
$ npx wrangler secrets-store secret create ストアID --name test-secret-01 --scopes workers
Enter a secret value: … ******
ローカルにsecretを作成した状態でローカルデプロイのコマンドを実行すれば同じように動きます。
$ npx wrangler dev
ただ1つ注意が必要なのが、間違って本番側環境に対してdeleteコマンドを実行してしまうと、workersにbindされてる状態でも躊躇なく削除されてしまいます。
削除後にCloudflareの画面から確認すると、2つSecrets Storeのsecretがbindされてるように見えます。

ただ、ブラウザからアクセスしてみるとエラー画面になってしまいました。

ローカルと本番環境を間違えてしまうと大変なことになりますので注意が必要です。
※GAされるくらいになればこういったところの制御も入るのではないかと思いますが。
アクセス権限の設定について
secretに入れる情報は基本的に秘匿情報などが入ることが多いと思います。
保存自体は暗号化されているのでセキュリティ的に安心ですが、その情報にアクセスして使用する権限についても気をつけなければいけません。
CloudflareですとSecrets Storeに対してロールベースでのアクセス権限のコントロールが可能です。
◆Cloudflare公式ドキュメント:https://developers.cloudflare.com/secrets-store/access-control/
Secrets Store関連の権限には下記があり、管理者・開発者・閲覧者といった役割でアカウントレベルで権限を分けることが可能です。
※super administratorの場合はSecrets Storeのすべての操作が可能です。


Cloudflare APIでSecrets Storeの情報を操作させる際の権限についても指定が可能です。
◆Cloudflare API(Secrets Store):https://developers.cloudflare.com/api/resources/secrets_store/subresources/stores/subresources/secrets/
アカウントAPIトークンからtokenを作成する際に下記権限が選択可能です。


適切な権限をアカウントなどに設定し、セキュアにsecretの取り扱いを行うことができます。
監査ログ
Secrets Storeの操作ログはCloudflareのaudit logsに記録されます。
◆Cloudflare公式ドキュメント:https://developers.cloudflare.com/secrets-store/audit-logs/
これにより誰が操作したのかがログとして記録されますので、作成・変更・削除されたりなどした際に原因を追うことが可能となっております。
・作成ログ例

・削除ログ例

要件によっては監査ログをストレージなどに長期保存することが求められる場合があると思います。
その場合には、log pushでaudit logsをS3などのクラウドストレージなどに送信したり、CloudflareのAPIを使用してaudit logsをダウンロードをして保存を行うことが可能です。
最後に
今までWorkersごとに同じ名前、同じ内容のsecretを作成してましたが、Secrets Storeを使用することで一元管理できるようになるので管理が非常に楽になります。
また、現在はCloudflare WorkersでしかSecrets Storeのsecretを利用することができませんが、今後Cloudflare Workers以外でも使用できるようになるということですので、管理が楽になる幅が広がりますので楽しみです。
そしてCloudflareなら上記以外でも、
・パフォーマンスの向上
・サイトの信頼性の向上
・セキュリティの向上
が、一つのサービスで実現できますので非常におすすめです。
Cloudflareに、アクセリアの運用サポートをプラスしたCDNサービスを提供しています
移行支援によるスムーズな導入とともに、お客様の運用負担を最小限にとどめながら、WEBサイトのパフォーマンスとセキュリティを最大限に高めます。運用サポートはフルアウトソーシングからミニマムサポートまで、ご要望に合わせてご提供します。
Cloudflare(クラウドフレア)の導入や運用について、またそれ以外のことでもなにか気になることがございましたらお気軽にご相談下さい。
サービスにご興味をお持ちの方は
お気軽にお問い合わせください。
Webからお問い合わせ
お問い合わせお電話からお問い合わせ
平日09:30 〜 18:00
Free Service