Deno DeployでAPIキーを環境変数に隠す

2024/04/29に公開

ビルドプロセスを伴わない(ごく普通の)ウェブコンテンツでサードパーティ製の API を使うときに、そのまま GitHub Pages にアップロードすると API キーが見えてしまう問題があります。
その対処法の一つとして、API を呼び出している部分をサーバーサイドで動かすようにして、Deno Deploy の環境変数を使って API キーを隠す方法を紹介します。

本記事の内容は、以下のオンラインテキストの続きです。

https://zenn.dev/ojk/books/intro-to-vue/viewer/vue-webapi-3

概要

JavaScript ファイルはウェブコンテンツとして公開されてしまうので、API キーを JavaScript ファイルに埋め込んでいると、ブラウザーで「ページのソースを表示」などをすると見られてしまいます。

API キーを公開しないようにするには、例えば、以下のようにする方法があります。

  1. API を使う部分をサーバーサイドのプログラムとして切り出す
  2. サーバーサイドプログラムを置くサービスの “環境変数”(プログラミングの変数みたいなもの)に API キーを登録する
  3. サーバーサイドプログラムでその環境変数を使って記述する

サーバーサイドプログラムはブラウザーなどからは中身(ソースコード)が見えませんし、ソースコードを GitHub などに公開しても見えるのは環境変数の名前だけになります。

ここでは、サーバーサイドプログラムを置くサービスとして Deno Deploy というサービスを使います。Deno Deploy だとサーバーサイドプログラムを JavaScript で記述することができます。
HTML と JavaScript のファイルが 1 つずつで構成されていたような簡単なプログラムなら、クライアントサイドとサーバーサイドの JavaScript スクリプトを同じところ(リポジトリー)に置いておくことで管理の手間も省けます。

GitHub リポジトリーを用意する

Deno Deploy は GitHub のリポジトリーと連動して動作するため、GitHub が使えるようになっていることが前提です。必要に応じて、以下のオンラインテキストのチャプター 2 まで(VSCode から使いたい人はチャプター 4 まで)を先に学んでおいてください。

https://zenn.dev/ojk/books/github-vscode

必要なファイルの作成

HTML から script 要素で呼び出している「通常の JavaScript」から API を使用している部分をサーバーサイドで動かすスクリプトとして切り出します。そして、残りの部分(クライアントサイドで動かす JavaScript や HTML など)とまとめて 1 つの GitHub リポジトリーにします。

JavaScript の切り分け作業については こちら を参照してください(petite-vue のテキストですが)。以下では、切り分けた後のコードがあるものとして進めます。

まず、クライアントサイドで動かす HTML(index.html)と JavaScript(script.js)のサンプルを示します。[サーバーにアクセス]というボタンを押すとサーバーに fetch で接続し、サーバーから返ってきた JSON(の env プロパティ)を h1 要素に表示するだけのものです。サーバーはひとまずローカルホスト(自分の PC)にしています。

index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button>サーバーにアクセス</button>
    <h1></h1>
    <script src="script.js"></script>
    <!-- ↑このJavaScriptはブラウザー上で実行される -->
  </body>
</html>
script.js
'use strict';

/* サーバーに接続する非同期関数 */
async function getResource() {
  // クライアントサイドからサーバーサイドへはfetchで接続する
  const res = await fetch('http://localhost:8000/');
  const obj = await res.json();
  console.log(obj); // ここはブラウザーの開発者ツールのコンソール
  document.querySelector('h1').textContent = obj.env;
}

// button要素のclickイベントに登録
document.querySelector('button').addEventListener('click', getResource);

次に、Deno Deploy で動かすサーバーサイドのサンプルコード(main.js)を示します。
このサンプルコードでは、サードパーティー製の API を使用する代わりに、取得した環境変数の値を JSON でクライアントに返すだけの処理にしています。

Deno を使う場合、Deno.env.get('環境変数名') で環境変数の値を取得することができます。この機能を使用するには先頭の import の行も必要です。

main.js
import 'https://deno.land/std/dotenv/load.ts';

/* サーバーにアクセス(fetch)があったら呼び出される関数 */
Deno.serve(async (req) => {  
  const apiKey = Deno.env.get('API_KEY'); // 環境変数の読み込み
  console.log(apiKey); // ここはVSCodeのターミナル

  // メッセージボディを構成
  const body = JSON.stringify({ env: apiKey });

  // アクセスしてきたクライアントにJSONを返す
  return new Response(body, {
    headers: {
      'Access-Control-Allow-Origin': '*', // アクセス制限(全許可)
      'content-type': 'application/json; charset=utf-8',
    },
  });
});

環境変数は Deno Deploy というサービス上に登録(設定)するのですが、まずはローカルで動作確認するために、ローカル環境にも環境変数を設定しておきます。

ローカルの環境変数は .env という名前のファイルに「変数名=値」という形式で記述します。先頭にドット(ピリオド)のついたファイルはエクスプローラー(や Finder)では作れないため、VSCode で作成します。なお、作成した .env ファイルもエクスプローラーなどでは見えません。

ここでは「API_KEY」という名前の環境変数に、適当な文字列(API キーのダミー)を値として設定しました。設定したい環境変数が複数ある場合は改行して列挙します。

.env
API_KEY=AbcDefGhiJkl

あとで VSCode から GitHub にファイルをプッシュ(同期)する場合、この .env ファイルが GitHub にプッシュされてしまう(=公開されてしまう)と困るので、Git で無視されるように .gitignore ファイルを新規作成し、.env と書いておきます。.gitignore もドットで始まるので VSCode で作成します。

.gitignore
.env

「.gitignore」というファイル名の 1 文字でも間違っていてはいけません。正しく名前を付けると、VSCode の左ペインのアイコンが Git アイコンになります(黒い菱形がひび割れたようなアイコン)。

以上でファイルの作成は終わりです。

ローカルでの動作確認

プログラムが意図どおりに動くかローカル(自分の PC 上)で確認してみましょう。VSCode のターミナルを使います(Windows なら Ctrl-@ でも起動します)。

Deno をインストールしていない人は以下のコマンドでまずインストールしてください(参考)。

Windows(PowerShell)
iwr https://deno.land/x/install/install.ps1 -useb | iex
Mac、WSL
curl -fsSL https://deno.land/x/install/install.sh | sh

次のコマンドでサーバーサイドプログラム(ここでは main.js)を実行します。

deno run -A main.js

そうすると、http://localhost:8000/ でサーバーが動いている…というメッセージが表示されるので、試しにこの URL をブラウザーにコピペして開いてみましょう(Ctrlキーを押しながらクリックしても開きます)。
サンプルコードでは、以下のようにクライアントに返される JSON が表示されます。

続いて、クライアント(ウェブアプリケーション)を Live Server などで動かしてみます。
サンプルコードでは、[サーバーにアクセス]というボタンが表示されるので、それを押すとローカルの環境変数(.env ファイルに書いたもの)の値が表示されます。

このローカルの段階で自分のプログラムが正しく動くことを確認し、うまくいくまでは次のステップに進まないようにしてください。

GitHub のリポジトリーとして用意する

以上のファイルを GitHub のリポジトリーとして用意します。すでにリポジトリー上で管理している…という人はさきに進めてください。

新規のリポジトリーは、GitHub のウェブサイト、あるいは VSCode から作成できます。

  • GitHub サイトでリポジトリーを新規作成してファイルを追加する → 作成ファイルの追加
  • VSCode から新規のリポジトリーとしてプッシュする → 参考

GitHub サイトからファイルを追加する場合、.env ファイルは追加しないようによく注意してください(履歴が残るので削除しても遅いです)。VSCode から GitHub にプッシュする場合は、.gitignore ファイルが正しく設定できていれば .env ファイルは無視されてプッシュされません。

ここでは deno-deploy-test というリポジトリー名にしました。サンプルではクライアントサイド(index.htmlscript.js)とサーバーサイド(main.js)のスクリプトを同じフォルダーに置いています。一覧の中に .env がないことを確認します。

クライアントサイド(ウェブアプリ)にブラウザーからアクセスできるように設定します。GitHub サイトから、当該リポジトリーの Setting タブ > Pages と進みます。

真ん中あたりの「Branch」というところで、「None」となっている部分を「main」に変更します。

以下のようになったことを確認して[Save]ボタンを押します。

これで、ウェブアプリに URL「GitHub アカウント名.github.io/リポジトリー名」でブラウザーからアクセスできるようになります。設定が反映されるまで少し時間がかかるので気長に待ってください。

以下のようにボタンは表示されます。現時点ではローカルのサーバーにアクセスするように記述しているのでアプリはまだ正しく動きません(ボタンを押しても何も起こらない)。

Deno Deployの設定

プロジェクトの登録

GitHub リポジトリーの準備ができたら、Deno Deploy の準備をしていきましょう。

以下の URL にアクセスしてください。下の方にある[Get started now]から進みます。

https://deno.com/deploy

GitHub アカウントと連携するよう誘導されます。

Deno Deploy に権限を与え、メールの認証をします。

成功すると以下のような画面になります。「I have an exsiting project」のほうから進みます。

あるいは、以下のような画面(Deno Deploy のダッシュボード)になっていた場合は右側にある[New Project]ボタンを押します。

Create new project という文字の下にある「Select User or Organization」というフォームから [+ Add GitHub Account]を選択します。

こんな感じで GitHub に Deno Deploy をインストールする画面になります。

「Only select repositories」を選び、検索ボックスから今回作成したリポジトリーを選びます。

下のほうにある[Install]ボタンを押します。

さきほどの画面に戻ると、「Select User or Organization」から自分の GitHub アカウントが選べるようになっています。

アカウントを選ぶと、さらにさきほど登録したリポジトリーが選べます。[select]ボタンを押します。

こういう状態に。「Prodution Branch」では「main」を選びます。

下のほうはほぼそのままで OK ですが、「Project Name」は好きに変更してください。

Entrypoint(エントリーポイント)では main.js を選びます。エントリーポイントとは、サーバーにアクセスがあったときに最初に起動されるサーバーサイドプログラムです。

最後に[Deploy Project]ボタンを押します。

成功!(Success!)と表示されても[Go Project]ボタンは押さず、下の方にある[Add environment variables]ボタンを押します。

環境変数を設定する

以下のような画面になるので、[+ Add Variable]ボタンを押します。

環境変数の設定画面になります。「KEY」というのが環境変数の名前、「VALUE」というのが環境変数の値です。

KEY と VALUE を設定して、[Save]ボタンを押します。KEY はサーバーサイドの JavaScript から参照している「API_KEY」という文字列になってます。

Save すると値(VALUE)は見えなります。あとから見るための操作方法は用意されていないので、アプリを動かしてみて上手くいかなければ削除して作り直します。

ページを上のほうにスクロールしていくと、ここがプロジェクトのページであることがわかります。

ページの右のほうに[View]というボタンがあります。これを押すとサーバーサイドプログラムが動いているウェブサイトに飛びます。ちなみに、View ボタンの下のほうに「Environment Variables」というページ内リンクがあり、ここから環境変数がいつでも追加できます。

[View]ボタンをクリックしてみましょう。ローカルでローカルホスト(localhost:8000)で確かめたのと同じ画面が表示されますが、今回表示されている JSON の内容は Deno Deploy に設定した環境変数を読み込んだものです。

さて、いま確認したのはサーバーサイドプログラムで合って、ブラウザーから直接アクセスすることはありません。ウェブアプリは GitHub に公開している GitHub アカウント名.github.io/リポジトリー名 のほうです(さきほど確認したはずです)。

しかし、(繰り返しますが)いま GitHub にプッシュされているコードはローカルで確認するためのものなので、そのままではボタンを押しても何も反応しません。

リポジトリーの更新

まず、script.js を修正して、クライアントからアクセスするサーバーのアドレスをローカルホストから Deno Deploy に設定したサーバーの URL にします(GitHub の差分ページを示します)。

それから、サードパーティ製の API を利用するなら Access-Control-Allow-Origin の値も適切に設定しておきましょう。「*」だと誰でもサーバーにアクセスできてしまうので、「GitHub アカウント名.github.io」にしておきます(以下のサンプル画像は gitojk というアカウントのものなのでそのままコピペしないように)。

変更を GitHub にプッシュすると、Deno Deploy のほうも自動的に更新されます。

GitHub に公開しているウェブアプリの URL(GitHub アカウント名.github.io/リポジトリー名)に再度アクセスします。[サーバーにアクセス]ボタンを押すと…

今度はちゃんと(Deno Deploy の環境変数に登録した)API キーが表示されます。

おしまい

Discussion