Skip to content

Commit 2fd4fa4

Browse files
committed
Fixes nginx#118
The gateway will now use the S3_ACCESS_KEY_ID and S3_SECRET_KEY environment variables when running in an EC2 instance. Signed-off-by: Elijah Zupancic <e.zupancic@f5.com>
1 parent 7baa2c0 commit 2fd4fa4

File tree

5 files changed

+107
-24
lines changed

5 files changed

+107
-24
lines changed

common/docker-entrypoint.d/00-check-for-required-env.sh

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ required=("S3_BUCKET_NAME" "S3_SERVER" "S3_SERVER_PORT" "S3_SERVER_PROTO"
3434
if [[ -v AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ]]; then
3535
echo "Running inside an ECS task, using container credentials"
3636

37+
elif [[ -v S3_SESSION_TOKEN ]]; then
38+
echo "S3 Session token specified - not using IMDS for credentials"
39+
3740
# b) Using Instance Metadata Service (IMDS) credentials, if IMDS is present at http://169.254.169.254.
3841
# See https://docs.aws.amazon.com/sdkref/latest/guide/feature-imds-credentials.html.
3942
# Example: We are running inside an EC2 instance.
@@ -52,10 +55,6 @@ else
5255
required+=("S3_ACCESS_KEY_ID" "S3_SECRET_KEY")
5356
fi
5457

55-
if [[ -v S3_SESSION_TOKEN ]]; then
56-
echo "S3 Session token present"
57-
fi
58-
5958
for name in ${required[@]}; do
6059
if [[ ! -v name ]]; then
6160
>&2 echo "Required ${name} environment variable missing"

common/etc/nginx/include/s3gateway.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import awssig2 from "./awssig2.js";
1919
import awssig4 from "./awssig4.js";
2020
import utils from "./utils.js";
2121

22-
_require_env_var('S3_BUCKET_NAME');
23-
_require_env_var('S3_SERVER');
24-
_require_env_var('S3_SERVER_PROTO');
25-
_require_env_var('S3_SERVER_PORT');
26-
_require_env_var('S3_REGION');
27-
_require_env_var('AWS_SIGS_VERSION');
28-
_require_env_var('S3_STYLE');
22+
_requireEnvVars('S3_BUCKET_NAME');
23+
_requireEnvVars('S3_SERVER');
24+
_requireEnvVars('S3_SERVER_PROTO');
25+
_requireEnvVars('S3_SERVER_PORT');
26+
_requireEnvVars('S3_REGION');
27+
_requireEnvVars('AWS_SIGS_VERSION');
28+
_requireEnvVars('S3_STYLE');
2929

3030
const fs = require('fs');
3131

@@ -208,7 +208,7 @@ function _s3ReqParamsForSigV2(r, bucket) {
208208
if (PROVIDE_INDEX_PAGE && _isDirectory(r.variables.uri_path)){
209209
uri = r.variables.uri_path + INDEX_PAGE
210210
}
211-
211+
212212
return {
213213
uri: '/' + bucket + uri,
214214
httpDate: s3date(r)
@@ -469,11 +469,11 @@ function _isDirectory(path) {
469469
* @param envVarName {string} environment variable to check for
470470
* @private
471471
*/
472-
function _require_env_var(envVarName) {
472+
function _requireEnvVars(envVarName) {
473473
const isSet = envVarName in process.env;
474474

475475
if (!isSet) {
476-
throw('Required environment variable ' + envVarName + ' is missing');
476+
throw(`Required environment variable ${envVarName} is missing`);
477477
}
478478
}
479479

@@ -509,7 +509,7 @@ const maxValidityOffsetMs = 4.5 * 60 * 1000;
509509
async function fetchCredentials(r) {
510510
/* If we are not using an AWS instance profile to set our credentials we
511511
exit quickly and don't write a credentials file. */
512-
if (process.env['S3_ACCESS_KEY_ID'] && process.env['S3_SECRET_KEY']) {
512+
if (utils.areAllEnvVarsSet(['S3_ACCESS_KEY_ID', 'S3_SECRET_KEY'])) {
513513
r.return(200);
514514
return;
515515
}
@@ -539,8 +539,9 @@ async function fetchCredentials(r) {
539539

540540
utils.debug_log(r, 'Cached credentials are expired or not present, requesting new ones');
541541

542-
if (process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI']) {
543-
const uri = ECS_CREDENTIAL_BASE_URI + process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'];
542+
if (utils.areAllEnvVarsSet('AWS_CONTAINER_CREDENTIALS_RELATIVE_URI')) {
543+
const relative_uri = process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] || '';
544+
const uri = ECS_CREDENTIAL_BASE_URI + relative_uri;
544545
try {
545546
credentials = await _fetchEcsRoleCredentials(uri);
546547
} catch (e) {
@@ -549,7 +550,7 @@ async function fetchCredentials(r) {
549550
return;
550551
}
551552
}
552-
else if(process.env['AWS_WEB_IDENTITY_TOKEN_FILE']) {
553+
else if (utils.areAllEnvVarsSet('AWS_WEB_IDENTITY_TOKEN_FILE')) {
553554
try {
554555
credentials = await _fetchWebIdentityCredentials(r)
555556
} catch(e) {

common/etc/nginx/include/utils.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,27 @@
2121
*/
2222
const DEBUG = parseBoolean(process.env['S3_DEBUG']);
2323

24+
/**
25+
* Checks to see if all of the elements of the passed array are present as keys
26+
* in the running process' environment variables. Alternatively, if a single
27+
* string is passed, it will check for the presence of that string.
28+
* @param envVars {array[string]|string} array of expected keys or single expected key
29+
* @returns {boolean} true if all keys are set as environment variables
30+
*/
31+
function areAllEnvVarsSet(envVars) {
32+
if (envVars instanceof Array) {
33+
const envVarsLen = envVars.length;
34+
for (let i = 0; i < envVarsLen; i++) {
35+
if (!process.env[envVars[i]]) {
36+
return false;
37+
}
38+
}
39+
40+
return true;
41+
}
42+
43+
return envVars in process.env;
44+
}
2445

2546
/**
2647
* Parses a string delimited by semicolons into an array of values
@@ -133,5 +154,6 @@ export default {
133154
getEightDigitDate,
134155
padWithLeadingZeros,
135156
parseArray,
136-
parseBoolean
157+
parseBoolean,
158+
areAllEnvVarsSet
137159
}

test/unit/s3gateway_test.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,10 @@ function testEscapeURIPathPreservesDoubleSlashes() {
204204

205205
async function testEcsCredentialRetrieval() {
206206
printHeader('testEcsCredentialRetrieval');
207-
process.env['S3_ACCESS_KEY_ID'] = undefined;
207+
delete process.env['S3_ACCESS_KEY_ID'];
208208
process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] = '/example';
209209
globalThis.ngx.fetch = function (url) {
210+
console.log(' fetching mock credentials');
210211
globalThis.recordedUrl = url;
211212

212213
return Promise.resolve({
@@ -245,14 +246,14 @@ async function testEcsCredentialRetrieval() {
245246
await s3gateway.fetchCredentials(r);
246247

247248
if (globalThis.recordedUrl !== 'http://169.254.170.2/example') {
248-
throw 'No or wrong ECS credentials fetch URL recorded: ' + globalThis.recordedUrl;
249+
throw `No or wrong ECS credentials fetch URL recorded: ${globalThis.recordedUrl}`;
249250
}
250251
}
251252

252253
async function testEc2CredentialRetrieval() {
253254
printHeader('testEc2CredentialRetrieval');
254-
process.env['S3_ACCESS_KEY_ID'] = undefined;
255-
process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'] = undefined;
255+
delete process.env['S3_ACCESS_KEY_ID'];
256+
delete process.env['AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'];
256257
globalThis.ngx.fetch = function (url, options) {
257258
if (url === 'http://169.254.169.254/latest/api/token' && options && options.method === 'PUT') {
258259
return Promise.resolve({

test/unit/utils_test.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,73 @@ function testPad() {
122122
}
123123
}
124124

125+
function testAreAllEnvVarsSet() {
126+
function testAreAllEnvVarsSetStringFound() {
127+
console.log(' ## testAreAllEnvVarsSetStringFound');
128+
const key = 'TEST_ENV_VAR_KEY';
129+
process.env[key] = 'some value';
130+
const actual = utils.areAllEnvVarsSet(key);
131+
if (!actual) {
132+
throw 'Environment variable that was set not indicated as present';
133+
}
134+
}
135+
136+
function testAreAllEnvVarsSetStringNotFound() {
137+
console.log(' ## testAreAllEnvVarsSetStringNotFound');
138+
const actual = utils.areAllEnvVarsSet('UNKNOWN_ENV_VAR_KEY');
139+
if (actual) {
140+
throw 'Unknown environment variable indicated as being present';
141+
}
142+
}
143+
144+
function testAreAllEnvVarsSetStringArrayFound() {
145+
console.log(' ## testAreAllEnvVarsSetStringArrayFound');
146+
const keys = ['TEST_ENV_VAR_KEY_1', 'TEST_ENV_VAR_KEY_2', 'TEST_ENV_VAR_KEY_3'];
147+
for (let i = 0; i < keys.length; i++) {
148+
process.env[keys[i]] = 'something';
149+
}
150+
const actual = utils.areAllEnvVarsSet(keys);
151+
if (!actual) {
152+
throw 'Environment variables that were set not indicated as present';
153+
}
154+
}
155+
156+
function testAreAllEnvVarsSetStringArrayNotFound() {
157+
console.log(' ## testAreAllEnvVarsSetStringArrayNotFound');
158+
const keys = ['UNKNOWN_ENV_VAR_KEY_1', 'UNKNOWN_ENV_VAR_KEY_2', 'UNKNOWN_ENV_VAR_KEY_3'];
159+
const actual = utils.areAllEnvVarsSet(keys);
160+
if (actual) {
161+
throw 'Unknown environment variables that were not set indicated as present';
162+
}
163+
}
164+
165+
function testAreAllEnvVarsSetStringArrayWithSomeSet() {
166+
console.log(' ## testAreAllEnvVarsSetStringArrayWithSomeSet');
167+
const keys = ['TEST_ENV_VAR_KEY_1', 'UNKNOWN_ENV_VAR_KEY_2', 'UNKNOWN_ENV_VAR_KEY_3'];
168+
process.env[keys[0]] = 'something';
169+
170+
const actual = utils.areAllEnvVarsSet(keys);
171+
if (actual) {
172+
throw 'Unknown environment variables that were not set indicated as present';
173+
}
174+
}
175+
176+
printHeader('testAreAllEnvVarsSet');
177+
testAreAllEnvVarsSetStringFound();
178+
testAreAllEnvVarsSetStringNotFound();
179+
testAreAllEnvVarsSetStringArrayFound();
180+
testAreAllEnvVarsSetStringArrayNotFound();
181+
testAreAllEnvVarsSetStringArrayWithSomeSet();
182+
}
183+
125184
async function test() {
126185
testAmzDatetime();
127186
testEightDigitDate();
128187
testPad();
129188
testParseArray();
189+
testAreAllEnvVarsSet();
130190
}
131-
191+
132192
function printHeader(testName) {
133193
console.log(`\n## ${testName}`);
134194
}

0 commit comments

Comments
 (0)