0.1.0 は登録済みで同一バージョンは再発行されないため、スキーマ解決エラーの 修正を届けるパッチリリース。挙動・設定項目の変更なし。
secret-manager
クラスター内の複数プロジェクトで横断的に使う 認証情報(Secrets)を一元管理 する Helm チャートです。
外部メールの SMTP/IMAP 設定、外部 API の認証キー、その他の汎用資格情報を 1 箇所(この
チャートの values.yaml)で定義し、指定した 複数のネームスペースへ同一の Kubernetes
Secret として配布 します。
設計目標 — 認証情報の変更が発生したら、このチャートの values を更新して
helm upgradeするだけで、クラスター上の全プロジェクトに反映される。
- Gitea リポジトリ:
ssh://git@192.168.9.65/helmchart/secret-manager - Helm リポジトリ:
https://git.cafepieters.com/api/packages/helmchart/helm
目次
- なぜ必要か
- 仕組み
- セキュリティモデル
- インストール
- values リファレンス
- 生成される Secret の構造
- 他プロジェクトからの参照方法
- 代表的なメールプロバイダの設定値
- 変更の反映(伝播)とライフサイクル
- 自動化ワークフロー(Gitea Actions)
- reflector / Reloader 連携
- トラブルシューティング
なぜ必要か
Kubernetes の Secret は ネームスペース単位 です。同じ SMTP パスワードや API キーを 10 個のプロジェクトで使う場合、通常は 10 個のネームスペースそれぞれに Secret を作り、 変更のたびに 10 箇所を更新することになります。
このチャートは「認証情報の定義」を 1 リポジトリに集約し、配布はチャートに任せます。 パスワードローテーションやエンドポイント変更は このチャートの 1 回の更新 で全体に 行き渡ります。
仕組み
値の定義(1箇所)
┌──────────────────────────────┐
│ secret-manager / values.yaml│
│ mail.providers.gmail │
│ api.credentials.stripe │
│ generic.secrets.registry │
└───────────────┬──────────────┘
│ helm upgrade
┌───────────────┼───────────────┐
▼ ▼ ▼
ns: web ns: batch ns: ml
Secret cred-gmail Secret cred-... Secret cred-...
Secret cred-stripe ...
- 1 つの論理エントリ(
mail.providers.gmailなど)から、配布先ネームスペースの数だけ 同名の Secret が生成されます(common.namePrefix+ エントリ名)。 - 配布方式は 2 通り。既定は Helm による複製(外部依存なし)。オプションで kubernetes-reflector による自動同期 も選べます。
セキュリティモデル
この values.yaml には平文の資格情報を書かないでください。Git にコミットしないでください。
Kubernetes の Secret は etcd 上では base64 で「エンコード」されているだけで「暗号化」では
ありません。同様に Helm values に平文で書けば、それが Git・CI ログ・Helm リリース履歴
(helm get values)に残ります。実値は次のいずれかで注入します。
| 方法 | 用途 | 例 |
|---|---|---|
CI から --set / --set-file |
Gitea Actions が Gitea Secrets を注入(推奨) | --set mail.providers.gmail.smtp.password="$GMAIL_APP_PASSWORD" |
| SOPS 暗号化 values | 暗号化したまま Git 管理したい場合(helm secrets プラグイン) |
helm secrets upgrade -f secrets.enc.yaml ... |
| git 管理外の values ファイル | 手元運用 | -f secrets.values.yaml(.gitignore 済み) |
追加の推奨:
- etcd の保存時暗号化(EncryptionConfiguration) をクラスターで有効化する。
- 配布先を必要なネームスペースだけに絞る(
distribution.namespacesを最小化、またはreflector.namespaceRegexで限定)。defaultへの配布は避ける。 - 変更頻度が低い資格情報は
common.immutable: trueにして誤更新を防ぐ。 - Secret を参照する RBAC(
get secrets)を各ネームスペースで最小権限に保つ。 - このチャートは Secret 以外のリソース(Deployment 等)を一切作りません。監査が容易です。
インストール
# Helm リポジトリ経由
helm repo add cafepieters https://git.cafepieters.com/api/packages/helmchart/helm
helm repo update
helm upgrade --install secrets cafepieters/secret-manager \
-n secret-manager --create-namespace \
-f my-secrets.values.yaml
# ローカルのチャートディレクトリから
helm upgrade --install secrets ./secret-manager \
-n secret-manager --create-namespace \
-f examples/mail-providers.values.yaml \
--set mail.providers.gmail.smtp.password="$GMAIL_APP_PASSWORD" \
--set mail.providers.m365.smtp.password="$M365_PASSWORD"
配布先ネームスペース(
distribution.namespaces)は 事前に存在している必要があります。
values リファレンス
distribution — 配布先
| キー | 型 | 既定 | 説明 |
|---|---|---|---|
distribution.namespaces |
[]string |
["default"] |
同一 Secret を複製配置するネームスペース。リストから外して helm upgrade すると、そのコピーは削除される。 |
distribution.includeReleaseNamespace |
bool |
true |
リリース先ネームスペース(-n の値)も配布対象へ自動追加する。 |
distribution.reflector.enabled |
bool |
false |
kubernetes-reflector による自動同期を使う。有効時、Secret はリリース先のみに作成し reflector アノテーションを付与する。 |
distribution.reflector.namespaceRegex |
string |
".*" |
同期先ネームスペースを絞る正規表現。例 "prod-.*|shared-services"。 |
distribution.reloader.enabled |
bool |
false |
各 Secret に reloader.stakater.com/match: "true" を付与。参照側 Deployment に reloader.stakater.com/auto: "true" があれば Secret 変更時に自動ローリング再起動される。 |
common — 共通設定
| キー | 型 | 既定 | 説明 |
|---|---|---|---|
common.namePrefix |
string |
"cred-" |
生成される Secret 名のプレフィックス。cred- + gmail → cred-gmail。 |
common.labels |
map |
{} |
全 Secret に付与する追加ラベル。 |
common.annotations |
map |
{} |
全 Secret に付与する追加アノテーション。 |
common.immutable |
bool |
false |
Secret を immutable: true にする。値変更には一度 kubectl delete secret が必要。 |
mail — 外部メール接続情報
mail.providers.<名前> ごとに 1 つの Secret を生成します。パスワードだけでなく
SMTP/IMAP/POP3 のサーバ情報も一元管理 できます。
| キー | 型 | 必須 | 説明 |
|---|---|---|---|
enabled |
bool |
✓ | true で生成対象。 |
smtp.host |
string |
✓ | SMTP サーバホスト名。 |
smtp.port |
int |
既定 587。 |
|
smtp.security |
string |
none / starttls(既定) / tls。 |
|
smtp.username |
string |
認証ユーザー名。空なら認証なし。 | |
smtp.password |
string |
認証パスワード。--set / SOPS で注入。 |
|
smtp.from |
string |
既定送信元アドレス。省略時は username。 |
|
smtp.fromName |
string |
送信者表示名。 | |
smtp.replyTo |
string |
Reply-To アドレス。 | |
smtp.authMethod |
string |
plain(既定) / login / cram-md5。 |
|
imap.host ほか |
受信 (IMAP) 情報。host があれば IMAP_* キーを追加。username/password 省略時は SMTP の値を流用。既定ポート 993。 |
||
pop3.host ほか |
受信 (POP3) 情報。同上。既定ポート 995。 |
||
renderMsmtprc |
bool |
true で Secret に msmtprc(msmtp / PHP sendmail 用設定)を含める。 |
|
namespacesOverride |
[]string |
このエントリだけ別のネームスペースへ配布する。 | |
annotations |
map |
このエントリの Secret だけに付ける追加アノテーション。 |
api — API 認証情報
api.credentials.<名前> ごとに 1 つの Opaque Secret を生成します。data 配下のキーが
そのまま Secret のキーになります(envFrom でまとめて注入しやすい形)。
| キー | 型 | 必須 | 説明 |
|---|---|---|---|
enabled |
bool |
✓ | true で生成対象。 |
data |
map |
✓ | 1 つ以上のキー/値。値は文字列化される。 |
namespacesOverride |
[]string |
配布先の上書き。 | |
annotations |
map |
追加アノテーション。 |
generic — 汎用 Secret
generic.secrets.<名前> ごとに 1 つの Secret を生成します。任意の Secret type を
指定できます(kubernetes.io/dockerconfigjson、kubernetes.io/tls、
kubernetes.io/basic-auth など)。
| キー | 型 | 必須 | 説明 |
|---|---|---|---|
enabled |
bool |
✓ | true で生成対象。 |
type |
string |
Secret の type。既定 Opaque。 |
|
data |
map |
✓ | 1 つ以上のキー/値。kubernetes.io/tls なら tls.crt / tls.key を入れる。 |
namespacesOverride |
[]string |
配布先の上書き。 | |
annotations |
map |
追加アノテーション。 |
生成される Secret の構造
mail エントリ(例: cred-gmail)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=no-reply@example.com
SMTP_PASSWORD=********
SMTP_FROM=no-reply@example.com
SMTP_FROM_NAME=Example
SMTP_REPLY_TO=
SMTP_AUTH_METHOD=login
IMAP_HOST=imap.gmail.com # imap 定義時のみ
IMAP_PORT=993
IMAP_SECURITY=tls
IMAP_USERNAME=no-reply@example.com
IMAP_PASSWORD=********
smtp.env # ↓ source して使える env ファイル
export SMTP_HOST="smtp.gmail.com"
export SMTP_PORT="587"
...
msmtprc # renderMsmtprc: true のとき。msmtp / PHP sendmail 用
api / generic エントリ
data に書いたキーがそのまま Secret のキーになります。
他プロジェクトからの参照方法
配布先ネームスペースにいる Deployment から、通常の Secret として参照します。 このチャートに依存関係を張る必要はありません(Secret が既にそのネームスペースにある)。
# まとめて環境変数へ(api / generic 向き)
envFrom:
- secretRef:
name: cred-stripe
# 個別キーを参照(mail 向き)
env:
- name: SMTP_HOST
valueFrom: { secretKeyRef: { name: cred-gmail, key: SMTP_HOST } }
- name: SMTP_PASSWORD
valueFrom: { secretKeyRef: { name: cred-gmail, key: SMTP_PASSWORD } }
# env ファイル / msmtprc をファイルとしてマウント
volumes:
- name: smtp
secret:
secretName: cred-gmail
items:
- { key: smtp.env, path: smtp.env }
- { key: msmtprc, path: msmtprc, mode: 0600 }
volumeMounts:
- { name: smtp, mountPath: /etc/smtp, readOnly: true }
# コンテナ起動時に env ファイルを読み込む例
set -a; . /etc/smtp/smtp.env; set +a
helmchart/phpfpm チャートと組み合わせる場合は、phpfpm 側の phpEnv や既存の SMTP
セクションに、ここで配布した cred-* Secret を secretKeyRef で渡してください。
代表的なメールプロバイダの設定値
| プロバイダ | SMTP host | port | security | username | 備考 |
|---|---|---|---|---|---|
| Gmail / Google Workspace | smtp.gmail.com |
587 | starttls | メールアドレス | 2 段階認証 + アプリ パスワードが必要 |
| Microsoft 365 | smtp.office365.com |
587 | starttls | メールアドレス | SMTP AUTH の有効化が必要な場合あり |
| SendGrid | smtp.sendgrid.net |
587 | starttls | apikey(固定) |
password が API キー本体 |
| Amazon SES | email-smtp.<region>.amazonaws.com |
587 | starttls | SES SMTP 認証情報 | IAM キーとは別物。要リージョン |
| Mailgun | smtp.mailgun.org |
587 | starttls | postmaster@mg.<domain> |
|
| 社内 SMTP リレー | クラスター内 Service 等 | 25 | none | (なし) | 認証・TLS なし構成 |
IMAP 受信の代表値: Gmail imap.gmail.com:993/tls、M365 outlook.office365.com:993/tls。
そのまま使えるサンプル: examples/mail-providers.values.yaml、
examples/api-and-generic.values.yaml、
examples/reflector.values.yaml。
変更の反映(伝播)とライフサイクル
- 値の変更 — values を更新して
helm upgradeすると、全配布先の Secret が同時に 更新されます。実行中の Pod の環境変数は再起動するまで変わりません。ファイル マウント(smtp.env等)は数十秒〜で更新されます。自動再起動が必要ならdistribution.reloader.enabled: true+ 参照側の Reloader アノテーションを使います。 - 配布先の追加 —
distribution.namespacesに足してhelm upgrade。 - 配布先の削除 —
distribution.namespacesから外してhelm upgradeすると、 そのネームスペースのコピーは Helm が削除します。 - エントリの削除 —
enabled: falseにするか、エントリごと削除してhelm upgrade。 全ネームスペースから当該 Secret が削除されます。 - アンインストール —
helm uninstallで、このチャートが作った全ネームスペースの Secret が削除されます。
reflector / Reloader 連携
kubernetes-reflector(配布の自動化)
ネームスペースが頻繁に増減する環境では、distribution.namespaces の列挙が手間になります。
emberstack/kubernetes-reflector を
クラスターに導入し、distribution.reflector.enabled: true にすると、Secret はリリース先
ネームスペースにのみ作られ、namespaceRegex に一致する全ネームスペースへ reflector が
複製・追従します。
distribution:
namespaces: []
reflector:
enabled: true
namespaceRegex: "prod-.*|shared-services"
stakater/Reloader(参照側の自動再起動)
stakater/Reloader 導入済みなら
distribution.reloader.enabled: true で各 Secret に reloader.stakater.com/match: "true"
が付きます。参照側 Deployment に reloader.stakater.com/auto: "true" を付けておくと、
Secret 更新時に自動でローリング再起動されます。
自動化ワークフロー(Gitea Actions)
.gitea/workflows/helm-release.yaml の 1 本のみ。main への push(Chart.yaml /
values.yaml / values.schema.json / templates/** 変更時)と手動実行で発火し、
helm lint --strict → 現在の version が Package Registry に未公開のときだけ
リリースする(公開済みなら何もしない。README・examples だけの変更ではリリースされない)。
リリース内容は Package Registry への発行 + Git タグ v<version> + Gitea リリース
(.tgz 添付)。
上流イメージの週次自動追従は行わない — 他チャート(phpfpm・n8n 等)は
image-update-and-release.yamlで Docker Hub の最新イメージを毎週チェックしバージョンを 自動採番するが、secret-manager は Secret を生成するだけで追従対象の上流イメージが 無いため、このワークフロー自体を持たない。バージョンは常に手動でChart.yamlを更新する。
新しいバージョンを出す手順: Chart.yaml の version と appVersion を上げて
main に push するだけ。あとは helm-release.yaml がリリースする。
必要な Gitea Secrets: GITEA_TOKEN(リリース・タグ)、REGISTRY_USER /
REGISTRY_TOKEN(Package Registry)。
トラブルシューティング
| 症状 | 原因 / 対処 |
|---|---|
namespaces "xxx" not found で install 失敗 |
配布先ネームスペースは事前作成が必要。kubectl create namespace xxx。 |
helm upgrade しても Pod の挙動が変わらない |
Pod の環境変数は再起動まで不変。Pod を再起動するか Reloader 連携を使う。 |
| reflector 有効なのに他 ns に複製されない | reflector コントローラー未導入 / namespaceRegex 不一致 / 対象 ns がまだ無い。 |
cannot convert int64 to string 等の型エラー |
通常は発生しない(テンプレートで文字列化済み)。values の該当箇所を確認し Issue へ。 |
| Secret に平文が見える | Secret は設計上、参照側から平文で読める。RBAC で get secrets を最小化し、etcd 保存時暗号化を有効化する。 |
helm lint で metadata.namespace 警告 |
意図的(クロス ns 配布)。エラーではない。 |
変更履歴
各リリースの詳細は CLAUDE.md の「チャート改修履歴」を参照。
v0.1.1(2026-09-08)
values.schema.jsonの$schema行を削除。新しめの JSON Schema バリデータを内蔵する デプロイ環境(Helm / Argo CD / Flux 等)でno schema with key or ref "https://json-schema.org/draft-07/schema#"エラーが出て デプロイできない問題を修正。helm lint --strictの検証内容は不変。
v0.1.0(2026-08-31)
- 初版。
distribution(namespaces 複製 / reflector / reloader)、common、mail.providers(SMTP/IMAP/POP3 +smtp.env+ 任意msmtprc)、api.credentials、generic.secrets(任意 type)を実装。values.schema.json・examples/を同梱。 - CI:
helm-release.yaml(push 時・未公開バージョンのみリリース)を追加。 Package Registry 発行 + Git タグ + Gitea リリースまで実施。上流イメージが無いため 週次の自動更新ワークフローは持たない。