Skip to content

Repository files navigation

Restium

A declarative reconciling REST client in Rust. Define REST resources in YAML, and Restium converges your API state to match — creating, updating, or cleaning up resources as needed.

Replace fragile curl scripts with readable, reviewable YAML.

Restium is built for platform engineers who need to provision resources against REST APIs (Netbird, Keycloak, API gateways) as part of automated deployment pipelines. It ships as a 3.5MB distroless container — no shell, no package manager, zero CVEs.

Quick Start

# Install (after crate is published)
cargo install restium
# Or build from source
cargo build --release
# Or pull the container
docker pull ghcr.io/kitstream/restium:latest
# Validate your spec
restium validate --spec resources.yaml
# Reconcile — converge API state to match your spec
restium reconcile --spec resources.yaml

Example: Netbird Bootstrapping

global:
base_url: https://api.netbird.io/apiauth:
type: bearertoken_env: NETBIRD_TOKENresources:
- name: internal_networkendpoint: /networksread_endpoint: /networks/internalpayload:
name: internaldescription: Internal service networkoutputs:
id: id
- name: monitoring_routeendpoint: /routespayload:
network_id: "${internal_network.output.id}"peer: monitoring-peernetwork: 10.100.0.0/24description: Route to monitoring subnetdepends_on:
- internal_network
- name: monitoring_access_policyendpoint: /policiespayload:
name: monitoring-accessenabled: truerules:
- sources: ["monitoring-group"]destinations: ["${internal_network.output.id}"]action: acceptdepends_on:
- internal_network
export NETBIRD_TOKEN="your-api-token"
restium reconcile --spec netbird.yaml

Restium resolves dependencies automatically: internal_network is created first, its id is extracted, then monitoring_route and monitoring_access_policy use that ID in their payloads. On subsequent runs, unchanged resources are skipped.

Spec Reference

Global Settings

FieldTypeDefaultExampleDescription
base_urlstringhttps://api.example.comBase URL prepended to all resource endpoints
default_headersmapContent-Type: application/jsonHeaders applied to all requests (overridable per resource)
authobjectSee AuthenticationGlobal authentication config
ca_bundlestring/etc/ssl/custom-ca.pemPath to PEM CA bundle for internal/self-signed certs

Resource Fields

FieldTypeDefaultExampleDescription
namestringrequiredmy_resourceUnique resource identifier
endpointstringrequired/api/v1/resourcesAPI endpoint path (appended to base_url)
methodstringPOSTPUTHTTP method for create operations
payloadobjectname: fooRequest body (YAML, sent as JSON)
headersmapX-Custom: valuePer-resource headers (merged with global, overrides on conflict)
base_urlstringglobalhttps://other-api.comOverride global base URL for this resource
depends_onlist[network, policy]Explicit dependency on other resource names
read_endpointstring/api/v1/resources/mineGET endpoint for state discovery (enables idempotent updates)
outputsmapid: idExtract fields from API response (output_key: json_field)
actionstringdeleteSet to delete for explicit resource deletion
authobjectglobalSee AuthenticationPer-resource auth override

References

Use ${resource_name.output.field} to reference outputs from other resources. Dependencies are resolved automatically.

payload:
network_id: "${my_network.output.id}"

If a reference cannot be resolved, Restium reports which resource and field are missing.

Failure Modes

ConditionExit CodeError
Spec file not found2Failed to read spec file '<path>': No such file
Invalid YAML2Failed to parse spec file '<path>': <details>
Unknown field in spec2unknown field '<name>'
Broken reference2Resource '<name>' references unknown resource '<ref>'
Circular dependency2Circular dependency detected: a -> b -> a
Missing env var for auth2Environment variable '<VAR>' is not set
API error during reconcile1Failed to create resource '<name>': 403 Forbidden on POST /api/... — check authentication token permissions

Authentication

All credentials come from environment variables — never from spec files.

Bearer Token

auth:
type: bearertoken_env: MY_API_TOKEN

Sets Authorization: Bearer <value> header.

Basic Auth

auth:
type: basicusername_env: API_USERpassword_env: API_PASS

Sets Authorization: Basic <base64> header.

API Key

# As a headerauth:
type: api_keykey_env: MY_API_KEYheader_name: X-API-Key# As a query parameterauth:
type: api_keykey_env: MY_API_KEYquery_param: api_key

OIDC Client Credentials

auth:
type: oidctoken_url: https://auth.example.com/oauth/tokenclient_id_env: OIDC_CLIENT_IDclient_secret_env: OIDC_CLIENT_SECRETscope: api:read api:write # optional

Fetches an access token via OAuth2 client_credentials grant and sets Authorization: Bearer <token>.

mTLS

auth:
type: mtlsclient_cert_path: /certs/client.pemclient_key_path: /certs/client.key

Presents client certificate during TLS handshake. Combine with ca_bundle for internal CAs.

CLI Reference

restium [OPTIONS] <COMMAND>
Commands:
reconcile Converge API state to match the spec
validate Validate spec file without making API calls
Options:
--json Structured JSON log output [env: RESTIUM_JSON]
--insecure-tls Skip TLS certificate verification [env: RESTIUM_INSECURE_TLS]
--sidecar Keep process alive after completion [env: RESTIUM_SIDECAR]
Subcommand options:
--spec <PATH> Path to YAML spec file [env: RESTIUM_SPEC]

Exit Codes

CodeMeaning
0All resources reconciled successfully
1One or more resources failed during reconciliation
2Spec validation error (bad YAML, broken refs, cycles, missing env vars)

Environment Variables

All flags can be set via RESTIUM_* environment variables:

VariableEquivalent Flag
RESTIUM_SPEC--spec
RESTIUM_JSON--json
RESTIUM_INSECURE_TLS--insecure-tls
RESTIUM_SIDECAR--sidecar

Security

  • Distroless container: FROM scratch — no shell, no package manager, no OS packages, zero CVEs
  • No secrets in logs: Credentials are automatically redacted in all log output
  • TLS by default: Certificate verification enabled; --insecure-tls requires explicit opt-in
  • Credentials via env vars: Auth tokens never appear in spec files
  • Non-root: Container runs as user 65534 (nobody)
  • 3.5MB image: Minimal attack surface

Deployment

Docker

docker run --rm \
-v $(pwd)/spec.yaml:/config/spec.yaml \
-e NETBIRD_TOKEN="$NETBIRD_TOKEN" \
ghcr.io/kitstream/restium:latest \
reconcile --spec /config/spec.yaml

Kubernetes Job

apiVersion: batch/v1kind: Jobmetadata:
name: restium-bootstrapspec:
template:
spec:
containers:
- name: restiumimage: ghcr.io/kitstream/restium:latestargs: ["reconcile", "--spec", "/config/spec.yaml"]volumeMounts:
- name: specmountPath: /configenvFrom:
- secretRef:
name: restium-credentialsvolumes:
- name: specconfigMap:
name: restium-specrestartPolicy: Never

Helm

helm install restium-bootstrap charts/restium \
--set secretName=restium-credentials

Sidecar Mode

Use --sidecar to keep the process alive after reconciliation completes — useful for sidecar containers that must not exit:

restium --sidecar reconcile --spec /config/spec.yaml

Development

make fmt # cargo fmt
make lint # cargo clippy --all-targets -- -D warnings
make test# cargo test
make build # cargo build --release
make cross # cargo zigbuild for musl targets
make docker-build # docker build

License

Apache-2.0

About

A declarative reconciling REST client in Rust

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages