Skip to content

ivere27/kelp

Repository files navigation

Kelp

Secure Windows automation API gateway. Kelp exposes allow-listed COM, COM+, VB6, ADO, vendor COM SDK, and operator wrapper objects over authenticated gRPC/TLS, from XP SP2/Server 2003 to Windows 11/Server 2025.

Kelp runs beside Windows-only components and turns them into a modern, firewall-friendly API. Its core capability is deliberately narrow: instantiate an allow-listed COM object and invoke allow-listed methods, with COM VARIANT arguments, binary streams, and ADO recordsets (native ADTG/XML) preserved end to end.

That makes Kelp useful anywhere valuable Windows functionality is trapped behind COM, COM+, VB6, ADO, or an automation wrapper:

  • Integrate — call Windows-only business components and vendor COM SDKs from Linux, web, .NET, Java, Python, mobile, CI, or automation agents.
  • Modernize — replace DCOM, RDS/IIS, RDP runbooks, and fragile script-driven control paths with one authenticated gRPC/TLS contract.
  • Operate — manage COM+ applications, components, deployments, sessions, logs, runtime policy, and Proxy auth through the Admin API or embedded web dashboard.
  • Test — drive the real Windows objects from repeatable smoke, regression, migration, or AI-assisted test harnesses.
  • Automate safely — expose narrow, audited wrappers for file transfer, command runners, diagnostics, service health, event logs, and monitoring.

Everything is default-deny: only the ProgIDs and methods you explicitly allow are reachable.

Where it fits

Modern clients / CI / operators
        |
        | gRPC + TLS / mTLS + bearer auth
        v
     kelp.exe
        |
        +--> COM / COM+ / VB6 business components
        +--> ADO Recordset and ADODB.Stream workflows
        +--> Windows-only vendor COM SDK automation objects
        +--> Purpose-built operator wrappers

Kelp can still replace the classic RDS/DCOM/IIS pattern:

Before:  client -> RDS-over-HTTP / DCOM -> IIS + msadcs.dll -> COM+ -> SQL
After:   client -> gRPC + TLS -> kelp.exe -> COM+ / VB6 / ADO -> SQL

But RDS migration is only one scenario. The same contract can front other Windows ecosystem capabilities when the operation is represented as a COM automation object or a small wrapper component. Treat that power carefully: Kelp is convenient because COM can reach deep into Windows; it is dangerous for exactly the same reason.

Scenario map

Business need Kelp pattern
Modern apps need Windows-only business logic Allow-list the business ProgID and expose typed gRPC clients generated from proto/kelp.proto.
A vendor product only ships a COM automation SDK Wrap or allow-list the supported SDK methods and put TLS/auth/audit in front of them.
COM+ must cross firewalls or a DMZ Use one fixed gRPC/TLS endpoint instead of DCOM dynamic ports.
Existing ADO/RDS clients depend on disconnected recordsets Return ADTG/XML recordset blobs that clients rehydrate as real ADODB.Recordsets.
COM+ deployments are manual and risky Use BeginDeployment -> ValidateDeployment -> tests -> ActivateDeployment or RollbackDeployment.
Operators use RDP/MMC for routine COM+ tasks Use Admin RPCs or the web dashboard to inspect, recycle, shut down, dump, and reload policy.
CI needs to test real Windows behavior Run smoke/regression clients against the actual allow-listed objects.
Hosts need controlled file, log, service, or diagnostic access Expose purpose-built wrappers, not general shell/filesystem ProgIDs.
Teams need machine health without a remote shell Return read-only WMI/performance/service/event-log snapshots as variants or recordsets.

Tech stack

Layer Technology
Transport / API gRPC, Protocol Buffers (proto3), HTTP/2
Security TLS / mTLS, OpenSSL 4.0.1, bearer API keys
Language C++17
Windows integration COM / COM+ (STA/MTA), ADO, VARIANT/SAFEARRAY, ADTG/XML recordsets, COMAdmin
Build CMake, MinGW-w64 (i686 + x86_64 cross), Docker
gRPC base upstream gRPC v1.81.1 with the XP SP2 backport patch for both MinGW targets
Observability Prometheus metrics, HTTP-style access log, gRPC health
Admin UI embedded responsive web dashboard over gRPC-Web
Client bindings C ABI + synurang-generated typed C++ lite headers

Contract

The wire contract is proto/kelp.proto:

  • kelp.v1.Proxy — end-user sessions and caller-owned COM calls; a caller manages only its own session objects and calls.
  • kelp.v1.Admin — status, runtime component policy, COM+ management, and deployment staging/activation/rollback.

Source layout

Start with the design code map when changing code. The largest implementation files are split into private, feature-named *.inc units under their owning directory, so service, COM runtime, client ABI, and web dashboard changes have obvious entry points.

Quick start

# Build for the host. The embedded dashboard build needs npm; add
# -DKELP_EMBED_WEB_ADMIN=OFF if you only need the native binaries.
cmake -S . -B build/native
cmake --build build/native -j"$(nproc)"

# Kelp auto-generates managed TLS material when no manual cert/key is supplied.
build/native/kelp \
  --listen 127.0.0.1:5001 --admin-listen 127.0.0.1:5002 \
  --api-key dev-secret \
  --allow ADODB.Recordset:*

Prefer YAML? cp examples/kelp.yaml kelp.yaml && build/native/kelp --config kelp.yaml.

Building for Windows

Docker is the supported release path and builds both architectures:

make docker-build VERSION=0.7.0               # win-xp-i686 + win-xp-x64 + symbols
make docker-build VERSION=0.7.0 BUILD_X64=0   # 32-bit only
make release      VERSION=0.7.0 GITHUB_REPO=ivere27/kelp   # upload (needs gh)

Output: kelp-<version>-win-xp-i686.zip, kelp-<version>-win-xp-x64.zip, matching -symbols.zip archives, and SHA256SUMS. Each package has kelp.exe (server/CLI/service), kelp.dll (client SDK), import libraries, headers, proto, docs, and examples. Releases are stripped by default with DWARF sidecars in the symbols archive; pass STRIP_RELEASE=0 for unstripped binaries.

Two targets, one codebase:

Target Toolchain API floor Use
win-xp-i686 i686 MinGW, patched gRPC 1.81.1 + OpenSSL 4.0.1 _WIN32_WINNT=0x0501 XP SP2/Server 2003 → Win11/Server 2025 (via WoW64); hosts 32-bit in-process VB6/COM
win-xp-x64 x86_64 MinGW, patched gRPC 1.81.1 + OpenSSL 4.0.1 _WIN32_WINNT=0x0502 Windows XP Professional x64 / Server 2003 x64 → Win11/Server 2025; native 64-bit COM hosting and >2 GB address space

The two complement each other — cross-bitness in-process COM is not possible, so 32-bit VB6/COM components still need the 32-bit build.

Local cross builds without Docker (needs g++-mingw-w64-i686 / g++-mingw-w64-x86-64):

scripts/build-grpc-xp-latest.sh && make build-mingw-xp   # XP SP2 i686
make build-grpc-x64-deps && make build-mingw-x64         # XP x64 / Server 2003 x64

Manual details: docs/BUILDING.md.

Configuration

Kelp is default-deny: a ProgID can be created only if it appears in allow, --allow, or the Admin policy API.

server:
  listen: "0.0.0.0:5001"          # Proxy data-plane endpoint for clients
  adminListen: "127.0.0.1:5002"   # Optional Admin control plane
  tls:
    enabled: true
    sans: ["kelp.example.local"]
  auth:
    required: true
    apiKeys: ["env:KELP_API_KEY"]  # supply via environment, not plaintext YAML
com:
  apartment: STA                   # STA (recommended) | MTA
  poolSize: 100
  callTimeoutMs: 65000
  cancelOnTimeout: true
allow:
  - progId: "Your.ComPlus.Controller"
    methods: ["RunQuery", "SaveBatch"]   # prefer explicit methods

Keep Admin on loopback or a private network. Admin bearer auth is always required when the Admin listener is enabled; if no Admin key is configured, Kelp generates a bootstrap key and prints it once to stdout. Proxy and Admin can carry separate bearer keys and TLS material; set them under server.proxy / server.admin, which override the global server.auth / server.tls:

server:
  admin:
    listen: "127.0.0.1:5002"
    tls:
      certPath: "C:\\ProgramData\\Kelp\\admin.crt"
      keyPath: "C:\\ProgramData\\Kelp\\admin.key"
      clientCaPath: "C:\\ProgramData\\Kelp\\admin-clients.pem"  # require mTLS
      keyPassEnv: "KELP_ADMIN_TLS_KEY_PASS"                     # encrypted key passphrase
    auth:
      apiKeys: ["env:KELP_ADMIN_API_KEY"]

clientCaPath requires client-certificate (mTLS) auth on that listener. keyPassEnv names the env var holding an encrypted PEM key's passphrase — never put the passphrase itself in YAML. See examples/kelp.yaml for the fully annotated config.

Security

Kelp is a Windows automation API gateway, not an attack tool. There is no cracking, brute-forcing, or exploitation in it. But its core primitive (remote invocation of a COM object by ProgID) is the same kind of primitive that made classic RDS/RDS.DataFactory a remote-code-execution surface. The allow-list and auth are the security boundary — a careless allow-list turns Kelp into an authenticated RCE/file-access gateway.

Never allow-list general-purpose host/scripting objects on a production or shared endpoint — they hand every authenticated caller command execution, filesystem, or registry access:

  • WScript.Shell, Shell.Application — run arbitrary commands
  • Scripting.FileSystemObject, ADODB.Stream — arbitrary file I/O
  • ADODB.Connection — arbitrary database access (vs ADODB.Recordset, which is just data and is normally fine)
  • WbemScripting.SWbemLocator (WMI), MSXML2.ServerXMLHTTP, WinHttp.WinHttpRequest — outbound requests / SSRF
  • Scriptlet.TypeLib, Scripting.Signer, anything that registers code

Allow-list only the specific business, vendor, or operator-wrapper ProgIDs you intend to expose.

For operator automation, prefer a purpose-built wrapper such as Kelp.Tools.FileTransfer, Kelp.Tools.CommandRunner, or Kelp.Tools.SystemMonitor with explicit methods and argument validation. See docs/REMOTE-AUTOMATION.md for controlled examples using Scripting.FileSystemObject, ADODB.Stream, WScript.Shell, and remote monitoring.

Hardening checklist:

  • Keep default-deny; add ProgIDs one at a time, for a reason.
  • Prefer explicit methods: over allowAllMethods: true.
  • Require auth, keep keys in env, and use mTLS (clientCaPath) where the client set is known.
  • Isolate Admin on loopback/private network with its own key + TLS (it can register components, manage COM+ apps, and break-glass terminate processes).
  • Keep the metrics listener on loopback; never point the static root at config, TLS, or deployment directories.
  • Run under a least-privilege Windows identity.

TLS operations

kelp.exe manages local PEM certificates without an external OpenSSL command:

kelp.exe tls show          --path C:\Kelp\tls
kelp.exe tls rotate-server --path C:\Kelp\tls --san kelp.example.local
kelp.exe tls rotate-ca     --path C:\Kelp\tls --san kelp.example.local
kelp.exe tls client create app-client --path C:\Kelp\tls

Managed files are kelp-ca.crt/key, kelp-server.crt/key, and clients/<name>.crt/key. Defaults: a 10-year local CA, 397-day certificates, and automatic server-cert renewal within 30 days of expiry while the process runs — new handshakes pick up the renewed cert without dropping live connections. rotate-ca reissues the server cert and requires clients to trust the new CA, so stage it manually. Auto-generated keys are unencrypted for unattended restart; encrypted manual keys work via --tls-key-pass-env (and the --proxy-/--admin- variants).

Client SDK

clients/cpp is a C++17 gRPC client library built with the same Linux and MinGW paths as the server; human commands are available via kelp client .... It exposes a small C ABI:

  • kelp_client_version — DLL/API build version.
  • kelp_client_connect[_mtls][_with_key_passphrase] — channel setup for plaintext, TLS, mTLS, and encrypted client keys.
  • kelp_client_unary — method path + request bytes → reply bytes.
  • kelp_client_stream / kelp_client_stream_open|send|recv|close — streaming.
  • KelpSynurang_StartStaticProxy / KelpSynurang_StartAdminDashboardProxy — local loopback HTTP browser proxies with random ports, tokenized URLs, and upstream TLS/mTLS.
  • KelpSynurang_ProbeServerCertificatePem — certificate capture for native hosts that need an operator trust-on-first-use flow.

The release archive includes kelp.lib, a VC++ import library that loads the DLL at runtime (not static); MinGW hosts use libkelp-client.a. The ABI sits under synurang-generated typed bindings, so C++ callers need no Rust and no hand-written marshaling: generated/kelp_lite.hpp is generated from the proto, and synurang_lite.hpp is the pinned header-only runtime — make codegen-synurang refreshes both.

Operations and monitoring

Kelp exposes gRPC health, Prometheus text at /metrics, optional combined or split access logs, and an embedded browser dashboard/gRPC-Web gateway. Access logs write one completed call per line with timestamp, peer, actor, method, status, duration, scope, target, and reason. Proxy and Admin logs can be split and size-rotated independently. Metrics cover per-RPC counts/durations, active calls, sessions, COM handles, timeouts, cancellations, and worker recycles. Admin ListSessions / GetSessionAdmin report owner, peer, timestamps, live handles, and active calls.

  • Metrics listener is unauthenticated plaintext HTTP on 127.0.0.1:9464; bind it publicly only behind a firewall.
  • Static server reuses the effective Proxy TLS identity, can require mTLS with --static-client-ca, rejects .. and symlink/reparse traversal, normalizes dot segments, and treats paths as UTF-8 (non-ASCII/Korean filenames work). Keep Admin on a separate port.
  • Web dashboard is enabled with --web-listen, is embedded in kelp.exe unless --web-root is supplied, and shows Proxy/Admin/Web TLS state, certificate SHA-256 fingerprints, an emoji fingerprint visual, and bounded combined/proxy/admin log tails.
  • Wine can validate the binary and the gRPC/TLS/auth/admin/session/deployment plumbing plus in-process COM/ADO, but not the COM+ catalog or COM+ hosting — COMAdmin, recycle, and real VB6/COM+ round trips need real Windows.

More: Windows ecosystem scenarios (docs/WINDOWS-ECOSYSTEM-SCENARIOS.md), remote automation patterns (docs/REMOTE-AUTOMATION.md), running as a service (docs/BUILDING.md), testing on Windows — Wine + XP SP2 QEMU (docs/TESTING.md), Client browser proxies (docs/CLIENT-STATIC-PROXY.md), Browser gRPC-Web dashboard (docs/WEB-PROXY-API.md). See the full documentation index.

Testing and automation

The stable protobuf/gRPC contract makes the COM+/VB6 tier programmatically drivable from any language, CI, or an AI agent:

  • Smoke / integration / regression tests against the real allow-listed methods — see tests/ (smoke_client.cpp, security_smoke_client.cpp, complus_admin_smoke_client.cpp, benchmark_client.cpp) and the test component in tests/windows.
  • AI-driven or scripted exploration via the typed contract and C ABI — the agent drives a client and gains nothing beyond the methods you allow-listed.
  • Deploy-and-verify by combining a harness with the Admin deployment RPCs (BeginDeployment → ValidateDeployment → tests → ActivateDeployment / RollbackDeployment).

Kelp never uploads-and-runs arbitrary programs: the harness lives on the client/CI side, the server only invokes allow-listed methods, and deployment artifacts are COM+ components gated by ValidateDeployment. Point harnesses with side effects at a staging instance.

Status

Implemented: all COM call/create/invoke/release RPCs (unary + streaming); VARIANT/protobuf conversion with byref/out/optional args and shaped SAFEARRAY(VARIANT) values; ADO Recordset ADTG/XML save and rehydrate; end-user and Admin services; runtime component policy and deployment staging/activation/rollback; call timeout/cancellation via CoCancelCall with worker recycle; COMAdmin-backed COM+ management; break-glass process-terminate gate; static serving, Prometheus metrics, split/rotating access logs, embedded gRPC-Web dashboard, per-listener TLS/mTLS, multi-key bearer auth; Windows service mode.

Not yet: server-held COM return values as object_handle; typed-array fast paths beyond VT_ARRAY | VT_UI1 blobs; streaming COM connection-point events; out-of-process workers for force-killing below-COM-RPC wedges.

License

Apache-2.0

About

Secure Windows automation API gateway

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors