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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ talos/secrets.plain.yaml
# **平文のまま置かないこと。** talos/registries.yaml は SOPS 済みのものをコミットする
# (talos/README.md「fj.doany.io の資格情報」)。書きかけの平文はこの名前に逃がす。
talos/registries.plain.yaml
# 平文の kubeconfig / talosconfig も置かない。talos/kubeconfig.yaml は SOPS 済みのものをコミットする
# 平文の kubeconfig / talosconfig も置かない。どちらも tools/t.ps1 が毎回その場で作る
# (tools/README.md「クラスタの資格情報」)。talosctl kubeconfig と gen config がこの名前で書き出す
kubeconfig
talosconfig
Expand Down
5 changes: 0 additions & 5 deletions .sops.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,3 @@ creation_rules:
# 選り分ける意味が無い(k3s 期の /etc/rancher/k3s/registries.yaml の移し先)。
- path_regex: ^talos/registries\.yaml$
age: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r
# talos/kubeconfig.yaml(管理者。`talosctl kubeconfig` の出力)も丸ごと。
# 中身は証明書と鍵がほとんどで、選り分ける意味が無い。tools/t.ps1 の kubectl がその場で復号して使う
# (tools/README.md「クラスタの資格情報」)。
- path_regex: ^talos/kubeconfig\.yaml$
age: age1sgnnkn67wpt4wgjsff4c36w3cmjkk557ng504e4aczx2lzls9y6ssy0x9r
4 changes: 2 additions & 2 deletions talos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ talosctl -n 10.0.0.2 -e 10.0.0.2 --talosconfig /tmp/talos-config/talosconfig boo
talosctl -n 10.0.0.2 -e 10.0.0.2 --talosconfig /tmp/talos-config/talosconfig kubeconfig
```

ふだんの kubectl / talosctl は `tools/t.ps1` が資格情報を用意する。管理者の kubeconfig は SOPS で
`talos/kubeconfig.yaml` に置く(手順は [../tools/README.md](../tools/README.md)「クラスタの資格情報」)。
ふだんの kubectl / talosctl は `tools/t.ps1` が資格情報を毎回その場で作る。管理者の kubeconfig も
ファイルでは持たない([../tools/README.md](../tools/README.md)「クラスタの資格情報」)。

`clusterconfig/` と平文の秘密は `.gitignore` 済み。

Expand Down
18 changes: 4 additions & 14 deletions tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,31 +57,21 @@ tools/t.ps1 # 引数なしならシェルに入る

| | 読み取り用(既定) | 管理者(`--admin`) |
| --- | --- | --- |
| kubectl / helm | その場で作る。`talos/secrets.yaml` の Kubernetes の CA で、グループ `entra:viewer` の証明書(1 日で切れる) | `talos/kubeconfig.yaml`(SOPS 済み)を復号する |
| kubectl / helm | その場で作る。`talos/secrets.yaml` の Kubernetes の CA で、グループ `entra:viewer` の証明書(1 日で切れる) | 同じく `system:masters` |
| talosctl | その場で作る。Talos の CA で `os:reader` の証明書(1 日で切れる) | 同じく `os:admin` |

- 読み取り用の権限は [`../bootstrap/apiserver/rbac.yaml`](../bootstrap/apiserver/rbac.yaml) の `entra:viewer`
(組み込みの `view` と `readonly-extra`。ログは読めて、Secret は読めない)。Headlamp で Entra の viewer が持つものと同じ
- **helm はリリースの情報を Secret に持つ**ので、`helm list` や `helm status` も `--admin` を付ける
- **talosconfig は保存しない**([../docs/decisions.md](../docs/decisions.md)「手で持つもの」)。`secrets.yaml` から毎回作る
- 管理者の kubeconfig だけはファイルで持つ。Talos が出す正式なもの(`talosctl kubeconfig`)を使い、証明書は 1 年で切れる。
中身は `secrets.yaml` の CA で作れるものなので、置いても開けられる範囲は今と変わらない
- **管理者の kubeconfig も保存しない。** 毎回その場で作るので、作り直しも期限切れも無い。
`talosctl kubeconfig` は 1 年もつ証明書を呼ぶたびに出す(取り消せない)ので使わない
- 行き先はどれも `10.10.0.4`(ノードの、作業用 PC の LAN 側の口。`creds.sh` の `ep`)。`talos/render.sh` の `10.0.0.2` は
クラスタの LAN で手元から届かず、NetBird はクラスタの上で動くので落ちたときに使えない。API は外に開かない。
外からは mado で作業用 PC に入って打つ。`10.10.0.4` は Talos の証明書の SAN に入っている。`KUBECONFIG` / `TALOSCONFIG` や `--kubeconfig` / `--talosconfig` /
`--server` を自分で渡したときは何もしない。繋がないもの(`kubectl kustomize`、`helm template`、`talosctl gen`、`--client` など)も同じ

**管理者の kubeconfig の入れ方**(作り直すときも同じ。切れる前に):

```powershell
tools/t.ps1 --admin sh -c 'talosctl kubeconfig /dev/shm/k && sops -e --filename-override talos/kubeconfig.yaml /dev/shm/k > talos/kubeconfig.yaml'
tools/t.ps1 --admin kubectl get nodes # 確かめる
git add talos/kubeconfig.yaml # 暗号化済み(`sops:` がある)ことを見てからコミットする
```

`talosctl kubeconfig` が書き出す先も暗号化の入力も `/dev/shm` なので、平文は一度もディスクに出ない。
規則は [`../.sops.yaml`](../.sops.yaml)。平文の `kubeconfig` / `talosconfig` という名前のファイルは `.gitignore` 済みで、
`creds.sh` も暗号化されていない `talos/kubeconfig.yaml` は使わずに止まる。
平文の `kubeconfig` / `talosconfig` という名前のファイルは `.gitignore` 済み(手で書き出したものを誤って入れないように)。

## wslc の制限

Expand Down
52 changes: 29 additions & 23 deletions tools/creds.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#
# 既定は読み取り用。管理者は `tools/t.ps1 --admin …`(GITOPS_ADMIN=1)のときだけ。
# kubectl / helm 読み取り用は talos/secrets.yaml の CA でその場で証明書を作る(1 日で切れる)。
# 管理者は talos/kubeconfig.yaml(SOPS 済み。talosctl kubeconfig の出力)を復号する
# 管理者も同じく system:masters の証明書をその場で作る(ファイルで持たない)
# talosctl 同じく CA でその場で作る(os:reader / os:admin)。talosconfig は保存しない
# (docs/decisions.md「手で持つもの」)
set -eu
Expand Down Expand Up @@ -88,35 +88,41 @@ mint() {
# render.sh の 10.0.0.2 はクラスタの LAN で、手元からは届かない。NetBird はクラスタの上で動くので、
# クラスタが落ちたときに使えない。10.10.0.4 は Talos の証明書(apid・kube-apiserver)の SAN に入っている
ep=10.10.0.4
if [ "$tool" = talosctl ]; then
out=$shm/talosconfig-$role
if [ ! -s "$out" ]; then
if [ $role = admin ]; then os=os:admin; else os=os:reader; fi
mint os "/O=$os" "$out.c.$$" ed25519

# talosconfig を $shm に作って置き場所を返す($1 = admin / readonly)。作るのは初回だけ
talosconfig() {
t=$shm/talosconfig-$1
if [ ! -s "$t" ]; then
if [ "$1" = admin ]; then os=os:admin; else os=os:reader; fi
mint os "/O=$os" "$t.c.$$" ed25519
(umask 077 && printf 'context: doany\ncontexts:\n doany:\n endpoints: [%s]\n nodes: [%s]\n ca: %s\n crt: %s\n key: %s\n' \
"$ep" "$ep" "$(cat "$out.c.$$.ca")" "$(cat "$out.c.$$.crt")" "$(cat "$out.c.$$.key")" >"$out.$$" && mv "$out.$$" "$out")
rm -f "$out.c.$$".*
"$ep" "$ep" "$(cat "$t.c.$$.ca")" "$(cat "$t.c.$$.crt")" "$(cat "$t.c.$$.key")" >"$t.$$" && mv "$t.$$" "$t")
rm -f "$t.c.$$".*
fi
export TALOSCONFIG="$out"
echo "$t"
}

if [ "$tool" = talosctl ]; then
TALOSCONFIG=$(talosconfig $role)
export TALOSCONFIG
exec "$real" "$@"
fi

out=$shm/kubeconfig-$role
if [ ! -s "$out" ] && [ $role = readonly ]; then
# 読み取り用は bootstrap/apiserver/rbac.yaml の entra:viewer(組み込みの view + readonly-extra。Secret は読めない)。
# Headlamp で Entra の viewer が持つ権限と同じにするため、同じグループ名を使う
mint k8s "/O=entra:viewer/CN=tools-readonly" "$out.c.$$" ec
(umask 077 && printf 'apiVersion: v1\nkind: Config\nclusters:\n- name: doany\n cluster:\n server: https://%s:6443\n certificate-authority-data: %s\ncontexts:\n- name: readonly@doany\n context:\n cluster: doany\n user: readonly\ncurrent-context: readonly@doany\nusers:\n- name: readonly\n user:\n client-certificate-data: %s\n client-key-data: %s\n' \
"$ep" "$(cat "$out.c.$$.ca")" "$(cat "$out.c.$$.crt")" "$(cat "$out.c.$$.key")" >"$out.$$" && mv "$out.$$" "$out")
if [ ! -s "$out" ]; then
if [ $role = admin ]; then
# 管理者は system:masters(Talos の talosctl kubeconfig と同じグループ)。talosctl kubeconfig は 1 年もつ
# 証明書を毎回出すので使わず、読み取り用と同じく 1 日で切れるものを作る
subj=/O=system:masters/CN=tools-admin
else
# 読み取り用は bootstrap/apiserver/rbac.yaml の entra:viewer(組み込みの view + readonly-extra。Secret は読めない)。
# Headlamp で Entra の viewer が持つ権限と同じにするため、同じグループ名を使う
subj=/O=entra:viewer/CN=tools-readonly
fi
mint k8s "$subj" "$out.c.$$" ec
(umask 077 && printf 'apiVersion: v1\nkind: Config\nclusters:\n- name: doany\n cluster:\n server: https://%s:6443\n certificate-authority-data: %s\ncontexts:\n- name: %s@doany\n context:\n cluster: doany\n user: %s\ncurrent-context: %s@doany\nusers:\n- name: %s\n user:\n client-certificate-data: %s\n client-key-data: %s\n' \
"$ep" "$(cat "$out.c.$$.ca")" $role $role $role $role "$(cat "$out.c.$$.crt")" "$(cat "$out.c.$$.key")" >"$out.$$" && mv "$out.$$" "$out")
rm -f "$out.c.$$".*
elif [ ! -s "$out" ]; then
f=talos/kubeconfig.yaml
[ -f $f ] || die "$f が無い。作り方は tools/README.md「クラスタの資格情報」"
grep -q '^sops:' $f || die "$f が暗号化されていない。git に入れる前に tools/README.md の手順で暗号化する"
nokey
# talosctl kubeconfig が書く行き先は 10.0.0.2(クラスタの endpoint)なので、手元から届く口に替える
(umask 077 && sops -d $f >"$out.$$" && sed -i "s#^\( *server:\) https://.*#\1 https://$ep:6443#" "$out.$$" && mv "$out.$$" "$out") ||
{ rm -f "$out.$$"; die "$f を復号できなかった"; }
fi
export KUBECONFIG="$out"
exec "$real" "$@"
Loading