開発環境と本番環境の分離と設定管理環境ごとの設定ファイル(DB接続情報など)の安全な切り替え。
DB接続情報やAPIキーなどの「機密情報」を安全に扱うことは、バックエンド開発において最も重要なスキルのひとつです。「コードと設定を切り離す(Twelve-Factor Appの原則)」という考え方を軸に、具体的な実践方法を解説します。
1. なぜ環境を分離し、設定を切り替えるのか?
最大の目的は 「事故の防止」 と 「情報の保護」 です。
- 事故防止: 開発中に誤って本番用データベースのデータを削除(DROP)してしまうのを防ぐ。
- 情報保護: 本番環境のパスワードが開発者のローカルPCやGitHub上に残らないようにする。
2. Goにおける設定管理のベストプラクティス
Goでは、「環境変数(Environment Variables)」 を使って設定を注入するのが標準的なスタイルです。
① 基本:os.Getenv を使う
標準ライブラリだけで完結する方法です。
package main
import (
"fmt"
"os"
)
func main() {
// 環境変数から取得。なければデフォルト値を設定
dbUser := os.Getenv("DB_USER")
if dbUser == "" {
dbUser = "user_dev"
}
fmt.Println("DB User:", dbUser)
}
② ローカル開発:.env ファイルの活用
ローカル環境では、環境変数をいちいちコマンドラインで打つのは大変です。そこで、.env ファイルに設定を書き込み、アプリ起動時に読み込む手法がよく取られます。
- よく使われるライブラリ例: joho/godotenv
-
注意点:
.envファイルは絶対にGitにコミットしてはいけません!
【重要】.gitignoreの設定
.gitignoreに必ず以下を追記してください。.env代わりに、設定項目のテンプレートとして
.env.example(値は空にする)をコミットするのが一般的です。
3. 設定管理手法の比較
プロジェクトの規模に応じて、以下のいずれかを選択します。
| 手法 | 適した環境 | メリット | デメリット |
|---|---|---|---|
| 環境変数 | コンテナ/クラウド | セキュリティが高く、標準的 | 変数が多いと管理が煩雑 |
| .envファイル | ローカル開発 | 簡単に設定を切り替えられる | 本番環境での利用は非推奨 |
| シークレットマネージャー | 大規模・本番環境 | 非常に安全。一元管理が可能 | AWS/GCP等のクラウド依存 |
4. 本番環境での安全な切り替え(クラウド・コンテナ)
本番環境では、設定ファイルをサーバーに置くのではなく、インフラ側から「注入」します。
-
Docker/Kubernetes:
docker-compose.ymlや K8sのConfigMap / Secret機能を使って、実行時に環境変数を渡します。 - クラウドサービス:
- AWS Secrets Manager / Parameter Store
-
Google Cloud Secret Manager
これらのサービスを使うと、Goアプリが起動する際にAPI経由で最新のパスワードを安全に取得できます。
初心者が守るべき「鉄の掟」
- パスワードをコードに書かない:
const DB_PASS = "12345"と書いた瞬間、それは脆弱性になります。- 本番と開発で鍵を分ける: 開発で使うパスワードは「password」、本番は「複雑なランダム文字列」にする。
- 間違えてコミットしたら「漏洩」とみなす: もし秘密情報をGitHubにプッシュしてしまったら、すぐにパスワードを変更(無効化)してください。履歴を消すだけでは不十分です。
プロジェクトに .env ファイルを導入し、godotenv で読み込む処理を実装する流れ
実際に joho/godotenv を使って、プロジェクトに設定管理を導入する手順を4つのステップで解説します。
エンジニアとして「実務で使える」構成にしていきましょう!
ステップ1:ライブラリのインストール
ターミナルでプロジェクトのディレクトリに移動し、ライブラリをインストールします。
go get github.com/joho/godotenv
ステップ2:設定ファイル(.env)の作成
プロジェクトのルートディレクトリ(main.go がある場所)に、2つのファイルを作成します。ここが セキュリティ上の最重要ポイント です。
① .env (本物の秘密情報:自分だけが持つ)
DB_USER=myuser
DB_PASSWORD=supersecretpassword
API_KEY=abcdef123456
② .env.example (テンプレート:GitHubにコミットする)
値は空にするか、ダミーを入れておきます。これにより、他の開発者が「どの項目が必要か」分かります。
DB_USER=
DB_PASSWORD=
API_KEY=
ステップ3:.gitignore の設定(絶対に忘れない!)
.env を誤ってGitHubにアップロードしないよう、.gitignore ファイルに追記します。
# .gitignore への追記
.env
※ .env.example はGitに含めてOKです。
ステップ4:Goで読み込む処理を書く
次に、main.go でこれらを読み込むコードを書きます。
package main
import (
"fmt"
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
// 1. .envファイルを読み込む
// ファイルが存在しなくてもエラーにならないように、ローカル開発時のみ読み込むのが一般的です
err := godotenv.Load()
if err != nil {
// 本番環境(.envがない環境)ではエラーを出さず、OSの環境変数をそのまま使う
log.Println(".env file not found. Using system environment variables.")
}
// 2. os.Getenv で値を取得する
dbUser := os.Getenv("DB_USER")
dbPass := os.Getenv("DB_PASSWORD")
apiKey := os.Getenv("API_KEY")
// 3. 取得した値を使う(セキュリティのためパスワードは出力しないように!)
fmt.Printf("Starting server with user: %s\n", dbUser)
if apiKey == "" {
log.Fatal("API_KEY is not set!")
}
// DB接続処理などが続く...
}
知恵:なぜ godotenv.Load() のエラーを無視するのか?
実務のコードでは、err != nil でも log.Fatal(プログラム停止)にしないことが多いです。
-
ローカル開発:
.envを読み込んで環境変数をセットする。 -
本番環境(Docker/AWSなど): クラウド側の設定で環境変数が既にセットされているため、
.envファイル自体を置きません。そのためLoad()は失敗しますが、OSの環境変数は取れるので問題なく動きます。
ネクストアクション
これで「秘密情報をコードに書かない」仕組みができました。
もし、設定項目が10個、20個と増えてきたら、os.Getenv を何度も書くのは大変です。そんな時は、前にお話しした envconfig を使って、これらを一気に 「構造体」 に流し込む手法のステップアップするのをおすすめされることが多いようです。