Florete

CLI Surface

retectl and flor command reference for C0

CLI Surface

Two binaries, split by audience:

  • retectloperator workstation only. Authors rete state: CA operations, validation, compilation, bundle issuance. Never touches a running agent and never ships to a node.
  • florevery node. The daemon plus the node-local user CLI: enrollment, apply, status. One binary serves end users, server admins, and the system service.

This matches the author-vs-participant split used by kubectl/kubelet, terraform/agent, and similar tooling — and the names mirror the layer each acts on: retectl administers the rete (the trust domain — not any single flor, and not one Coordinator), while flor is the node agent, exactly as kubectl administers the cluster and kubelet runs on the node. The -ctl suffix names the thing controlled (the rete), which is why it is not florctl: the tool never controls a flor, it authors rete state. An end user installing Florete on their laptop gets flor with a small, focused command set; operators additionally install retectl on their own machine for rete-authoring work.

retectl (operator, authoring)

retectl ca init --out <dir>                 # once per rete: generate CA keypair + ca.crt
retectl ca sign <csr> --name <name>
                      --kind <user|service|node|management-plane|control-plane|vertex>
                      [--scope rete|node]
                                            # sign a CSR; append to enrollment.log.
                                            # All six kinds are recognised from day one;
                                            # `vertex` and `control-plane` aren't exercised
                                            # at runtime in C0 (see ADR-0005).
                                            # `management-plane` is how the rete's
                                            # mgmt-envelope signer is minted in C0 — e.g.
                                            #   retectl ca sign --kind management-plane \
                                            #                   --name primary
                                            # produces the keypair `retectl publish` signs with.
retectl issue-bundle --node <node-name> --rete <config-server-url>
                     [--csr <csr-bundle>] [--validity <duration>] [--out <bundle>]
                                            # per-node enrollment bundle: CA cert, node
                                            # identity, and every workload identity
                                            # (users/services) declared in YAML to run
                                            # on this node, plus config-server bootstrap.
                                            # Flow B: consume `flor id create` CSR bundle.

retectl validate [--repo <dir>] [-f <file|glob>…]
                                            # schema + cross-ref + access consistency
retectl compile [--node <name>] [--repo <dir>] [--out <dir>] [-f <file|glob>…]
                                            # compile all nodes (or one); write to
                                            # <repo>/.flor/compiled/ by default
retectl publish [--repo <dir>] [--target <config-server-url>]
                                            # push compiled artifacts to the rete
                                            # config-server (see Config-server)

Notes:

  • Source discovery. validate/compile require rete.yaml at the --repo root; if it is missing or nested elsewhere, discovery cannot start and a command fails. Then recursively glob *.yaml/*.yml under --repo (skipping .flor/, certs/, dotfiles; honoring include/exclude in rete.yaml), then merge same-kind collections into one whole-view before compiling. File layout is operator-chosen — see Source Layout. -f <file|glob>… (repeatable) overrides discovery for partial or CI runs; when used, at least one selected file must contain the singleton rete block.
  • retectl ca init runs once per rete. CA private key never leaves operator's secure storage.
  • retectl ca sign is the low-level primitive; retectl issue-bundle is the high-level wrapper that computes which principals live on a node (from users.yaml + services.yaml), signs each of their certs, and packages everything alongside the node identity and config-server bootstrap info. One bundle per node, not per principal (avoids the combinatorial mess of separate bundles for a node hosting five services).
  • --kind on ca sign selects the SPIFFE path namespace and the X.509 extension policy applied to the resulting cert. All six kinds are accepted from day one (user, service, node, management-plane, control-plane, vertex); vertex and control-plane aren't exercised at runtime in C0 but the CLI surface is stable. TLS-capable kinds (user, service, node, vertex) get keyUsage: digitalSignature, keyEncipherment + extKeyUsage: serverAuth, clientAuth; signing-only kinds (management-plane, control-plane) get keyUsage: digitalSignature only, no extKeyUsage — see ADR-0005 for the rationale.
  • retectl compile writes artifacts to .flor/compiled/<node>/mgmt/ inside the repo (with agent.json and vertices/flor.json per node). Artifacts contain only scope-relative path references (bare filenames like ca.crt, alpha.crt) — the agent resolves them against the rete install root at startup. No secrets in artifacts; committing them turns the git log into an auditable shipment history. Nodes don't pull from git; they fetch from the config-server (see Config-server).
  • retectl publish uploads the current .flor/compiled/ tree to the rete's config-server; nodes fetch their own artifacts on the next flor agent sync. Publish is separate from compile so the operator can review the diff (and the audit commit) before the change is visible to nodes. Publish is idempotent — re-running with the same tree is a no-op on the server.
  • Nothing in retectl affects running agents directly. It reads and writes the rete repo plus operator-local CA material, and talks to the config-server over the rete's own Florete. Safe to run anywhere the operator has the repo checked out and is enrolled as an operator principal.

flor (node, daemon + user CLI)

flor id create --node <node> [--principal <kind>/<name>]...
                                            # generate keypairs locally for the node and
                                            # any workload principals to run on it;
                                            # package CSRs into a bundle (Flow B)
flor enroll <bundle> [--as <scope>]         # bootstrap: install certs, install initial
                                            # compiled artifacts, start agent
                                            # (two-step: bundle → sync)
                                            # scope defaults to rete name in bundle;
                                            # --as overrides if name collides locally
flor version                                # binary version

flor agent run    [--rete <scope>]          # the supervisor daemon (system service);
                                            # reads <root>/mgmt/agent.json; auto-detects
                                            # the scope if only one rete is enrolled;
                                            # supervises one `flor vertex run` in C0
flor agent sync   [--rete <scope>]          # select rete by scope name;
                  [--commit-timeout <d>]    # auto-detected if only one rete enrolled
                  [--dry-run]               # default timeout 5m; 0 disables
                  [--confirm]               # show artifact diff, no restart
                                            # finalise a pending commit-timeout sync
flor agent status [--rete <scope>]          # local agent state + active artifact version

flor vertex run   [--rete <scope>]          # the data-plane daemon spawned by the agent;
                  --name <name>             # same rete scope as the agent (auto-detected if
                                            # only one enrolled). Under the rete root
                                            # ~/.flor/retes/<scope>/ it reads
                                            # mgmt/vertices/<name>.json (plus the ctrl/
                                            # sibling for mesh in C1+) and resolves
                                            # ca.crt + identities there; run by hand to debug

Notes:

  • flor home. Node-local commands resolve their install root from <flor-home>: $FLOR_HOME if set, otherwise $HOME/.flor. Enrolled retes live at <flor-home>/retes/<scope>/. The $FLOR_HOME override exists mainly to relocate the tree for development and CI (currently at <flor-repo>/.flor-dev/, git-ignored); production uses the $HOME/.flor default.
  • flor id create runs on the target machine for Flow B (security-purist) enrollment; generates keypairs for the named node + any principals hosted on it, emitting a CSR bundle for the operator to sign. The operator tells the user which principal names to include (out-of-band), so the bundle matches what users.yaml + services.yaml declare for that node.
  • flor enroll <bundle> is a two-step bootstrap. Step 1: unpack the bundle (CA cert + node cert + key + workload certs + keys + config-server URL + expected config-server SPIFFE ID + a current agent.json and vertices/flor.json) and write everything to ~/.flor/retes/<scope>/, where <scope> is the rete name embedded in the bundle (override with --as <scope> if it collides with an already-enrolled rete). This gives the node enough material to start running immediately. Step 2: start flor agent run, which brings up the vertex and then runs flor agent sync once to refresh against whatever the rete currently runs. Re-keying (or adding a new workload on this node) re-runs the same command with a freshly-issued bundle.
  • flor agent sync fetches <this-node>/{agent.json, vertices/flor.json} from the rete's config-server over Florete (acting as the node/<node> principal via the local vertex's SOCKS5), installs the new artifacts, and restarts the supervised vertex with a commit-timeout guard. No compilation on the node — artifacts were pre-compiled by the operator and published to the config-server.
  • --commit-timeout is on by default (5 min). New artifacts become active; if flor agent sync --confirm isn't run within the timeout, the previous artifacts are restored and the vertex restarts. Cisco IOS commit confirmed pattern.
  • flor agent run is the long-running supervisor process per node. It reads <root>/mgmt/agent.json (where <root> = ~/.flor/retes/<scope>/) and spawns a flor vertex run --rete <scope> --name <name> per entry in its vertices list. In C0 that's one child; C1 adds a second vertex for the mesh-flor layer. How exactly the agent launches vertices (direct fork, systemd unit, future local workload-runtime interface) is intentionally not pinned here; the runtime contract is just "a vertex starts when given its scope and name".
  • flor vertex run is the data-plane daemon. Given --rete <scope> (the same scope the agent runs under) and --name <name>, it resolves the rete root ~/.flor/retes/<scope>/, reads mgmt/vertices/<name>.json (and, for a mesh vertex, the ctrl/ sibling), resolves its ca.crt and per-principal certs/keys against that root, and runs the workloads/io/transport-endpoint/connection-manager described there. It does not re-verify signatures (the agent is the sole verifier); apart from resolving its own scope directory it is unaware of the agent, the config-server, and the rest of the rete.
  • flor agent status reads from a per-rete Unix socket (~/.flor/retes/<scope>/agent.sock) exposed by that rete's agent. --rete <scope> selects which socket to use; auto-detected when only one rete is enrolled. A future tray-icon GUI (B1+) will be another client of the same socket — CLI and GUI share the same daemon API.

Explicitly deferred from C0:

  • Any YAML-mutation subcommands.
  • Multi-hop paths and label allocation (C1 feature).
  • SIGHUP hot reload.
  • CRL / OCSP. (Revocation is by name removal + flor agent sync.)
  • Delta state updates.
  • iptables-based transparent outbound redirection for services that can't speak SOCKS5.

On this page