🐭

【Next.js】GCPのCloud KMSを使って環境変数を暗号化/復号化させる | Offers Tech Blog

2024/02/22に公開

概要

こんにちは、Offers を運営している株式会社 overflow でフロントエンドのテックリードをしている Kazuya です。

今回は、Next.jsにおける環境変数をGCPのCloud KMSで暗号化する方法を解説します。Next.jsの環境変数ファイルで解説しますが、他の言語/フレームワークでも活用できると思います。初心者の方でも理解しやすいよう、できるだけ詳しく解説していきますので、ぜひ参考にしてもらえればと思います。

はじめに

本記事で紹介する方法は、暗号化/復号化をする手段の1つです。要件定義や使用しているフレームワークによっては導入できない場合があります。今回の方法は一例であることをご理解の上、参考にしていただけると幸いです。

なぜ暗号化する必要があるのか?

まず、環境変数ファイルをなぜ暗号化する必要があるのか解説していこうと思います。
暗号化する理由ですが、簡単にまとめると「機密情報を保護するため」です。.envをはじめとした環境変数ファイルでは、APIのシークレットキーやデータベースに接続情報などの機密情報を扱うことがあります。これらをgithubやサーバーにアップロードしてしまうと、機密情報が漏洩するリスクがあるため、何らかの手段で暗号化する必要があります。そこで、今回はGCPの提供しているCloud KMS(Key Management Service)を利用して、機密情報を暗号化していきます。

Cloud KMSを採用する理由

GCPにはCloud KMSSecret Managerという2つの機密情報を管理するサービスが存在しています。どちらでも管理することは可能ですが、KMSは対称鍵をファイルとして管理できるため、githubにコミットできます。環境変数ファイルの存在を視覚的に把握できるため、暗号化/復号化の知見があまりない方でも比較的理解しやすく、チーム開発でも運用しやすいというメリットがあります。もちろんメリットだけでなくデメリットもあるのですが、そちらに関しては後述します。

Cloud KMSとは?

Cloud KMSとは、ファイルを暗号化する際に使用する対称鍵をクラウドに保存できるGCPのサービスです。 もう少し噛み砕いて表現すると「キーリングとキーを用いて、秘匿情報を暗号/復号化できるサービス」と言った感じでしょうか。ローカルで鍵を管理する方式と異なりクラウド(GCP)上で管理されるため、鍵の紛失や漏出するリスクを回避できます。

特徴

  • 暗号鍵を一元管理
  • 鍵のローテーション
  • IAMで暗号化/復号化も権限を付与
  • 秘密鍵やその他秘匿情報を安全に管理できる
  • Cloud Build上で復号化できる

https://cloud.google.com/security-key-management

鍵のローテーションについて

上記でワードが出たので、鍵のローテーションについて少し解説します。暗号化した際の鍵が流出した場合、総当りで無理やり復号化されてしまう可能性あります。そこで鍵を切り替えることで意図しない復号化を防止し、機密情報の流出するリスクを低下させています。

料金

基本的な料金に関しては以下の通りです。そこまで高額ではありませんが、できるだけ節約したい方は使用していないバージョンの鍵を無効化しておくと良さそうです。また、オプションによっては料金が変動するので、利用前に公式サイトで確認してください。

サービス 料金(ドル)
アクティブな鍵バージョン $0.06(月額)
鍵管理オペレーション 無料
鍵使用オペレーション(暗号化/復号化) $0.03 / 10,000 オペレーション

https://cloud.google.com/kms/pricing/?hl=ja

Secret Managerとの使い分け

GCPには機密情報を管理するサービスにSecret Managerも存在しています。Secret Managerは、シークレット名とバージョンを指定することで機密情報を取得できます。暗号化/復号化の処理をSecret Manager側が実行してくれるため、Cloud KMSに比べ扱いやすいのが特徴です。また、シークレット毎にIAMで権限を設定できるため、細かいアクセス制御を実現できます。

サービス比較

サービス 用途 アクセス制御 扱いやすさ
KMS データベース内の行、イメージやファイルなどのバイナリデータ KMS全体に設定可能
Secret Manager データベース パスワード、API キー シークレット毎に設定可能

https://cloud.google.com/secret-manager/docs/overview

運用上のメリット/デメリット

メリット

  • GCPのサービスであるCloud Build等と連携しやすい
  • 復号鍵をGitで管理できる
  • 暗号化/復号化の仕組みがシンプルのため、エンジニア以外でも扱いやすい
  • 導入コストが比較的低め

デメリット

  • 環境変数の変更時に暗号化をするフローを徹底しないといけない
  • アクセス権限をキー毎に設定できない

メリットが多い反面やや面倒なデメリットがあります。それが環境変数ファイルの更新時に発生するフローです。実際に運用してみたところ以下のような問題が発生しました。

  1. Aさんが環境変数を変更して暗号化を実行
  2. そのブランチを元にBさんが開発する
  3. 環境変数依存の変更が入っていたため、起動できない

上記の場合、1と2の間にBさんが復号化の処理をしないといけません。慣れていない場合、このフローを忘れがちになり、安定したチーム開発が難しい状態になってしまいました。

Cloud KMSの設定方法

前提

今回はGoogle Cloud SDKに内包されているgcloudを使って暗号化/復号化を行うため、事前にインストール/設定が必要になります。Google Cloud SDKに関する説明は省略しますので、詳しく知りたい方は以下のサイトをご参照ください。

https://cloud.google.com/sdk/gcloud?hl=ja
https://cloud.google.com/sdk/docs/install?hl=ja

サービスを有効化する

まずはじめにCloud KMSを利用するために、以下のページにアクセスして「Cloud Key Management Service (KMS) API」を有効化させます。ただ有効までに少し時間がかかるので、ここでコーヒーでも飲んで一服しましょう

https://console.cloud.google.com/marketplace/product/google/cloudkms.googleapis.com

キーリング/キーを設定する

APIを有効化できたら次にキーリングとキーを設定していきます。こちらの操作をするには、Cloud KMS 管理者(roles/cloudkms.admin)の権限が必要になります。あらかじめ、ログインアカウントに該当する権限が付与されているか確認してください。

キーリングを作成

KMSのキーリング設定
まずはキーリングを作成します。キーリングは、キー及びバージョンのルートリソース(親)になります。こちらのページにアクセスして「キーリング名」を入力し、リージョンを選択します。今回は、デフォルトの「global」を選択していますが、ここは各環境にあわせて適宜変更してください。

CLI
$ gcloud kms keyrings create "nextjs-frontend-env" \
      --project $PROJECT_ID \
      --location "global"

キーを設定

KMSのキー設定

キーリングを設定できたらキーを設定していきます。今回は本番環境用の環境変数を対象とするので、キーの名前は「production」としています。特に命名規則ないですが、暗号化/復号化をする際に入力するため、分かりやすい命名にしておくと良いと思います。
また、今回は保護レベルやローテーション期間などの項目はデフォルトのままにしていますが、ここも適宜変更がしてください。

CLI
gcloud kms keys create "production" \
    --project $PROJECT_ID \
    --keyring "nextjs-frontend-env" \
    --location "global" \
    --purpose "encryption" \
    --protection-level "software"

暗号化

下準備を終えたので環境変数ファイルを暗号化する準備していきます。ここからはgcloud(CLI)が必要になりますので、まだ準備できていない方はこちらを参考にしてインストールをしてください。
今回は前述した通り、本番環境用の環境変数ファイルを暗号化するので、「.env.production」を指定しています。暗号化されたコンテンツを保存する際にファイル名が必要なので、ciphertext-fileで指定しています。

$ gcloud kms encrypt \
      --project $PROJECT_ID \
      --location "global" \
      --keyring "nextjs-frontend-env" \
      --key "production"
      --ciphertext-file .env.production.enc \
      --plaintext-file .env.production \

復号化

これで最低限の準備はできたので、暗号化されたファイルから復号化してみます。キー情報、暗号化されたファイル名、復号化されたコンテンツのファイル名を入力して以下のコマンドを実行します。

$ gcloud kms decrypt \
      --project $PROJECT_ID \
      --location "global" \
      --keyring "nextjs-frontend-env" \
      --key "production"
      --ciphertext-file .env.production.enc \
      --plaintext-file .env.production \

実行後に「.env.production」が生成されていれば成功です。運用時はステージングなど他環境の変数があると思うので、適宜キーを追加して暗号化させてください。

まとめ

今回は、Next.jsにおける環境変数をGCPのKMSで暗号化/復号化する方法を解説しました。暗号化/復号化は苦手意識を持つ人も多いと思いますが、セキュリティ上いずれは向き合わないといけない存在です。本記事で少しでも理解の助けになっていれば幸いです。

最後まで読んで頂き、ありがとうございました。いいねしていただけると記事執筆の励みになりますので、参考になったと思った方は是非よろしくお願いします!

関連記事

https://zenn.dev/kazumax4395/articles/643ffc25d3f803
https://zenn.dev/kazumax4395/articles/427cc791f6145b

参考記事

https://zenn.dev/catnose99/articles/8303b8a195afee

Offers Tech Blog

Discussion