Help us shape the future of Go! Take the 2026 Go Developer Survey

cosmoguard

module
v0.1.8-0...-2d3a009 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 24, 2026 License: MIT

README

CosmoGuard

Test GoReleaser Docker Builds

CosmoGuard is a security-focused proxy + cache + auth gateway in front of Cosmos-SDK nodes. It gates access at the API-endpoint level (not just by port), caches deterministic responses, throttles abusive traffic, fans out to multiple upstream nodes with active healthchecks, and authenticates clients via API keys / JWT / external validators.

The current major version is v4. See the release notes for what changed from v3; existing v3 configs continue to work — run cosmoguard migrate-config to rewrite them in v4 form when ready.

Highlights

  • Endpoint-level access control across every Cosmos surface: Tendermint RPC (HTTP + JSON-RPC + WebSocket), Cosmos LCD/REST, gRPC (Query), and EVM RPC + WS.
  • Expressive rule schema (v4): combine all/any/none predicates over method, path, query, headers, source IP/CIDR. Globs supported on every value.
  • Response caching with per-rule namespacing, content-type preservation, configurable header allowlists. Backed by an embedded olric distributed cache with an in-process L1 — single binary, no external dependency, shared automatically across replicas when cluster mode is on.
  • Rate limiting with per-ip, global, and (post-auth) per- identity scopes. Buckets are sharded across replicas through the same olric runtime in cluster mode, so configured rates stay correct under HPA without an external store.
  • Authentication: api-key, JWT (HMAC + RSA/ECDSA/Ed25519), RFC 7662 token introspection, and an external-validator method for developer-portal style credential checks. Credential headers are always stripped before forwarding upstream.
  • CORS owned by cosmoguard, not the upstream — preflight handled directly; upstream's CORS headers are stripped and replaced.
  • Multi-upstream nodes with active healthchecks, weighted round- robin, and per-upstream circuit breakers. /readyz reflects pool health.
  • Hardened defaults: HTTP timeouts, request body caps, JSON-RPC batch size caps, WS origin allowlist, atomic-fail-safe config reload, no glob.MustCompile panics.
  • Production polish: graceful shutdown on SIGTERM, cosmoguard validate for CI gates, cosmoguard migrate-config for v3→v4 rewrites, /healthz / /readyz / /info / /metrics for k8s probes and Prometheus.
  • Hot-reload of config rules without dropping in-flight requests; WebSocket subscriptions the new rules deny are revoked.
  • Live observability dashboard: a read-only UI with per-protocol traffic, cache hit rates, rule/identity views, recent denials, unmatched endpoints, a live request feed, and a WebSocket connection/subscription panel. In cluster mode it fans out across peers for a single cluster-wide view. OpenTelemetry tracing and Prometheus metrics round out the surface.

Installation

Install script (Linux / macOS)

The quickest way to grab the latest release binary. The trailing ! tells the installer (jpillora/installer) to move the binary into your PATH rather than just dropping it in the current directory:

curl -s https://get.voluzi.com/cosmoguard! | bash
Prerequisites
  • Go 1.25+ (for building from source).
Docker
docker run -it --name cosmoguard \
  -v /path/to/cosmoguard.yaml:/etc/cosmoguard/cosmoguard.yaml \
  ghcr.io/voluzi/cosmoguard \
  --config /etc/cosmoguard/cosmoguard.yaml

Image tags: X.Y.Z for each release, latest for the newest stable release, and edge for the current main branch (unreleased, may break).

Helm (k8s)

Each release publishes the chart as oci://ghcr.io/voluzi/helm/cosmoguard, versioned with cosmoguard itself (chart X.Y.Z deploys image X.Y.Z):

kubectl create secret generic cosmoguard-cluster-key \
  --from-literal=encryptionKey="$(head -c32 /dev/urandom | base64)"

helm upgrade --install cosmoguard oci://ghcr.io/voluzi/helm/cosmoguard \
  --set config.nodes[0].host=cosmos-node.default.svc \
  --set cluster.existingEncryptionKeySecret=cosmoguard-cluster-key

Create the shared key Secret once; do not regenerate it on each deploy. The Secret and Helm release must use the same namespace (both commands above use default).

Installing from a checkout (./helm/cosmoguard) deploys the floating latest image, because the chart's version fields are only stamped at release. Pin the image for anything but local testing, e.g. --set image.tag=4.0.3 (no v prefix).

See helm/cosmoguard/README.md for cluster-mode + HPA setup.

Build from source
git clone https://github.com/voluzi/cosmoguard.git
cd cosmoguard
make install

Quick start

Minimal config — allow /status on Tendermint RPC and cache for 10s:

nodes:
  - host: 127.0.0.1
    rpcPort: 26657
    lcdPort: 1317
    grpcPort: 9090

cache:
  ttl: 10s

rpc:
  rules:
    - action: allow
      match:
        path: /status
        methods: [GET]
      cache:
        enable: true

  jsonrpc:
    rules:
      - action: allow
        methods: [status]
        cache:
          enable: true

A fuller example with multi-upstream, auth, CORS, and rate limiting is in example.config.yml.

See CONFIG.md for the complete reference.

Validate + run

# Pre-deploy / CI check: parse + compile the config without binding ports.
cosmoguard validate --config /etc/cosmoguard/cosmoguard.yaml

# Rewrite a v3 config in v4 form (the original is backed up to .v3.bak).
cosmoguard migrate-config --config /etc/cosmoguard/cosmoguard.yaml

# Run cosmoguard.
cosmoguard --config /etc/cosmoguard/cosmoguard.yaml

Compatibility

CosmoGuard is designed as a drop-in stand-in for a direct Cosmos node connection. Any request that worked against a bare Tendermint/Cosmos/ EVM node returns a byte-identical response through cosmoguard when allowed. There are six intentional v4 behavioral changes to review before upgrading (default-deny on WS cross-origin, cosmoguard-owned CORS, content-type fidelity on cache hits, Prometheus label cleanup, no force-allowed gRPC reflection, and mandatory positive rates in configured rate-limit blocks).

A compatibility test suite recordable via scripts/record-golden.sh captures live-node responses and replays them through cosmoguard, asserting byte-identical relay.

Checking a live node

cmd/cosmoguard-compat calls every read endpoint it can find on a node, both directly and through cosmoguard, and reports where the answers differ. It finds the endpoints itself: gRPC query methods through server reflection (only *.Query / *.QueryService services and the SDK's known read-only services are called; others are listed as skipped), the LCD routes annotated on them, every read-only CometBFT RPC method (URI and JSON-RPC forms, plus a batch), a fixed set of read-only EVM JSON-RPC methods, and the NewBlock / newHeads WebSocket subscriptions. Queries that take a height are pinned to one, so their answers compare byte for byte; answers about the latest state or the answering node (status, latest block, node info, gas price and the like) are compared by JSON shape only, and a WebSocket event is compared as a JSON value for the same block. Each cosmoguard answer is fetched twice so cached answers are checked too. The status, body and Content-Type are compared; other response headers are not. A few cross-height probes also ask for the same query at two heights, so a cache that ignores the requested height is caught.

The node side must be a raw node, not one already behind cosmoguard; a chain's public endpoints usually are, and comparing against them tests cosmoguard against itself. By default the tool expects the node on localhost at the standard ports, so with a Cosmopilot node forward them first:

kubectl port-forward svc/<chainnode> 1317 26657 9090   # add 8545 8546 for an EVM chain
make compat

make compat builds cosmoguard, starts it in front of the node, compares and stops it. A chain without EVM leaves ports 8545 and 8546 closed; its EVM checks are reported as skipped. --node-lcd, --node-rpc, --node-grpc (http:// for plaintext, https:// for TLS), --node-evm and --node-evm-ws override each default, and an EVM URL given this way must be reachable. To check a cosmoguard you already run:

go run ./cmd/cosmoguard-compat \
  --guard-lcd http://cosmoguard:11317 --guard-rpc http://cosmoguard:16657 \
  --guard-grpc http://cosmoguard:19090 --report compat.json

Each endpoint is reported as identical, differs (cosmoguard answered differently), denied (cosmoguard refused a request the node answered), failed (the node itself did not answer), unstable or skipped (a path parameter has no live value; --param name=value supplies chain-specific ones). An endpoint is unstable when the node disagrees with itself between two calls, or answers at a different height despite the pin. A node behind a load balancer can do both, so a differing endpoint is compared again, up to three rounds, and only reported as differs when no round matched. Rounds and height retries are --round-delay apart (3s with make compat, whose cosmoguard caches for 2s), so each reaches the node rather than cosmoguard's cache; set it above your cache TTL when checking a running deployment.

The run exits 1 when any endpoint differs, when nothing could be compared, or, with make compat (whose config allows everything), when any request was denied. With make compat the cosmoguard log is kept after a failing run and its path is printed.

The tool needs network access and is not part of make test.

License

Unless a file notes otherwise, it falls under the MIT License.

Directories

Path Synopsis
cmd
cosmoguard command
cosmoguard-compat command
Command cosmoguard-compat checks that cosmoguard answers like the node behind it.
Command cosmoguard-compat checks that cosmoguard answers like the node behind it.
internal
compat
Package compat compares a Cosmos node's responses with the responses cosmoguard gives for the same requests.
Package compat compares a Cosmos node's responses with the responses cosmoguard gives for the same requests.
pkg
cosmoguard/testharness
Package testharness boots an in-process fake Cosmos upstream and a real cosmoguard instance in front of it, exposing helpers that make end-to-end tests of the proxy pipeline straightforward.
Package testharness boots an in-process fake Cosmos upstream and a real cosmoguard instance in front of it, exposing helpers that make end-to-end tests of the proxy pipeline straightforward.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL