Skip to content

Conversation

@tarunb12
Copy link
Contributor

Issue

aws/aws-cdk-rfcs#789

Reason for this change

This change adds a new alpha module for EC2 Image Builder L2 Constructs (@aws-cdk/aws-imagebuilder-alpha), as outlined in aws/aws-cdk-rfcs#789. This PR specifically implements the Component construct.

Description of changes

This change implements the Component construct, which is a higher-level construct of CfnComponent.

Example

const component = new imagebuilder.Component(this, 'Component', {
  componentName: 'build-and-test-component',
  componentVersion: '1.0.0',
  description: 'A build and test component',
  changeDescription: 'Initial version',
  // Encrypt component data with a KMS key
  kmsKey: kms.Key.fromKeyArn(
    this,
    'ComponentKey',
    this.formatArn({ service: 'kms', resource: 'key', resourceName: '1234abcd-12ab-34cd-56ef-1234567890ab' })
  ),
  platform: imagebuilder.Platform.LINUX,
  // Include the OS versions this component supports
  supportedOsVersions: [
    imagebuilder.OSVersion.AMAZON_LINUX,
    imagebuilder.OSVersion.RHEL_10,
    imagebuilder.OSVersion.SLES_15,
    imagebuilder.OSVersion.UBUNTU
  ],
  // Hello world component data
  data: imagebuilder.ComponentData.fromJsonObject({
    name: 'build-and-test-component',
    schemaVersion: imagebuilder.ComponentSchemaVersion.V1_0,
    phases: [
      {
        name: imagebuilder.ComponentPhaseName.BUILD,
        steps: [
          {
            action: imagebuilder.ComponentAction.EXECUTE_BASH,
            name: 'hello-world-build',
            inputs: {
              commands: ['echo "Hello build!"']
            }
          }
        ]
      },
      {
        name: imagebuilder.ComponentPhaseName.VALIDATE,
        steps: [
          {
            action: imagebuilder.ComponentAction.EXECUTE_BASH,
            name: 'hello-world-validate',
            inputs: {
              commands: ['echo "Hello validate!"']
            }
          }
        ]
      },
      {
        name: imagebuilder.ComponentPhaseName.TEST,
        steps: [
          {
            action: imagebuilder.ComponentAction.EXECUTE_BASH,
            name: 'hello-world-test',
            inputs: {
              commands: ['echo "Hello test!"']
            }
          }
        ]
      }
    ]
  })
});

Describe any new or updated permissions being added

N/A - new L2 construct in alpha module

Description of how you validated changes

Validated with unit tests and integration tests. Manually verified generated CFN templates as well.

Checklist


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

@github-actions github-actions bot added the beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK label Nov 11, 2025
@aws-cdk-automation aws-cdk-automation requested a review from a team November 11, 2025 08:18
@github-actions github-actions bot added the p2 label Nov 11, 2025
@aws-cdk-automation aws-cdk-automation added the pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes. label Nov 11, 2025
@tarunb12 tarunb12 force-pushed the imagebuilder-component branch from 2b1ee8a to b9d17a0 Compare November 11, 2025 09:23
@tarunb12 tarunb12 marked this pull request as ready for review November 11, 2025 09:30
@ozelalisen ozelalisen self-assigned this Nov 11, 2025
Copy link
Member

@ozelalisen ozelalisen left a comment

Choose a reason for hiding this comment

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

Left some comments as first part of the review, I am not fully completed

changeDescription: props.changeDescription,
description: props.description,
platform: props.platform,
kmsKeyId: props.kmsKey?.keyArn,
Copy link
Member

Choose a reason for hiding this comment

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

I do not see any configuration for kmsKey, should we not configure permissions for grantEncryptDecrypt for the key to be able to use it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call. I can add a method.

Copy link
Member

Choose a reason for hiding this comment

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

Also please add an integ test regarding this, since this is only way we can test it

Copy link
Contributor Author

@tarunb12 tarunb12 Nov 14, 2025

Choose a reason for hiding this comment

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

Ah i think i misunderstood. So, IB APIs are able to use the key so long as the caller (deployer of the CFN stack or the role associated with the stack) have permissions to do so. The only other principal that would need access is the instance profile role in the Infrastructure Configuration. We can grant the role permissions on the key automatically if you suggest (whenever we create an image or pipeline in the Image/ImagePipeline construct), or just add a grantDecrypt method on the component.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regarding integ test - the key is actually only used during image builds. Given the construct does not exist yet for Image/ImagePipeline, we probably cannot test that the key permission grant works in an image build until we have those constructs

Copy link
Member

Choose a reason for hiding this comment

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

Yes, that makes sense to add grantDecrypt method on constructor when key exists.

Sounds good, we can add integ tests when those constructs created

Copy link
Member

Choose a reason for hiding this comment

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

I think we should go with the first approach where you grant permissions on the role within Image/Image Pipeline, not with exposing grantDecrypt on this interface, as it has basically no usage rather than exposing a public method, that kmsKey already does. Let's remove this grantMethod in this class

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah got it - I had misunderstood. we can do that then

Copy link
Member

@ozelalisen ozelalisen left a comment

Choose a reason for hiding this comment

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

Publishing second round of comments

changeDescription: props.changeDescription,
description: props.description,
platform: props.platform,
kmsKeyId: props.kmsKey?.keyArn,
Copy link
Member

Choose a reason for hiding this comment

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

Also please add an integ test regarding this, since this is only way we can test it

@ozelalisen ozelalisen changed the title feat(imagebuilder): add support for EC2 Image Builder L2 Constructs - Component feat(imagebuilder-alpha): add support for Component Construct Nov 13, 2025
Comment on lines 938 to 1068
const [componentNameFromArn, componentVersionFromArn] = (() => {
if (cdk.Token.isUnresolved(componentNameVersion)) {
const componentNameVersionSplit = cdk.Fn.split('/', componentNameVersion);
return [cdk.Fn.select(0, componentNameVersionSplit), cdk.Fn.select(1, componentNameVersionSplit)];
}

const componentNameVersionSplit = componentNameVersion.split('/');
return [componentNameVersionSplit[0], componentNameVersionSplit[1]];
})();

return [componentNameFromArn, componentVersionFromArn];
Copy link
Member

Choose a reason for hiding this comment

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

This overcomplicates the token validation with redundant checking. Fn.split and Fn.select already handle tokens internally. So you could basically simplify this as:

const componentNameVersionSplit = componentNameVersion.split('/');
return [componentNameVersionSplit[0], componentNameVersionSplit[1]];

Copy link
Member

Choose a reason for hiding this comment

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

Sorry about this, I recommended wrong method, this should be with FN functions since they can be tokens:

const componentNameVersionSplit = cdk.Fn.split('/', componentNameVersion);
    return [
      cdk.Fn.select(0, componentNameVersionSplit),
      cdk.Fn.select(1, componentNameVersionSplit),
    ];

Copy link
Member

Choose a reason for hiding this comment

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

What I mean here is that you do not need that second split on implementation, as Fn.split checks internally if componentNameVersion is token, so you do not need to provide second part where you use native typescript split function, using only Fn.select and Fn.split is sufficient

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see - didn't know Fn worked like that! Updated

@ozelalisen
Copy link
Member

Just reminder for next PRs that title should include alpha suffix to be appeared in the CHANGELOG correctly

@tarunb12 tarunb12 force-pushed the imagebuilder-component branch from b9d17a0 to 5667d1a Compare November 14, 2025 09:46
@mergify mergify bot dismissed ozelalisen’s stale review November 14, 2025 09:46

Pull request has been modified.

Comment on lines 938 to 1068
const [componentNameFromArn, componentVersionFromArn] = (() => {
if (cdk.Token.isUnresolved(componentNameVersion)) {
const componentNameVersionSplit = cdk.Fn.split('/', componentNameVersion);
return [cdk.Fn.select(0, componentNameVersionSplit), cdk.Fn.select(1, componentNameVersionSplit)];
}

const componentNameVersionSplit = componentNameVersion.split('/');
return [componentNameVersionSplit[0], componentNameVersionSplit[1]];
})();

return [componentNameFromArn, componentVersionFromArn];
Copy link
Member

Choose a reason for hiding this comment

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

Sorry about this, I recommended wrong method, this should be with FN functions since they can be tokens:

const componentNameVersionSplit = cdk.Fn.split('/', componentNameVersion);
    return [
      cdk.Fn.select(0, componentNameVersionSplit),
      cdk.Fn.select(1, componentNameVersionSplit),
    ];

@mergify mergify bot dismissed ozelalisen’s stale review November 14, 2025 16:05

Pull request has been modified.

@tarunb12 tarunb12 force-pushed the imagebuilder-component branch from 33fb075 to 0d7a7d4 Compare November 14, 2025 19:01
@aws-cdk-automation aws-cdk-automation removed the pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes. label Nov 14, 2025
@tarunb12 tarunb12 force-pushed the imagebuilder-component branch from c913c97 to ac32fa8 Compare November 14, 2025 22:48
@aws-cdk-automation aws-cdk-automation added the pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes. label Nov 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK p2 pr/needs-further-review PR requires additional review from our team specialists due to the scope or complexity of changes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants