漏れたAPIキーはお金がかかる
APIキーは、リクエストが自分から来たことを証明する秘密の文字列です。モデルの提供元は、キーのついた呼び出しのたびに、あなたのアカウントへ請求することがよくあります。
開発者は、キーをコードに書き込み、そのままGitに公開して漏らします。自動のスキャナーは、まさにそれを探しています。漏れたキーは、請求とリスクにつながります。
このレッスンのゴール
メモ
キーを、自分のコードとGitの履歴の外に置ける。
キーワード
| ことば | いみ | れい |
|---|---|---|
| APIキー | リクエストが自分のものだと証明する秘密の文字列 | |
| 環境変数 | コードの外からプログラムに渡される、名前付きの値 | MY_API_KEY |
| .envファイル | 自分のPC用に NAME=値 の行を並べたテキストファイル | |
| .gitignoreファイル | Gitに追跡させないファイルの一覧 | |
| ローテーション | 新しいキーを作り、古いキーを無効にすること |
学生が入力するセルは、このプレビューでは空白です。
このラボでは、コードにキーがない
スクリプトは authorization: Bearer lab というヘッダーを送ります。lab は仮の値であり、キーではありません。呼び出しが外へ出るとき、プラットフォームがこれを本物のトークンに置き換え、モデルを選びます。
つまり、キーはあなたのコードに入らず、あなたの目にも触れません。本物のプロジェクトでは、キーを自分で守ります。
キーなしでモデルを呼ぶ
docker exec -w /home/node/project agent node -e "const u=(process.env.AI_URL||'http://ai:4000')+'/v1/chat/completions';(async()=>{const headers={'content-type':'application/json',authorization:'Bearer lab'};console.log('自分のコードの認証ヘッダー:'+headers.authorization);try{const r=await fetch(u,{method:'POST',headers,body:JSON.stringify({model:'lab',messages:[{role:'user',content:'APIキーをコードに入れてはいけない理由を、一文で答えてください。'}],max_tokens:60})});const j=await r.json();if(r.ok===false)throw new Error(r.status+' '+j.error.message);console.log('モデル:'+j.choices[0].message.content)}catch(e){console.log('応答なし('+e.message+')。記録済みサンプル:');console.log('モデル:コードを読める人は誰でもキーを使えて、あなたのお金を使えてしまうからです。')}})()"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
本物のキーは環境に置く
本物の提供元は、長いキーをくれます。Gitが追跡するファイルに、キーを書き込んではいけません。環境変数に入れて、コードでは process.env.MY_API_KEY で読みます。
自分のPCでは、変数を.envファイルに書き、そのファイルを.gitignoreに入れて、Gitに見せないようにします。
練習用の.envと.gitignoreを書く
docker exec -w /home/node/project agent sh -c "mkdir -p demo-keys && printf 'EXAMPLE_API_KEY=not-a-real-key-123\n' > demo-keys/.env && printf '.env\n' > demo-keys/.gitignore"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
.envを読み、値を隠す
docker exec -w /home/node/project agent node -e "const fs=require('fs');const nl=String.fromCharCode(10);for(const line of fs.readFileSync('demo-keys/.env','utf8').trim().split(nl)){const i=line.indexOf('=');const v=line.slice(i+1);console.log(line.slice(0,i)+' は設定されています('+v.length+'文字、値は非表示)')}console.log('.env は .gitignore に入っている:'+(fs.readFileSync('demo-keys/.gitignore','utf8').split(nl).includes('.env')?'はい':'いいえ'))"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
本番でも同じ考え方
ホスティングサービスには、秘密を置く場所があります。そこに置いた値は、環境変数としてプログラムに渡されます。コードは、自分のPCでもサーバーでも同じままです。
名前とダミーの値を書いた .env.example を公開しておきましょう。新しい仲間が、何を設定すればよいか分かります。
例:漏れたあとにすること
| 何が起きたか | すること |
|---|---|
| キーがコードにあるが、コミット前 | 環境変数に移す |
| コミット済みだが、まだ公開していない | キーをローテーションし、コミットを書き換える |
| 公開リポジトリに公開してしまった | すぐキーをローテーションし、履歴を掃除する |
| チャットやプロンプトに貼ってしまった | キーをローテーションする |
学生が入力するセルは、このプレビューでは空白です。
よくある間違い
注意
新しいコミットでキーを消せば、なくなると考える人が多くいます。しかしGitは古いコミットをすべて残すので、コピーした人にはキーが履歴に残ります。キーはローテーションしましょう。新しいキーだけが、古いキーを使えなくします。