Skip to content

Instantly share code, notes, and snippets.

@danopia
Last active May 10, 2021 18:11
Show Gist options
  • Save danopia/5a63d8bd7fa19ca87d7b9029473b38fd to your computer and use it in GitHub Desktop.
Save danopia/5a63d8bd7fa19ca87d7b9029473b38fd to your computer and use it in GitHub Desktop.
Print table in terminal with saml2aws assumed role profile information, as Deno script

$ aws-profiles

Purpose

When using saml2aws to assume AWS roles from a single-sign-on account, you'll need to get new credentials every workday (if not hourly). And users who use multiple accounts need to manage multiple sessions. It becomes hard to track which sessions you have active, and which sessions are expired.

This script prints a table of your saml2aws sessions and which are currently valid.

Install

Get Deno if you don't have it already. Deno is very handy for writing and using small isolated scripts such as this.

Here's a multiline command to install this command with Deno, you can copy/paste it as-is if you're using a normal Linux or Mac setup.

deno install \
  --allow-read=$HOME/.aws/credentials \
  https://gist.githubusercontent.com/danopia/5a63d8bd7fa19ca87d7b9029473b38fd/raw/96bbeacaae352f091f95fb4cae0d9144444bdf13/aws-profiles.ts \
  $HOME/.aws/credentials

You'll need to adjust the paths if using in Windows without a Linuxy environment, or if your credentials file is in a nonstandard location.

Usage

Once installed, just run aws-profiles.

Use with fzf

You can use the fzf fuzzy-selector program to select table rows and export the AWS_PROFILE variable.

# sh/bash/zsh:
export AWS_PROFILE="$(aws-profiles|sed '1,3d;$d'|sed '$d'|fzf --header-lines=3 -n 2|cut -d' ' -f2)"
# Fish shell:
set -x AWS_PROFILE (aws-profiles|sed '1,3d;$d'|sed '$d'|fzf --header-lines=3 -n 2|cut -d' ' -f2)

Example

$ aws-profiles

.------------------------------------------------------------------------.
|                           Local AWS Profiles                           |
|------------------------------------------------------------------------|
|     AWS_PROFILE    |     Validitiy     | AWS Account  |   Role name    |
|--------------------|-------------------|--------------|----------------|
| live-Developer     | ❌ Expired        | 123145121342 | StaffDeveloper |
| live-ReadOnly      | ✅ Until 22:56:48 | 123145121342 | StaffReadOnly  |
| staging-Developer  | ✅ Until 22:56:43 | 643515213532 | StaffDeveloper |
| staging-ReadOnly   | ❌ Expired        | 643515213532 | StaffReadOnly  |
'------------------------------------------------------------------------'
import * as ini from 'https://crux.land/6mMyhY#ini@v1';
import AsciiTable from 'https://deno.land/x/[email protected]/mod.ts';
// Read AWS credentials file
let filename = Deno.args[0];
if (!filename) throw new Error(
`Specify a file to read, usually as $HOME/.aws/credentials`);
const text = await Deno.readTextFile(filename);
const profiles: {[name: string]: {
x_principal_arn?: string;
x_security_token_expires?: string;
}} = ini.decode(text);
// Sort profiles alphabetically
const profileList = Object
.entries(profiles)
.sort((a, b) => a[0].localeCompare(b[0]));
// Print a table
console.log();
console.log(AsciiTable.fromJSON({
title: 'Local AWS Profiles',
heading: ['AWS_PROFILE', 'Validity', 'AWS Account', 'Role name'],
rows: profileList.map(([name, config]) => {
// Non-assumed credentials aren't relevant to us
if (!config.x_principal_arn) return [name, '', 'Unknown'];
// Split up assumed-role ARN
const arnParts = config.x_principal_arn.split(':');
if (arnParts.length !== 6) return [name, '', 'Failed to read ARN'];
const roleParts = arnParts[5].split('/');
const roleName = roleParts[1] || arnParts[5];
// Parse the expires date if any
let expires: Date | null = new Date(config.x_security_token_expires ?? 'none');
if (isNaN(expires.valueOf())) expires = null;
// Put together our data row
return [name,
!expires ? "❓ Unknown"
: (expires < new Date) ? '❌ Expired'
: `✅ Until ${expires.toTimeString().split(' ')[0]}`,
arnParts[4], // account ID
roleName,
];
}),
}).toString() // Render table into a string
.replace(/[\u1000-\uDFFF] /g, x => x[0])); // Fix spacing issues caused by emojis
console.log();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment