Skip to content

Conversation

pahud
Copy link
Contributor

@pahud pahud commented Aug 29, 2025

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.

Additionally, we wanted to provide a better developer experience than the existing LaunchTemplate implementation, where users must specify at least one property to opt into metadata options.

Description of changes

1. Added new metadataOptions property to Instance construct

  • New InstanceMetadataOptions interface with all metadata configuration options
  • Follows the same property structure as LaunchTemplate for consistency

2. Improved developer experience with clean opt-in

  • metadataOptions: undefined (omitted) → Uses legacy EC2 behavior
  • metadataOptions: {} → Clean way to opt into CloudFormation defaults for all properties
  • metadataOptions: { httpEndpoint: false } → Uses CloudFormation defaults for unspecified properties

3. Added comprehensive @default documentation tags

Added evidence-based @default tags to all properties in the InstanceMetadataOptions interface based on official AWS CloudFormation documentation:

Properties updated:

  • httpEndpoint: @default true - CloudFormation default is "enabled"
  • httpProtocolIpv6: @default false - CloudFormation default is "disabled"
  • httpPutResponseHopLimit: @default - No default specified in CloudFormation docs
  • httpTokens: @default - Complex default based on AMI and account settings
  • instanceMetadataTags: @default false - CloudFormation default is "disabled"

Key improvements:

  1. Better developer experience: Users can write metadataOptions: {} to cleanly opt into modern metadata options with CloudFormation defaults.

  2. No breaking changes: This is a new property on Instance construct, so no existing code is affected.

  3. Consistent with LaunchTemplate: Uses the same property names and types for familiarity.

  4. Conflict prevention: Validates that metadataOptions and requireImdsv2 are not used together to prevent configuration conflicts:

    • requireImdsv2: true creates a LaunchTemplate with httpTokens: 'required'
    • metadataOptions sets metadata options directly on the Instance
    • Using both would create conflicting CloudFormation configurations
    • Solution: Throws a clear validation error when both are specified
  5. Clear documentation: All @default tags clarify "(only applies when metadataOptions is specified)" and are backed by CloudFormation documentation.

Describe any new or updated permissions being added

N/A - No IAM permissions changes. This adds a new optional property that controls CloudFormation template generation but doesn't require additional permissions.

Description of how you validated changes

  1. Documentation verification: Cross-referenced all default values against official AWS CloudFormation documentation:

  2. Code analysis: Implemented clean opt-in logic in renderMetadataOptions():

    • Before: Would need to specify a property to trigger metadata options
    • After: metadataOptions: {} cleanly opts into CloudFormation defaults
  3. Breaking change analysis: Confirmed this is safe because metadataOptions is a new property on Instance construct - no existing code could be affected.

  4. Conflict validation: Added validation in renderMetadataOptions() to prevent using requireImdsv2 and metadataOptions together:

    if (props.requireImdsv2) {
      throw new ValidationError('Cannot use both requireImdsv2 and metadataOptions. Use requireImdsv2 for simple IMDSv2 enforcement or metadataOptions for advanced configuration, but not both.', this);
    }

Updated Behavior:

  • requireImdsv2: undefined, metadataOptions: undefined → Legacy EC2 behavior ✅
  • requireImdsv2: true, metadataOptions: undefined → Uses LaunchTemplate with IMDSv2 required ✅
  • requireImdsv2: undefined, metadataOptions: {} → Uses CloudFormation defaults ✅
  • requireImdsv2: true, metadataOptions: {} → Throws validation error ✅

Why this approach is best:

  • Clear error message - Users understand they can't use both
  • No silent conflicts - No unexpected behavior from overlapping configurations
  • Clear choice - Use requireImdsv2 for simple cases, metadataOptions for advanced cases
  • Future-proof - If AWS changes how LaunchTemplate + Instance metadata options interact, we won't have silent bugs
  1. TypeScript compilation: Verified all changes compile without errors and maintain existing type safety.

  2. Validation testing: Confirmed the validation error is thrown when both requireImdsv2: true and metadataOptions are specified together.

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.

@aws-cdk-automation aws-cdk-automation requested a review from a team August 29, 2025 20:30
@github-actions github-actions bot added effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2 labels Aug 29, 2025
@mergify mergify bot added the contribution/core This is a PR that came from AWS. label Aug 29, 2025
Copy link
Collaborator

@aws-cdk-automation aws-cdk-automation left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This review is outdated)

@pahud pahud changed the title feat(aws-ec2): expose EC2 instance MetadataOptions feat(ec2): expose EC2 instance MetadataOptions Aug 29, 2025
@pahud pahud marked this pull request as ready for review August 29, 2025 20:37
@aws-cdk-automation aws-cdk-automation dismissed their stale review August 29, 2025 20:37

✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.

@alvazjor alvazjor self-assigned this Sep 1, 2025
metadataOptions.httpTokens === undefined &&
metadataOptions.instanceMetadataTags === undefined
)) {
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to do this, then we need to remove the documentation that states the default values for the properties in InstanceMetadataOptions, as we are not respecting that here. In my opinion, if you define the metadataOptions, then the properties that have a default value should use that (even if they are undefined by the user)

*
* @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-instance-metadataoptions.html#cfn-ec2-instance-metadataoptions-httpputresponsehoplimit
*
* @default 1
Copy link
Contributor

@alvazjor alvazjor Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we defaulting to 1? CFN does not provides any default, so I wonder where this value is coming from

… in tests

- Updated import statement to use HttpTokens instead of LaunchTemplateHttpTokens
- Replaced all usage references in test cases
- Aligns with deprecation notice in favor of HttpTokens enum
- Fixed trailing spaces in instance.ts
@pahud pahud marked this pull request as draft September 2, 2025 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution/core This is a PR that came from AWS. effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants