Skip to content

Commit

Permalink
feat: expose core functions: revokePermissions and grantPermissions
Browse files Browse the repository at this point in the history
Expose main functions to allow use by other libraries

fixed #3
  • Loading branch information
niallmccullagh committed Dec 11, 2018
1 parent 65134b3 commit ed39c02
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 76 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ module.exports = {
],
'extends': ['airbnb-base', 'plugin:security/recommended'],
'rules': {
"no-console": "off",
"security/detect-non-literal-fs-filename": "off",
'no-restricted-syntax': [
2,
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,13 @@ Options:
-p, --profile AWS profile to use
-h Show help [boolean]
```

## Using in another application/library

The library exports a number of functions:

1. `revokePermissions`, revokes any permissions for the user in the supplied user groups
1. `grantPermissions`, grants permissions for the user in the supplied ip and user groups
1. `useAWSProfile`, configures the AWS authentication to use the supplied profile.

See `bin/aws-manage-sg.js` for an example.
79 changes: 79 additions & 0 deletions bin/aws-manage-sg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/local/bin/node
const fs = require('fs');
const yargs = require('yargs');
const delay = require('timeout-as-promise');
const request = require('request-promise');
const debugCore = require('debug');
const { revokePermissions, grantPermissions, useAWSProfile } = require('../index');

const debug = debugCore('aws-manage-sg-cli');

debugCore.enable('aws-manage-sg*');

async function getIPAddress() {
const response = await request('http://checkip.amazonaws.com/');
return response.replace(/\s/g, '');
}

async function buildConfig(configFile) {
return {
...configFile,
ipAddress: await getIPAddress(),
};
}

async function run(options, config) {
async function giveRevocationTimeToSet() {
await delay(1000);
}

function shouldRunByDefault() {
return !options.revoke && !options.grant;
}

const revoke = options.revoke || shouldRunByDefault();
const grant = options.grant || shouldRunByDefault();

if (options.profile) {
useAWSProfile(options.profile);
}

if (revoke) {
await revokePermissions(config);
await giveRevocationTimeToSet();
}

if (grant) {
await grantPermissions(config);
}
}

function getOptions() {
return yargs
.usage('Usage: $0 <command> [options]')
.alias('f', 'file')
.describe('f', 'Path to config file')
.alias('g', 'grant')
.describe('g', 'Run only the grant')
.alias('r', 'revoke')
.describe('r', 'Run only the revoke')
.alias('p', 'profile')
.describe('p', 'AWS profile to use')
.demandOption(['file'], 'Please provide a path to a config file')
.help('h').argv;
}

function readConfigFile(path) {
return JSON.parse(fs.readFileSync(path));
}

(async () => {
try {
const options = getOptions();
const config = readConfigFile(options.file);
await run(options, await buildConfig(config));
} catch (e) {
debug(`ERROR: ${e.message}`);
process.exit(1);
}
})();
91 changes: 20 additions & 71 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#!/usr/local/bin/node
const AWS = require('aws-sdk');
const delay = require('timeout-as-promise');
const fs = require('fs');
const request = require('request-promise');
const yargs = require('yargs');
const debug = require('debug')('aws-manage-sg');

function EC2(config) {
const region = config.region || 'us-east-1';
Expand Down Expand Up @@ -44,23 +40,23 @@ async function revokePermission(config, securityGroupId, permission) {
IpProtocol: permission.IpProtocol,
};

console.log(`Revoking rule ${JSON.stringify(revokeParam)} on ${securityGroupId}`);
debug(`Revoking rule ${JSON.stringify(revokeParam)} on ${securityGroupId}`);

return EC2(config).revokeSecurityGroupIngress({
GroupId: securityGroupId,
IpPermissions: [revokeParam],
}).promise();
}

async function grantPermission(config, ipAddress, { securityGroupId, ports }) {
console.log(`Granting rule to ${securityGroupId} on ports ${ports} for IP ${ipAddress}`);
async function grantPermission(config, { securityGroupId, ports }) {
debug(`Granting rule to ${securityGroupId} on ports ${ports} for IP ${config.ipAddress}`);

const permissions = await ports.map((port) => {
const p = parseInt(port, 10);
return {
IpRanges: [
{
CidrIp: `${ipAddress}/32`,
CidrIp: `${config.ipAddress}/32`,
Description: `${config.username}`,
},
],
Expand All @@ -73,15 +69,15 @@ async function grantPermission(config, ipAddress, { securityGroupId, ports }) {
return EC2(config).authorizeSecurityGroupIngress({
GroupId: securityGroupId,
IpPermissions: permissions,
}).promise();
})
.promise();
}

async function getIPAddress() {
const response = await request('http://checkip.amazonaws.com/');
return response.replace(/\s/g, '');
function useAWSProfile(profile) {
const credentials = new AWS.SharedIniFileCredentials({ profile });
AWS.config.credentials = credentials;
}


async function revokePermissions(config) {
const results = [];

Expand All @@ -94,64 +90,17 @@ async function revokePermissions(config) {
return Promise.all(results);
}

function useAWSProfile(profile) {
const credentials = new AWS.SharedIniFileCredentials({ profile });
AWS.config.credentials = credentials;
}

async function run(options, config) {
async function giveRevocationTimeToSet() {
await delay(1000);
}

function shouldRunByDefault() {
return !options.revoke && !options.grant;
}

const ipAddress = await getIPAddress();
const revoke = options.revoke || shouldRunByDefault();
const grant = options.grant || shouldRunByDefault();

if (options.profile) {
useAWSProfile(options.profile);
}

if (revoke) {
await revokePermissions(config);
await giveRevocationTimeToSet();
async function grantPermissions(config) {
const results = [];
for (const rule of config.rules) {
results.push(grantPermission(config, rule));
}

if (grant) {
const results = [];
for (const rule of config.rules) {
grantPermission(config, ipAddress, rule);
}
await Promise.all(results);
}
await Promise.all(results);
}

function getOptions() {
return yargs
.usage('Usage: $0 <command> [options]')
.alias('f', 'file')
.describe('f', 'Path to config file')
.alias('g', 'grant')
.describe('g', 'Run only the grant')
.alias('r', 'revoke')
.describe('r', 'Run only the revoke')
.alias('p', 'profile')
.describe('p', 'AWS profile to use')
.demandOption(['file'], 'Please provide a path to a config file')
.help('h').argv;
}

(async () => {
try {
const options = getOptions();
const config = JSON.parse(fs.readFileSync(options.file));
await run(options, config);
} catch (e) {
console.log(`ERROR: ${e.message}`);
process.exit(1);
}
})();
module.exports = {
revokePermissions,
grantPermissions,
useAWSProfile,
};
4 changes: 1 addition & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"travis-deploy-once": "travis-deploy-once"
},
"bin": {
"aws-manage-sg": "./index.js"
"aws-manage-sg": "./bin/aws-manage-sg.js"
},
"preferGlobal": true,
"keywords": [
Expand All @@ -24,6 +24,7 @@
"license": "MIT",
"dependencies": {
"aws-sdk": "^2.373.0",
"debug": "^4.1.0",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"timeout-as-promise": "^1.0.0",
Expand Down

0 comments on commit ed39c02

Please sign in to comment.