0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

.npmrc と kubeconfig を、まだ手で渡している ── ファイルごと配る push と、commit の前に止める scan

0
Last updated at Posted at 2026-11-04

.npmrc と kubeconfig を、まだ手で渡している ── ファイルごと配る push と、commit の前に止める scan

上原正吉(EarthLink Network Co., Ltd.)。AI会社・AI社員による業務自動化と、人の逐次介入なしに24時間自動開発を回す仕組みを自社で実践しています。開発ノウハウと具体的な設定方法、運用して分かった改善点を公開しています。

.npmrc と kubeconfig を、まだ手で渡している ── ファイルごと配る push と、commit の前に止める scan

この記事は、連載「dotvault の使い方 ── .env を手で配るのをやめ、CI・チーム・AI エージェントに 1 コマンドで配るまで」の第 5 回です。この連載が終わる時に、dotvault を誰でも無料で使える形で公開する予定です。

新しい人が入った日に、Slack の DM で .npmrc を送る。社内の npm registry のトークンが入ったファイルです。.env は dotvault のような置き場に移しても、.npmrc は手で渡したまま、ということはよくあります。kubeconfig も同じです。クラスタに入るための認証情報が、誰かのノート PC の ~/.kube/config から、別の誰かの ~/.kube/config へ、コピーで渡っていきます。

「.env さえ管理すれば済む」と考えがちですが、key と値に分かれないファイルが、.env と同じくらいあります。そして、そういうファイルほど、うっかり commit に入ります。

この回で分かるのは、.npmrc や kubeconfig も 1 コマンドで預けて、受け取る側は .env と同じ pull か run で受け取れる、ということです。扱うのは、ファイルをそのまま配る dotvault push と、commit する前に secret の混入を見つける dotvault scan です。2 回目で作った demo-app に .npmrc と kubeconfig を push し、別のマシンで pull と run で受け取り、最後に、3 つの secret を含んだ commit を scan が止めるところまで進めます。

結論

  • key と値に分かれないファイルは dotvault push <ファイル> で登録します。 .npmrc、kubeconfig、YAML の設定のような、中身を丸ごと持ちたいテキストのファイルが対象です。4 回目の import や Upload タブは、ファイルの中の KEY=VALUE を 1 つずつ登録するもので、別の仕組みです。
  • 置き先と、環境変数での指し方を一緒に登録できます。 --as .kube/config で受け取る側の置き先を、--pointer KUBECONFIG で run の時に一時パスを入れる環境変数を指定します。.npmrc は何も指定しなくても NPM_CONFIG_USERCONFIG が付きました。
  • 受け取る側は dotvault pull か dotvault run です。 pull は .env と一緒に、push したファイルも置き先に書きます。run は一時ディレクトリに書いて環境変数を設定し、コマンドが終わると消します。pull --file は .env.local のような key のファイルを 1 つ受け取る指定です。
  • 画面の Files タブは、一覧・別の環境へのコピー・削除だけです。 追加とダウンロードは CLI からです。
  • dotvault scan . は、login しなくても動きます。 AWS のアクセスキー、GitHub のトークン、dotvault のトークンのような、形の決まった secret を探し、見つかれば終了コード 1 で止まります。.git/hooks/pre-commit から dotvault scan . を呼ぶと、commit が止まります。
  • scan は .env の中身の守りではありません。 素の .env の SMTP_PASSWORD=… は拾いません。.env を git に入れないのは .gitignore の仕事で、scan はコードや設定に紛れ込んだトークンを見るものです。

本文(読了 約13分)

前提

4 回目の続きで、demo-app の development に .env(5 key)と .env.local(1 key)がある状態から始めます。4 回目を読んでいなくても追えます。

1. key とファイルの違い

dotvault には、置き方が 2 つあります。

key ファイル
単位 名前と値の組(DATABASE_URL=…) ファイルの中身を丸ごと
登録 画面の + Add key / Upload、CLI の set / import CLI の push だけ
受け取り pull(.env などに書く)/ run(環境変数に入れる) pull(置き先に書く)/ run(一時ディレクトリに書いて pointer を設定)
画面 Keys タブ(見る・書く・消す) Files タブ(一覧・別の環境へコピー・消す。追加とダウンロードは不可)
変更の履歴 versions で一覧、rollback で前の値に戻す push のたびに変更の回数が 1 つ増える(画面の VERSION 列)
向くもの .env、.env.local、1 行ずつ意味のある設定 .npmrc、kubeconfig、YAML の設定(テキストのファイル)

.npmrc は KEY=VALUE の形をしていますが、//npm.pkg.github.com/:_authToken=… のような行は key の名前として扱いにくく、ファイルごと置く方が素直です。

2. ファイルを push する

demo-app のディレクトリで、.npmrc と ~/.kube/config を push します。

dotvault push の端末画面(再構成)。cat .npmrc で registry・@acme:registry・_authToken の 3 行、dotvault push .npmrc で「pushed .npmrc (v1) → .npmrc [run sets NPM_CONFIG_USERCONFIG] (project=demo-app, env=development)」、dotvault push ~/.kube/config --as .kube/config --pointer KUBECONFIG で「pushed .kube/config (v1) → .kube/config [run sets KUBECONFIG]」、dotvault files で .kube/config と .npmrc の 2 行(括弧に pointer の名前)。

出力の読み方です。pushed .npmrc (v1) → .npmrc は、「.npmrc という名前で v1 を登録し、受け取る側では .npmrc に書く」という意味です。[run sets NPM_CONFIG_USERCONFIG] は、run の時に NPM_CONFIG_USERCONFIG という環境変数に一時パスを入れる、という意味です。.npmrc には何も指定していません。よく使うファイルは、pointer が最初から決まっています。

kubeconfig は、置き先と pointer を自分で指定しました。--as .kube/config で、受け取る側の置き先を project のディレクトリの中の .kube/config に、--pointer KUBECONFIG で、run の時に KUBECONFIG を設定するようにしています。~/.kube/config のように project の外にあるファイルは、--as で置き先を、--pointer で環境変数を、こうして明示しておきます。

dotvault files で、この環境に登録されたファイルの一覧が出ます。「名前 → 置き先 (pointer)」の順です。同じファイルをもう一度 push すると v2 になります。

3. 画面の Files タブ

管理コンソールの project に Files タブがあります。push する前は空で、「Add one from the CLI with dotvault push」とだけ出ます。

demo-app の Files タブの空の状態(英語 UI)。環境の切り替え(development が選ばれている)、右に「Copy all files in this env…」のボタン、本文に「No files in this env yet. Add one from the CLI with dotvault push」。

ファイルの追加とダウンロードは CLI から行います(追加は push、受け取りは pull か run)。push した後に開くと、一覧になります。

push 後の Files タブ(英語 UI)。development (3) が選ばれ、FILE PATH・VERSION・UPDATED の表に .kube/config(1)・.npmrc(2)・cert.der(1)の 3 行。各行の右に Copy… と Delete のボタン。

表の cert.der は、9 節で push が text 専用であることを確かめるために入れたもので、この後で消します。.npmrc の VERSION が 2 なのは、撮影の途中で 1 行足してもう一度 push したからです。

「Copy all files in this env…」を押すと、別の環境へまとめてコピーする画面が出ます。

Copy all files in development… の画面(英語 UI)。Copy to の選択(staging)、「Overwrite files that already exist in staging」のチェック(外れている)、Cancel と Copy のボタン。

3 回目の Compare envs と同じ考え方です。コピー先に同じ名前のファイルがある時は、チェックを入れない限り上書きしません。この回では Cancel で閉じています(staging に何も作りたくないためです)。

行の Delete を押すと、ブラウザの確認(「Delete development/cert.der? This cannot be undone.」)が出て、OK で消えます。消した後は「Deleted development/cert.der.」の 1 行が出て、一覧が 2 行になります。

cert.der を消した後の Files タブ(英語 UI)。development (2) が選ばれ、表に .kube/config(1)と .npmrc(2)の 2 行。

4. 別のマシンで pull する

受け取る側です。project-config.json だけを置いた空のディレクトリで、dotvault pull を実行します。

別のディレクトリで dotvault pull した端末画面(再構成)。mkdir -p .kube の後の ls -la は .kube と project-config.json、dotvault pull で .env(5 keys)と .env.local(1 keys)の 2 行と「2 files synced, 0 excluded, 6 keys total」、ls -la で .env・.env.local・.npmrc が増え .npmrc は -rw-------、ls -la .kube で .kube の中に書かれた config、head -3 .kube/config で apiVersion: v1 / kind: Config / clusters:。

pull の出力に出るのは .env と .env.local の 2 行だけですが、ls -la を見ると .npmrc と .kube/config も書かれています。push したファイルは、pull のたびに、置き先に一緒に書かれます。新しく書かれたファイルのパーミッションは .env と同じ -rw-------(本人だけ読み書き)です。

最初の mkdir -p .kube が要る理由は、9 節で説明します。置き先のディレクトリが無いと、pull はファイルを書かずに、同じ出力を返します。

5. run で一時ディレクトリに書く

pull でファイルを置くと、そのマシンにファイルが残ります。CI や、短い作業なら、run の方が向いています。

dotvault run の端末画面(再構成)。dotvault run -- sh -c '…' で KUBECONFIG=/tmp の下の一時パスの config と、そのパスの ls -la(-rw-------・279 bytes)と head -3(apiVersion: v1 / kind: Config / clusters:)、終了後に同じパスを ls -la すると No such file or directory、2 つ目の run で NPM_CONFIG_USERCONFIG=/tmp の下の一時パスの .npmrc と npm config get @acme:registry で https://npm.pkg.github.com/。

run は、pointer のあるファイルを /tmp の下の一時ディレクトリに書き、pointer の環境変数にそのパスを入れて、コマンドを実行します。コマンドが終わると、一時ディレクトリごと消えます。2 つ目の ls -la が「No such file or directory」なのは、そのためです。

.npmrc の方は、npm config get @acme:registry が https://npm.pkg.github.com/ を返しています。push した .npmrc の 2 行目が、NPM_CONFIG_USERCONFIG 経由で npm に読まれています。project のディレクトリには .npmrc を置いていません。

pointer が無いファイル(9 節の cert.der のような、--pointer も既定の pointer も無いもの)は、run の間だけ置き先に書かれ、終わると消されます。手元に残したいファイルは、pull で受け取ります。

6. scan で secret の混入を見つける

ここからは、配る話ではなく、漏らさない話です。dotvault scan <パス> は、指定したファイルとディレクトリを読み、形の決まった secret を探します。サーバーには何も送りません。login していなくても動きます。撮影の最後に logout して(whoami が「Not logged in.」になる状態で)、secret を直した後のリポジトリに実行しても、login を求められずに「No secrets found.」が返りました。

試しに、3 つの secret を含むリポジトリを作りました。src/s3.js に AWS のアクセスキー、deploy.sh に GitHub のトークン、.github/workflows/ci.yml に dotvault のサービストークンです。node_modules の中にも、同じ AWS のキーを置いてあります。

dotvault scan の端末画面(再構成)。find . -type f | sort で 5 ファイル(node_modules/some-dep/index.js を含む)、dotvault scan . で .github/workflows/ci.yml:2 [dotvault-service-token]・deploy.sh:2 [github-pat]・src/s3.js:3 [aws-access-key-id] の 3 行(値は est_...ue (72 chars) のように先頭 4 文字と末尾 2 文字だけ)と「3 potential secret(s) found.」、echo $? で 1、dotvault scan src/ で 1 件、machine-b での dotvault scan . で「No secrets found.」と 0。

出力は「ファイル:行 [ルール名] 説明 — 値の一部」の形です。値は、先頭 4 文字と末尾 2 文字と文字数だけが出ます。端末の画面や CI のログに、secret そのものを出さないためです。node_modules の中のキーは出ていません。読まないディレクトリが決まっています(8 節)。

見つかると終了コード(コマンドが終わる時に返す数で、0 が成功)が 1、見つからなければ No secrets found. で 0 です。パスを複数渡せます(scan src/ tests/)。

7. commit の前に止める

git は、commit の直前に .git/hooks/pre-commit というファイルがあれば実行し、終了コードが 0 でなければ commit をやめます。scan は見つかると 1 を返すので、そこに置くだけで止まります。

pre-commit フックで commit が止まる端末画面(再構成)。cat .git/hooks/pre-commit で #!/bin/sh と exec dotvault scan . の 2 行、git add src deploy.sh .github .gitignore README.md && git commit で 6 節と同じ 3 件の検出と「3 potential secret(s) found.」、git log --oneline で「fatal: your current branch 'main' does not have any commits yet」、3 つの値を環境変数に置き換えてもう一度 git commit すると「No secrets found.」と「[main (root-commit) f2748e0] add deploy script」「5 files changed, 11 insertions(+)」。

フックの中身は 2 行です。

#!/bin/sh
exec dotvault scan .

1 回目の commit は、3 件を出して止まります。git log は「commits yet」で、何も記録されていません。3 つの値を process.env.AWS_ACCESS_KEY_ID や ${{ secrets.DOTVAULT_TOKEN }} に置き換えて、もう一度 commit すると通ります。

このフックは、ステージした差分ではなく、作業ツリー全体を読みます。.gitignore で外した .env も読むので、手元の .env に Stripe の本番 key のような形の決まった値があると、commit のたびに止まります。その時と、大きなリポジトリでは、exec dotvault scan src/ .github/ のように .env を含まない範囲に絞ります。チームで共有するなら、.git/hooks ではなく、lefthook や husky のようなフックの管理ツールの設定に同じ 1 行を書きます。

8. scan が見ているもの・見ていないもの

scan の検出は、形の決まった文字列との照合です。0.15.7 の CLI に入っている規則は 10 個です。

ルール名 探すもの
aws-access-key-id AKIA + 16 文字
aws-secret-access-key aws の近くに引用符で囲んだ 40 文字
private-key -----BEGIN PRIVATE KEY-----(RSA / EC / OPENSSH / DSA / PGP 付きも。ENCRYPTED PRIVATE KEY は対象外)
github-pat ghp_ + 36 文字
github-fine-grained-pat github_pat_ + 60 文字以上
slack-token xoxb- などで始まる文字列
stripe-secret-key sk_live_ + 24 文字以上
google-api-key AIza + 35 文字
dotvault-service-token est_ + 32 文字 + . + 20 文字以上
generic-assignment secret / token / password / passwd / api_key(api-key・apikey も)の後に = か : と、引用符で囲んだ空白なしの 16 文字以上(大文字小文字は区別しない)

読まないものも決まっています。

読まないもの 条件
ディレクトリ node_modules・.git・dist・build・.next・coverage・cdk.out・.turbo
大きいファイル 5MB を超えるもの
binary 先頭 8KB に NUL 文字があるもの

.gitignore は見ません。読まないディレクトリは名前で決まっています。

この 2 つの表は、公開されている CLI のコードを読んで書き、ディレクトリ・5MB・binary の 3 つは実測しました。6MB のテキストと、NUL 文字を含む 27 バイトのファイルの両方に AKIAIOSFODNN7EXAMPLE を入れて scan しても、No secrets found. です。

scan の限界の端末画面(再構成)。ls -la で big.txt(6000021 bytes)と blob.bin(27 bytes)、dotvault scan big.txt blob.bin で「No secrets found.」、cat .env で SMTP_PASSWORD=very-secret-mail-password-2026 と STRIPE_KEY=sk_live_demo…、cat docker-compose.yml で POSTGRES_PASSWORD: "${POSTGRES_PASSWORD_FROM_ENV}"、dotvault scan . で .env:2 [stripe-secret-key] と docker-compose.yml:4 [generic-assignment] の 2 件。

同じ画面の後半が、この回でいちばん伝えたいところです。.env に SMTP_PASSWORD=very-secret-mail-password-2026 と書いても、scan は拾いません。generic-assignment は引用符で囲んだ値だけを見るので、.env の素の書き方は対象外です。同じ .env の sk_live_… は、Stripe の形なので拾います。

つまり、scan は「.env を commit してしまう」事故を止めるものではありません。それは .gitignore に .env を書く仕事です。scan が止めるのは、コードや CI の設定や Dockerfile に、形の決まったトークンを直に書いてしまう事故です。

逆に、docker-compose.yml の POSTGRES_PASSWORD: "${POSTGRES_PASSWORD_FROM_ENV}" は、値ではなく環境変数の参照ですが、引用符の中が 16 文字以上なので拾われています。この形の時は、pre-commit で渡すパスをそのファイルを含まない範囲に絞るか、引用符を外します。

9. うまくいかない時の出力

この回で出た失敗と、その時の出力と終了コードをまとめます。

うまくいかない時の端末画面(再構成)。rm -rf .kube .npmrc && dotvault pull で 4 節と同じ 2 行と「2 files synced」、ls -la .npmrc .kube で両方 No such file or directory、dotvault pull --file .kube/config で「unexpected: Invalid env file name: ".kube/config"」と 99、dotvault pull --file .npmrc で PROJECT_NOT_FOUND(server: No DDB secrets for .npmrc)と 5、dotvault push .yarnrc で VALIDATION_ERROR(Could not read .yarnrc: ENOENT)と 6、dotvault files --env staging で「No files synced.」、dotvault scan nope/ で「No secrets found.」と 0。

操作 出力 終了コード
置き先のディレクトリ(.kube)が無い状態で pull .env の 2 行と「2 files synced」だけ。.npmrc も .kube/config も書かれない 0
pull --file .kube/config unexpected: Invalid env file name 99
pull --file .npmrc PROJECT_NOT_FOUND(server: No DDB secrets for .npmrc) 5
push .yarnrc(無いファイル) VALIDATION_ERROR(Could not read … ENOENT) 6
files --env staging(ファイルの無い環境) No files synced. 0
scan nope/(無いパス) No secrets found. 0

1 行目が、4 節で mkdir -p .kube をした理由です。置き先にディレクトリを含めるファイルは、受け取る側でそのディレクトリを先に作っておきます。無い時は、push したファイルはどれも書かれません(.kube/config の後の .npmrc も書かれていません)。「2 files synced」の 2 は .env と .env.local の数で、push したファイルは数に入らないので、受け取れたかは ls で確かめます。

2 行目と 3 行目は、push したファイルに pull --file を使った時の出力です。pull --file は .env.local のような key のファイルを 1 つ受け取る指定です。push したファイルは、pull(全部)か run で受け取ります。

最後の行は、パスを打ち間違えても「No secrets found.」で 0 が返る、という出力です。pre-commit に scan src/ と書いて src が無ければ、常に通るので、pre-commit に書くパスは、リポジトリにあるディレクトリかを確かめておきます。

もう 1 つ、push はテキストのファイル用です。

binary を push した端末画面(再構成)。od -c cert.der で 211 P N G で始まる 16 バイト、dotvault push cert.der で「pushed cert.der (v1) → cert.der」、dotvault run -- sh -c 'od -c cert.der …' で先頭が 357 277 275 P N G に変わり 18 バイト、run の中の ls -la cert.der で 18 バイト。

PNG の先頭 1 バイト(0x89)が、文字コードの置き換え文字(3 バイト)に変わっています。push はファイルを文字列として読むので、DER 形式の証明書のような binary は、そのままでは配れません。

次回

6 回目は、複数の project で同じ値を使う key を 1 か所に置き、project ごとに結び付ける Global Keys を、画面と CLI の global で進めます。


dotvault は、.env や設定ファイルの secret をサーバー側に置き、権限のある人・CI・AI エージェントが 1 コマンドで受け取るサービスです(https://dotvault.io)。この連載が終わる時に、dotvault を誰でも無料で使える形で公開する予定です。公開したら、この連載の手順どおりに使い始められます。

興味のある方は、ぜひ「いいね」と記事の購読をお願いいたします。

自社プロダクトは https://www.eln.ne.jp/products にまとめています。

筆者について

上原正吉。EarthLink Network Co., Ltd. 代表。AI社員に日々の業務を任せ、開発では人が逐一指示しなくても作業が進むHOOTL(Human Out Of The Loop)の仕組みを自社で実践しています。このブログでは、業務自動化と24時間自動開発のノウハウ、具体的な設定方法、日々の運用で見つかった問題と改善を共有します。

また、AIで業務や開発を組み替えたい会社・チーム向けに、AI活用のコンサルティングも受け付けています。ご相談は www.eln.ne.jp からどうぞ。


EarthLink Network は、会社の全業務を AI で回すために、必要になったものを自社で作っています。いま作っているプロダクトの一覧と概要は、こちらにまとめています。

→ EarthLink Network が自社でつくっている18のプロダクト

会社と各プロダクトの詳細は、公式サイト www.eln.ne.jp をご覧ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?