Setup provisioning docs and plans
This commit is contained in:
@@ -0,0 +1,84 @@
|
|||||||
|
# Host provisioning
|
||||||
|
|
||||||
|
Status: **planned**. Tracking doc for the host auto-provisioning tool that takes
|
||||||
|
a node from bare to a fully working Charlie deploy target, step by step. Pairs
|
||||||
|
with [shared home directories](shared-homes.md), whose autofs `/Users` work is
|
||||||
|
one provisioning role.
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
| Area | Decision |
|
||||||
|
| ---- | -------- |
|
||||||
|
| Tool | Ansible (declarative, idempotent, cross-platform incl. macOS). |
|
||||||
|
| Phases | Phase 0 trust bootstrap is operator-run; Phase 1+ convergence is CI-driven. |
|
||||||
|
| Phase 1 invocation | Gitea Actions, push from runner over step-ca SSH cert, mirroring `deploy-stack.yml`. |
|
||||||
|
| Repo | New `Charlie/provisioning` (playbooks, roles, inventory, Phase-1 workflow). |
|
||||||
|
| Inventory | Ansible inventory is authoritative; [hosts](hosts.md) links to it instead of duplicating host facts. |
|
||||||
|
| Secrets | SOPS/age, matching the rest of Charlie. |
|
||||||
|
|
||||||
|
## Provisioning steps
|
||||||
|
|
||||||
|
Dependency-ordered. "Bootstrap" steps must exist before the node can be a normal
|
||||||
|
CI/SSH-cert target.
|
||||||
|
|
||||||
|
| # | Step | Depends on | Phase |
|
||||||
|
| - | ---- | ---------- | ----- |
|
||||||
|
| 1 | Hostname + Marika DNS/DHCP entry | — | off-host |
|
||||||
|
| 2 | CA trust: X.509 root + SSH user CA | 1 | 0 |
|
||||||
|
| 3 | `/etc/charlie/age.key` | — | 0 |
|
||||||
|
| 4 | NFS `/mnt/nas` autofs mount | 1 | 1 |
|
||||||
|
| 5 | LDAP/SSSD users, groups, sudo | 2, 3 | 1 |
|
||||||
|
| 6 | Docker / Compose | — | 1 |
|
||||||
|
| 7 | `charlie-deploy` group + Docker socket access | 6 | 1 |
|
||||||
|
| 8 | `sys-gitea-runner` Git + registry creds | 2, 3 | 1 |
|
||||||
|
| 9 | otelcollector | 4, 7 | 1 |
|
||||||
|
| 10 | autofs `/Users` homes ([shared-homes](shared-homes.md)) | 4, 5 | 1 |
|
||||||
|
|
||||||
|
## Two-phase model
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Op[Operator + Sherlock] -->|Phase 0: out-of-band SSH| Bare[Bare host]
|
||||||
|
Bare -->|trust: CA roots, SSH CA, age key| Trusted[Trusted host]
|
||||||
|
Runner[Gitea runner] -->|Phase 1: step-ca SSH cert| Trusted
|
||||||
|
Trusted -->|converged| Target[Deploy target]
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Phase 0 — trust bootstrap (operator-run).** Resolves the chicken-and-egg:
|
||||||
|
a bare node has no age key, no CA trust, no LDAP identity, so it cannot be a
|
||||||
|
CI target yet. Operator connects out-of-band (console / initial key) and lays
|
||||||
|
down CA roots, the SSH user CA, and `/etc/charlie/age.key`. Minimal, run once.
|
||||||
|
- **Phase 1+ — convergence (CI-driven).** Once trust and LDAP land, the host is
|
||||||
|
a normal step-ca SSH target. A Gitea workflow runs the playbook idempotently;
|
||||||
|
re-runnable on every host forever.
|
||||||
|
|
||||||
|
## Proposed roles
|
||||||
|
|
||||||
|
| Role | Provides | Phase |
|
||||||
|
| ---- | -------- | ----- |
|
||||||
|
| `trust` | CA roots, SSH user CA, `/etc/charlie/age.key` | 0 |
|
||||||
|
| `nfs` | autofs `/mnt/nas` mount | 1 |
|
||||||
|
| `identity` | SSSD + LDAP client config; sudo via groups | 1 |
|
||||||
|
| `docker` | Docker/Compose engine | 1 |
|
||||||
|
| `deploy-group` | `charlie-deploy`, Docker socket access | 1 |
|
||||||
|
| `gitea-access` | `sys-gitea-runner` Git + registry creds | 1 |
|
||||||
|
| `observability` | otelcollector | 1 |
|
||||||
|
| `homes` | autofs `/Users` + LDAP automount map | 1 |
|
||||||
|
|
||||||
|
## Inventory & secrets
|
||||||
|
|
||||||
|
- `inventory/` holds the authoritative host list; `host_vars/<host>` carries
|
||||||
|
role, OS family, SOPS recipient pubkey, and whether the host runs stacks.
|
||||||
|
- Per-host/group secrets are SOPS-encrypted under the repo's `.sops.yaml`,
|
||||||
|
decrypted at run time with the host age key (Phase 1) or the operator key
|
||||||
|
(Phase 0). Same pattern as stack repos.
|
||||||
|
|
||||||
|
## Open questions
|
||||||
|
|
||||||
|
| Item | Note |
|
||||||
|
| ---- | ---- |
|
||||||
|
| macOS (Malenia) | Ansible supports it, but roles branch on OS (launchd vs systemd, no apt, native `/Users`). Decide per-role branching vs a separate playbook. |
|
||||||
|
| Existing hosts | Converge current hosts in place, or apply only to new nodes first? |
|
||||||
|
| First-run-only steps | Hostname/DNS and Phase-0 trust are not idempotent CI work; keep them operator-gated. |
|
||||||
|
| Home creation owner | Per-user home provisioning may belong to the `homes` role or DirectoryAdmin at account creation. See [shared-homes](shared-homes.md). |
|
||||||
|
| Break-glass | Keep a local sudoer with a local home so LDAP/NFS outages don't lock out provisioning. |
|
||||||
+2
-1
@@ -22,9 +22,10 @@ context.
|
|||||||
| Build-time image scanning | Source/image repos |
|
| Build-time image scanning | Source/image repos |
|
||||||
| Dashboards as code | `Charlie/victoriametrics` |
|
| Dashboards as code | `Charlie/victoriametrics` |
|
||||||
| Cert issuer hardening | `Charlie/cert-issuer` |
|
| Cert issuer hardening | `Charlie/cert-issuer` |
|
||||||
| Bootstrap tooling | Host onboarding |
|
| [Host provisioning tool][provisioning] | Host onboarding |
|
||||||
| [Shared home directories][shared-homes] | Host onboarding |
|
| [Shared home directories][shared-homes] | Host onboarding |
|
||||||
|
|
||||||
|
[provisioning]: provisioning.md
|
||||||
[shared-homes]: shared-homes.md
|
[shared-homes]: shared-homes.md
|
||||||
|
|
||||||
Done work stays in Git history, not this doc.
|
Done work stays in Git history, not this doc.
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
Status: **planned**. Tracking doc for moving host home directories onto the NAS
|
Status: **planned**. Tracking doc for moving host home directories onto the NAS
|
||||||
via LDAP-backed autofs, so per-user config (shells, `nvim`, etc.) follows the
|
via LDAP-backed autofs, so per-user config (shells, `nvim`, etc.) follows the
|
||||||
user across every host. This is the first slice of host auto-provisioning; see
|
user across every host. This is the first slice of host
|
||||||
[roadmap → Bootstrap tooling](roadmap.md). Fold the implemented parts into
|
[auto-provisioning](provisioning.md). Fold the implemented parts into
|
||||||
[identity](identity.md) and [onboarding](onboarding.md) once shipped.
|
[identity](identity.md) and [onboarding](onboarding.md) once shipped.
|
||||||
|
|
||||||
## Goal
|
## Goal
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Repository: [Charlie/project-charlie](https://gitea.alexandru.macocian.me/Charli
|
|||||||
| hosts | [Hosts](hosts.md) | Fleet roles and SOPS recipients. |
|
| hosts | [Hosts](hosts.md) | Fleet roles and SOPS recipients. |
|
||||||
| inventory | [Inventory](inventory.md) | Stack ownership, hosts, source/image repos, operator tooling. |
|
| inventory | [Inventory](inventory.md) | Stack ownership, hosts, source/image repos, operator tooling. |
|
||||||
| onboarding | [Host onboarding](onboarding.md) | Required host state and deploy-target prerequisites. |
|
| onboarding | [Host onboarding](onboarding.md) | Required host state and deploy-target prerequisites. |
|
||||||
|
| provisioning | [Host provisioning](provisioning.md) | Planned Ansible host auto-provisioning tool. |
|
||||||
| identity | [Identity & access](identity.md) | Authentik, LDAP, step-ca, Gssh, Sherlock, service identities. |
|
| identity | [Identity & access](identity.md) | Authentik, LDAP, step-ca, Gssh, Sherlock, service identities. |
|
||||||
| shared-homes | [Shared home directories](shared-homes.md) | Planned LDAP/autofs NFS-backed `/Users` homes. |
|
| shared-homes | [Shared home directories](shared-homes.md) | Planned LDAP/autofs NFS-backed `/Users` homes. |
|
||||||
| secrets | [Secrets](secrets.md) | SOPS, age keys, PAT identities, secret placement. |
|
| secrets | [Secrets](secrets.md) | SOPS, age keys, PAT identities, secret placement. |
|
||||||
|
|||||||
Reference in New Issue
Block a user