Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions .github/workflows/talos-boot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ name: talos boot

on:
pull_request:
paths:
# push と同じ一覧(YAML のアンカー。GitHub Actions は 2025-09 から読む。マージキー `<<:` は読まない)
paths: &paths
- talos/**
- bootstrap/cilium/**
- bootstrap/cert-manager/**
Expand All @@ -26,15 +27,7 @@ on:
- .github/workflows/talos-boot.yml
push:
branches: [main]
paths:
- talos/**
- bootstrap/cilium/**
- bootstrap/cert-manager/**
- bootstrap/argocd/**
- bootstrap/infisical/**
- bootstrap/gateway/**
- bootstrap/apiserver/**
- .github/workflows/talos-boot.yml
paths: *paths
workflow_dispatch:

permissions:
Expand Down Expand Up @@ -122,8 +115,8 @@ jobs:
username: ci-dummy
password: ci-dummy
PATCH
# **argocd / infisical の値は本物の values.yaml。** 秘密の側(secret-values.yaml)だけダミーに替えて重ねる。
# 通知の送り先は secret-values.yaml にしか無いので、渡さなければ通知も出ない。
# **argocd / infisical の値は本物の values.yaml。** 秘密の側(secret-values.sops.yaml)だけダミーに替えて重ねる。
# 通知の送り先は secret-values.sops.yaml にしか無いので、渡さなければ通知も出ない。
# extraObjects は app-of-apps(`apps`)と GitHub App の repo-creds。CI で本物を同期させない
echo 'extraObjects: []' > /tmp/argocd-secret-values.yaml
# SMTP は外(smtp.office365.com)に繋ぎに行くので抜く(リストなので丸ごと置き換える)
Expand All @@ -135,9 +128,9 @@ jobs:
| .stringData.ENCRYPTION_KEY = \"$(openssl rand -hex 16)\"
| .stringData.AUTH_SECRET = \"$(openssl rand -base64 32)\"
| .stringData.TELEMETRY_ENABLED = \"false\"" \
bootstrap/infisical/secrets.yaml > /tmp/infisical-secret.yaml
bootstrap/infisical/secrets.sops.yaml > /tmp/infisical-secret.yaml
yq 'del(.sops) | (.. | select(tag == "!!str" and test("^ENC\\["))) |= "ci-dummy"' \
bootstrap/cert-manager/cloudflare-secret.yaml > /tmp/cloudflare-secret.yaml
bootstrap/cert-manager/cloudflare-secret.sops.yaml > /tmp/cloudflare-secret.yaml
for f in /tmp/infisical-secret.yaml /tmp/cloudflare-secret.yaml; do
! grep -q 'ENC\[' "$f" || { echo "::error::$f に暗号文が残っている"; exit 1; }
done
Expand Down
10 changes: 6 additions & 4 deletions .sops.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
# tools/t.ps1 sh -c 'mkdir -p ~/.config/sops/age && age -d -o ~/.config/sops/age/keys.txt recovery/sops-age.key.age'
# のあと `tools/t.ps1 sops -d`(tools/t.ps1 の中の ~ はリポジトリの .home/)。
creation_rules:
# bootstrap/*/secret-values.yaml(chart の値のうち秘密だけ)は丸ごと暗号化する。
# bootstrap/*/secret-values.sops.yaml(chart の値のうち秘密だけ)は丸ごと暗号化する。
# 秘密しか入れない約束なので選り分けない。値の残りは同じ場所の平文の values.yaml。
- path_regex: ^bootstrap/[^/]+/secret-values\.yaml$
- path_regex: ^bootstrap/[^/]+/secret-values\.sops\.yaml$
age: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r
# 残りの bootstrap/ は「そのキーだけ」を暗号化する。マニフェストの構造は git で読めたほうが
# 残りの bootstrap/*.sops.yaml は「そのキーだけ」を暗号化する。マニフェストの構造は git で読めたほうが
# レビューできるため。
- path_regex: ^bootstrap/.*\.yaml$
# **bootstrap/ で暗号化するファイルは `.sops.yaml` で終える。** ArgoCD の `bootstrap` はその名前で外す
# (bootstrap/argocd/repos.yaml)。違う名前で `sops -e` すると、一致する規則が無いと言われて落ちる。
- path_regex: ^bootstrap/.*\.sops\.yaml$
encrypted_regex: ^(ENCRYPTION_KEY|AUTH_SECRET|CLIENT_ID_GITHUB_LOGIN|CLIENT_SECRET_GITHUB_LOGIN|CF_DNS_API_TOKEN)$
age: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r
# talos/secrets.yaml は丸ごと暗号化する。`talosctl gen secrets` の出力は
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Argo CD が git を読む GitHub App 鍵、cert-manager の Cloudflare トーク
```shell
# 鍵はリポジトリの .home/(git に入らない)に置く。コマンドは tools/t.ps1 で動かす(tools/README.md)
tools/t.ps1 sh -c 'mkdir -p ~/.config/sops/age && age -d -o ~/.config/sops/age/keys.txt recovery/sops-age.key.age'
tools/t.ps1 sops -d bootstrap/infisical/secrets.yaml # 中を見る(画面に出すと平文になるので注意)
tools/t.ps1 sops -d bootstrap/infisical/secrets.sops.yaml # 中を見る(画面に出すと平文になるので注意)
```

## ホスト名の付け方
Expand Down
2 changes: 1 addition & 1 deletion apps/matrix/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Entra だけ(Tuwunel の `[[global.identity_provider]]`)。パスワードのロ
| `server` | k8up の通知 | Infisical `/k8up/k8up-global` の `mattermostWebhook`(名前は据え置き) |
| 〃 | Infisical(秘密の変更) | Infisical のプロジェクトの webhook(Project Settings → Webhooks。環境 prod、パス `/`) |
| 〃 | Cloudflare(証明書・DDoS・オリジン不達など) | Cloudflare の通知の webhook の送り先([../../pulumi/notifications.ts](../../pulumi/notifications.ts)) |
| `argocd` | Argo CD | `bootstrap/argocd/secret-values.yaml`(SOPS)の `service.webhook.mattermost` |
| `argocd` | Argo CD | `bootstrap/argocd/secret-values.sops.yaml`(SOPS)の `service.webhook.mattermost` |
| `ashi` | ashi | Infisical `/ashi/ashi-secrets` の `notify-webhook-url` |
| `todoroku` | todoroku | Infisical `/todoroku/todoroku-secrets` の `mattermost-webhook-url` |
| `worklog` | worklog | Infisical `/worklog/worklog-secrets` の `mattermost-webhook-url` |
Expand Down
2 changes: 1 addition & 1 deletion apps/matrix/hookshot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ data:
result = parts.length
? { version: "v2", plain: parts.join("\n\n"), msgtype: "m.notice" }
: { version: "v2", empty: true };
# 部屋 argocd: Argo CD の通知(bootstrap/argocd/values.yaml・secret-values.yaml)
# 部屋 argocd: Argo CD の通知(bootstrap/argocd/values.yaml・secret-values.sops.yaml)
- connectionType: uk.half-shot.matrix-hookshot.generic.hook
stateKey: ${HOOK_ARGOCD}
roomId: "!BeZ3yus1s1E22DPYFauQjZ1AMGT2VkusuLzLk2r1cJk"
Expand Down
9 changes: 5 additions & 4 deletions bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ ArgoCD が動くのに要るもの(本体・repo の資格情報・ApplicationSe
最初の何回か落ちて retry で戻る。

**SOPS(age)で暗号化したファイルは ArgoCD が当てない** ── 復号鍵をクラスタにも CI にも渡さないため。
`bootstrap` の `exclude` に並べてある(**足したら exclude にも足す**)。
`infisical/secrets.yaml`、`cert-manager/cloudflare-secret.yaml`、`{argocd,infisical}/secret-values.yaml`。
**名前を `*.sops.yaml` で終える**と `bootstrap` の `exclude` が外す(`.sops.yaml` の規則も
その名前にしか一致しないので、別の名前では暗号化できない)。
`infisical/secrets.sops.yaml`、`cert-manager/cloudflare-secret.sops.yaml`、`{argocd,infisical}/secret-values.sops.yaml`。
鍵は [`recovery/sops-age.key.age`](../recovery/)。**中を編集するときも `sops edit` を通すこと。** MAC は暗号化して
いない値も含めて計算されるので、**平文で 1 行足すだけでも `sops -d` が MAC 不一致で落ちる。**

## Helm で入れるもの

どれも `render.sh` が `helm template` して machine config に載せる。どれも同じ形で、
`<name>/version.yaml`(chart・repo・版。Renovate が上げる)と `<name>/values.yaml`(値)。
argocd と infisical は、値のうち秘密だけを `<name>/secret-values.yaml`(SOPS、丸ごと暗号化)に分けて上に重ねる。
argocd と infisical は、値のうち秘密だけを `<name>/secret-values.sops.yaml`(SOPS、丸ごと暗号化)に分けて上に重ねる。
argocd・infisical の版は自動マージしない(`renovate.json` の `bootstrap charts`)。

## git と live がずれていないか
Expand All @@ -41,7 +42,7 @@ ConfigMap に出ているので、読むだけの権限で比べられる)。**
認証は Kubernetes 方式(TokenReview・長命の資格情報なし)。

- `infisical/` … Infisical 本体(chart + Postgres/Redis)。公開経路は [`apps/infisical/httproute.yaml`](../apps/infisical/httproute.yaml)。
`secrets.yaml` の `ENCRYPTION_KEY` が DB の暗号鍵で、これを失うと Infisical の中身が全部読めなくなる
`secrets.sops.yaml` の `ENCRYPTION_KEY` が DB の暗号鍵で、これを失うと Infisical の中身が全部読めなくなる
(クラスタで一番失ってはいけない値)。Postgres の PVC は既定の `local-path` で、`pg_dump` を k8up が日次で取っている。
- **operator と push-bridge はここには無い。** ArgoCD の Application に移した(`apps/infisical-operator/`、
`apps/infisical-push-bridge/`)。ArgoCD 自身は operator に依存しないので、bootstrap に置く理由がない。
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/argocd/oidc-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# reference from argocd-cm ($argocd-oidc:client-secret in values.yaml).
# The label is what lets argocd-server read it. Only the login depends on
# this: syncing runs on the GitHub App credential that ships in
# secret-values.yaml, so Infisical being down never blocks its own recovery.
# secret-values.sops.yaml, so Infisical being down never blocks its own recovery.
# Applied by hand like the rest of this directory (the apps Application only
# syncs repos.yaml).
apiVersion: secrets.infisical.com/v1alpha1
Expand Down
6 changes: 3 additions & 3 deletions bootstrap/argocd/repos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ spec:
# bootstrap/ の平文のマニフェスト(Gateway・auth・ClusterIssuer・InfisicalSecret など)。2026-10-17 まで
# GitHub Actions(bootstrap-apply.yml)が当てていた(../../docs/decisions.md「層の分け方」)。
#
# **machine config が持つものは外す。** Helm の値と版(`*values.yaml`・`*version.yaml`)、SOPS のファイル、
# **machine config が持つものは外す。** Helm の値と版(`*values.yaml`・`*version.yaml`)、SOPS のファイル
# (`*.sops.yaml`。名前で外すので、足しても exclude は触らなくてよい。../../.sops.yaml が他の名前では暗号化させない)、
# machine config が作る Namespace(argocd・cert-manager・infisical)、`apiserver/`、`cilium/`。
# このファイル自身は上の `apps`(argocd/values.yaml の extraObjects)が持つので外す。
# **SOPS のファイルを足したら exclude にも足すこと**(復号できないまま当たって同期が落ちる)。
# 照合は bootstrap/ からの相対パスで、`*` は `/` もまたぐ(argo-cd の util/glob は区切り文字無しの gobwas/glob)。
apiVersion: argoproj.io/v1alpha1
kind: Application
Expand All @@ -129,7 +129,7 @@ spec:
path: bootstrap
directory:
recurse: true
exclude: '{*values.yaml,*version.yaml,apiserver/*,cilium/*,argocd/repos.yaml,argocd/namespace.yaml,cert-manager/namespace.yaml,infisical/namespace.yaml,cert-manager/cloudflare-secret.yaml,infisical/secrets.yaml}'
exclude: '{*values.yaml,*version.yaml,*.sops.yaml,apiserver/*,cilium/*,argocd/repos.yaml,argocd/namespace.yaml,cert-manager/namespace.yaml,infisical/namespace.yaml}'
destination:
server: https://kubernetes.default.svc
namespace: argocd
Expand Down
8 changes: 4 additions & 4 deletions bootstrap/argocd/values.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# argo-cd の chart の値。版は version.yaml、秘密の値(通知の webhook と GitHub App の鍵)は
# secret-values.yaml(SOPS)。描いて machine config に載せるのは talos/render.sh。
# secret-values.sops.yaml(SOPS)。描いて machine config に載せるのは talos/render.sh。
#
# CRD は chart から描かせない。3 つで 1.83 MB あり、描き出しの 95%。
# render.sh が `KubeExternalManifestConfig` で URL を渡す
Expand Down Expand Up @@ -68,7 +68,7 @@ notifications:
# true by default; anything applied out-of-band gets wiped the next time
# the chart is re-rendered.
#
# notifiers は secret-values.yaml(`service.webhook.mattermost`)。送り先は Matrix の部屋 argocd
# notifiers は secret-values.sops.yaml(`service.webhook.mattermost`)。送り先は Matrix の部屋 argocd
# (スペース「通知」)の hookshot の webhook(2026-10-06 に Mattermost → Zulip → Matrix と移した)。
# 名前は mattermost のまま ── テンプレートと subscriptions が参照している。
# 送るのは {"text": …}(Slack 互換)。hookshot の変換のスクリプト(apps/matrix/hookshot.yaml)が読む
Expand Down Expand Up @@ -127,7 +127,7 @@ extraObjects:
# come from Infisical: ArgoCD syncing is how Infisical itself gets
# deployed and recovered -- this repo is private.
#
# 中身は下の githubAppRepoCreds(鍵だけ secret-values.yaml にあり、helm が map として重ねる)。
# 中身は下の githubAppRepoCreds(鍵だけ secret-values.sops.yaml にあり、helm が map として重ねる)。
# extraObjects はリストなので、そのままでは値ファイルを重ねると丸ごと置き換わる。
# 文字列の要素は chart が `tpl` に通すので、ここで toYaml して 1 つの要素にする。
- '{{ toYaml .Values.githubAppRepoCreds }}'
Expand Down Expand Up @@ -175,4 +175,4 @@ githubAppRepoCreds:
url: https://github.com/danything
githubAppID: "4434943"
githubAppInstallationID: "150067651"
# githubAppPrivateKey は secret-values.yaml
# githubAppPrivateKey は secret-values.sops.yaml
2 changes: 1 addition & 1 deletion bootstrap/cert-manager/clusterissuer.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Let's Encrypt を Cloudflare の DNS-01 で。ワイルドカード証明書を取るので DNS-01。
# トークンは同じ namespace の Secret にしか置けない(cert-manager は自分の namespace の
# Secret しか読まない)ので、cloudflare-secret.yaml がここに置いている。
# Secret しか読まない)ので、cloudflare-secret.sops.yaml がここに置いている。
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions bootstrap/infisical/values.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# infisical-standalone の chart の値。版は version.yaml、DB と Redis のパスワードは
# secret-values.yaml(SOPS)。描いて machine config に載せるのは talos/render.sh
# secret-values.sops.yaml(SOPS)。描いて machine config に載せるのは talos/render.sh
# (ArgoCD に置けない理由は docs/decisions.md「infisical だけは ArgoCD に移せない」)。
#
# https://github.com/Infisical/infisical/tree/main/helm-charts/infisical-standalone-postgres
Expand All @@ -16,7 +16,7 @@ infisical:
repository: mirror.gcr.io/infisical/infisical
# The chart's default tag lags releases; pin explicitly.
tag: v0.166.8
# ENCRYPTION_KEY / AUTH_SECRET / SITE_URL live in infisical/secrets.yaml.
# ENCRYPTION_KEY / AUTH_SECRET / SITE_URL live in infisical/secrets.sops.yaml.
kubeSecretRef: infisical-secrets
extraEnv:
# Kubernetes auth makes Infisical call https://kubernetes.default.svc
Expand Down
4 changes: 2 additions & 2 deletions docs/cloudflare-tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Pulumi で作ると値を Infisical に書く鍵が CI に要る。その鍵は
| `external-dns (doany.io DNS write)` | アカウント | `doany.io` の Zone Read + DNS Write | Infisical `/external-dns/external-dns` の `cloudflare-api-token` | apps/external-dns |
| `doany-restic` | アカウント | R2 バケット `doany-restic` だけの Object Read & Write | Infisical `/k8up/k8up-global`、`recovery/env.age` | k8up、復元(手元の restic) |
| cloudflare-ddns | ユーザー(アカウントの一覧に無い) | 画面で確かめる(DNS Write が要る) | Infisical `/cloudflare-ddns/cloudflare-ddns-secrets` の `CLOUDFLARE_API_TOKEN` | apps/cloudflare-ddns |
| cert-manager | ユーザー(アカウントの一覧に無い) | 画面で確かめる(DNS Write が要る) | SOPS の `bootstrap/cert-manager/cloudflare-secret.yaml` | cert-manager(DNS-01) |
| cert-manager | ユーザー(アカウントの一覧に無い) | 画面で確かめる(DNS Write が要る) | SOPS の `bootstrap/cert-manager/cloudflare-secret.sops.yaml` | cert-manager(DNS-01) |
| `todoroku-pulumi (state)` | アカウント | R2 バケット `todoroku-pulumi` だけの Object Read & Write | Forgejo `doa/todoroku` の secrets `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`(ID と値の SHA-256) | todoroku の `infra/`(Pulumi の state) |
| `gitops pulumi apply` / `preview` | アカウント | pulumi/README.md「鍵と state」 | GitHub の secrets | gitops の Pulumi |

Expand All @@ -25,7 +25,7 @@ Pulumi で作ると値を Infisical に書く鍵が CI に要る。その鍵は
- **external-dns / cloudflare-ddns:** Infisical の値を差し替える。operator が Secret を書き換え、
push-bridge が同期させる。Deployment の `secrets.infisical.com/auto-reload` 注釈で入れ替わる。
- **todoroku-pulumi (state):** Forgejo の 2 つの secrets を差し替える(S3 の鍵の導き方は下の doany-restic と同じ)。
- **cert-manager:** `tools/t.ps1 sops bootstrap/cert-manager/cloudflare-secret.yaml` で書き換えてコミットする。
- **cert-manager:** `tools/t.ps1 sops bootstrap/cert-manager/cloudflare-secret.sops.yaml` で書き換えてコミットする。
- **doany-restic(R2):** S3 の鍵はトークンから導く。アクセスキー ID はトークンの ID、シークレットはトークンの値の
SHA-256(16 進)。**2 か所を両方変える**。Infisical が古いとバックアップが落ち(k8up の通知で気づく)、`env.age` が古いと建て直しで Infisical を戻せない(こちらは誰も気づかない)。
1. Infisical `/k8up/k8up-global` の `accessKeyId` / `secretAccessKey`
Expand Down
7 changes: 4 additions & 3 deletions docs/talos.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ restic dump <ID> /work/etcd.snapshot > etcd.snapshot

Sidero のドキュメントの「Talos only creates missing resources from inline manifests」は起動時の適用の話で、
**`talosctl apply-config` では更新も削除もされないが、`talosctl upgrade-k8s`(同じ版でも)を通せば SSA とインベントリで更新も削除もされる**
(prune は既定で有効)。プローブ用の `ConfigMap` で確かめた。この実測を根拠に `bootstrap/` をまるごと inlineManifests に載せた。
(prune は既定で有効)。プローブ用の `ConfigMap` で確かめた。この実測を根拠に `bootstrap/` の起動に要る層(Cilium・cert-manager・ArgoCD・Infisical と SOPS の Secret)を inlineManifests に載せた。
残りの平文は ArgoCD の Application `bootstrap` が当てる(2026-10-17 から。[bootstrap/README.md](../bootstrap/README.md))。
当て直しの手順は [talos/README.md](../talos/README.md)「上げ方 / 当て直し方」。

## VM ブートドリル
Expand Down Expand Up @@ -151,8 +152,8 @@ CNI の交換は構築時にやる ── 稼働中の差し替えは全 Pod 再
| レイヤー | 決めること | 変更手段 |
| --- | --- | --- |
| イメージ | カーネル引数、system extension(GPU ドライバ等) | Image Factory で schematic を作って `talosctl upgrade` |
| machine config | CNI、kube-proxy、ディスク、ネットワーク、`bootstrap/` の大半 | `render.sh` → `apply-config`(inlineManifests は `upgrade-k8s` まで) |
| Kubernetes | ワークロード | Argo CD(`apps/` と各リポジトリの `deploy/`) |
| machine config | CNI、kube-proxy、ディスク、ネットワーク、`bootstrap/` の chart と SOPS のファイル | `render.sh` → `apply-config`(inlineManifests は `upgrade-k8s` まで) |
| Kubernetes | ワークロード | Argo CD(`apps/`・`bootstrap/` の残りの平文・各リポジトリの `deploy/`) |

SSH もシェルもパッケージマネージャも無く gRPC API だけなので、**障害時は「直さず作り直す」**。
デバッグは `talosctl dmesg` / `logs` / `read`、debug コンテナ。
Loading
Loading