A fast, keyboard-driven multi-cloud navigator. One TUI for Azure, GCP, and AWS — drill through tenants, subscriptions, projects, accounts, resource groups, resources, costs, and IAM without leaving the terminal.
┌─ cloudnav ───────────────────────────────── azure • acme-prod ─┐
│ azure › acme-prod › resource groups 47 items │
├────────────────────────────────────────────────────────────────┤
│ NAME LOCATION STATE COST │
│ web-api-prod-rg uksouth OK £2,355 │
│ analytics-prod-rg uksouth OK £869 │
│ ... │
├────────────────────────────────────────────────────────────────┤
│ ↵ open / search c costs o portal p PIM r refresh ? help │
└────────────────────────────────────────────────────────────────┘
cloudnav is a navigator, not an orchestrator. Every command is read-only
unless it's explicitly documented as mutating and requires --yes:
vm start/vm stop— start/stop VMs (opt-in mutation,--yesrequired).pim activate— requests time-bound role elevation via the cloud's own PIM/SSO/JIT surface. This changes IAM state but doesn't create resources.
Nothing else writes — not ls, cost, advisor, doctor, the TUI, or
anything in the palette.
Jumping between az, gcloud, aws, the three web portals, and half a dozen cost dashboards wastes minutes every time. cloudnav puts it all behind one keyboard-first TUI:
- Unified hierarchy — Azure tenants/subs/RGs, GCP orgs/projects, AWS orgs/accounts/regions all rendered the same way.
- Real auth — no new credentials. Uses whatever
az/gcloud/awsalready have logged in (SSO, federated, SP, workload identity). - PIM-first on Azure — list and activate eligible roles from inside the TUI.
- Costs inline — 30-day spend as a sortable column per resource group / project / account.
- Portal handoff — one keystroke opens the current row in the cloud's web console.
- CLI escape hatch —
xruns any provider CLI command inside the current context (subscription / project / account already selected).
brew tap tesserix/tap
brew install cloudnavgo install github.com/tesserix/cloudnav/cmd/cloudnav@latestGrab the latest from Releases — darwin/linux/windows on amd64 and arm64.
cloudnav talks to each cloud's API directly via the official Go SDKs. Auth flows through the standard SDK credential chains, so any method each cloud already supports works out of the box — CLI cached tokens, Service Principals, federated workload identity, IAM roles, IRSA, and metadata servers all resolve transparently.
| Provider | Common login | Other supported methods |
|---|---|---|
| Azure | az login |
Service Principal (secret / certificate), Workload Identity (federated token), Managed Identity |
| GCP | gcloud auth application-default login |
Service Account JSON, Workload Identity Federation, Impersonated SA, metadata server |
| AWS | aws configure sso |
Static IAM keys, Web Identity / OIDC (IRSA, GitHub Actions), AssumeRole profiles, ECS task role, EC2 IMDS |
Full method matrix + env vars for every flow: docs/auth.md.
Run cloudnav doctor to verify each cloud is reachable and to see
which auth method is currently active:
✓ azure alice@example.com · Azure CLI cached token
✓ gcp sa@my-proj.iam.gserviceaccount.com · Service Account JSON (GOOGLE_APPLICATION_CREDENTIALS)
✓ aws arn:aws:iam::123:user/alice · Default profile / SSO (~/.aws/credentials)
- Install the tool (pick one of the options above).
- Authenticate to the cloud you care about. Either the CLI flow:
…or set the env vars for any non-CLI method (Service Principal, federated workload identity, IRSA, etc.) — see
az login # Azure gcloud auth application-default login # GCP aws configure sso # AWS (recommended)
docs/auth.md. - Verify everything is wired up:
Expected output (the right-hand label shows which auth method resolved):
cloudnav doctor
✓ azure you@example.com · Azure CLI cached token ✓ gcp you@example.com · gcloud cached ADC (`gcloud auth application-default login`) ✓ aws arn:aws:iam::123:user/you · Default profile / SSO (~/.aws/credentials) - Launch the TUI:
Use
cloudnav
↑/↓(orj/k) to move,↵to drill down,escto go back,?for help,qto quit. - Open the current selection in the cloud portal with
o. - Run a CLI command in the current scope with
x— cloudnav will pre-fill the right--subscription/--project/--profile. - (Azure only) List and activate PIM roles with
p.
cloudnav find scopes prod
cloudnav find resources web --cloud azure --subscription <id>
cloudnav find pim admin --cloud azure
cloudnav ls azure subs --json | jq '.[].name'
cloudnav ls azure rgs --subscription <id>
cloudnav ls azure resources --subscription <id> --resource-group my-rg --jsoncloudnav find is the discovery-first layer.
Use it when you know part of a name or scope but not the exact path yet.
cloudnav ls is still there as the lower-level, script-friendly primitive.
Press x from anywhere in the TUI to open an embedded shell that
inherits the active row's cloud context (subscription / project /
account / resource group exported as env vars). The terminal is a
real PTY rendered inside bubbletea, so gcloud, aws, az,
kubectl, terraform — anything you'd run in a shell — works
without leaving cloudnav. Each cloud has its own theme: GCP shows
in blue / red / yellow, AWS in orange / slate, Azure in cyan / blue.
Ctrl-d (or exit) closes the terminal and returns to the
navigator.
| Key | Action |
|---|---|
↵ / l |
Drill down |
esc / h |
Back up one level |
j k / ↑ ↓ |
Move selection |
/ |
Fuzzy search current view |
: |
Command palette — switch cloud, tenant, subscription |
c |
Toggle cost column |
s |
Cycle sort (name → cost → state) |
o |
Open selected resource in cloud portal |
i |
Show full JSON detail |
p |
PIM — list/activate eligible roles (Azure) |
x |
Open embedded terminal (themed per active cloud, with row context as env vars) |
r |
Refresh |
f |
Bookmark current view |
? |
Help |
q / ctrl+c |
Quit |
cloudnav reads ~/.config/cloudnav/config.json (macOS/Linux) or %APPDATA%\cloudnav\config.json (Windows). Every field is optional; sensible defaults apply.
{
"default_provider": "azure",
"auto_upgrade": false,
"gcp": {
"billing_table": "my-project.billing.gcp_billing_export_v1"
}
}Highlights:
auto_upgrade— whentrue, cloudnav detects a newer GitHub release on startup, runs the upgrade plan silently (brew update && brew upgrade cloudnavon Homebrew,go install …@lateston Go), then re-execs into the new binary. Browser plans (manual releases) are never auto-launched.gcp.billing_table— BigQuery billing-export table backing the GCP cost column.bookmarks— populated byfinside the TUI.
See docs/config.md for the full reference (cache paths, env var overrides, all fields).
- cloudnav does not read, write, or cache tokens, keys, passwords, or refresh tokens.
- All authentication is delegated to the wrapped CLIs (
az,gcloud,aws). When you runcloudnav, it inherits their logged-in session for the duration of the subprocess call. - The optional config file holds preferences only (theme, bookmarks, sort order). You can delete it at any time with no loss of access.
- Logs go to
~/.local/state/cloudnav/cloudnav.log(Linux) /~/Library/Logs/cloudnav/cloudnav.log(macOS) and contain only the CLI commands we executed plus any stderr — never tokens.
cloudnav is a TUI by default, but every navigation step is also exposed as a scriptable command:
cloudnav search scopes prod
cloudnav find resources vm-01 --cloud azure --subscription <id> --details
cloudnav jit list --cloud azure
cloudnav costs services --json
cloudnav ls azure subs --json | jq '.[].name'
cloudnav ls azure rgs --subscription <id> --json
cloudnav ls azure resources --subscription <id> --resource-group my-rg --jsonWhen stdout is not a terminal (pipe, CI, Docker without -t), cloudnav ls will emit plain output by default and --json switches to machine-readable. The TUI binary itself requires a terminal; on headless machines use cloudnav ls, cloudnav doctor, and cloudnav version only.
┌──────────────────┐ ┌───────────────┐ ┌────────────────────────────┐
│ Bubbletea TUI │◀─▶│ provider API │◀─▶│ Azure SDK + ARM REST │
│ components+styles│ │ (normalized) │ │ cli.Runner (gcloud / aws) │
└──────────────────┘ └───────────────┘ └────────────────────────────┘
cmd/cloudnav— entrypoint.internal/cmd— Cobra commands (tui,doctor,version,ls,find,completion).internal/provider—Providerinterface + Azure / GCP / AWS implementations.internal/provider/azure— SDK-first (azcore/azidentity/armsubscription) withcli.Runnerfallback. Direct ARM REST via a sharedhttp.Clientwith HTTP/2, connection pooling, andRetry-Afterbackoff. Resource Graph (KQL) for multi-RG and multi-sub enumeration.internal/cli— generic subprocess runner with timeout + context, used forgcloud/awsand the Azure fallback path.internal/cache— on-disk key-value store (JSON per key, atomic writes) powering the persistent cost cache.internal/nav— navigation stack (breadcrumbs, back, context).internal/tui— Bubbletea model, per-feature files (advisor / billing / costs / delete / detail / health / palette / pim …).internal/tui/components— reusable layout widgets (Shell,Breadcrumb,Keybar,Modal,Composite).internal/tui/styles— single-source lipgloss theme.internal/iam— provisioning of scoped SP / SA / IAM Role with least-privilege presets.
See docs/architecture.md for the full design,
docs/design-system.md for the UI style rules
and palette that every view shares,
docs/resource-types-runbook.md for
how to add a new short alias to the TYPE column,
docs/config.md for every config knob, and
CHANGELOG.md for recent work — including the SDK
migration, cross-tenant discovery, Resource Graph fast path, persistent
cost cache, overlay compositor + adaptive column widths, PIM hardening,
the rate-limit-safe update check (1-hour poll), and the one-keystroke
self-relaunch on upgrade.
See ROADMAP.md. Current phase: 1 — Azure navigation + PIM.
git clone https://github.com/tesserix/cloudnav.git
cd cloudnav
make dev # runs against your currently-logged-in az session
make test
make lint
make buildContributions welcome — read CONTRIBUTING.md first.
Found a vulnerability? Please follow the process in SECURITY.md — do not open a public issue.
Apache License 2.0 — see LICENSE.