Commit Graph
21 Commits
Author SHA1 Message Date
jensandClaude Sonnet 5 fd4d386108 Rotate unused jens dyndns password for hygiene
Account has no hostname or key left to act on since the auth-binding
fix, but its password predated the whole migration - rotated it via
htpasswd -b. Verified new password works, old one is rejected, and the
account is still fully inert for DNS updates either way.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 12:41:11 +02:00
jensandClaude Sonnet 5 cd6ff83d5f Confirm both uschi and vpn dyndns migrations fully done
Second real WAN IP change on vpn produced another clean authenticated
update with no test collision this time. Both uschi and vpn have now
each been confirmed live across a real IP change on their dedicated
per-host login - nothing further to track on this item.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 12:39:16 +02:00
jensandClaude Sonnet 5 399e3c17a7 Refresh docs to reflect completed dyndns per-host auth fix
README.md's credential-audit table and command-injection writeup still
described the per-user auth binding gap as open; it's been closed since
2026-07-26. SETUP.md's TSIG section still taught the old single-shared-
key pattern for a fresh install - replaced with the per-host key +
update-policy pattern actually running in production now, plus a
pointer to the phased-rollout approach documented in TODO.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:32:21 +02:00
jensandClaude Sonnet 5 6ea1b0f5f2 Confirm uschi dyndns migration live, note test-collision wrinkle
Real FritzBox update authenticated as uschi landed after a WAN IP
change, confirmed via dig. Documented the earlier test-value collision
where a verification write clobbered the device's first post-migration
update, resolved by its next natural IP change - no lasting impact,
but noted as a lesson for future verification steps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:30:44 +02:00
jensandClaude Sonnet 5 9ea26af65f Retire dyndns legacy shared-key fallback entirely
uschi's device should be using its own dedicated login now, and with
jens/kack/test's own hostnames already removed, nothing needed the
fallback anymore. Removed the update-policy fallback grant, retired
the original shared TSIG key (in production since March 2022), and
deleted the now-dead legacy code path from nsupdate.php and its ipv4/
ipv6 variants. Per-host auth binding for dyndns is now unconditional
with no exceptions. Verified jens can no longer update any host, while
uschi/vpn continue to update themselves normally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:24:46 +02:00
jensandClaude Sonnet 5 e82bcb15da Remove stale jens.dyndns.jayfield.org hostname, keep jens login active
Same treatment as kack/test: no device had actually updated jens's own
record since Feb 2024. Removed the DNS record and its dedicated
update-policy grant/key, but deliberately kept the jens login and the
legacy shared-key fallback grant in place, since uschi's device still
depends on it. Re-verified the jens->uschi fallback path still works
after the change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:20:31 +02:00
jensandClaude Sonnet 5 e64f152d31 Remove stale dyndns hosts kack and test instead of migrating them
Neither had shown real recent activity (kack not since Feb 2024, test
with no traffic in the per-vhost log's short history), so rather than
give them dedicated per-host logins like vpn/uschi, removed their DNS
records, TSIG keys, update-policy grants, and .htpasswd accounts
outright. Backed up before removal; jens/uschi/vpn unaffected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:16:16 +02:00
jensandClaude Sonnet 5 560a2f61b0 Note vpn dyndns migration confirmed live
FritzBox reconfigured with its dedicated per-host login; a real WAN IP
change after recycling the connection produced a genuine authenticated
update, confirmed in the access log and via dig. First device fully
migrated off the legacy shared-key fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 10:09:22 +02:00
jensandClaude Sonnet 5 213dedf5e0 Fix dyndns per-user auth binding with real per-host TSIG keys
Closes the gap where any dyndns credential could update any of the
zone's 5 hostnames. Confirmed live that a FritzBox was already exposed
to this (authenticating as the shared 'jens' account while updating
'uschi'), so implemented a phased rollout: new per-host TSIG keys and
.htpasswd accounts enforce the binding at the BIND layer itself, with
a logged legacy fallback for the pre-existing shared account only,
so unmigrated devices keep working until reconfigured. Also fixed a
bug where nic/update.php reported "good" even on a rejected update.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 09:53:26 +02:00
jensandClaude Sonnet 5 b926af5fca Follow up on postfix-sasl and apache-noscript watch items
Both were left as "revisit if it escalates" notes from earlier audits.
Checked live logs on alpha via SSH (port 10022): postfix-sasl remains
scattered low-volume noise, not a coordinated low-and-slow campaign like
the dovecot spray; the original three /24s behind the apache-noscript
distributed scan are no longer active, current activity is normal
per-IP jail behavior. No fixes needed for either; also reconfirmed the
dyndns per-user auth binding gap is still present and unfixed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 09:31:10 +02:00
jensandClaude Sonnet 5 a715c217d2 Note BRBL still clear on manual check (48h test still pending)
Manual dig confirms 89.58.8.149 still delisted as of 2026-07-26, matching
the automated 1h propagation check. Not conclusive yet - Barracuda's
temporary 48h reputation bump is still in effect; the scheduled 48h
routine on 2026-07-27 is the real test of whether removal stuck.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-26 09:16:05 +02:00
jensandClaude Sonnet 5 70d949f48f Document Barracuda BRBL listing and pending removal request
Mail IP 89.58.8.149 got flagged on Barracuda's BRBL; local checks found
no sign of actual abuse (empty queue, minimal legit outbound, no
compromised SASL accounts), so removal was requested. Tracking the
confirmation number and scheduled follow-up checks here until resolved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:05:28 +02:00
jensandClaude Sonnet 5 04fff20577 Fix dovecot low-and-slow fail2ban gap; generalize findtime guidance
Same evasion pattern already fixed for sshd recurred against dovecot: a
coordinated IMAP password spray paced just outside the 30-minute findtime
window ran unbanned for days. Widened dovecot's findtime the same way,
and updated SETUP.md so future provisioning applies this to every
credential jail up front instead of waiting for it to reappear.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:47:33 +02:00
jensandClaude Sonnet 5 3f51d6016e Add per-vhost CustomLog directives; document access-log root cause
Real root cause turned out to differ from the original TODO: there was
no broken global CustomLog, mod_vhost_combined was already logging
every vhost without its own CustomLog into other_vhosts_access.log.
Added a dedicated CustomLog per real site anyway for easier incident
review, verified live with curl against all 7 domains after reload.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 20:43:19 +02:00
jens cff15408bf Document dyndns command-injection fix and two remaining follow-ups
README's public-access table and "previously resolved" summary now
reflect the dyndns injection fix and the TSIG-permission regression it
uncovered. Adds two open TODO items found during that audit: the dyndns
app's lack of real per-user auth binding, and the fact that access
logging for every real vhost on this host is currently a no-op.
2026-07-20 00:43:18 +02:00
jens 2ee6aad2b7 Fix command injection in dyndns update scripts
nsupdate.php/nsupdate_ipv4.php/nsupdate_ipv6.php rewritten to build the
nsupdate command as a string written to proc_open()'s stdin, using the
array form of the command so no shell is ever invoked -- no value can be
interpreted as shell syntax regardless of content. Added hostname/IP
validation as defense in depth. Originals backed up.

Also fixes a regression discovered while testing: www-data never got
read access to the TSIG key when it was tightened to 640 root:bind
(2026-07-19), so legitimate dyndns updates were silently failing
(REFUSED) independent of the vulnerability. Fixed with a POSIX ACL
scoped to just that key file rather than group membership, since the
bind group also owns rndc.key (full remote BIND control).

Verified end-to-end via the real PHP functions: injection payloads
rejected with no side effects, invalid IP rejected, legitimate update
succeeds and is visible in the zone, unauthenticated requests still 401.
2026-07-20 00:41:46 +02:00
jens f69aa18bec Add HIGH PRIORITY TODO: command injection in dyndns update scripts
nsupdate.php/nsupdate_ipv4.php/nsupdate_ipv6.php pass unsanitized $_GET
input straight into exec()'d shell commands. Gated by Apache Basic Auth
on the dyndns vhost, so not anonymously exploitable, but a real OS
command injection reachable by anyone with valid (or leaked) dyndns
credentials. Documents the finding and the fix approach; not yet applied.
2026-07-20 00:37:22 +02:00
jens 20c24f5a03 Fix accidental public-site lockout; document credential audit
A stray /var/www/html/.htaccess (dated 2025-02-18, predating everything
else in TODO.md) was silently requiring HTTP Basic Auth for jayfield.org
and www.jayfield.org's shared DocumentRoot, 401ing every real visitor to
the intentionally-public static site. Removed (backed up, not deleted).
Also adds a README table auditing which public hostnames do/don't
require credentials, prompted by checking this.
2026-07-20 00:33:39 +02:00
jens a67895b4dd Fix Portainer :9443 HSTS/self-signed-cert conflict
Moved Portainer's HTTPS UI behind an Apache reverse proxy on its own
subdomain (portainer.jayfield.org) instead of publishing it directly on
:9443 with a self-signed cert, which HSTS's includeSubDomains policy made
unreachable in Firefox with no click-through exception. Same pattern as
the existing web.jayfield.org/cloud.jayfield.org proxied subdomains: DNS
A record, Apache vhost proxying to 127.0.0.1:9443 over HTTPS, real
Let's Encrypt cert via certbot, standard HSTS header. Portainer container
recreated to bind 9443 to loopback only; verified end-to-end (cert chain,
HSTS header, redirect, and that :9443 is no longer reachable externally).
2026-07-20 00:26:01 +02:00
jens 4644c983ff Document Portainer :9443 HSTS/self-signed-cert conflict
Firefox refuses https://alpha.jayfield.org:9443 with
MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT and no click-through: the
includeSubDomains HSTS policy on the real alpha.jayfield.org vhost pins
the hostname to trusted-cert-only HTTPS on every port, but Portainer
still serves its stock self-signed cert directly on 9443. Records the
root cause and the planned reverse-proxy fix; no server changes made yet.
2026-07-20 00:08:34 +02:00
jensandClaude Sonnet 5 92d871f2da Initial docs: alpha.jayfield.org server documentation
Records the host's service inventory, setup runbook, mail account list,
sync plan, package diff vs. clean install, and hardening TODOs, including
today's SSH hardening (key-only, no root login) and the fail2ban sshd
findtime fix for a low-and-slow brute-force evasion pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdTyvEJkfNLDVAWt8WQ6X9
2026-07-19 23:09:27 +02:00