feat: add home-assistant-dashboard-conventions skill + update multiple skills
- New: smart-home/home-assistant-dashboard-conventions (Mushroom cards, view tabs, no Bubble Cards) - Updated: rke2, ceph, galera, proxmox, brainstorming, compound-learning, 1password-cli, smart-home-automation skills - New references: ceph-cluster-administration, docker-volume-forensics, ceph-crush-weight, ceph-ec-mixed-size
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
# Hermes Host Git Remote Cutover to K8s Gitea — 2026-07-14
|
||||
|
||||
## Context
|
||||
|
||||
After ArgoCD self-management cutover (Section 4.3e), the Hermes host's
|
||||
own `iac-homelab` git remote still pointed to CT108
|
||||
(`10.0.30.105:3000`). User instructed: "nutze du intern in hermes ab
|
||||
jetzt auch das k8s gitea" — switch Hermes host's git remote to K8s Gitea.
|
||||
|
||||
## Key Learnings
|
||||
|
||||
### CoreDNS Is K8s-Internal Only
|
||||
|
||||
The CoreDNS `hosts` override (Section 4.3d) makes `git.schoen.codes`
|
||||
resolve to `10.0.30.203` **only inside K8s pods**. The Hermes host,
|
||||
being outside K8s, cannot use CoreDNS. Public DNS was explicitly
|
||||
rejected by the user ("Nutze für Internet Zwecke nicht den externen DNS
|
||||
Resolver, sondern einen internen").
|
||||
|
||||
Solution: `/etc/hosts` entry on the Hermes host:
|
||||
```bash
|
||||
echo "10.0.30.203 git.schoen.codes" | sudo tee -a /etc/hosts
|
||||
```
|
||||
|
||||
### Gitea API Tokens Do NOT Migrate
|
||||
|
||||
When repos are migrated from CT108 Gitea to K8s Gitea via the Gitea
|
||||
Migration API, **API tokens are NOT copied**. Tokens are stored hashed
|
||||
in the database and are instance-specific. The old token
|
||||
(`07efa...`) from CT108 returns `401 Unauthorized` on K8s Gitea.
|
||||
|
||||
New token must be generated on K8s Gitea:
|
||||
```bash
|
||||
# Via mgmt-runner (VM200) — Hermes host has no kubectl:
|
||||
ssh -i ~/.ssh/id_ed25519_proxmox root@10.0.30.124 \
|
||||
"KUBECONFIG=/root/.kube/config kubectl exec -n gitea deploy/gitea -- \
|
||||
gitea admin user generate-access-token \
|
||||
-u dominik -t hermes-gitops --scopes all --raw"
|
||||
```
|
||||
|
||||
Note: The `--config /data/gitea/conf/app.ini` flag is optional —
|
||||
`gitea admin user generate-access-token` auto-discovers the config when
|
||||
running inside the pod. The command outputs the raw token to stdout.
|
||||
|
||||
### JWT ≠ Gitea API Token (Critical Distinction)
|
||||
|
||||
The 1Password ExternalSecrets for Gitea (`gitea-security`) contain
|
||||
`internal_token`, `jwt_secret`, `secret_key`, `lfs_jwt_secret`. These
|
||||
are **internal security tokens** (JWTs), NOT API access tokens.
|
||||
|
||||
**How to distinguish:**
|
||||
- **Gitea API token**: hex string, e.g. `07efa534ea1a147fce1bf5813c669cb0ebc7b522`
|
||||
- **JWT / internal security token**: three base64 parts separated by dots,
|
||||
e.g. `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3ODM5NjM1NDd9.Lyr6fqc...`
|
||||
|
||||
A JWT passed as `Authorization: token <JWT>` or `Authorization: Bearer
|
||||
<JWT>` returns `401 Unauthorized` on both old and new Gitea instances.
|
||||
The `nbf` (Not Before) claim in the JWT payload identifies it as a
|
||||
security token, not an access token.
|
||||
|
||||
**If a user provides a token that looks like a JWT (dots separating
|
||||
base64 segments), it is NOT a Gitea API token.** Direct them to
|
||||
Settings → Applications → Generate New Token in the Gitea web UI, or
|
||||
generate one via `gitea admin user generate-access-token` (see above).
|
||||
|
||||
### K8s Gitea Reachability from Outside K8s
|
||||
|
||||
| Path | Works? | Notes |
|
||||
|------|--------|-------|
|
||||
| `http://10.0.30.203:3000` | ❌ Timeout | Port 3000 not exposed on VIP |
|
||||
| `http://10.0.30.203` (Host: git.schoen.codes) | ✅ 200 | Traefik routes by Host header |
|
||||
| `https://10.0.30.203` (Host: git.schoen.codes) | ✅ 200 | TLS via Traefik |
|
||||
| `10.0.30.202:2222` (SSH) | Separate LB | Gitea SSH LoadBalancer service |
|
||||
| `git.schoen.codes` (via /etc/hosts) | ✅ | Resolves to 10.0.30.203 |
|
||||
|
||||
### Hermes Host Has No kubectl
|
||||
|
||||
The Hermes host (`/home/debian`) does not have `kubectl`, `helm`, or
|
||||
`kubeconfig`. All K8s operations go through SSH to mgmt-runner (VM200)
|
||||
at `10.0.30.124`. See SKILL.md Section 1.2.
|
||||
|
||||
### ArgoCD Repo Secret Also Needs Token Update
|
||||
|
||||
After generating a new Gitea API token, the ArgoCD repository secret
|
||||
must also be patched with the new token — otherwise ArgoCD's repo
|
||||
connection breaks even though the Hermes host git remote works:
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_ed25519_proxmox root@10.0.30.124 \
|
||||
"KUBECONFIG=/root/.kube/config kubectl patch secret \
|
||||
argocd-repo-k8s-gitea -n argocd --type merge \
|
||||
-p '{\"data\":{\"password\":\"$(echo -n TOKEN | base64)\"}}'"
|
||||
```
|
||||
|
||||
### Gitea Helm Chart Admin Password Extraction
|
||||
|
||||
The Gitea Helm Chart v12 auto-generates an admin password on first
|
||||
install (unless explicitly set in values). The password is stored as
|
||||
the `GITEA_ADMIN_PASSWORD` environment variable in the `configure-gitea`
|
||||
init container — NOT in any K8s Secret or Helm values file.
|
||||
|
||||
```bash
|
||||
# Extract admin password from the init container env vars:
|
||||
ssh -i ~/.ssh/id_ed25519_proxmox root@10.0.30.124 \
|
||||
"KUBECONFIG=/root/.kube/config kubectl get deploy gitea -n gitea \
|
||||
-o jsonpath='{.spec.template.spec.initContainers[?(@.name==\"configure-gitea\")].env}'" \
|
||||
| python3 -c "
|
||||
import json,sys
|
||||
for e in json.load(sys.stdin):
|
||||
if e.get('name')=='GITEA_ADMIN_PASSWORD':
|
||||
print(e['value'])
|
||||
"
|
||||
```
|
||||
|
||||
Additional env vars in the same container:
|
||||
- `GITEA_ADMIN_USERNAME`: the admin username (e.g. `dominik`)
|
||||
- `GITEA_ADMIN_PASSWORD_MODE`: `keepUpdated` (chart syncs password on
|
||||
every sync) or `initialOnlyRequireReset`
|
||||
|
||||
**Pitfall:** The password is NOT in the `gitea-security` K8s Secret
|
||||
(that contains JWT-based internal tokens only — see "JWT ≠ Gitea API
|
||||
Token" above). It is also NOT in the Helm values `gitea.admin` section
|
||||
(unless explicitly set — by default the chart generates a random one).
|
||||
|
||||
### Storing Credentials in 1Password
|
||||
|
||||
After extracting the admin password and generating an API token, store
|
||||
both in 1Password vault "Hermes":
|
||||
|
||||
- **API Token**: Category `API Credential`, title `K8s Gitea Token
|
||||
(hermes-gitops)`. Requires two-step create+edit (see 1password-cli
|
||||
skill — `op item create` does not populate the `credential` field
|
||||
for API Credential items).
|
||||
- **Admin Login**: Category `Login`, title `K8s Gitea Admin (dominik)`.
|
||||
Works in one step with `op item create --category="Login"`.
|
||||
|
||||
## Steps Performed (Completed)
|
||||
|
||||
1. Checked current remote: `git remote -v` → CT108 (`10.0.30.105:3000`)
|
||||
2. Verified K8s Gitea reachable via Traefik VIP: `curl -H "Host: git.schoen.codes" http://10.0.30.203/` → 200
|
||||
3. Added `/etc/hosts` entry: `10.0.30.203 git.schoen.codes`
|
||||
4. Changed git remote URL to `http://dominik:TOKEN@git.schoen.codes/dominik/iac-homelab.git`
|
||||
5. `git fetch origin` → `Authentication failed` (old CT108 token invalid on K8s Gitea)
|
||||
6. User provided a JWT (internal security token from 1Password) — identified as NOT an API token (see pitfall above)
|
||||
7. Generated new API token via mgmt-runner SSH: `gitea admin user generate-access-token -u dominik -t hermes-gitops --scopes all --raw` → `4a3fd...`
|
||||
8. Updated git remote with new token: `git remote set-url origin "http://dominik:4a3fd...@git.schoen.codes/..."`
|
||||
9. `git fetch origin` → ✅ success (forced update from `d9135ca` → `68adfab`)
|
||||
10. `git push --dry-run origin main` → ✅ "Everything up-to-date"
|
||||
11. Patched ArgoCD repo secret `argocd-repo-k8s-gitea` with new token
|
||||
|
||||
## Result
|
||||
|
||||
Hermes host git operations now use K8s Gitea exclusively. ArgoCD also
|
||||
pulls from K8s Gitea. The entire GitOps loop is self-contained in K8s.
|
||||
CT108 can be decommissioned (Task 10 — pending user approval).
|
||||
Reference in New Issue
Block a user