Commit 4056e14
authored
feat(ec2): expose EC2 instance MetadataOptions (#35369)
### Issue # (if applicable)
Closes #35357.
### Reason for this change
The EC2 Instance construct lacked support for metadata options configuration, while the LaunchTemplate construct already had this capability. Users needed a way to configure instance metadata options (like IMDSv2 requirements, hop limits, etc.) directly on Instance constructs without resorting to escape hatches.
### Description of changes
Added metadata options properties to Instance construct with flat properties matching LaunchTemplate API design for consistency across the EC2 module.
**Key changes:**
1. **Instance construct enhancements** - Added individual metadata option properties directly to InstanceProps:
- `httpEndpoint?: boolean` - Enables or disables the HTTP metadata endpoint
- `httpProtocolIpv6?: boolean` - Enables or disables the IPv6 endpoint for IMDS
- `httpPutResponseHopLimit?: number` - Sets the hop limit for metadata requests (1-64)
- `httpTokens?: HttpTokens` - Controls IMDSv2 requirement (OPTIONAL or REQUIRED)
- `instanceMetadataTags?: boolean` - Enables or disables instance tag access from metadata API
2. **Separate enum for cleaner API** - Defined `HttpTokens` enum in instance.ts:
- Instance uses `HttpTokens` enum (cleaner API for new construct)
- LaunchTemplate keeps `LaunchTemplateHttpTokens` enum (backward compatible, no JSII breaking change)
- Both enums have identical members (OPTIONAL, REQUIRED) for consistency
3. **Validation and rendering** - Added validation to prevent conflicting use of metadata options with `requireImdsv2` and implemented smart rendering that only includes MetadataOptions when explicitly specified
4. **Testing** - Added 22 comprehensive unit tests covering all metadata options scenarios
**Before (using escape hatch):**
```typescript
const instance = new ec2.Instance(this, 'Instance', {
vpc,
instanceType,
machineImage,
});
const cfnInstance = instance.node.defaultChild as ec2.CfnInstance;
cfnInstance.addPropertyOverride('MetadataOptions', {
HttpTokens: 'required',
HttpPutResponseHopLimit: 2,
});
```
**After (idiomatic L2 API):**
```typescript
const instance = new ec2.Instance(this, 'Instance', {
vpc,
instanceType,
machineImage,
httpTokens: HttpTokens.REQUIRED,
httpPutResponseHopLimit: 2,
instanceMetadataTags: true,
});
```
**CloudFormation impact:**
- When metadata options are specified, generates MetadataOptions object with only the specified properties
- When not specified, CloudFormation template remains unchanged (backward compatible)
- No breaking changes to existing behavior
### Accurate CloudFormation defaults
All properties include evidence-based `@default` tags based on official AWS CloudFormation documentation:
- `httpEndpoint`: @default true - CloudFormation default is "enabled"
- `httpProtocolIpv6`: @default false - CloudFormation default is "disabled"
- `httpPutResponseHopLimit`: @default - No default specified in CloudFormation
- `httpTokens`: @default - Conditional default based on AMI and account settings
- `instanceMetadataTags`: @default false - CloudFormation default is "disabled"
### Separate enum approach
Instance defines its own `HttpTokens` enum with identical members:
```typescript
export enum HttpTokens {
OPTIONAL = 'optional',
REQUIRED = 'required',
}
```
This provides a cleaner API for Instance users while maintaining full backward compatibility:
- Instance API uses `HttpTokens` enum (cleaner for users)
- LaunchTemplate API uses `LaunchTemplateHttpTokens` enum (no JSII breaking change)
- Both enums have identical members for consistency
- Follows conventional CDK patterns (similar to ELBv2 shared enums)
### Description of how you validated changes
- **Unit tests**: Added 22 comprehensive tests covering:
- All metadata options with various values
- Boolean to enabled/disabled string mapping
- Hop limit validation (1-64 range)
- Partial configuration (only specified properties rendered)
- Conflict detection with requireImdsv2
- **Build verification**: TypeScript compilation, linting, and JSII build all pass successfully
- **Integration tests**: Updated integ.instance-metadata-options.ts to use the new flat API
- **CloudFormation validation**: Unit tests verify correct template generation with proper property structure
- **API consistency**: Verified the API matches LaunchTemplate's flat property design
- **Backward compatibility**: Verified LaunchTemplateHttpTokens alias works with existing code
### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)
----
*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*1 parent d284733 commit 4056e14
File tree
15 files changed
+2663
-7
lines changed- packages
- @aws-cdk-testing/framework-integ/test/aws-ec2/test
- integ.instance-metadata-options.js.snapshot
- asset.a1acfc2b5f4f6b183fd2bb9863f486bc5edef6a357b355a070d9a0e502df418c
- aws-cdk-lib/aws-ec2
- lib
- test
15 files changed
+2663
-7
lines changedSome generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 34 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments