Getting started
A full walkthrough: install, run, bootstrap a token, and create a tenant
all the way through to a running subscription — every command below is
copy-pasteable kayra-cli, with its raw curl equivalent in the
block that follows it.
1. Install#
Both binaries are published on every
GitHub release, each as its
own archive (kayra_<version>_<os>_<arch> and
kayra-cli_<version>_<os>_<arch>). Install them with
bin, which picks the archive
matching your OS/arch, extracts the binary onto your PATH and tracks
it for later bin update:
bin install github.com/infrapi/kayra ~/.local/bin/kayra # pick the kayra_* archive when prompted
bin install github.com/infrapi/kayra ~/.local/bin/kayra-cli # pick the kayra-cli_* archive when prompted
bin list # both tracked, so `bin update` upgrades them together
Both come from the same repository, so bin asks which release asset
to install — choose the matching archive each time (and, since each
archive also ships LICENSE/README.md, the kayra or kayra-cli
binary inside it). Giving each its own path keeps both tracked
separately.
Building from source instead
go build -o kayra ./cmd/kayra
go build -o kayra-cli ./cmd/cli
kayra runs the server and its background jobs. kayra-cli is the
separate, portable client an end user logs in with — it never reads
kayra.yaml or touches local config at all (see CLI).
2. Write a config#
One YAML file covers everything. This one uses a local on-disk store instead of etcd and a local fixture instead of real LDAP — good enough to try things out, see config for every option.
app:
name: "kayra"
url: "http://localhost:8080"
platform: "sandbox"
region: "eu-west-1"
location: "dc1"
listen_type: "tcp"
listen_address: "127.0.0.1:8080"
database:
main:
local:
path: /tmp/kayra-db
authorizations:
# A self-signed token's own groups claim is trusted directly — no
# directory round trip needed. This is what makes `token mint`
# below work on a deployment with nothing else configured yet.
self-claims:
claims:
from: token
groups_field: groups
authentifications:
self:
authorization: self-claims
local:
- enabled: true
algorithm: RS512
issuer: true
kid: dev-key
# generate your own: openssl genrsa 2048
secret: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
sysadmin:
groups: ["sandbox-core-sysadmin"]
3. Start the server and the reconciler#
Two separate processes, each with its own lifecycle:
kayra --config kayra.yaml serve &
kayra --config kayra.yaml reconciler &
4. Mint a bootstrap token#
A brand new deployment has no user, group or RBAC object yet, so
there’s nothing to log in against. token mint signs a JWT directly
from the config’s own local key — the one way in before any of that
exists:
TOKEN=$(kayra --config kayra.yaml token mint \
--provider self --group sandbox-core-sysadmin --ttl 1h)
# save it as a kayra-cli context — every command below uses it
kayra-cli context set bootstrap --server http://localhost:8080 --token "$TOKEN"
That token satisfies sysadmin.groups above, so it can call every
cluster-bootstrap endpoint below. Past this point, a real deployment
switches to real logins (kayra-cli login, see CLI) and
mints this bootstrap token only when actually needed again.
5. Create a tenant#
A namespace is a tenant — one call creates both:
kayra-cli
kayra-cli create system namespaces -d '{"name": "thetenant"}'
# {"active": false, "name": "thetenant"}
curl
curl -s -X POST http://localhost:8080/apis/system.example.com/v1/namespaces \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "thetenant"}'
# {"active": false, "name": "thetenant"}
It comes back active: false — only kayra reconciler ever flips
that (see Namespaces).
6. Grant a group access to it#
Group → role → rolebinding, cluster-scoped, so this tenant’s own admins can later manage its day-to-day RBAC themselves:
kayra-cli
kayra-cli create authorization clustergroups -d '{"name": "thetenant-admins",
"metadata": {"namespace": "thetenant", "region": "eu-west-1", "platform": "sandbox"},
"groups": ["sandbox-core-sysadmin"]}'
kayra-cli create authorization clusterroles -d '{"name": "thetenant-admin-role",
"metadata": {"namespace": "thetenant", "region": "eu-west-1", "platform": "sandbox"},
"rules": [{"apis": ["catalog.example.com"], "resources": ["*"], "verbs": ["*"]}]}'
kayra-cli create authorization clusterrolebindings -d '{"name": "thetenant-admin-binding",
"metadata": {"namespace": "thetenant", "region": "eu-west-1", "platform": "sandbox"},
"role": "thetenant-admin-role", "groups": ["thetenant-admins"]}'
curl
curl -s -X POST http://localhost:8080/apis/authorization.example.com/v1/clustergroups \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "thetenant-admins",
"metadata": {"namespace": "thetenant", "region": "eu-west-1", "platform": "sandbox"},
"groups": ["sandbox-core-sysadmin"]}'
curl -s -X POST http://localhost:8080/apis/authorization.example.com/v1/clusterroles \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "thetenant-admin-role",
"metadata": {"namespace": "thetenant", "region": "eu-west-1", "platform": "sandbox"},
"rules": [{"apis": ["catalog.example.com"], "resources": ["*"], "verbs": ["*"]}]}'
curl -s -X POST http://localhost:8080/apis/authorization.example.com/v1/clusterrolebindings \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "thetenant-admin-binding",
"metadata": {"namespace": "thetenant", "region": "eu-west-1", "platform": "sandbox"},
"role": "thetenant-admin-role", "groups": ["thetenant-admins"]}'
See who can manage a namespace’s RBAC for how this check is actually evaluated.
7. Register an API and subscribe the tenant to it#
An ApiRegistration declares that an API group exists (e.g. “vault.example.com”, its long name — its id)
and who owns it — Kayra never implements the API itself, only tracks
it and notifies on changes. A Subscription links one namespace to
one registration by name:
kayra-cli
kayra-cli create catalog apiregistrations \
-d '{"name": "vault.example.com", "short_name": "vault", "owner": "sre"}'
# sync_id is minted automatically — note it down, or just GET it back below
kayra-cli create catalog -n thetenant subscriptions -d '{"api": "vault.example.com"}'
# {"api": "vault.example.com", "active": false, "state": "init", ...}
curl
curl -s -X POST http://localhost:8080/apis/catalog.example.com/v1/apiregistrations \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "vault.example.com", "short_name": "vault", "owner": "sre"}'
# sync_id is minted automatically — note it down, or just GET it back below
curl -s -X POST http://localhost:8080/apis/catalog.example.com/v1/namespaces/thetenant/subscriptions \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"api": "vault.example.com"}'
# {"api": "vault.example.com", "active": false, "state": "init", ...}
Any caller whose groups are bound to the catalog.example.com API
can do the subscribe step — it doesn’t have to be the bootstrap token;
$TOKEN works here only because step 6’s rolebinding happens to grant
sandbox-core-sysadmin (the bootstrap token’s own group) that right
too. A real deployment would bind a tenant’s actual admin group there
instead.
8. Trigger a sync and check status#
kayra-cli
kayra-cli update catalog apiregistrations vault.example.com/sync -d '{}'
kayra-cli get catalog apiregistrations vault.example.com/status
curl
curl -s -X PUT http://localhost:8080/apis/catalog.example.com/v1/apiregistrations/vault.example.com/sync \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{}'
curl -s http://localhost:8080/apis/catalog.example.com/v1/apiregistrations/vault.example.com/status \
-H "Authorization: Bearer $TOKEN"
kayra reconciler picks up the new sync_id and runs whichever HTTP
step pipeline reconciler.mode configures (none here, so it just logs
and activates directly) — see
Subscriptions & reconciliation for the
full reconcile model.
What’s next#
- CLI reference —
kayra-cli login, contexts, personal access tokens. - Architecture — how every package fits together.
- Config reference — every YAML key.