※本記事はプロモーションを含みます
目次
Googleスプレッドシートの業務自動化を進めていると、外部のWeb API連携ツールを使う機会が増えてきます。なぜなら、Slackへの通知、OpenAIのAPIを用いたテキスト作成、社内システムとのWebhook通信を行うからです。外部サービスにアクセスするスクリプトを書く際には、絶対にAPIキーやアクセストークンなどの秘密情報を扱うことになります。ただし、スクリプトエディタ内のコードに「const API_KEY = ‘sk-xxxx…’;」のように生の文字列をそのまま書く運用は避ける必要があります。自分一人だけで使うファイルなら問題が起きにくいですが、チームメンバーにGoogleスプレッドシートを共有したり引き継ぎを行ったりすると問題が発生します。なので、スクリプトプロパティを使って安全に機密情報を保存して必要なタイミングで取得しましょう。
コード直書きによる事故の現実とプロパティ分離による運用の変化
まず、APIキーをコード内に平文で直接書く状態と、スクリプトプロパティへ分離した状態とで、安全性がどう変わるのかを説明します。外部APIを呼び出すコードを急いで書く段階では、スクリプトの先頭行に変数をそのまま定義してしまいがちです。ただし、Googleスプレッドシートに紐づくコンテナバインドスクリプトでは、Googleスプレッドシートの閲覧権限や編集権限を持つユーザーがメニューの「拡張機能」からApps Scriptエディタを開くことができます。というのは、業務の集計結果を見せたいだけの相手であっても、編集権限を渡した瞬間に有料APIの秘密鍵や外部チャットツールのトークンを見られてしまうからです。
さらに問題なのが、バージョン管理ツールや共有ドライブを経由した情報の漏洩事故です。スクリプトをパソコンのローカル環境で開発するためにClaspなどのCLIツールを導入したり、社内のコードレビュー用にテキストファイルとしてバックアップしたりする運用を始めると危険が生じます。なので、APIキーが書かれたコードがそのまま保存場所やチャットツールに送信されてしまいます。GitHubに公開された状態のまま誤って送信すると、数分で自動プログラムにキーを検出されます。その結果、高額な不正利用請求が発生した事例が存在します。
これに対して、スクリプトプロパティを活用した安全管理を導入すると、コードと秘密情報を完全に切り離すことができます。スクリプトプロパティに保存された値は、Googleのシステム側が保持するキーバリューストア(KVS)に保存されます。なので、スクリプトのソースコード自体には秘密情報が一切含まれません。Googleスプレッドシートの編集権限を持つメンバーがエディタを開いても、コード上に鍵の文字列が表示されることはありません。ただし、Clasp経由でローカル環境にコードを取り込んでも、取得できるのはプログラムの処理だけであり機密情報は落ちてきません。なので、Gitへの誤送信や情報漏洩を根本から防ぐことができます。これはWebアプリ開発における環境変数と同じ仕組みであり、GAS単体で安全な管理を実現できます。
スクリプトプロパティへの保存と安全な取得を行う実装
GASでスクリプトプロパティへ保存して取得する一連の流れを、具体的なコードで確認してみましょう。スクリプトプロパティを操作するには、標準で用意されているPropertiesServiceクラスを利用します。機密情報を登録する作業は通常、運用の初期設定時やキー更新時に一度だけ実行する専用のセットアップ関数を用意して行います。
function setupApiKeys() {
// プロパティストアのインスタンスを取得
const props = PropertiesService.getScriptProperties();
// APIキーをプロパティに保存(初回または更新時のみ実行)
props.setProperty("OPENAI_API_KEY", "sk-xxxxxx");
// 保存された値を正しく取得できるか検証
const apiKey = props.getProperty("OPENAI_API_KEY");
if (apiKey) {
Logger.log("API Key loaded successfully");
} else {
Logger.log("Failed to load API Key");
}
}
function callExternalApi() {
// 実務の業務ロジック側での取得処理
const props = PropertiesService.getScriptProperties();
const apiKey = props.getProperty("OPENAI_API_KEY");
if (!apiKey) {
throw new Error("APIキーがスクリプトプロパティに設定されていません。setupApiKeysを確認してください。");
}
// 取得したapiKeyを使ってUrlFetchApp等を実行する処理が続く
Logger.log("APIを実行可能な状態です: 文字数=" + apiKey.length);
}
このコードを使うタイミングは、新しい外部連携機能をプロジェクトに組み込む最初のセットアップの段階です。一時的に「setupApiKeys」という関数を作成したうえで、登録したいキーと値を記述して手動実行します。実行が完了して「API Key loaded successfully」のログが確認できたら、コード内に一時的に書いた「”sk-xxxxxx”」という平文の文字列を即座に削除してください。あるいは、ダミーの文字列に書き換えて関数自体を空にしましょう。というのは、キーを設定するためのコードに本物のキーを書いたまま放置すると、直接書く運用を排除した意味が無くなってしまうからです。
ここで見落としやすいのが、「setProperty」を実行した瞬間にスクリプトファイル自体の履歴にキーが残ってしまう問題です。Apps Scriptのエディタには変更履歴が存在します。なので、一時的であってもエディタ上で平文を入力して保存すると、履歴を遡ることで第三者にキーを見られてしまう可能性があります。このリスクを完全に回避したい場合は、ブラウザのデバッグ機能を利用するか、実行時に関数の引数として渡しましょう。あるいは、画面にプロンプト入力画面(Browser.inputBox)を表示して画面経由で値を入力し、コードエディタ上には1文字も本物のキーを入力しない運用を徹底しましょう。
型変換とnullハンドリングで発生する実務の落とし穴
PropertiesServiceを業務で使い始めると、JavaScriptの型変換に起因する予期せぬ不具合に直面することがあります。特に意識しなければならないのは、「スクリプトプロパティに保存される値は、すべて強制的に文字列型(String)として扱われる」というルールです。数値を保存した場合でも、JSON形式のデータを保存した場合でも、内部的にはすべて文字に変換されて保存されます。
例えば、APIの待ち時間や上限回数といった数値をプロパティに保存したとします。「props.setProperty(‘RETRY_LIMIT’, 3);」のように数値を渡して保存できたとしても、後から「props.getProperty(‘RETRY_LIMIT’)」で取り出した値は数値ではなく文字列の「”3″」になります。これをそのままコード内で比較するとプログラムの誤作動を引き起こします。特に「retryCount + props.getProperty(‘RETRY_LIMIT’)」のような計算を行うと、数値の足し算ではなく文字列の結合が行われてしまい、回数が「03」のような不自然な状態になります。なので、数値や真偽値を扱う場合は、取得した直後に「Number()」や「parseInt()」で数値へ変換する手順を徹底しましょう。
もう一つの問題は、設定したキーが存在しない場合にエラーが発生せず「null」が返される仕組みです。環境の移行中や誤ってプロパティを削除した状態で「props.getProperty(‘UNDEFINED_KEY’)」を実行しても、プログラムは停止せずにnullを返して次の処理に進んでしまいます。このnullをチェックせずに外部APIへの送信データにセットすると、無効なデータが送信されてサーバーから認証エラーが返ってきます。API呼び出しの失敗ログを見ても認証失敗の理由が分からず、キーの期限切れなのかコードのミスなのかを確認する作業で時間を無駄にします。なので、取得処理を行う場所には必ず「if (!apiKey)」による確認処理を入れておき、設定漏れをその場で検知できるようにコードを組み立てましょう。
プロパティスコープの使い分けと漏洩を防ぐ運用ルール
PropertiesServiceには「ScriptProperties(スクリプトプロパティ)」のほかに、「UserProperties(ユーザープロパティ)」と「DocumentProperties(ドキュメントプロパティ)」という合計3種類の範囲が存在します。これらを正しく理解して使い分けないと、データの共有範囲が狂ってエラーや情報漏洩が発生します。
スクリプトプロパティは、そのスクリプトを実行するすべてのユーザー間で共有される全体の設定エリアです。組織全体の共通Slackチャンネルへの通知設定や、会社のアカウントで契約しているOpenAI、Google Cloud等のキーを保存する用途には、スクリプトプロパティが最も適しています。一方で、ユーザープロパティはスクリプトを実行したユーザー個人のエリアに値が分けられます。全社共通のキーではなく、実行したユーザー自身のトークンを使って処理を行わせたい場合はユーザープロパティを使用しましょう。スクリプトプロパティを使ってしまうと他人の権限で処理が実行されてしまいます。また、ドキュメントプロパティはコンテナバインドスクリプトが紐づいている特定のファイル単位で値を保持するエリアであり、Googleスプレッドシートごとに異なる設定を持たせたい場合に役立ちます。
業務で安全にAPI連携を運用するためのルールとして、スクリプトプロパティに値を登録した後は、不要になった設定用の関数を完全に削除するか中身を消去しましょう。また、複数人でスクリプトを管理する場合、プロパティの「キー名一覧(例: OPENAI_API_KEY, SLACK_WEBHOOK_URL)」だけを説明文やコメントに記載しておきましょう。実際の値はそれぞれの環境やパスワード管理アプリで管理する運用を行いましょう。安全な保存と取得のやり方を身につけて、コードと秘密情報を分けて管理する仕組みを作りましょう。

