-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(ec2): add aspect to require imdsv2 (#16051)
Partially fixes: #5137 Related PR: #16052 **Note:** This PR and the above related PR have common code that has been duplicated across these two PRs because I decided it made more sense for these Aspects to be in the same package with the constructs they work with. However, it means I had to duplicate some of the base class code across the two PRs. Looking for an opinion on what's better here: - Should we keep it as is (2 PRs) so these Aspects are cleanly separated? or, - Does it make sense to either combine them in some way (e.g. a new package `@aws-cdk/aspects`) or have one reference the other (maybe the AutoScalingGroup aspect can reference the code in this PR since it already depends on this package). ### Changes Adds an aspect that can enable/disable IMDSv1 on Instances and Launch Templates. ### Testing Added unit tests ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information
Showing
9 changed files
with
457 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './require-imdsv2-aspect'; |
150 changes: 150 additions & 0 deletions
150
packages/@aws-cdk/aws-ec2/lib/aspects/require-imdsv2-aspect.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
import * as cdk from '@aws-cdk/core'; | ||
import { CfnLaunchTemplate } from '../ec2.generated'; | ||
import { Instance } from '../instance'; | ||
import { LaunchTemplate } from '../launch-template'; | ||
|
||
/** | ||
* Properties for `RequireImdsv2Aspect`. | ||
*/ | ||
interface RequireImdsv2AspectProps { | ||
/** | ||
* Whether warning annotations from this Aspect should be suppressed or not. | ||
* | ||
* @default - false | ||
*/ | ||
readonly suppressWarnings?: boolean; | ||
} | ||
|
||
/** | ||
* Base class for Aspect that makes IMDSv2 required. | ||
*/ | ||
abstract class RequireImdsv2Aspect implements cdk.IAspect { | ||
protected readonly suppressWarnings: boolean; | ||
|
||
constructor(props?: RequireImdsv2AspectProps) { | ||
this.suppressWarnings = props?.suppressWarnings ?? false; | ||
} | ||
|
||
abstract visit(node: cdk.IConstruct): void; | ||
|
||
/** | ||
* Adds a warning annotation to a node, unless `suppressWarnings` is true. | ||
* | ||
* @param node The scope to add the warning to. | ||
* @param message The warning message. | ||
*/ | ||
protected warn(node: cdk.IConstruct, message: string) { | ||
if (this.suppressWarnings !== true) { | ||
cdk.Annotations.of(node).addWarning(`${RequireImdsv2Aspect.name} failed on node ${node.node.id}: ${message}`); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Properties for `InstanceRequireImdsv2Aspect`. | ||
*/ | ||
export interface InstanceRequireImdsv2AspectProps extends RequireImdsv2AspectProps { | ||
/** | ||
* Whether warnings that would be raised when an Instance is associated with an existing Launch Template | ||
* should be suppressed or not. | ||
* | ||
* You can set this to `true` if `LaunchTemplateImdsAspect` is being used alongside this Aspect to | ||
* suppress false-positive warnings because any Launch Templates associated with Instances will still be covered. | ||
* | ||
* @default - false | ||
*/ | ||
readonly suppressLaunchTemplateWarning?: boolean; | ||
} | ||
|
||
/** | ||
* Aspect that applies IMDS configuration on EC2 Instance constructs. | ||
* | ||
* This aspect configures IMDS on an EC2 instance by creating a Launch Template with the | ||
* IMDS configuration and associating that Launch Template with the instance. If an Instance | ||
* is already associated with a Launch Template, a warning will (optionally) be added to the | ||
* construct node and it will be skipped. | ||
* | ||
* To cover Instances already associated with Launch Templates, use `LaunchTemplateImdsAspect`. | ||
*/ | ||
export class InstanceRequireImdsv2Aspect extends RequireImdsv2Aspect { | ||
private readonly suppressLaunchTemplateWarning: boolean; | ||
|
||
constructor(props?: InstanceRequireImdsv2AspectProps) { | ||
super(props); | ||
this.suppressLaunchTemplateWarning = props?.suppressLaunchTemplateWarning ?? false; | ||
} | ||
|
||
visit(node: cdk.IConstruct): void { | ||
if (!(node instanceof Instance)) { | ||
return; | ||
} | ||
if (node.instance.launchTemplate !== undefined) { | ||
this.warn(node, 'Cannot toggle IMDSv1 because this Instance is associated with an existing Launch Template.'); | ||
return; | ||
} | ||
|
||
const name = `${node.node.id}LaunchTemplate`; | ||
const launchTemplate = new CfnLaunchTemplate(node, 'LaunchTemplate', { | ||
launchTemplateData: { | ||
metadataOptions: { | ||
httpTokens: 'required', | ||
}, | ||
}, | ||
launchTemplateName: name, | ||
}); | ||
node.instance.launchTemplate = { | ||
launchTemplateName: name, | ||
version: launchTemplate.getAtt('LatestVersionNumber').toString(), | ||
}; | ||
} | ||
|
||
protected warn(node: cdk.IConstruct, message: string) { | ||
if (this.suppressLaunchTemplateWarning !== true) { | ||
super.warn(node, message); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Properties for `LaunchTemplateRequireImdsv2Aspect`. | ||
*/ | ||
export interface LaunchTemplateRequireImdsv2AspectProps extends RequireImdsv2AspectProps {} | ||
|
||
/** | ||
* Aspect that applies IMDS configuration on EC2 Launch Template constructs. | ||
* | ||
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-launchtemplate-launchtemplatedata-metadataoptions.html | ||
*/ | ||
export class LaunchTemplateRequireImdsv2Aspect extends RequireImdsv2Aspect { | ||
constructor(props?: LaunchTemplateRequireImdsv2AspectProps) { | ||
super(props); | ||
} | ||
|
||
visit(node: cdk.IConstruct): void { | ||
if (!(node instanceof LaunchTemplate)) { | ||
return; | ||
} | ||
|
||
const launchTemplate = node.node.tryFindChild('Resource') as CfnLaunchTemplate; | ||
const data = launchTemplate.launchTemplateData; | ||
if (cdk.isResolvableObject(data)) { | ||
this.warn(node, 'LaunchTemplateData is a CDK token.'); | ||
return; | ||
} | ||
|
||
const metadataOptions = (data as CfnLaunchTemplate.LaunchTemplateDataProperty).metadataOptions; | ||
if (cdk.isResolvableObject(metadataOptions)) { | ||
this.warn(node, 'LaunchTemplateData.MetadataOptions is a CDK token.'); | ||
return; | ||
} | ||
|
||
const newData: CfnLaunchTemplate.LaunchTemplateDataProperty = { | ||
...data, | ||
metadataOptions: { | ||
...metadataOptions, | ||
httpTokens: 'required', | ||
}, | ||
}; | ||
launchTemplate.launchTemplateData = newData; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.