Skip to content

Releases: theazz/awless-ro

awless-ro v0.2.2

Choose a tag to compare

@github-actions github-actions released this 03 Oct 13:52

awless-ro v0.2.2

tail comes out of hiding, and tail scaling-activities says when there is nothing to
show.

tail is listed

tail shows recent CloudFormation stack events or autoscaling activities, or follows
them. It had been hidden from --help and completion since it first appeared upstream,
as an experiment — though it works, and the README already documented it. It is now
listed, with help and examples:

awless-ro tail stack-events my-stack                 # the last 10 events of a stack
awless-ro tail stack-events my-stack --follow        # follow a deployment until it completes
awless-ro tail scaling-activities -n 20              # the last 20 autoscaling activities
awless-ro tail scaling-activities --follow           # wait for new ones

tail scaling-activities with nothing to show

Two defects inherited from upstream:

  • No activity printed nothing and exited 0, which reads the same as a command that
    failed silently. Autoscaling keeps six weeks of history, so in a quiet account this
    is the usual answer. It now says so — on stderr, so stdout stays the events alone.
  • --follow returned at once when there was no activity yet, which is exactly when
    one waits for the first. It now polls from that moment on. An invalid --frequency
    is refused before any AWS call.

README

The README now opens with a short recorded demo, and its "What it is good for" section
says plainly how the tool gets its data: list, search, whoami and tail ask the
AWS API every time; show and inspect work on a synced graph of the account, which
is where relations come from; list, show and inspect take --local to answer from
that copy without calling AWS.

No change to any command's output, flag or exit code beyond the above, hence a patch
release. Full detail in
CHANGELOG.md.

Verified

Against a live account: tail stack-events prints the header and events, and fails
with exit 1 on a stack that does not exist; tail scaling-activities with no activity
prints the notice and exits 0; --follow keeps waiting.

awless-ro v0.2.1

Choose a tag to compare

@github-actions github-actions released this 03 Oct 12:50

awless-ro v0.2.1

A first sync in about half the time, and list buckets no longer falls over on a
flaky DNS lookup.

sync from scratch: 31–47s → 15.5s

Almost all of a first sync was IAM. Users, groups, roles and managed policies come from
one GetAccountAuthorizationDetails pagination, and its pages were fetched one after
another. IAM caps a page by size — policy documents make them heavy — so an account
with ~500 roles and ~560 policies took 25 sequential pages. Asking for bigger pages
does not help; IAM truncates by size regardless.

Each entity type now has its own pagination, and they run side by side. Measured on
the same account, from an empty home:

v0.2.0 v0.2.1
sync 31.4 / 47.0 / 37.7s 15.6 / 15.5 / 15.7s
list policies 18.9 / 18.9s 11.1 / 12.7s

Same API call, same permission, same data.
(#12)

list buckets failing with "no such host"

The first list buckets could fail like this, and the second succeed:

[error]   operation error S3: GetBucketLocation, ... dial tcp:
          lookup <bucket>.s3.<region>.amazonaws.com: no such host

To keep only the current region's buckets, the tool asked for the location of every
bucket in the account, all at once — each request to the bucket's own hostname, so
as many simultaneous DNS lookups of different names. A resolver with a cold cache,
typically behind a VPN, answered some of them "no such host"; the AWS SDK does not
retry that, and the first failure ended the listing.

S3 can filter by region itself now, so this is one request instead of one per bucket,
and GetBucketLocation is no longer among the operations awless-ro can perform —
61, all reads. (#10, inherited from
upstream)

Per-item requests are bounded

The same pattern — one request per item, all at once, the first failure ending
everything — was in every place that makes a call per bucket, task definition, IAM
user, load balancer, queue, hosted zone or ECS cluster. In a large account that is
hundreds or thousands of requests in the same instant, and AWS throttles beyond what
the SDK's retries absorb. At most eight are now in flight at a time, and a failure
stops the rest cleanly instead of leaving them hanging.

Also

  • AWS SDK for Go v2 modules updated (patch and minor releases).
  • Installing with Homebrew picks this release up through brew upgrade awless-ro.

No change to any command, flag, output format or exit code, hence a patch release.
Full detail in
CHANGELOG.md.

Verified

Against a live account (~500 roles, ~560 policies, 77 buckets): list of buckets,
access keys, task definitions, containers, listeners, queues, zones and load
balancers returns exactly what v0.2.0 returned, and the synced IAM graph has the same
resources and properties.

awless-ro v0.2.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 08:28

awless-ro v0.2.0

Shell completion, redone: fish is new, zsh now works when installed by a package
manager, and what Tab offers is the same in every shell.

What changed

Completion used to be the scheme inherited from upstream: a hand-written generator for
bash, a zsh script that emulated bash, and lookups written as bash functions. There was
no fish, and the zsh script could only be sourced — installed as a completion file, it
was silently ignored, which is why the Homebrew formula shipped bash only.

It is now cobra's own completion:

awless-ro completion bash|zsh|fish|powershell

and Tab completes, in every shell:

  • show — resource ids and names from your local copy; ssh — instances, keeping a
    user@ you typed; tail stack-events — stacks
  • switch, -r, -p — regions and profiles
  • config get|set|unset — keys with their description, then values for set
  • inspect -i, search images, list --format

Commands that take no argument no longer offer file names.

Installing it

With Homebrew the files are installed for bash, zsh and fish. fish picks them up on
its own; zsh and bash do once the shell is set up for Homebrew's completions — if Tab
already completes brew, it is. Otherwise see
Homebrew's guide.

Otherwise:

echo 'eval "$(awless-ro completion bash)"' >> ~/.bashrc          # bash, with bash-completion
awless-ro completion zsh > "${fpath[1]}/_awless-ro"                # zsh
awless-ro completion fish > ~/.config/fish/completions/awless-ro.fish

Safe to press Tab

Completion answers from local state only — the synced graph, the config, ~/.aws. It
never calls AWS, never syncs, and on a machine where awless-ro has not run yet it never
starts first-run setup: it offers nothing and writes nothing. A test runs the binary in
an empty home directory to hold it to that.

Profile completion also stops offering the sso-session and services sections of
~/.aws/config, which are not profiles.

Compatibility

A new capability with nothing removed, hence a minor version. awless-ro completion bash
and awless-ro completion zsh still exist; if you load them with source <(…) or
eval, that keeps working.

ssh is still disabled — #1.

Full detail in
CHANGELOG.md.

Verified

Unit tests for every completion and end-to-end tests on the built binary. By hand: fish
against a synced test graph; zsh registering the installed _awless-ro file through
compinit; bash loading the script (interactive use needs the bash-completion package,
as before).

awless-ro v0.1.1

Choose a tag to compare

@github-actions github-actions released this 03 Oct 08:17

awless-ro v0.1.1

A speed fix, and it is a large one: the first command you run no longer reads the
whole account before doing its own work.

The first run was slow for no reason

awless-ro whoami needs a single GetCallerIdentity. On a machine with no
~/.awless-ro it took about thirty-five seconds, because nine services and several
thousand resources were synced first.

Writing the region for the first time went through the same code path as changing it,
and a region change does schedule a sync — reasonably, since the local graph is
per-region, so the one already on disk describes somewhere else. But the first run is
the initial write, not a change, and nothing distinguished the two.

Nothing needed that sync. list, search, whoami and tail ask AWS directly, and
show and inspect fetch what they need on their own; sync is for working offline.
The README said as much, so the first run was contradicting the documentation.

Measured against the same account, from an empty home:

command before after
whoami 37s 3s
list instances 30s 1s
list vpcs 32s 1s
list users 36s 1s
search images canonical --latest-id 41s 1s
ssh … (refused, as in v0.1.0) 35s 0s

Changing the region later still syncs, and aws.autosync false still turns that off.

--local now says when there is nothing to read

"No results found." answers a question about the account. Asked before anything has
been synced, the account was never read, and those are not the same thing. It now
says which profile and region have nothing, and what to do:

$ awless-ro list instances --local
[info]    nothing has been synced for profile 'default' in region 'eu-west-1' yet, so
          --local has nothing to read. Run `awless-ro sync`, or drop --local to ask
          AWS directly.

This was reachable in v0.1.0 too, but rarely: the first run used to sync, so there was
usually something there. Removing that sync makes an empty local copy the normal
starting state, so the message had to be right.

Unchanged

Everything else, including ssh, which is still disabled —
#1 tracks the three defects that have
to be fixed first.

No change to any command, flag, output format or exit code, which is why this is a
patch release. Full detail in
CHANGELOG.md.

Verified

Every command was run on a fresh home against a live account, with the v0.1.0 binary
and this one side by side: identical exit statuses, identical output, no panics. The
only differences are the timings above.

awless-ro v0.1.0

Choose a tag to compare

@github-actions github-actions released this 03 Oct 07:13

awless-ro v0.1.0

A CLI for looking at an AWS account: readable tables instead of JSON, resources
by name instead of by id, how they relate to each other, and output you can pipe.
Optionally, a local copy of the account to explore offline.

It cannot change anything — and that is enforced, not promised. Every AWS operation
the binary is capable of calling is a Describe, Get, List or Head, and a test
fails the build if that stops being true.

This is a fork of wallix/awless, unmaintained
since 2018 and no longer buildable. The read half aged well and has no close
equivalent; the write half — templates, hundreds of create/delete commands,
revert — was both the larger maintenance burden and the part least safe to run
unmaintained against a live account. So the read half was kept and modernised, and
read-only became a property of the tool.

Try it

brew install theazz/tap/awless-ro
awless-ro list instances
awless-ro show my-database

No setup step: list asks AWS directly, and show fetches what it needs. Existing
~/.aws profiles are picked up; anything missing is prompted for on first run. State goes to ~/.awless-ro, so an installed upstream awless is untouched.

What works

list — 49 resource types across EC2, IAM, S3, RDS, AutoScaling, SNS, SQS,
Route53, CloudWatch, CloudFormation, Lambda, ECS, ECR, ELB (classic and v2),
CloudFront and ACM.

awless-ro list instances --filter state=running --sort uptime
awless-ro list instances --columns name,state,architecture,lifecycle
awless-ro list volumes --tag-key Dept --format tsv
awless-ro list users --format json
awless-ro list vpcs --ids

--columns reaches any property a resource carries, not only the default columns.
Formats: table, csv, tsv, json, porcelain. --ids is ids only, one per
line.

show — one resource by id, by name, or by @name, with its properties, its
lineage of parents and children, what it applies to, what depends on it, and its
siblings. Names are not unique in AWS, so an ambiguous one lists the candidates.

search images — official AMIs by vendor, pinned to the publishing account and
resolving to the vendor's ordinary image rather than a specialised build.

awless-ro search images canonical --latest-id
awless-ro search images redhat::9
awless-ro search images --owner 123456789012 --name 'my-base-*'

inspect and tail — port_scanner (security groups opening ports, and to
what they are attached), open_buckets, bucket_sizer; CloudFormation stack events
and autoscaling activities.

whoami, switch (region and profile), config, completion,
version.

sync — optional. Fetches all nine services in parallel into a local graph
under ~/.awless-ro, after which any command with --local answers from it without
calling AWS. A service you lack permission for is reported and skipped; the rest still
land. Two resource types are off by default because they cost an API call per parent,
and the sync says so rather than reporting zero of them.

What does not work yet

awless-ro ssh is disabled in this release. The resolution and connection logic
is largely sound — against a live account it resolved an instance name to its private
IP through the local graph and reached the host — but --local panics, --print-cli
connects instead of printing, and the host key prompt loops when there is no
terminal. The command explains this instead of running. Until then, show tells you
what to connect to and ssh does the rest.

The write half is gone for good: templates, create/delete/attach/…, log,
revert, the scheduler, awless web.

On read-only, precisely

Every AWS call goes through a narrow per-service interface. Nothing else in the tree
holds an SDK client, so the methods on those interfaces are the complete list of
operations the binary can perform — currently 62 across 18 services.
TestEveryAWSOperationIsARead reflects over them and fails the build if a name is not
a read, or if a field is a concrete client rather than an interface.

The rest of the security posture, and what is checked automatically, is in the
README.

Notable if you used awless

  • Failures exit non-zero. Upstream discarded the error from the root command, so
    everything exited 0.
  • --ids prints ids only; it used to interleave names, which a script cannot tell
    apart from an id.
  • AMI vendors coreos and centos are gone, the first end-of-life since 2020 and
    the second unverifiable — shipping an unverified account id is the mistake the
    whoAMI attack relies on.
  • The pricer inspector is gone. It posted an inventory of your EC2 instances to a
    third-party host over plain HTTP, and that domain was not registered when this
    fork was made.
  • Version restarts at v0.1.0; continuing upstream's v0.1.11 would imply a
    compatibility that does not exist.

Full accounting, including the nine defects found by running against a live account
and the inherited ones among them, is in
CHANGELOG.md.

Install

go install github.com/theazz/awless-ro@latest

Or download a binary below and verify it:

shasum -a 256 -c SHA256SUMS --ignore-missing

Builds for macOS and Linux on amd64 and arm64, and Windows on amd64. Requires Go 1.26
if building from source.

Status

go test ./... -race is green and no test needs AWS credentials. The tool is also
checked against live accounts, which is where the defects that matter turn up: nine
were found that way, and none of them was visible to a unit test.

The Windows and Linux binaries here are cross-compiled and have not been exercised on
those platforms.

Feature requests and pull requests are welcome, and bugs get fixed as time allows. If
you point this at your account and something looks wrong, that finding is useful —
please open an issue.