保護你的 Environment Variables

tags: Env CI
category: DevOps
description: 保護你的 Environment Variables
created_at: 2024/11/08 11:00:00

cover image


前言

昨天剛把部落格的推播(通知)功能完成,所以今天就先快速記錄一篇文章來做實驗推播給自己,所以這一篇內容也會比較輕鬆一些。不會那麼燒腦

這一篇要記錄的是如何保護環境變數(?),通常環境變數會放一些比較敏感的資訊,例如 API Key 或是 DB Password 等等,雖然也可以放一些共用的東西來方便抽換,這些資訊通常會不希望被拿走,所以通常都會有一些處理方式。

這篇主要是使用 .env 的方式。


預備知識

  • 你應該知道什麼是環境變數 (廢話
  • 你用過 .env 檔案: 因為這篇使用.env介紹
  • 認識 JavaScript 或是 Node.js: 因為這篇會用 Node.js 來做範例
  • Windows 可能需要 WSL 去幫助你執行相關指令

建立 .env 檔案

首先我們先建立一個 .env 檔案,這個檔案通常會放在專案的根目錄下,這個檔案會放一些環境變數,例如:

API_KEY=123456

嗯..非常陽春,反正只是當範例用,所以就隨便放一個 API_KEY 進去。


讀取 .env 檔案

這邊使用 dotenv 這個套件來讀取 .env 檔案。

首先先安裝 dotenv:

$ npm install dotenv

然後在你的程式碼中引入 dotenv:

require('dotenv').config()

這樣就可以讀取 .env 檔案了。

console.log(process.env.API_KEY)

然後去執行你的程式碼,你應該會看到 123456 這個值。


就這樣?

如果只是這樣的話標題應該不會是「保護你的 Environment Variables」,因為這樣的話就只是把敏感資訊放在 .env 檔案中,但是這樣的話還是有一些問題,例如:

  1. 被拿走就看光光了(?): 不管任何拿法,直接拿檔案或是傳訊息
  2. CI 平台有可能會有漏洞,導致你的環境變數被拿走,這時如果你的環境變數是放機密資訊的話就很危險

所以這時我們需要的是讓 .env 被拿走也沒關係的解決方案;或是說最終部署就不要採 .env 了,也許 .env 就讓你在 local 開發時方便使用即可。

這時可以使用一個套件 dotenv-vault 來幫助我們。


使用 dotenv-vault

這個套件有支援 cloud 版本,但是 cloud 版本需要登入(也有付費版),而對於自己日常開發用的話我不太喜歡登入(送個資),所以這邊只會介紹 local 版本,也很方便。

就以剛才的範例延續,我們直接在專案中執行 build 指令:

$ npx dotenv-vault local build

這時你會看到根目錄下多了兩個檔案,分別是

  1. .env.vault: 這個檔案是加密過的 .env 檔案,這個檔案可以上版控
  2. .env.keys: 這個檔案是解密用的金鑰: 這個檔案不要上版控,如果你用 CI 平台,就放對應的 Secrets 中即可
    • 但剛剛不是說不要放機密資訊嗎? 這個檔案只是用來解密 .env.vault 的,攻擊者只拿的到你的環境變數(key),沒有你的 .env.vault 也沒用。

這時你可以先做個實驗,把 .env 刪除,然後再執行你的程式碼,你會發現程式碼輸出變成 undefined 了。

這時來看看怎麼把原來的環境變數倒入你的程式中:

所以依照剛才說的,用 key 來解密,所以先把你的 key 複製好(假設我複製的 key 叫做 <key>):

$ DOTENV_KEY=<key> command

嗯.. 可能需要一點想像,所以再做個假設,我的程式碼是 main.js,那麼:

$ DOTENV_KEY=<key> node main.js

這樣你就會又看到了 123456 這個值。

然後如果你想要取得原本的 .env 檔案,可以使用:

$ npx dotenv-vault local decrypt <key>

這樣就會看到輸出原本的 .env 檔案。

API_KEY=123456

一點小細節

在一開始執行 build 指令時,會看到一個 DEPRECATED 的訊息(雖然不知道未來還在不在),總之是作者希望你改用 dotenvx 的方式做加密,所以這裡也提一下。


使用 dotenvx

這邊一樣使用前面的 .env 內容,但是這次使用 dotenvx 來做加密。

這時指令變成了:

$ npx @dotenvx/dotenvx encrypt -f .env

然後你會看到你的 .env 內容直接被加密了,然後目錄下也多了一個 .env.keys 檔案。

接著如果你直接執行你的程式碼,他的值會是加密過的東西,沒辦法使用,所以要使用 dotenvx 的執行方式:

$ npx @dotenvx/dotenvx run -f .env -- node main.js

這樣你就可以看到 123456 這個值了。

然後版控的邏輯和剛才一樣:

  • .env.keys 不要上版控
  • .env 可以上版控,因為已經被加密過了

簡單的 POC 要這麼麻煩嗎?

當然是不用啊廢話,甚至你的 .env 根本沒有敏感資訊你要推上版控也不是不行,工具總是用來解決問題的,如果你的問題不是這個,那當然不用這麼麻煩。

那幹嘛要有這一個小節?

嗯.. 因為我想順便介紹說 nodejs20 版本之後新增了 --env-file 的參數,如果只是做簡單的 POC 之類的小東西也滿方便的 (當然他有些不足的地方,期望未來變得更好)

用法非常簡單,這樣你連 dotenv 都不用了: (記得把 require('dotenv').config() 移除)

$ node --env-file=.env main.js

你一樣會看到 123456 這個值。

而且這樣 Windows 也解脫了


結論

這篇文章主要是介紹如何保護你的環境變數,這樣的話就不用擔心環境變數被拿走,然後可以接著整合 CI 平台,就可以安全的切換你的環墋變數。

希望我的推播(通知)功能正常




最後更新時間: 2024年11月08日.