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.
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.
| 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. |
| 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 |
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.
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.
# 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.
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 x64Manual details: docs/BUILDING.md.
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 methodsKeep 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.
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 commandsScripting.FileSystemObject,ADODB.Stream— arbitrary file I/OADODB.Connection— arbitrary database access (vsADODB.Recordset, which is just data and is normally fine)WbemScripting.SWbemLocator(WMI),MSXML2.ServerXMLHTTP,WinHttp.WinHttpRequest— outbound requests / SSRFScriptlet.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:overallowAllMethods: 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.
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).
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.
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 inkelp.exeunless--web-rootis 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.
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 intests/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.
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.