Why is there a CLI and a GitHub Action?¶
sluisctl is one small CLI whose subcommands share a login cache and an issuer configuration. Every command, flag and
exit code is in the sluisctl reference.
Why a CLI at all?¶
A CI platform's token needs no client binary, because the issuer's exchange is a standard token-endpoint call any curl
can make. The cloud CLI has no interactive login. A person needs something that runs the browser flow once. It then
exchanges for a role's audience and answers as a credential process. kubectl has kubelogin for the same job.
Run login once. Then use kubeconfig, kube-token, aws-config, aws, token, github-token, bao, psql/pg,
r2 or exchange. setup writes the kubeconfig and AWS profiles in one go.
render and policy render work on files, not on a sign-in. They turn an installation document into the service and
policy documents deterministically.
How does a job run the same commands?¶
With ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN set, the credential commands ask GitHub for the
job's own identity token, minted for the issuer, and exchange that. They present the audience as the client, as the
action does. One committed kubeconfig and one aws.ini serve a laptop and a job alike
(in a job).
The GitHub Action, at the repository root, is for a repository that downloads nothing of ours into a job. It exchanges
the job's token per audience. It prepares a kubeconfig context per k8s:<cluster> audience and a profile
<role>@<account> per aws:<account>:<role> audience, with web_identity_token_file pointing at the exchanged token.
It can also prepare a GitHub App installation token. It uses curl, jq and two files. Pin a release, because there is no
floating v1. Inputs and outputs are in Connect GitHub Actions.
Everything downstream of an AWS credential, such as ECR login or CodeArtifact tokens, is AWS's tooling running on those profiles. Neither the action nor the CLI wraps it (recipes).
bao, psql / pg, r2: couriers for what a store mints¶
They are couriers for what a store mints. The commands sluisctl credential ssh|db|client were removed in v1.34.0. The
courier decides little:
| Decided by | What |
|---|---|
the exchange client's requires |
who may ask. A revoked session stops issuance within the exchange's token cap |
| the OpenBao role | the lifetime, extensions, key id, principals and names. No request carries a TTL |
bao itself |
everything after sluisctl's own flags |
| the caller | which public key is signed and which principals are asked for: a request, never a grant |
For psql and pg, an ECDSA P-384 key is made in the process. A CSR goes to pki/sign/<role>. The key is written beside
the returned certificate in a 0600 file in a 0700 directory and is never sent. The certificate is reused only while
it has enough life left and has the same common name.
The OpenBao token is cached per address, login namespace and subject until a margin before expiry. --forget revokes it
and removes it. A login whose answer carries no lease is used for one command and never cached.
bao gets BAO_ADDR, BAO_TOKEN and, when named, BAO_CACERT in its environment alone. The process image is replaced
where the platform allows, so bao ssh -mode=ca gets the terminal. psql and pg get libpq's own variables. Output
never includes the key.
Installing it¶
Every release carries a Nix flake beside the archives. A repository whose tools come from devbox names it in
devbox.json, and devbox.lock pins it. See installing it.
What does it never do?¶
It holds no stored secrets and has no cloud SDK inside. What is on disk is short-lived and advisory, except the refresh token. A refresh rotates the token, so two commands refreshing at once would sign the operator out of everything. Each credential cache has a lock beside it, and a command with a fresh access token does not spend the refresh token.
No cache can mint its own successor. login replaces the refresh token. A job has no login cache. Paths and modes are in
where things are kept.