├── .gitignore ├── CHANGELOG.md ├── README.md ├── bin └── assume-aws-role.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 1.4.0 2 | ------------------ 3 | - Update contributors list 4 | - #12 Add the role to the environment of the subshell 5 | 6 | 1.3.1 7 | ------------------ 8 | - Updating the aws-sdk to `2.4.3` and fs-extra to `0.30.0`, currently these are the latest for both modules, the fs-extra upgrade fixes a warning that was appearing with node v6. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # assume-aws-role 2 | 3 | Work with multiple AWS accounts more easily. 4 | 5 | If you currently manage multiple AWS accounts and use role switching to do work in them, this is the tool for you! 6 | 7 | ## Requirements 8 | 9 | * [nodejs](https://nodejs.org/download/) v0.12 or higher 10 | 11 | ## Usage 12 | 13 | First, you need to install the tool from NPM: 14 | 15 | `npm install -g assume-aws-role` 16 | 17 | Next, you need to add a role that you'd like to assume. As an example, lets say I wanted to add the Administrator role for my sandbox account with MFA required: 18 | 19 | ``` 20 | assume-aws-role add sandbox \ 21 | "arn:aws:iam::123456789012:role/Administrator" \ 22 | "arn:aws:iam::109876543210:mfa/jbuck" 23 | ``` 24 | 25 | Now you can assume that role we just added: 26 | 27 | `assume-aws-role sandbox 123456` 28 | 29 | Now you've got a shell with your temporary security credentials in the environment: 30 | 31 | `(assume-aws-role sandbox)$ ` 32 | 33 | You can also add roles without MFA devices: 34 | 35 | ``` 36 | assume-aws-role add sandbox \ 37 | "arn:aws:iam::123456789012:role/Administrator" 38 | ``` 39 | 40 | You can list all the defined roles with a single command: 41 | 42 | `assume-aws-role list` 43 | 44 | You can delete a defined alias with a single command: 45 | 46 | `assume-aws-role delete ` 47 | 48 | ## How does it work? 49 | 50 | Any roles you add are stored in `~/.assume-aws-role/config`. It's optional but highly recommended that you use a MFA device. 51 | 52 | `assume-aws-role` uses the [STS:AssumeRole API](http://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html) to assume the role you specified. 53 | 54 | After receiving valid credentials `assume-aws-role` will spawn the shell specified in `$SHELL` with the environment modified to include `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`. The environment also includes an overridden `PS1` with a minimal custom prompt, and `ASSUME_AWS_ROLE` with the role so you can fully customize the `PS1` prompt by yourself. 55 | -------------------------------------------------------------------------------- /bin/assume-aws-role.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var AWS = require("aws-sdk"); 4 | var fs = require("fs-extra") 5 | var path = require("path"); 6 | var spawn = require("child_process").spawn; 7 | 8 | var command = process.argv[2]; 9 | var home = process.env.HOME || 10 | process.env.USERPROFILE || 11 | (process.env.HOMEPATH ? ((process.env.HOMEDRIVE || 'C:/') + process.env.HOMEPATH) : null); 12 | var filename = path.join(home, ".assume-aws-role", "config"); 13 | var readConfig = function(filename) { 14 | var config = {}; 15 | 16 | try { 17 | config = fs.readJsonSync(filename, {throws: false}); 18 | } catch (read_error) { 19 | if (read_error.code != 'ENOENT') { 20 | throw read_error; 21 | } 22 | } 23 | 24 | return config; 25 | }; 26 | 27 | if (!command) { 28 | console.error("Usage: assume-aws-role add [mfa-arn]"); 29 | console.error(" assume-aws-role delete "); 30 | console.error(" assume-aws-role list"); 31 | console.error(" assume-aws-role [mfa-token]"); 32 | process.exit(1); 33 | } 34 | 35 | if (command === "add") { 36 | var alias = process.argv[3]; 37 | var role = process.argv[4]; 38 | var mfa = process.argv[5]; 39 | 40 | if (!alias) { 41 | console.error("No alias specified"); 42 | console.error("Usage: assume-aws-role add [mfa-arn]"); 43 | process.exit(1); 44 | } 45 | if (!role) { 46 | console.error("No role ARN specified"); 47 | console.error("Usage: assume-aws-role add [mfa-arn]"); 48 | process.exit(1); 49 | } 50 | if (!home) { 51 | console.error("Cannot save credentials, $HOME path not set"); 52 | process.exit(1); 53 | } 54 | 55 | var config = readConfig(filename); 56 | 57 | config[alias] = { 58 | RoleArn: role 59 | }; 60 | if (!!mfa) { 61 | config[alias].SerialNumber = mfa 62 | } 63 | 64 | fs.outputJsonSync(filename, config); 65 | process.exit(0); 66 | } 67 | 68 | if (command == "list") { 69 | var config = readConfig(filename); 70 | var aliases = Object.keys(config); 71 | console.log("Defined aliases: %s" , aliases); 72 | process.exit(0); 73 | } 74 | 75 | if (command == "delete") { 76 | var alias = process.argv[3]; 77 | if (!alias) { 78 | console.error("No alias specified"); 79 | console.error("Usage: assume-aws-role delete "); 80 | process.exit(1); 81 | } 82 | var config = readConfig(filename); 83 | var role = config[alias]; 84 | if (!role) { 85 | console.error("The specified alias does not exist"); 86 | process.exit(1); 87 | } 88 | delete config[alias]; 89 | fs.outputJsonSync(filename, config); 90 | process.exit(0); 91 | } 92 | 93 | var config = readConfig(filename); 94 | if (!config[command]) { 95 | console.error("%s not found.", command); 96 | 97 | var aliases = Object.keys(config); 98 | if (aliases.length === 0) { 99 | console.error("You need to add an alias before you can use it"); 100 | console.error("Usage: assume-aws-role add [mfa-arn]"); 101 | } else { 102 | console.error("Did you mean:"); 103 | console.error(aliases.map(function(a) { 104 | return " " + a 105 | }).join("\n")) 106 | console.error("assume-aws-role [mfa-token]"); 107 | } 108 | 109 | process.exit(1); 110 | } 111 | 112 | var role = config[command]; 113 | var token = process.argv[3]; 114 | 115 | if (role.SerialNumber && !token) { 116 | console.error("You need to specify your MFA token to assume this role"); 117 | console.error("assume-aws-role [mfa-token]"); 118 | process.exit(1); 119 | } 120 | 121 | var STS = new AWS.STS(); 122 | STS.assumeRole({ 123 | RoleArn: role.RoleArn, 124 | RoleSessionName: "assume-aws-role-cli", 125 | SerialNumber: role.SerialNumber, 126 | TokenCode: token 127 | }, function(error, data) { 128 | if (error) { 129 | console.error(error); 130 | process.exit(1); 131 | } 132 | 133 | var modEnv = process.env; 134 | modEnv.AWS_ACCESS_KEY_ID = data.Credentials.AccessKeyId; 135 | modEnv.AWS_SECRET_ACCESS_KEY = data.Credentials.SecretAccessKey; 136 | modEnv.AWS_SESSION_TOKEN = data.Credentials.SessionToken; 137 | 138 | // required for boto sts to work 139 | modEnv.AWS_SECURITY_TOKEN = data.Credentials.SessionToken; 140 | modEnv.PS1 = "(assume-aws-role " + command + ")$ "; 141 | modEnv.ASSUME_AWS_ROLE = command; 142 | 143 | var sh = spawn(process.env.SHELL, { 144 | env: modEnv, 145 | stdio: "inherit" 146 | }); 147 | 148 | sh.on('close',(code)=>{ 149 | process.exit(code); 150 | }); 151 | 152 | }); 153 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "assume-aws-role", 3 | "version": "1.4.0", 4 | "description": "Work with multiple AWS accounts more easily", 5 | "homepage": "https://github.com/jbuck/assume-aws-role", 6 | "bugs": { 7 | "url": "https://github.com/jbuck/assume-aws-role/issues" 8 | }, 9 | "bin": "bin/assume-aws-role.js", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/jbuck/assume-aws-role" 13 | }, 14 | "preferGlobal": true, 15 | "scripts": { 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "author": "Jon Buckley ", 19 | "contributors": [ 20 | "Benson Wong ", 21 | "Eric Rutherford ", 22 | "Frank Pavageau " 23 | ], 24 | "license": "Apache-2.0", 25 | "dependencies": { 26 | "aws-sdk": "^2.4.3", 27 | "fs-extra": "^0.30.0" 28 | } 29 | } 30 | --------------------------------------------------------------------------------