GitHub
05/14/2026, 5:40 PMStack order: depends on #813. The shared infrastructure consumed here —What this changes 5 files in,pkg/auditlog.FailedEnroll,pkg/ratelimit/ updatedutils.SetTrustedProxies— ships in #813. If you read the diff here againstGetIPit will include those #813 changes; the carve-out is the 5 files undermain+cmd/tls/. Once #813 merges this PR's diff drops to those 5 files only.deploy/config/tls.yml
cmd/tls/ + deploy/config/tls.yml. Three independent defenses on the only osctrl service that is internet-facing in a typical deployment:
1. Constant-time secret comparison
cmd/tls/handlers/utils.go — checkValidSecret and checkValidRemovePath use subtle.ConstantTimeCompare instead of the previous byte-by-byte short-circuiting compare. Removes a response-time timing oracle on the public enroll endpoint.
2. Per-IP rate-limit on /enroll
cmd/tls/main.go — 20 req/min per remote IP, idle eviction after 10 min, backed by pkg/ratelimit (from #813). Rejected requests:
• return 429
• record AuditLog.FailedEnroll(ip, env, "rate limit exceeded", 0) so SoC tooling can alert
3. Audit-log on failed enrollment
• cmd/tls/handlers/handlers.go — HandlersTLS gains an AuditLog field + WithAuditLog option; defensive default is a disabled manager so handler code can call h.AuditLog.FailedEnroll(...) without nil-checks.
• cmd/tls/handlers/post.go — EnrollHandler records FailedEnroll on the invalid-secret path.
• cmd/tls/main.go — initializes auditlog.CreateAuditLogManager and threads it via WithAuditLog. Service name osctrl-tls flows through.
4. Trusted-proxies plumbing
cmd/tls/main.go — reads flagParams.Service.TrustedProxies (CIDR list) and calls utils.SetTrustedProxies before any request reaches GetIP. Empty default = GetIP ignores X-Forwarded-For / X-Real-IP, preventing internet-side header-spoofed bypass of the rate-limiter or audit-log poisoning.
Config
`deploy/config/tls.yml`:
• auditLog: true (on by default; was false)
• trustedProxies: "" (empty default; operators behind a trusted reverse proxy can list CIDRs)
Verified
• go build ./... clean
• go vet ./... clean
• go test ./cmd/tls/... green
• Live smoke on a dev stack: 4 osquery nodes enrolled, audit_logs records enroll_failure rows with correct IPs for forced bad-secret attempts
Test plan
• CI: lint + build + tests pass once workflows are approved
• Manual: with trustedProxies empty, confirm X-Forwarded-For: 1.2.3.4 doesn't override RemoteAddr in audit_logs
• Manual: trigger >20 enroll requests from the same IP in <1 min, confirm 429 + audit-log entry
• Manual: bad enroll-secret produces an enroll_failure audit-log row with the source IP
jmpsec/osctrlGitHub
05/17/2026, 3:46 PM