Skip to content

Commit

Permalink
Load, backstop, and pass around AWS credentials the correct way: via …
Browse files Browse the repository at this point in the history
…`aws-lite`

Stop populating credential-related process env vars: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`
No longer use Dynamo client init as a missing credential backstop
  • Loading branch information
ryanblock committed Oct 25, 2023
1 parent 74e519a commit 94a1b62
Show file tree
Hide file tree
Showing 13 changed files with 61 additions and 51 deletions.
2 changes: 0 additions & 2 deletions bin/binary-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ let config = {
// Don't manually include runtimes/deno.js in scripts, as it fails on pkg#997
scripts: [
'../node_modules/@architect/inventory/**/*.js',
// Utils now has a child process-executed script for checking credentials
'../node_modules/@architect/utils/**/*.js',
'../node_modules/dynalite/**/*.js',
// This line is only necessary when testing RC releases of Inventory, do NOT use it in production binary builds of Sandbox:
'../node_modules/**/@architect/inventory/**/*.js',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"@architect/create": "~4.2.3",
"@architect/hydrate": "~3.4.1",
"@architect/inventory": "~3.6.2",
"@architect/utils": "~4.0.0-RC.0",
"@architect/utils": "~4.0.0-RC.1",
"@aws-lite/client": "~0.11.1",
"@aws-lite/dynamodb": "~0.2.2",
"@begin/hashid": "~1.0.0",
Expand Down
2 changes: 0 additions & 2 deletions src/cli/arc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@ let cli = require('./index.js')
*/
module.exports = function arcCalling ({ inventory }) {
cli({
checkCreds: false,
disableBanner: true,
inventory,
needsValidCreds: false,
runtimeCheck: 'warn',
},
function _done (err) {
Expand Down
4 changes: 3 additions & 1 deletion src/http/middleware/_fallback.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ let httpProxy = require('http-proxy')
* - Error out
*/
module.exports = function fallback (args, req, res, next) {
let { apiType, cwd, inventory, ports, staticPath, update } = args
let { apiType, creds, cwd, inventory, ports, staticPath, update } = args
let { inv, get } = inventory
let httpAPI = apiType.startsWith('http')
let method = req.method.toLowerCase()
Expand Down Expand Up @@ -111,6 +111,7 @@ module.exports = function fallback (args, req, res, next) {
let name = `${rootParam[0]} /${rootParam[1]}`
let lambda = get.http(name)
let exec = invoker({
creds,
cwd,
lambda,
apiType,
Expand Down Expand Up @@ -144,6 +145,7 @@ module.exports = function fallback (args, req, res, next) {
function invokeProxy (src, arcStaticAssetProxy) {
let exec = invoker({
apiType,
creds,
cwd,
lambda: {
name: 'get /*',
Expand Down
11 changes: 6 additions & 5 deletions src/invoke-lambda/env/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ let { version } = require('../../../package.json')

// Assemble Lambda-specific execution environment variables
module.exports = function getEnv (params, requestID) {
let { apiType, cwd, lambda, host, inventory, ports, staticPath } = params
let { apiType, creds, cwd, lambda, host, inventory, ports, staticPath } = params
let { accessKeyId, secretAccessKey, sessionToken } = creds
let { config, src, build, handlerFile } = lambda
let { inv } = inventory
let { AWS_ACCESS_KEY_ID, AWS_PROFILE, AWS_REGION, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, PATH } = process.env
let { AWS_PROFILE, AWS_REGION, PATH } = process.env

let lambdaContext = getContext(params)
let envVars = userEnvVars(params)
Expand All @@ -23,16 +24,16 @@ module.exports = function getEnv (params, requestID) {
// Runtime environment variables
let env = {
// AWS-specific
AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID || 'arc_dummy_access_key',
AWS_ACCESS_KEY_ID: accessKeyId,
AWS_LAMBDA_FUNCTION_MEMORY_SIZE: lambda.config.memory,
AWS_LAMBDA_FUNCTION_NAME: `@${lambda.pragma} ${lambda.name}`,
AWS_LAMBDA_FUNCTION_VERSION: '$latest',
AWS_LAMBDA_RUNTIME_API,
AWS_PROFILE,
AWS_REGION,
AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE: true, // Sigh.
AWS_SECRET_ACCESS_KEY: AWS_SECRET_ACCESS_KEY || 'arc_dummy_secret_key',
AWS_SESSION_TOKEN,
AWS_SECRET_ACCESS_KEY: secretAccessKey,
AWS_SESSION_TOKEN: sessionToken,
LAMBDA_TASK_ROOT: src,
TZ: 'UTC',
// Internal for handler bootstrap
Expand Down
25 changes: 25 additions & 0 deletions src/sandbox/creds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
let awsLite = require('@aws-lite/client')
module.exports = function loadCreds (params, callback) {
let { inventory } = params
awsLite({
autoloadPlugins: false,
profile: inventory.inv?.aws?.profile,
region: 'us-west-1',
})
.then(aws => {
params.creds = {
// secretAccessKey + sessionToken are non-enumerable, so we can't just ref or spread
accessKeyId: aws.credentials.accessKeyId,
secretAccessKey: aws.credentials.secretAccessKey,
sessionToken: aws.credentials.sessionToken,
}
callback()
})
.catch(() => {
params.creds = {
accessKeyId: 'arc_dummy_access_key',
secretAccessKey: 'arc_dummy_secret_key',
}
callback()
})
}
6 changes: 6 additions & 0 deletions src/sandbox/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ let series = require('run-series')
let create = require('@architect/create')

let env = require('./env')
let creds = require('./creds')
let ports = require('./ports')
let checkRuntimes = require('./check-runtimes')
let maybeHydrate = require('./maybe-hydrate')
Expand All @@ -27,6 +28,11 @@ function _start (params, callback) {
env(params, callback)
},

// Load credentials
function (callback) {
creds(params, callback)
},

// Get the ports for services
function (callback) {
ports(params, callback)
Expand Down
4 changes: 2 additions & 2 deletions src/sandbox/seed.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ let getDBClient = require('../tables/_get-db-client')

module.exports = function startupSeedData (params, callback) {
let { ARC_ENV } = process.env
let { cwd, inventory, update, ports } = params
let { creds, cwd, inventory, update, ports } = params
let { inv, get } = inventory
let { app, tables } = inv
if (!tables || ARC_ENV !== 'testing') return callback()
Expand Down Expand Up @@ -54,7 +54,7 @@ module.exports = function startupSeedData (params, callback) {
})
}).filter(Boolean)

getDBClient(ports, (err, aws) => {
getDBClient({ creds, ports }, (err, aws) => {
if (err) callback(err)
else {
dynamo = aws.DynamoDB
Expand Down
41 changes: 10 additions & 31 deletions src/tables/_get-db-client.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
let { join } = require('path')
let awsLite = require('@aws-lite/client')

module.exports = function initDynamoClient (ports, callback) {
/**
* Final DynamoDB credentials backstop
* - Assumes credentials are loaded via aws-lite
* - Populate AWS-specific env vars necessary to mock Lambda + make SDK calls if not already loaded
* - Only AWS_SECRET_ACCESS_KEY + AWS_ACCESS_KEY_ID are technically required to mock Lambda
*/
let plugins = []
// Binary dist mode
if (process.pkg) {
plugins.push(join(__dirname, '_aws-lite-dynamodb-vendor.js'))
}
else plugins.push('@aws-lite/dynamodb')
module.exports = function initDynamoClient ({ creds, ports }, callback) {
let plugins = [
// Binary dist mode
process.pkg
? join(__dirname, '_aws-lite-dynamodb-vendor.js')
: '@aws-lite/dynamodb'
]
let config = {
autoloadPlugins: false,
host: 'localhost',
plugins,
port: ports.tables,
protocol: 'http',
region: process.env.AWS_REGION || 'us-west-2',
}
function go (aws) {
if (!process.env.AWS_ACCESS_KEY_ID) {
process.env.AWS_ACCESS_KEY_ID = aws.credentials.accessKeyId
}
if (!process.env.AWS_SECRET_ACCESS_KEY) {
process.env.AWS_SECRET_ACCESS_KEY = aws.credentials.secretAccessKey
}
callback(null, aws)
...creds,
}
awsLite(config)
.then(go)
.catch(err => {
if (err.message.match(/You must supply AWS credentials/)) {
config.accessKeyId = 'arc_dummy_access_key'
config.secretAccessKey = 'arc_dummy_secret_key'
awsLite(config).then(go).catch(callback)
}
else callback(err)
})
.then(client => callback(null, client))
.catch(callback)
}
4 changes: 2 additions & 2 deletions src/tables/_init.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ let getDBClient = require('./_get-db-client')
let createTables = require('./create-table')

// Just a thin passthrough to enable the abstraction of getDBClient (for testing)
module.exports = function init ({ inventory, ports }, callback) {
getDBClient(ports, (err, aws) => {
module.exports = function init ({ creds, inventory, ports }, callback) {
getDBClient({ creds, ports }, (err, aws) => {
if (err) return callback(err)
createTables({ aws, inventory, ports }, callback)
})
Expand Down
6 changes: 3 additions & 3 deletions test/integration/tables-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ let getDBClient = require(join(process.cwd(), 'src', 'tables', '_get-db-client')
let TableName = 'mockapp-production-accounts'
let TableName2 = 'mockapp-production-pets'
let mock = join(process.cwd(), 'test', 'mock')
let { run, startup, shutdown } = require('../utils')
let { credentials: creds, run, startup, shutdown } = require('../utils')
let str = s => JSON.stringify(s, null, 2)
let dynamo
let tablesPort = 5555
Expand Down Expand Up @@ -45,7 +45,7 @@ function runTests (runType, t) {

t.test(`${mode} Get client`, t => {
t.plan(1)
getDBClient(ports, function _gotDBClient (err, client) {
getDBClient({ creds, ports }, function _gotDBClient (err, client) {
if (err) console.log(err) // Yes, but actually no
dynamo = client.DynamoDB
t.ok(dynamo, 'Got Dynamo client')
Expand Down Expand Up @@ -267,7 +267,7 @@ function runTests (runType, t) {
t.test(`${mode} Get client (external DB)`, t => {
t.plan(1)
setup(t, externalDBPort)
getDBClient({ tables: externalDBPort }, function _gotDBClient (err, client) {
getDBClient({ creds, ports: { tables: externalDBPort } }, function _gotDBClient (err, client) {
if (err) console.log(err) // Yes, but actually no
dynamo = client.DynamoDB
t.ok(dynamo, 'Got Dynamo client')
Expand Down
3 changes: 2 additions & 1 deletion test/unit/src/invoke-lambda/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ let update = require('@architect/utils').updater()
let cwd = process.cwd()
let mock = join(cwd, 'test', 'mock')
let { invocations } = require(join(cwd, 'src', 'arc', '_runtime-api'))
let { credentials: creds } = require(join(cwd, 'test', 'utils'))

let runtimes = {
asap: 0,
Expand Down Expand Up @@ -36,7 +37,7 @@ let event = { something: 'happened' }
let inventory = { inv: { _project: { env: { local: { testing: null, staging: null, production: null } } }, app: 'hi' } }
let ports = {}
let userEnv = {}
let params = { event, inventory, update, userEnv, ports }
let params = { creds, event, inventory, update, userEnv, ports }
let inv
let get

Expand Down
2 changes: 1 addition & 1 deletion test/unit/src/sandbox-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ test('Sandbox uses continuation passing', t => {
])
})

// Standard env vars that may be populated during a banner / AWS init
// Nothing should be mutating these, but reset them jic!
let envVars = [
'ARC_APP_NAME',
'ARC_AWS_CREDS',
Expand Down

0 comments on commit 94a1b62

Please sign in to comment.