Skip to content
This repository has been archived by the owner on Dec 6, 2024. It is now read-only.

Commit

Permalink
feat: add IMDSv2 support on AMI creation (#1215)
Browse files Browse the repository at this point in the history
  • Loading branch information
maghirardelli authored Jul 26, 2023
1 parent 9be3b40 commit 3432768
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ docs/build

# rStudio specific
source/ServiceWorkbenchOnAWS/main/solution/machine-images/config/infra/files/rstudio/*

# temp packer log files
main/solution/machine-images/*_build.log
71 changes: 69 additions & 2 deletions addons/addon-base-raas/packages/serverless-packer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ServerlessPackerPlugin {
this.commands = {
'build-image': {
usage: 'Build an AMI using packer',
lifecycleEvents: ['build'],
lifecycleEvents: ['build', 'add-imds-v2-support'],
options: {
files: {
usage:
Expand All @@ -49,6 +49,7 @@ class ServerlessPackerPlugin {

this.hooks = {
'build-image:build': this.buildImages.bind(this),
'build-image:add-imds-v2-support': this.addIMDSv2Support.bind(this),
};
}

Expand All @@ -67,7 +68,7 @@ class ServerlessPackerPlugin {
filePaths.map(async filePath => {
this.serverless.cli.log(`${filePath}: Building packer image`);

const args = _.concat('build', this.packageVarArgs(), `${PACKER_FILE_DIR}/${filePath}`);
const args = _.concat('build', '-machine-readable', this.packageVarArgs(), `${PACKER_FILE_DIR}/${filePath}`);

try {
await runCommand({
Expand All @@ -78,6 +79,7 @@ class ServerlessPackerPlugin {
raw: msg => {
this.serverless.cli.log(`${filePath}: ${msg}`);
},
fileStream: fs.createWriteStream(`${filePath}_build.log`),
},
});
} catch (err) {
Expand All @@ -89,6 +91,71 @@ class ServerlessPackerPlugin {
);
}

async addIMDSv2Support() {
this.serverless.cli.log('Adding IMDSv2 support to AMIs');
let filePaths;
if (this.options.files) {
// Parse files passed via CLI arg
filePaths = this.options.files.split(',');
} else {
// Look for files in default location
filePaths = await this.getPackerFiles();
}
this.serverless.cli.log(`Adding IMDSv2 support to: ${filePaths.join(', ')}`);
// Parse AMI IDs from packer build log
const amis = [];
filePaths.forEach(filePath => {
const logFile = fs.readFileSync(`${filePath}_build.log`, 'utf8');
const amiLineIndexStart = logFile.lastIndexOf('AMIs were created');
const amiLine = logFile.substring(amiLineIndexStart);
const amiRegex = 'ami-[0-9a-z]{17}';
const result = amiLine.match(amiRegex);
amis.push(result);
});

// Get AWS Profile name and region from settings
const customSettings = this.serverless.service.custom.settings;
if (customSettings.enableAmiSharing) {
customSettings.awsProfile = customSettings.devopsProfile;
}
const awsProfile = customSettings.awsProfile;
const awsRegion = customSettings.awsRegion;

// For each AMI, add IMDSv2 support
return Promise.all(
amis.map(async ami => {
this.serverless.cli.log(`${ami}: Adding IMDSv2 support`);
const args = _.concat(
'ec2',
'modify-image-attribute',
'--image-id',
ami,
'--imds-support',
'v2.0',
'--profile',
awsProfile,
'--region',
awsRegion,
);

try {
await runCommand({
command: 'aws',
args,
stdout: {
log: this.serverless.cli.consoleLog,
raw: msg => {
this.serverless.cli.log(`${ami}: ${msg}`);
},
},
});
} catch (err) {
throw new Error(`${ami}: Error running aws command: ${err}`);
}
}),
);
}

async getPackerFiles() {
return new Promise((resolve, reject) => {
fs.readdir(PACKER_FILE_DIR, (err, files) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ const chalk = require('chalk');
const spawn = require('cross-spawn');

const runCommand = ({ command, args, successCodes = [0], cwd, stdout }) => {
const child = spawn(command, args, { stdio: 'pipe', cwd });
const options = { stdio: 'pipe', cwd };
if (stdout.fileStream) options.stdout = stdout.fileStream;
const child = spawn(command, args, options);
stdout.log(`${chalk.bgGreen('>>')} ${command} ${args.join(' ')}`);
if (stdout.fileStream) child.stdout.pipe(stdout.fileStream);
return new Promise((resolve, reject) => {
// we are using _.once() because the error and exit events might be fired one after the other
// see https://nodejs.org/api/child_process.html#child_process_event_error
Expand Down

0 comments on commit 3432768

Please sign in to comment.