Permalink
Browse files

Added commands (verbs): listkeys, addkey, removekey

  • Loading branch information...
1 parent 54f3cda commit 603bd56b106cb2a766ac6eb497523be06d32c1d9 @jedp jedp committed Nov 14, 2012
Showing with 167 additions and 7 deletions.
  1. +114 −1 awsbox.js
  2. +32 −0 doc/HOW_DO_I.md
  3. +16 −1 lib/ssh.js
  4. +5 −5 lib/vm.js
View
115 awsbox.js
@@ -42,6 +42,26 @@ function validateName(name) {
if (!name.length) {
throw "invalid name! must be non-null)";
}
+ return name;
+}
+
+function validatePath(path) {
+ try {
+ var stats = fs.statSync(path);
+ return path;
+ } catch (err) {
+ throw "invalid path! " + err.message;
+ }
+}
+
+function getKeyTexts(path) {
+ var key = fs.readFileSync(validatePath(path)).toString();
+
+ key = key.trimRight();
+ if (key.match('\r\n')) {
+ return key.split('\r\n');
+ }
+ return key.split('\n');
}
function copySSLCertIfAvailable(opts, deets, cb) {
@@ -359,7 +379,7 @@ verbs['list'] = function(args) {
console.log(" IP:\t\t" + v.ipAddress);
console.log(" launched:\t" + relativeDate(v.launchTime));
// console.log(" ssh key:\t" + v.keyName);
- console.log("")
+ console.log("");
});
});
};
@@ -393,6 +413,99 @@ verbs['update'] = function(args) {
}
});
+verbs['describe'] = function(name) {
+ validateName(name);
+ vm.describe(name, function(err, deets) {
+ if (err) throw(err);
+ console.log(JSON.stringify(deets, null, 2));
+ });
+};
+
+verbs['listkeys'] = function(name) {
+ validateName(name);
+ vm.describe(name, function(err, deets) {
+ if (err) throw(err);
+
+ console.log("Fetching authorized keys for " + name + " (" + deets.ipAddress + ") ...\n");
+ ssh.listSSHPubKeys(deets.ipAddress, function(err, keys) {
+ if (err) throw(err);
+ console.log(keys);
+ });
+ });
+};
+
+verbs['addkey'] = function(args) {
+ if (args.length != 2) {
+ throw 'Args required for addkey: instance_name, path_to_key_file';
+ }
+
+ var name = [ validateName(args[0]) ];
+ var keys = getKeyTexts(args[1]);
+ var numKeys = keys.length;
+ var added = 0;
+
+ vm.describe(name, function(err, deets) {
+ if (err) throw(err);
+
+ // We don't want a whole bunch of asynchronous ssh processes adding
+ // and removing keys from the same file at the same time. Ensure
+ // only one key is added at a time.
+ console.log("Adding the " + numKeys + " key" + (numKeys > 1 ? "s" : "") + " found in that file.");
+ addNextKey();
+
+ function maybeAddAnotherKey() {
+ added += 1;
+ if (added < numKeys) {
+ addNextKey();
+ } else {
+ console.log("done.");
+ return;
+ }
+ }
+
+ function addNextKey() {
+ var key = keys[added];
+ console.log("\nAdding key: " + key);
+ ssh.addSSHPubKey(deets.ipAddress, key, maybeAddAnotherKey);
+ }
+ });
+};
+
+verbs['removekey'] = function(args) {
+ if (args.length != 2) {
+ throw 'Args required for removekey: instance_name, path_to_key_file';
+ }
+
+ var name = [ validateName(args[0]) ];
+ var keys = getKeyTexts(args[1]);
+ var numKeys = keys.length;
+ var removed = 0;
+
+ vm.describe(name, function(err, deets) {
+ if (err) throw(err);
+
+ // We don't want a whole bunch of asynchronous ssh processes adding
+ // and removing keys from the same file at the same time. Ensure
+ // only one key is removed at a time.
+ console.log("Removing the " + numKeys + " key" + (numKeys > 1 ? "s" : "") + " found in that file.");
+ removeNextKey();
+
+ function maybeRemoveAnotherKey() {
+ removed += 1;
+ if (removed < numKeys) {
+ removeNextKey();
+ } else {
+ console.log("done.");
+ return;
+ }
+ }
+
+ function removeNextKey() {
+ var key = keys[removed];
+ console.log("\nRemoving key: " + key);
+ ssh.removeSSHPubKey(deets.ipAddress, key, maybeRemoveAnotherKey);
+ }
+ });
};
var error = (process.argv.length <= 2);
View
@@ -32,13 +32,45 @@ Or as an admin user with sudo privileges
Add their key to `~ec2-user/.ssh/authorized_keys` to give access to
administer the machine and the app.
+You can do this like so:
+
+```shell
+awsbox addkey <name> /path/to/keyfile.rsa.pub
+```
+
+Where `<name>` is either the AWS instance identifier or your name for it.
+
+The `addkey` command will add each key in the keyfile you give it,
+excluding any that are already in the `authorized_keys` file.
+
Alternately, to only give app access, turn the symlink in
`~app/.ssh/authorized_keys` to a real file, and add your buddy's key
there:
$ cp -L ~/.ssh/authorized_keys ~/.ssh/foo && mv .ssh/foo .ssh/authorized_keys
$ # now add the key
+## How Do I Revoke Other People's Access to the VM?
+
+YOu can manually edit the `~ec2-user/.ssh/authorized_keys` file, or
+use the `removekey` command like so:
+
+```shell
+awsbox removekey <name> /path/to/keyfile.rsa.pub
+```
+
+Where `<name>` is either the AWS instance id or your name for it.
+
+## How Do I List the People Who Have Access to the VM?
+
+Look in the `~ec2-user/.ssh/authorized_keys` file, or simply run:
+
+```shell
+awsbox listkeys <name>
+```
+
+Where `<name>` is your instance id or name.
+
## How Do I Enable SSL?
SSL is already enabled with a self signed SSL certificate. You can update the
View
@@ -84,7 +84,22 @@ exports.runScript = function(host, script, cb) {
};
exports.addSSHPubKey = function(host, pubkey, cb) {
- var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " 'echo \'" + pubkey + "\' >> .ssh/authorized_keys'";
+ // Add the key if it is not already in the file
+ var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " 'grep \"" + pubkey + "\" .ssh/authorized_keys || echo \"" + pubkey + "\" >> .ssh/authorized_keys'";
+ child_process.exec(cmd, cb);
+};
+
+exports.removeSSHPubKey = function(host, pubkey, cb) {
+ // Remove the key from the file
+ // Escape characters that could break sed regex
+ // (nb NOT the + sign)
+ var escapedPubkey = pubkey.replace(/(["'`\$\!\*\?\\\/\(\)\[\]\{\}])/g, '\\$1');
+ var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " 'sed -i \"/" + escapedPubkey + "/d\" .ssh/authorized_keys'";
+ child_process.exec(cmd, cb);
+};
+
+exports.listSSHPubKeys = function(host, cb) {
+ var cmd = 'ssh -o "StrictHostKeyChecking no" ec2-user@' + host + " 'cat .ssh/authorized_keys'";
child_process.exec(cmd, cb);
};
View
@@ -1,5 +1,5 @@
const
-aws = require('./aws.js');
+aws = require('./aws.js'),
jsel = require('JSONSelect'),
key = require('./key.js'),
sec = require('./sec.js');
@@ -33,7 +33,7 @@ exports.describe = function(name, cb) {
exports.list(function(err, r) {
if (err) return cb('failed to list vms: ' + err);
- deets = findInstance(r, name);
+ var deets = findInstance(r, name);
if (!deets) return cb('no such vm');
cb(null, deets);
});
@@ -58,16 +58,16 @@ exports.list = function(cb) {
// given something the user typed in, try to figure out what instance they're talking about
function findInstance(r, name) {
// is what the human typed in an instance id?
- var x = jsel.match("object:has(:root > .instanceId:val(?))", [ name ], r);
+ var x = jsel.match('object:has(:root > .instanceId:val("?"))', [ name ], r);
if (x.length) return x[0];
// is what the human typed in the vm "short name" ?
var fn = process.env['USER'] + "'s awsbox deployment (" + name + ")";
- var x = jsel.match('.?:has(:root > .instanceId).', [ fn ], r);
+ x = jsel.match('.?:has(:root > .instanceId).', [ fn ], r);
if (x.length) return x[0];
// or did the human type in the full name?
- var x = jsel.match('.?:has(:root > .instanceId).', [ name ], r);
+ x = jsel.match('.?:has(:root > .instanceId).', [ name ], r);
if (x.length) return x[0];
return undefined;

0 comments on commit 603bd56

Please sign in to comment.