この記事はスタンバイ アドベントカレンダー2025の23日目の記事です。
昨日は、@taaaogi さんの記事でした。
はじめに
初めまして。スタンバイで検索エンジニアをやっている@mick-azです。
アドベントカレンダーの記事に何を書こうか考えているうちに年末が近づいてきました。
今日は23日なのでクリスマスのほうが近いですが、少しフライングして大掃除の話をさせてください。
棚の奥とか換気扇とか、普段は見て見ぬふりをしている場所が気になる季節です。開発環境にも似たような場所があります。私にとっては .env ファイルがそれにあたります。
.env ファイルは手軽で、多くの場面で十分に機能します。ただ、プロジェクトが増えてくると、ちょっとした不便が積み重なっていきます。どのプロジェクトにどの API キーを使っていたか分からなくなる、ローテーションのタイミングを逃す、新しい環境変数を追加したときにチームへの共有が漏れる。致命的ではないけれど、なんとなく気になり続ける類の問題です。
少し前に Secret 管理ツールの Doppler を試していたので、改めて整理しつつ記事にまとめてみます。
公式ドキュメント: https://docs.doppler.com/docs
Doppler を試してみた理由
クラウドプロバイダーのSecret 管理サービス(AWS Secrets Manager、Google Cloud Secret Managerなど)は機能が充実していますが、IAM の設計やTerraform での記述など、導入の準備がそれなりに必要です。
もう少し手軽に試せるものを探していて見つけたのがDoppler でした。SaaS として完結していて、CLI をインストールすればdoppler run -- npm startで環境変数が注入される。.envファイルを作らなくていいので、「このキー、どの.envに書いたっけ」がなくなります。
Development、Staging、Productionと環境ごとにSecret を管理でき、Web UI で一覧できるのも便利でした。どこに何があるか、把握しやすくなります。
セットアップ
導入は数分で終わります。
# macOS(gnupgはバイナリ署名検証に必要)
brew install gnupg
brew install dopplerhq/cli/doppler
# Linux(Shell Script)
curl -Ls --tlsv1.2 --proto "=https" --retry 3 https://cli.doppler.com/install.sh | sudo sh
補足: Homebrew でのインストールは自動更新がサポートされていません。更新は
doppler updateで手動実行するか、Shell Scriptでのインストールを検討してください。
他のOS・パッケージマネージャーについては公式のインストールガイドを参照してください。
認証してプロジェクトを選択すれば準備完了です。
doppler login
doppler setup # 対話形式でプロジェクトと環境を選択
あとはdoppler runを経由してコマンドを実行するだけで、環境変数が注入されます。
doppler run -- npm start
doppler run -- python main.py
基本的なワークフロー
プロジェクトの構造
Doppler ではプロジェクトの中に環境(Config)を持つ構造になっています。
my-app/
├── dev # 開発環境
├── stg # ステージング環境
└── prd # 本番環境
各環境に同じキー名で異なる値を設定できるので、DATABASE_URLのような変数を環境ごとに切り替えるのが簡単です。
CLIでの操作
# Secret の一覧を表示
doppler secrets
# 特定のSecret を取得
doppler secrets get DATABASE_URL
# Secret を設定(対話モード、値がシェル履歴に残らない)
doppler secrets set API_KEY
# 複数まとめて設定
doppler secrets set API_KEY=xxx ANOTHER_KEY=yyy
# .envファイルからインポート(JSON、YAML も可)
doppler secrets upload .env
詳細はCLIガイドおよびSecretsの設定ガイドを参照してください。
ローカル開発での使い方
プロジェクトルートでdoppler setupを実行しておけば、そのディレクトリでは設定した環境が使われます。チームで開発している場合、各メンバーが自分の担当環境を選択できます。
# プロジェクトルートで一度だけ実行
doppler setup
# → プロジェクト: my-app
# → 環境: dev
# 以降は doppler run で環境変数が注入される
doppler run -- npm run dev
便利だった機能
Secret参照
同じ値を複数のSecret で使いたいとき、参照機能が使えます。Web UI で${DATABASE_HOST}のように書くと、他のSecret の値を参照できます。
DATABASE_HOST = db.example.com
DATABASE_URL = postgres://user:pass@${DATABASE_HOST}:5432/mydb
JDBC_URL = jdbc:postgresql://${DATABASE_HOST}:5432/mydb
アプリケーションやライブラリによって、期待される環境変数名や接続文字列のフォーマットは異なります。Pythonのpsycopg2 はDATABASE_URLを、JavaのJDBC ドライバはJDBC_URLを期待する、といった具合です。ホスト名自体は同じでも、それを埋め込む形式がサービスごとに違うため、複数のSecret を用意せざるを得ません。
参照機能を使えば、ホスト名の変更時にDATABASE_HOSTだけを更新すれば済みます。各接続文字列を個別に編集する必要がなくなり、変更漏れを防げます。
補足: 同一Config 内の参照は無料のDeveloper プランでも利用できます。プロジェクト間やConfig 間での参照(
${project.config.SECRET_NAME}形式)は有料プランが必要です。
詳細はReferencing Secretsを参照してください。
変更履歴とロールバック
誰がいつ何を変更したかがActivity Logに残ります。Datadog、Slack、Discord、Microsoft Teamsなど主要なサービスとの連携があり、変更通知を受け取ることもできます。
試していませんが、Enterprise プランでは、Access Logsで、誰がいつSecret を読み取ったかまで追跡できるようです。漏洩が発生した際の影響範囲の特定にも役立ちます。
誤った変更をしてしまったときも、Web UI から以前のバージョンにロールバックできます。
CI/CDとの連携
GitHub Actions では、Doppler公式のAction を使うのが簡単です。事前にDoppler ダッシュボードでService Token を作成し、GitHub リポジトリのSecretsにDOPPLER_TOKENとして登録しておきます。
- name: Fetch secrets
uses: dopplerhq/secrets-fetch-action@v1
id: doppler
with:
doppler-token: ${{ secrets.DOPPLER_TOKEN }}
補足: Service Token は作成時に特定のプロジェクトとConfig に紐づくため、Action 側での指定は不要です。複数のプロジェクトやConfig にアクセスする必要がある場合は、Service Account Token を使用し、
doppler-projectとdoppler-configを明示的に指定します。
また、例えば、VercelやCloudflareなど特定のサービスとの連携はWeb UI からワンクリックで設定できます。Doppler で値を変更すると自動的にVercel 側にも反映されるので、両方のダッシュボードを行き来する必要がなくなります。
その他の連携についてはIntegrations一覧を参照してください。
.envファイルとの連携
既存の.envファイルがあれば、そのままインポートできます。
doppler secrets upload .env
逆に、Dopplerから.env形式で出力することもできます。Doppler 未対応のツールやローカルでの一時的な検証に便利です。
doppler secrets download --no-file --format env > .env
ただし、.envファイルはSecret が平文で保存されるため、出力したら検証後に削除するなど取り扱いには注意が必要です。
また、.envを読み込む既存のコードを変更せずにDoppler を試すこともできます。--mountオプションを使うと、Doppler が一時的な.envファイルを作成し、プロセス終了時に自動で削除してくれます。
doppler run --mount .env -- npm run dev
既存プロジェクトにDoppler を導入する際、コードを変更せずに試せるので、移行のハードルが下がります。うまくいったら.env読み込みのコードを削除すればよいですし、合わなければDoppler をやめるだけで済みます。
Developer プランでも環境変数の数や API コール数に制限はなく、個人で数プロジェクト回す程度なら問題なかったため、気軽に試すことができました。
SecretOps という補助線
Doppler の公式ブログに、こんな記事がありました。
From Chaos to Control: Transform Your Secrets Workflow with SecretOps
要約すると、Secret は設定ファイルではなくライフサイクルを持つ運用対象であり、保管・アクセス制御・配布・ローテーション・監視まで含めて設計すべきだ、という話です。
言われてみれば当たり前なのですが、普段の.env運用では「作成」と「利用」しか意識する機会はあまりないため、ローテーションや失効は、問題が起きてから対処する形になりがちです。
Secret や環境変数の扱いについては、以前から「もっと良いやり方はないものか」と思っていました。重複管理の煩わしさ、誰がなにを使っているのか、どこに何があるか分からなくなる問題。SecretOps という言葉は、その漠然とした感覚に補助線を引いてくれた気がします。
おわりに
今回は基本的な機能を中心に紹介しましたが、Doppler には他にも気になる機能があります。開発者ごとに設定を上書きできる Personal Configs、ブランチ単位で環境を切れる Branch Configs、自動ローテーション、Webhook 連携など。動的シークレット(AWS IAM の一時クレデンシャル発行など)は Enterprise プラン限定ですが、大規模運用では魅力的です。
doppler使ってみた感想としては、導入の手軽さが印象的でした。CLI をインストールして doppler run するだけで、.env ファイルを意識しなくてよくなる。既存プロジェクトでも --mount オプションでコードを変えずに試せるので、移行のハードルが低いのも良かったです。
SecretOps という考え方を知って、漠然と感じていた「もっと良いやり方があるはず」が少なからず言語化できました。Infisical や HashiCorp Vault など他のソリューションも、いずれ触ってみたいと思っています。
年末の大掃除、皆さんも開発環境で気になっている場所はありませんか。
明日は@taca10さんの記事です。お楽しみに!