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

に公開

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

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

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

概要

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

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

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

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

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

サンプルプログラムの準備

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 というサービス上に登録(設定)するのですが、まずはローカル(自分の PC)で動作確認するために、ローカル環境にも環境変数を設定しておきます。

ローカルの環境変数は .env という名前のファイルに「変数名=値」という形式で記述します。先頭にドット(ピリオド)のついたファイルはエクスプローラーなどでは作れないため、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 をインストールしていない人は以下のコマンドでまずインストールしてください(参考)。この作業は 1 度だけで OK です。

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

Deno がインストールされていたら、まず、次のコマンドでサーバーサイドプログラム(ここでは main.js)から実行します。

deno run -A main.js

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

続いて、上記で用意したクライアントプログラム(script.js)からサーバーサイドプログラム(server.js)にアクセスしてみます。といっても、Live Server などでクライアント(index.html)を開くだけです。
サンプルコードでは、[サーバーにアクセス]というボタンが表示されるので、それを押すとローカルの環境変数(.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/リポジトリー名」でブラウザーからアクセスできるようになります。設定が反映されるまで少し時間がかかるので気長に待ってください。

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

Deno Deploy の設定

ここからが本番です。ローカルで動作確認した環境変数の読み込みを、本物のサーバーでやってみます。
サーバーとして使用する Deno Deploy の準備をしていきましょう。

プロジェクトの登録

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

https://deno.com/deploy

GitHub アカウントと連携するよう誘導されます(Deno deploy の画面が改訂されている可能性があります)。

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

成功すると以下のような画面になります。「I have an exsiting 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]ボタンは押さないでください。その前に Deno deploy に環境変数を設定する必要があります。

下の方にある[Add environment variables]ボタンを押します。

環境変数を設定する

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

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

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

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

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

確認(ブラウザーから)

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

試しに[View]ボタンをクリックして、ブラウザーからサーバーサイドプログラムにアクセスしてみましょう。ローカル環境(localhost:8000)で確かめたときと同じ画面が表示されますが、今回表示されている JSON の内容は(.env ファイルではなく) Deno Deploy に設定した環境変数を読み込んだものです。

さて、実際には、サーバーサイドプログラムには(ブラウザーではなく)クライアントプログラムからアクセスします。今回の場合、ウェブアプリは GitHub に公開している GitHub アカウント名.github.io/リポジトリー名 です。

しかし、(繰り返しになりますが)現在 GitHub にプッシュされている script.js は .env ファイルの環境変数を読み込むコードになっているので、そのままではボタンを押しても何も反応しません。

リポジトリーの更新

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

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

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

確認(本番)

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

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

おしまい

Discussion