SPIFFE CLI is a command line tool to run a SPIFFE Workload API locally and request and validate SVIDs.
Download the spiffecli binary for your OS in the Releases page.
Or build from source by cloning the repo and running:
make build
./bin/spiffecliRun a local Workload API:
./bin/spiffecli run
Unable to find an existing configuration (see --config flag).
If you continue, a default configuration will be used and saved at ~/.spirl/dev.toml
? Continue? [y/N] y█
Saved $HOME/.spirl/dev.toml
2023/10/17 10:59:58 Trust domain: name="example.com" X509AuthorityTTL="24h0m0s" JWTAuthorityTTL="24h0m0s"
2023/10/17 10:59:58 Trust domain: name="acme-corp" X509AuthorityTTL="24h0m0s" JWTAuthorityTTL="24h0m0s"
2023/10/17 10:59:58 Rotating X.509 authority for trust domain "example.com"
2023/10/17 10:59:58 Rotating X.509 authority for trust domain "acme-corp"
2023/10/17 10:59:58 Rotating JWT authority for trust domain "acme-corp"
2023/10/17 10:59:58 Rotating JWT authority for trust domain "example.com"
2023/10/17 10:59:58 Workload: id="spiffe://acme-corp/pubsub" trustDomain="acme-corp" socket="/var/folders/by/rf9wqg_d5z150k1fb1wh_s180000gn/T/spirl-dev/acme-corp/pubsub.sock"
2023/10/17 10:59:58 Workload: id="spiffe://example.com/frontend" trustDomain="example.com" socket="/var/folders/by/rf9wqg_d5z150k1fb1wh_s180000gn/T/spirl-dev/example.com/frontend.sock"
2023/10/17 10:59:58 Workload: id="spiffe://example.com/backend" trustDomain="example.com" socket="/var/folders/by/rf9wqg_d5z150k1fb1wh_s180000gn/T/spirl-dev/example.com/backend.sock"This will create a new default configuration file at ~/.spirl/dev with two trust domains example.com and acme.corp.
To get an SVID, specify the unix domain socket for the SPIFFE ID and request an SVID:
$ export SPIFFE_ENDPOINT_SOCKET=unix:///var/folders/by/rf9wqg_d5z150k1fb1wh_s180000gn/T/spirl-dev/example.com/frontend.sock
$ ./bin/spiffecli get x509-svidmake check # lint + test-race + mod-tidy-check + govulncheckThis mirrors what CI enforces on every push. Run it after any code change before committing.
make lint # golangci-lint (staticcheck, errcheck, gosec, gocritic, govet)
make lint-fix # auto-fix lint issues
make test-race # go test -race ./... (catches data races)
make test-cover # tests with coverage report
make mod-tidy-check # ensure go.mod/go.sum are tidy (no drift)
make govulncheck # scan dependencies for known CVEs
make gosec # standalone gosec security scan# All tests
go test ./...
# Single package
go test ./internal/jwtinspect/... -v
# Single test function
go test ./internal/jwtinspect -run TestHappyCasesE2E tests compile the spiffecli binary and test complete CLI workflows. Each test starts a real Workload API server as a subprocess.
# Run all E2E tests (~20s)
go test ./internal/test/e2e/... -v -timeout 180s
# Offline tests only (no server, fast)
go test ./internal/test/e2e/... -run "TestE2E_Inspect" -v -timeout 60sEvery push and pull request runs four checks: lint, test (with race detector), mod-tidy, and govulncheck. Security scans (gosec SARIF, Trivy image scan) run on pushes to main and weekly — results appear in the GitHub Security tab.
spiffecli can be injected into a running Kubernetes pod as an ephemeral container (no pod restart required) using kubectl debug. The debug image is based on nicolaka/netshoot with the spiffecli binary added.
- Docker (to build the debug image)
kubectlwith access to the target cluster- Kubernetes 1.23+ (ephemeral containers are GA)
Two approaches — choose based on your situation:
Option 1: Ephemeral container (in-place, recommended)
Always pass TARGET. Without it the ephemeral container is fully isolated and spiffecli fails with context deadline exceeded.
make inject POD=<pod-name> TARGET=<container-name> [NAMESPACE=<ns>]Inside the shell, the socket is at /proc/<pid>/root/<original-path>. PID is usually 1 — verify with ps:
export SPIFFE_ENDPOINT_SOCKET=unix:///proc/1/root/spirl-agent-socket/agent.sock
spiffecli get x509-svidIf /proc/<pid>/root/ returns Permission denied, the target container runs as a non-root UID. Use kubectl debug --profile=sysadmin directly (kubectl 1.30+).
Option 2: Clone pod (simpler socket access)
Clones the pod with the debug image — all volume mounts are preserved, so the socket is at its original path. Requires deleting the clone when done.
kubectl debug -it <pod> --namespace=<ns> \
--image=ghcr.io/defakto-security/spiffecli-debug:latest \
--copy-to=spiffecli-debug-pod --same-node=true \
--set-image='*=ghcr.io/defakto-security/spiffecli-debug:latest'
# Inside shell:
export SPIFFE_ENDPOINT_SOCKET=unix:///spirl-agent-socket/agent.sock
spiffecli get x509-svid
# Cleanup:
kubectl delete pod spiffecli-debug-pod --namespace=<ns>For Istio workloads the socket lives in the sidecar. make inject-istio targets the istio-proxy container and pre-sets SPIFFE_ENDPOINT_SOCKET automatically:
make inject-istio POD=<pod-name>
# Inside the shell:
spiffecli get x509-svid # socket already configured| Variable | Default | Description |
|---|---|---|
POD |
(required) | Target pod name |
NAMESPACE |
default |
Pod namespace |
TARGET |
(none) | Container whose process namespace to share. Required to reach the Workload API socket (inject only; inject-istio always uses istio-proxy) |
IMAGE |
ghcr.io/defakto-security/spiffecli-debug:latest |
Debug image ref |
CLUSTER_TYPE |
registry |
How to distribute the image: registry, kind, or k3d |
KIND_CLUSTER |
kind |
kind cluster name (override if created with --name) |
For local clusters, skip the registry push by loading the image directly:
# kind (non-default cluster name: add KIND_CLUSTER=<name>)
make inject POD=<pod> TARGET=<container> CLUSTER_TYPE=kind
# k3d
make inject POD=<pod> TARGET=<container> CLUSTER_TYPE=k3dmake inject-build # build locally
make inject-build IMAGE=myrepo/debug:v1 # custom image tagWe use Github actions to build spiffecli binaries and publish them on Github Container Registry and as a Github Release. To trigger the actions create a release branch and tag it with the next release number. Push the branch and tag and open a Pull Request. Once the Pull Request is merged the Github Actions will trigger and you should see a Github Release with the spiffecli binaries in the Artifacts section.
Contributions are welcome! Please read CONTRIBUTING.md for
build, test, and pull-request guidelines, and note that contributions require a
Developer Certificate of Origin sign-off
(git commit -s). By participating you agree to our
Code of Conduct.
To report a security vulnerability, please follow our Security Policy.
Licensed under the Apache License, Version 2.0. See the NOTICE file for attribution.