Skip to content

feat: Add Kerberos/SPNEGO authentication support for repeater#751

Open
bararchy wants to merge 5 commits into
nextfrom
feat/kerberos-auth
Open

feat: Add Kerberos/SPNEGO authentication support for repeater#751
bararchy wants to merge 5 commits into
nextfrom
feat/kerberos-auth

Conversation

@bararchy

Copy link
Copy Markdown
Member

Summary

Add native Kerberos/SPNEGO (Negotiate) authentication support for the repeater agent. This allows the CLI to transparently authenticate with target services protected by Kerberos, leveraging libcurl's built-in GSSAPI/SSPI support — no new npm dependencies required.


Usage

Basic — Use System Kerberos Ticket

If you already have a valid ticket (via kinit), just enable the flag:

bright-cli repeater --id <REPEATER_ID> --token <API_KEY> --kerberos

The repeater will use the system's cached Kerberos ticket for all target domains.

Restrict to Specific Domains

Apply Kerberos only to specific hosts (supports wildcards):

bright-cli repeater --id <REPEATER_ID> --token <API_KEY> \
  --kerberos \
  --kerberos-domains "*.corp.internal" "intranet.company.com"

Requests to other domains proceed without Kerberos authentication.

Explicit Credentials (No kinit Required)

Provide username and password directly — useful in CI/CD pipelines or containers where you can't run kinit beforehand:

bright-cli repeater --id <REPEATER_ID> --token <API_KEY> \
  --kerberos \
  --kerberos-credentials "admin@CORP.INTERNAL:S3cret!"

Format: user@REALM:password or user:password (libcurl will use the default realm from krb5.conf if only user:password is given).

Credential Delegation

Allow the target server to use your credentials to access other Kerberos-protected services on your behalf (constrained delegation):

bright-cli repeater --id <REPEATER_ID> --token <API_KEY> \
  --kerberos \
  --kerberos-delegation

⚠️ Only enable delegation when you trust the target service. This allows it to impersonate you.

Environment Variables

All options are also available via environment variables (prefix REPEATER_):

CLI Option Environment Variable Example
--kerberos REPEATER_KERBEROS true
--kerberos-domains REPEATER_KERBEROS_DOMAINS *.corp.internal *.ad.company.com
--kerberos-credentials REPEATER_KERBEROS_CREDENTIALS user@REALM:pass
--kerberos-delegation REPEATER_KERBEROS_DELEGATION true

Full Example (Docker / CI)

docker run --rm \
  -e REPEATER_TOKEN=<API_KEY> \
  -e REPEATER_ID=<REPEATER_ID> \
  -e REPEATER_KERBEROS=true \
  -e REPEATER_KERBEROS_CREDENTIALS="svc_scanner@CORP.INTERNAL:P@ssw0rd" \
  -e REPEATER_KERBEROS_DOMAINS="*.corp.internal" \
  brightsec/cli repeater

Implementation Details

Architecture

The implementation hooks into the existing HttpRequestExecutor pipeline by adding two private methods:

  1. shouldApplyKerberos(request) — Determines whether Kerberos should be applied for a given request URL by matching against configured domains (or returning true for all if no domains specified).

  2. applyCurlKerberos(curl, request) — Sets the libcurl options when Kerberos applies:

    • HTTPAUTH = 4 (CURLAUTH_NEGOTIATE) — tells libcurl to use SPNEGO/Negotiate
    • USERPWD = credentials || ":" — empty : means "use system ticket cache"
    • GSSAPI_DELEGATION = 1 — when --kerberos-delegation is set

Connection Reuse

Kerberos/SPNEGO is a multi-round-trip protocol. The initial request gets a 401 with WWW-Authenticate: Negotiate, then libcurl automatically retries with the SPNEGO token. This requires TCP connection reuse, so when Kerberos is enabled:

  • The Multi handle pool is activated (same mechanism as --ntlm)
  • TCP_KEEPALIVE and TCP_KEEPIDLE are set
  • FRESH_CONNECT / FORBID_REUSE are not set

Domain Matching

Uses the same wildcard-to-regex mechanism (Helpers.wildcardToRegExp) as --proxy-domains, supporting patterns like *.corp.internal, host.example.com, 192.168.*.

Conflicts & Validation

  • --kerberos conflicts with --ntlm (both use HTTPAUTH, can't combine)
  • --kerberos-domains, --kerberos-credentials, --kerberos-delegation all imply --kerberos (yargs implies)

Prerequisites

  • Linux/macOS: libcurl must be built with GSSAPI (GSS-Negotiate) support. This is standard on most distributions (curl --version should show GSS-API or SPNEGO).
  • Windows: Automatically uses SSPI (built into Windows) — no extra setup needed.
  • Kerberos infrastructure: A KDC must be reachable, and either a valid ticket exists (klist to verify) or credentials are provided.

Files Changed

File Change
src/RequestExecutor/RequestExecutorOptions.ts Added KerberosOptions interface
src/RequestExecutor/HttpRequestExecutor.ts Added shouldApplyKerberos(), applyCurlKerberos(), connection reuse logic
src/Commands/RunRepeater.ts Added CLI options, yargs conflicts/implies
src/RequestExecutor/HttpRequestExecutor.spec.ts Added 3 unit tests for Kerberos behavior

@bararchy bararchy requested review from alonchin and derevnjuk May 21, 2026 20:50
@bararchy bararchy self-assigned this May 21, 2026
@bararchy

Copy link
Copy Markdown
Member Author

⚠️ Upstream Dependency: @brightsec/node-libcurl

Docker build confirmed the prebuilt node-libcurl binary lacks GSSAPI support:

libcurl/8.17.0 OpenSSL/3.5.6 zlib/1.3.1 brotli/1.2.0 ...

No GSS-API in the feature list. This is because vcpkg.template.json in @brightsec/node-libcurl does not include the "gssapi" feature.

What's needed in @brightsec/node-libcurl (separate PR):

Add "gssapi" to the vcpkg features array:

{
  "name": "curl",
  "features": [
    "brotli", "c-ares", "http2", "http3", "ldap",
    "gsasl", "gssapi", "idn", "idn2", "openssl",
    "ssh", "sspi", "websockets", "zstd", "tool"
  ]
}

Then rebuild and publish prebuilt binaries for linux-x64 and linux-arm64.

Current state:

  • ✅ CLI code is complete and correct (HTTPAUTH=Negotiate, domain matching, connection reuse)
  • ✅ Docker has krb5 + krb5-libs runtime packages (kinit, libgssapi_krb5.so)
  • @brightsec/node-libcurl prebuilds need gssapi vcpkg feature
  • ✅ On Windows, sspi feature already handles Negotiate (works today)

@bararchy

Copy link
Copy Markdown
Member Author

Upstream PR for GSSAPI support in node-libcurl: NeuraLegion/node-libcurl#19

Once that merges and prebuilds are published, Kerberos will work end-to-end on Linux.

bararchy added a commit to NeuraLegion/node-libcurl that referenced this pull request May 21, 2026
Add the 'gssapi' vcpkg feature on non-Windows platforms to enable
SPNEGO/Negotiate authentication. On Windows, SSPI (already included)
handles Negotiate, so gssapi is skipped there.

Changes:
- scripts/vcpkg-setup.js: conditionally inject 'gssapi' feature into
  vcpkg.json on Linux/macOS (vcpkg does not support curl[gssapi] on Windows)
- install-system-packages: add krb5-dev (Alpine) and libkrb5-dev (Ubuntu)
  so vcpkg can link curl against system GSSAPI libraries

Related: NeuraLegion/bright-cli#751

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bararchy bararchy requested a review from aborovsky May 22, 2026 11:16

@aborovsky aborovsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx for new feature delivery. Pls check few comments.

Comment thread src/RequestExecutor/HttpRequestExecutor.ts Outdated
Comment thread src/RequestExecutor/HttpRequestExecutor.ts Outdated
Comment thread src/RequestExecutor/HttpRequestExecutor.ts Outdated
Comment thread src/RequestExecutor/HttpRequestExecutor.ts
Comment thread src/RequestExecutor/HttpRequestExecutor.ts
aborovsky added a commit that referenced this pull request Jun 3, 2026
…Executor

Exercises the actual code path changed by PR #751:
  HttpRequestExecutor (kerberos: true, credentials: scanner@EXAMPLE.COM:ScannerPass1)
    → libcurl CURLAUTH_NEGOTIATE (HTTPAUTH=4)
      → mit-krb5 GSSAPI handshake
        → Apache httpd mod_auth_gssapi (Require valid-user)
          → HTTP 200

Previously test.sh only validated build-time artifacts and static analysis.
This new step confirms the end-to-end authentication path works at runtime.
@aborovsky

Copy link
Copy Markdown
Contributor

I've test full flow for Kerberos auth at HttpRequestExecutor with single test case and it seems to work.

bararchy and others added 5 commits June 25, 2026 20:22
Add native Kerberos/SPNEGO authentication via libcurl's CURLAUTH_NEGOTIATE.
This allows the repeater to authenticate with target services that require
Kerberos, using either explicit credentials or system keytab/kinit tickets.

New CLI options:
  --kerberos               Enable Kerberos/SPNEGO auth
  --kerberos-domains       Restrict Kerberos to specific domains (wildcards)
  --kerberos-credentials   user:password format (optional)
  --kerberos-delegation    Allow credential delegation

Also configurable via REPEATER_KERBEROS* environment variables.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The connection reuse test failed in environments without GSSAPI/SPNEGO
support (libcurl errors before connecting). Changed the test to verify
the executor handles kerberos-enabled requests gracefully regardless
of GSSAPI availability.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add krb5-dev (build-time) and krb5-libs + krb5 (runtime) to enable
libcurl's GSSAPI/Negotiate authentication inside the container.

- krb5-dev: needed at build-time for curl GSSAPI linkage
- krb5-libs: runtime GSSAPI shared libraries
- krb5: client tools (kinit, klist, kdestroy) for ticket management

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The krb5/krb5-libs packages provide:
- kinit/klist/kdestroy for Kerberos ticket management
- libgssapi_krb5.so runtime library

NOTE: Full Kerberos support also requires @brightsec/node-libcurl to be
rebuilt with the 'gssapi' vcpkg feature (upstream change needed).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…close

- Replace CURLAUTH_NEGOTIATE=4 with CurlAuth.Negotiate enum
- Replace CURLGSSAPI_DELEGATION_FLAG=1 with CurlGssApi.DelegationFlag (value 2)
- Don't send Connection: close when Kerberos is active (breaks SPNEGO)
@bararchy bararchy force-pushed the feat/kerberos-auth branch from 4e8e9a4 to 4ca1ee8 Compare June 25, 2026 17:23
@bararchy bararchy requested a review from aborovsky June 25, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants