Commit graph

9 commits

Author SHA1 Message Date
codex
b93af8cc78 Implement reproducible S1 handoff contracts
Some checks failed
CI Smoke / source-contract (push) Failing after 2s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02994-7685-7940-bf34-3555b8256018
2026-08-23 12:02:23 +02:00
codex
4d9e77c968 Close RAIL-HO-WP-0009 declared-state gaps; leave live 6443 prune gated
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Make the k3s API tunnel-only (ADR-005), stop declaring Flannel VXLAN
open to Anywhere, tag the base role so firewall can be scoped, and
schedule the Goss declared-vs-live check. CoulombCore sets ufw_manage
false so a converge cannot enable UFW there. T02 still needs operator
approval for make converge-firewall HOST=Railiance01.
2026-08-15 15:41:59 +02:00
codex
3c38b0625a Declare a third operator address; record T02 progress and why full converge was held
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
89.244.90.255 appeared in the live allowlist mid-session. Verified legitimate:
SSH pubkey auth as tegwick from that address on 2026-08-02, and UFW BLOCK
entries on 6443 immediately before it was granted. Now declared.

Both stale grants are deleted from the live host, so the security goal of T02 is
met and the live 6443 allowlist matches the declaration exactly.

Full convergence deliberately held: --check reports 11 changes, mostly unrelated
to the firewall, including MemoryMax=1500M on user-1000.slice which could OOM
running agent workloads, plus an sshd restart. That is a separate decision, and
the base role has no tags so convergence cannot be scoped to UFW alone. Records
both follow-ons.

The allowlist drifting again by hand during the session that was fixing
allowlist drift is now recorded as the strongest argument for T04, removing the
API from the public internet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 01:46:36 +02:00
codex
c84fe7a3de Make the k3s API firewall allowlist declarative
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
The live host restricted 6443/tcp to specific operator addresses, added by hand,
while this role still declared the port open to Anywhere with no source
restriction. The declared config was weaker than reality: running the base role
would have REMOVED the restriction and exposed the Kubernetes API to the
internet. Security was tightened on the host and never fed back into the source
of truth.

Found 2026-08-11 while diagnosing lost cluster access, which turned out to be an
ISP lease rotation (89.244.90.246 -> .236) against a hand-maintained allowlist.

Changes:
- defaults: k3s_api_allowed_sources (empty = 6443 closed to all external
  sources, the safe failure; SSH unaffected so the host stays recoverable) and
  k3s_api_revoked_sources, so rotated addresses are pruned rather than left as
  standing grants to whoever the ISP reassigns them to
- tasks: grant approved sources, then remove any blanket rule, then revoke
  retired ones. Order matters - grants are added before the blanket rule is
  deleted so convergence never opens a window with no API access
- group_vars/all.yaml: the current operator address, plus the two stale grants
  (.246 rotated, 85.132.220.102 historic) marked for revocation
- docs/verification.md: state that 6443 is source-restricted rather than
  listing it as a plainly allowed port

Not yet converged against the live host - the role change is committed but
running it is a production action needing operator approval.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:56:28 +02:00
c31d70b53f feat(ssh): add bootstrap-ssh-ca role for OpenBao SSH user CA trust
Deploy TrustedUserCAKeys, auth_principals from ssh_principals.yaml, and
Makefile targets bootstrap-ssh-ca / bootstrap-ssh-ca-host (NET-WP-0020 T5).
2026-06-18 01:06:43 +02:00
3f4f03e838 feat(ansible): inject ops-bridge key in base role at bootstrap
Add ops_bridge_pubkey to group_vars/all.yaml (public key only, safe to
commit) and inject it via ansible.posix.authorized_key in the base role,
immediately after SSH hardening. This ensures ops-bridge tunnel
connectivity is available as soon as SSH infrastructure is up on any
managed host — no manual key provisioning required for new nodes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 23:52:54 +01:00
ff59d4e0f8 feat(ansible): add swapfile + resource_limits roles; add CoulombCore to inventory
T01: roles/swapfile — idempotent 4GB swapfile, vm.swappiness=10, fstab entry
T02: roles/resource_limits — PAM nproc caps (512/1024), systemd user-1000.slice
     memory limits (1500M/512M); templated per-host via host_vars
- inventory/host_vars/CoulombCore.yml — host-specific vars for both roles
- inventory/servers.yaml — add CoulombCore with id_ops SSH key
- inventory_from_yaml.py — load host_vars files into Ansible hostvars
- playbooks/bootstrap.yaml — include swapfile + resource_limits roles
- workplans/WP-0004 — flag T04/T09/T10 needs_human, add CoulombCore-local convergence note

Codifies manual INC-002 hardening. See RAIL-HO-WP-0004-T01/T02.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:49:35 +01:00
f5bfc1a922 feat(custodian-agent): add custodian agent public key
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC/V9fe5MGKdhTBz9KwEvC1NE+HjdoCtQocpGxP6Pko9

Generated 2026-03-27 via make custodian-keygen. Private key at workstation
only (~/.ssh/id_custodian_agent), never committed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:22:45 +01:00
30a3f908aa feat(custodian-agent): Ansible role + Makefile for Custodian SSH identity
Establishes a dedicated SSH keypair for the Custodian automation agent:
- ansible/roles/custodian_agent/: authorized_key task (tagged custodian_agent)
- ansible/inventory/group_vars/all.yaml: custodian_agent_user/pubkey vars
- ansible/playbooks/bootstrap.yaml: custodian_agent role added
- Makefile: provision-custodian-agent / provision-custodian-agent-host targets

Keypair generation: cd ~/the-custodian && make custodian-keygen
Then deploy:        cd ~/railiance-infra && make provision-custodian-agent

The private key lives at ~/.ssh/id_custodian_agent — never committed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:21:57 +01:00