Skip to content

(feat) add support to secrets (SSM and Secrets Manager) #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ inputs:
environment-variables:
description: 'Variables to add to the container. Each variable is of the form KEY=value, you can specify multiple variables with multi-line YAML strings.'
required: false
accountId:
description: 'AWS Account ID.'
required: true
region:
description: 'AWS Region.'
required: true
stage:
description: 'Current working stage (DEV, STAGING, PROD)'
required: true
secrets:
description: 'Secrets to add to the container. Each variable is of the form KEY=value, you can specify multiple variables with multi-line YAML strings.'
required: false
outputs:
task-definition:
description: 'The path to the rendered task definition file'
Expand Down
85 changes: 63 additions & 22 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1188,12 +1188,17 @@ const fs = __webpack_require__(747);

async function run() {
try {
const accountId = core.getInput('accountId', { required: true });
const region = core.getInput('region', { required: true });
const stage = core.getInput('stage', { required: true });

// Get inputs
const taskDefinitionFile = core.getInput('task-definition', { required: true });
const containerName = core.getInput('container-name', { required: true });
const imageURI = core.getInput('image', { required: true });

const environmentVariables = core.getInput('environment-variables', { required: false });
const secrets = core.getInput('secrets', { required: false });

// Parse the task definition
const taskDefPath = path.isAbsolute(taskDefinitionFile) ?
Expand Down Expand Up @@ -1253,6 +1258,49 @@ async function run() {
})
}

if (secrets) {
// If secrets array is missing, create it
if (!Array.isArray(containerDef.secrets)) {
containerDef.secrets = [];
}

// Get pairs by splitting on newlines
secrets.split('\n').forEach(function (line) {
// Trim whitespace
const trimmedLine = line.trim();
// Skip if empty
if (trimmedLine.length === 0) { return; }
// Split on =
const separatorIdx = trimmedLine.indexOf("=");
// If there's nowhere to split
if (separatorIdx === -1) {
throw new Error(`Cannot parse the secret '${trimmedLine}'. Secrets pairs must be of the form NAME=arn.`);
}

const secretValue = trimmedLine.substring(separatorIdx + 1)
const secretName = trimmedLine.substring(0, separatorIdx)

const secretSource = secretName.split(':')[0]
const secretAddress = secretName.split(':')[1]

// Build object
const secret = {
name: secretName,
valueFrom: `arn:aws::${secretSource}:${region}:${accountId}:secret:${stage}${secretAddress}`,
};

// Search container definition secret for one matching name
const secretDef = containerDef.secret.find((e) => e.name == secret.name);
if (secretDef) {
// If found, update
secretDef.valueFrom = secret.valueFrom;
} else {
// Else, create
containerDef.secrets.push(secret);
}
})
}


// Write out a new task definition file
var updatedTaskDefFile = tmp.fileSync({
Expand Down Expand Up @@ -2729,7 +2777,6 @@ exports.PersonalAccessTokenCredentialHandler = PersonalAccessTokenCredentialHand
module.exports = globSync
globSync.GlobSync = GlobSync

var fs = __webpack_require__(747)
var rp = __webpack_require__(302)
var minimatch = __webpack_require__(93)
var Minimatch = minimatch.Minimatch
Expand All @@ -2739,8 +2786,6 @@ var path = __webpack_require__(622)
var assert = __webpack_require__(357)
var isAbsolute = __webpack_require__(681)
var common = __webpack_require__(856)
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
var ownProp = common.ownProp
var childrenIgnored = common.childrenIgnored
Expand Down Expand Up @@ -2976,7 +3021,7 @@ GlobSync.prototype._readdirInGlobStar = function (abs) {
var lstat
var stat
try {
lstat = fs.lstatSync(abs)
lstat = this.fs.lstatSync(abs)
} catch (er) {
if (er.code === 'ENOENT') {
// lstat failed, doesn't exist
Expand Down Expand Up @@ -3013,7 +3058,7 @@ GlobSync.prototype._readdir = function (abs, inGlobStar) {
}

try {
return this._readdirEntries(abs, fs.readdirSync(abs))
return this._readdirEntries(abs, this.fs.readdirSync(abs))
} catch (er) {
this._readdirError(abs, er)
return null
Expand Down Expand Up @@ -3172,7 +3217,7 @@ GlobSync.prototype._stat = function (f) {
if (!stat) {
var lstat
try {
lstat = fs.lstatSync(abs)
lstat = this.fs.lstatSync(abs)
} catch (er) {
if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
this.statCache[abs] = false
Expand All @@ -3182,7 +3227,7 @@ GlobSync.prototype._stat = function (f) {

if (lstat && lstat.isSymbolicLink()) {
try {
stat = fs.statSync(abs)
stat = this.fs.statSync(abs)
} catch (er) {
stat = lstat
}
Expand Down Expand Up @@ -3583,7 +3628,6 @@ module.exports = require("assert");

module.exports = glob

var fs = __webpack_require__(747)
var rp = __webpack_require__(302)
var minimatch = __webpack_require__(93)
var Minimatch = minimatch.Minimatch
Expand All @@ -3594,8 +3638,6 @@ var assert = __webpack_require__(357)
var isAbsolute = __webpack_require__(681)
var globSync = __webpack_require__(245)
var common = __webpack_require__(856)
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts
var ownProp = common.ownProp
var inflight = __webpack_require__(674)
Expand Down Expand Up @@ -4046,7 +4088,7 @@ Glob.prototype._readdirInGlobStar = function (abs, cb) {
var lstatcb = inflight(lstatkey, lstatcb_)

if (lstatcb)
fs.lstat(abs, lstatcb)
self.fs.lstat(abs, lstatcb)

function lstatcb_ (er, lstat) {
if (er && er.code === 'ENOENT')
Expand Down Expand Up @@ -4087,7 +4129,7 @@ Glob.prototype._readdir = function (abs, inGlobStar, cb) {
}

var self = this
fs.readdir(abs, readdirCb(this, abs, cb))
self.fs.readdir(abs, readdirCb(this, abs, cb))
}

function readdirCb (self, abs, cb) {
Expand Down Expand Up @@ -4291,13 +4333,13 @@ Glob.prototype._stat = function (f, cb) {
var self = this
var statcb = inflight('stat\0' + abs, lstatcb_)
if (statcb)
fs.lstat(abs, statcb)
self.fs.lstat(abs, statcb)

function lstatcb_ (er, lstat) {
if (lstat && lstat.isSymbolicLink()) {
// If it's a symlink, then treat it as the target, unless
// the target does not exist, then treat it as a file.
return fs.stat(abs, function (er, stat) {
return self.fs.stat(abs, function (er, stat) {
if (er)
self._stat2(f, abs, null, lstat, cb)
else
Expand Down Expand Up @@ -5728,6 +5770,9 @@ function range(a, b, str) {
var i = ai;

if (ai >= 0 && bi > 0) {
if(a===b) {
return [ai, bi];
}
begs = [];
left = str.length;

Expand Down Expand Up @@ -5981,8 +6026,6 @@ module.exports = require("fs");
/***/ 856:
/***/ (function(__unusedmodule, exports, __webpack_require__) {

exports.alphasort = alphasort
exports.alphasorti = alphasorti
exports.setopts = setopts
exports.ownProp = ownProp
exports.makeAbs = makeAbs
Expand All @@ -5995,17 +6038,14 @@ function ownProp (obj, field) {
return Object.prototype.hasOwnProperty.call(obj, field)
}

var fs = __webpack_require__(747)
var path = __webpack_require__(622)
var minimatch = __webpack_require__(93)
var isAbsolute = __webpack_require__(681)
var Minimatch = minimatch.Minimatch

function alphasorti (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase())
}

function alphasort (a, b) {
return a.localeCompare(b)
return a.localeCompare(b, 'en')
}

function setupIgnores (self, options) {
Expand Down Expand Up @@ -6064,6 +6104,7 @@ function setopts (self, pattern, options) {
self.stat = !!options.stat
self.noprocess = !!options.noprocess
self.absolute = !!options.absolute
self.fs = options.fs || fs

self.maxLength = options.maxLength || Infinity
self.cache = options.cache || Object.create(null)
Expand Down Expand Up @@ -6133,7 +6174,7 @@ function finish (self) {
all = Object.keys(all)

if (!self.nosort)
all = all.sort(self.nocase ? alphasorti : alphasort)
all = all.sort(alphasort)

// at *some* point we statted all of these
if (self.mark) {
Expand Down
48 changes: 48 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ const fs = require('fs');

async function run() {
try {
const accountId = core.getInput('accountId', { required: true });
const region = core.getInput('region', { required: true });
const stage = core.getInput('stage', { required: true });

// Get inputs
const taskDefinitionFile = core.getInput('task-definition', { required: true });
const containerName = core.getInput('container-name', { required: true });
const imageURI = core.getInput('image', { required: true });

const environmentVariables = core.getInput('environment-variables', { required: false });
const secrets = core.getInput('secrets', { required: false });

// Parse the task definition
const taskDefPath = path.isAbsolute(taskDefinitionFile) ?
Expand Down Expand Up @@ -70,6 +75,49 @@ async function run() {
})
}

if (secrets) {
// If secrets array is missing, create it
if (!Array.isArray(containerDef.secrets)) {
containerDef.secrets = [];
}

// Get pairs by splitting on newlines
secrets.split('\n').forEach(function (line) {
// Trim whitespace
const trimmedLine = line.trim();
// Skip if empty
if (trimmedLine.length === 0) { return; }
// Split on =
const separatorIdx = trimmedLine.indexOf("=");
// If there's nowhere to split
if (separatorIdx === -1) {
throw new Error(`Cannot parse the secret '${trimmedLine}'. Secrets pairs must be of the form NAME=arn.`);
}

const secretValue = trimmedLine.substring(separatorIdx + 1)
const secretName = trimmedLine.substring(0, separatorIdx)

const secretSource = secretValue.split(':')[0]
const secretAddress = secretValue.split(':')[1]

// Build object
const secret = {
name: secretName,
valueFrom: `arn:aws::${secretSource}:${region}:${accountId}:secret:${stage}${secretAddress}`,
};

// Search container definition secret for one matching name
const secretDef = containerDef.secrets.find((e) => e.name == secret.name);
if (secretDef) {
// If found, update
secretDef.valueFrom = secret.valueFrom;
} else {
// Else, create
containerDef.secrets.push(secret);
}
})
}


// Write out a new task definition file
var updatedTaskDefFile = tmp.fileSync({
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aws-actions-amazon-ecs-render-task-definition",
"version": "1.1.0",
"version": "1.1.1",
"description": "Render Amazon ECS task definition file",
"main": "index.js",
"scripts": {
Expand Down
Loading