Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(servicecatalog): Add Product Stack Asset Support #22143

Closed
wants to merge 4 commits into from

Conversation

wanjacki
Copy link
Contributor

@wanjacki wanjacki commented Sep 20, 2022

Currently Assets are not supported in Product Stacks. Service Catalog has an unique use case where assets need to be shared cross account and sharing the entire CDK asset bucket is not ideal. Users can either create their own ProductStackAssetBucket or have one automatically generated for them based on their account Id and region. By using S3 Deployments we able to copy the assets to that bucket and share it when a portfolio is shared in Service Catalog.

More details can be found here: #20690. Closes #20690


All Submissions:

Adding new Unconventional Dependencies:

  • This PR adds new unconventional dependencies following the process described here

New Features

  • Have you added the new feature to an integration test?
    • Did you use yarn integ to deploy the infrastructure and generate the snapshot (i.e. yarn integ without --dry-run)?

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


Co-authored-by: Theron Mansilla[imanolympic]

@gitpod-io
Copy link

gitpod-io bot commented Sep 20, 2022

@github-actions github-actions bot added the p2 label Sep 20, 2022
@aws-cdk-automation aws-cdk-automation requested a review from a team September 20, 2022 14:28
@wanjacki wanjacki force-pushed the asset_support branch 2 times, most recently from 4d764ea to 593cec0 Compare September 20, 2022 15:08
@padaszewski
Copy link

Hi,
Thanks for the great job.
I was comparing the new API with our implementation and I didn't found any way to incorporate the own ProductStackAssetBucket into the ProductStackHistory construct.
Do You plan to provide this option?

@wanjacki
Copy link
Contributor Author

@padaszewski That should automatically be supported.
ie. if you want to specify your own bucket

    const productStackHistory = new ProductStackHistory(this, 'ProductStackHistory', {
      productStack: new HelloServerlessProduct(this, 'HelloServerlessProduct', {
        assetBucket: myBucket,}),
      currentVersionName: 'v1',
      currentVersionLocked: true
      }
    )

@padaszewski
Copy link

@wanjacki
Ah right, this is a property of the ProductStack. After a quick read of the README I was convinced that the bucket is passed like this servicecatalog.CloudFormationTemplate.fromProductStack(productStack, bucket). My bad, sorry.

Copy link
Contributor

@kaizencc kaizencc left a comment

Choose a reason for hiding this comment

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

Hi @wanjacki! Given this a quick read through with some initial comments.

packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-servicecatalog/README.md Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-servicecatalog/lib/product.ts Outdated Show resolved Hide resolved
packages/@aws-cdk/aws-servicecatalog/lib/portfolio.ts Outdated Show resolved Hide resolved
}

/**
* Fetch the expected S3 location of an asset.
Copy link
Contributor

Choose a reason for hiding this comment

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

this is doing more than fetch right? adds an asset to this.assets

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated to be a bit more descriptive.


this.assets = [];

cdk.Aspects.of(this).add({
Copy link
Contributor

Choose a reason for hiding this comment

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

what is the reasoning behind using cdk.Aspects to run deploy assets? not questioning, just wondering.

Copy link
Contributor Author

@wanjacki wanjacki Sep 27, 2022

Choose a reason for hiding this comment

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

It can be done without Aspects I believe, but Aspects fits the use case and allows us to cleanly implement our use case as well as abstract the additional code to the new product-stack-asset-bucket construct rather than modifying and adding additional code to product-stack.

@github-actions github-actions bot added effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p1 and removed p2 labels Sep 26, 2022
@mergify mergify bot dismissed kaizencc’s stale review September 27, 2022 20:51

Pull request has been modified.

Copy link
Contributor

@corymhall corymhall left a comment

Choose a reason for hiding this comment

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

I have a couple of big concerns with this PR.

  1. We need an integration test that tests creating a product with assets and provisioning a
    product with assets.
  2. I'm not sure about how you are currently handling the asset buckets. Each individual product will
    get it's own asset bucket? What about having a single bucket that the user needs to create
    themselves? A bucket per product seems like it will lead to more work on the consumer side (if
    you want to provision product ABC then add a policy to your role with access to bucket ABC).


/**
* The S3 bucket containing product stack assets.
* @default - None
Copy link
Contributor

Choose a reason for hiding this comment

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

What does None mean? If this is not provided are assets not supported?

Copy link
Contributor Author

@wanjacki wanjacki Sep 29, 2022

Choose a reason for hiding this comment

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

This class is the result of binding a Artifact Template into a Product.
In the event that it is not binding to a Product Stack (URL or local asset template instead), there is no asset bucket and no asset support.
In the event that they are binding a Product Stack, if they are not using assets, then the asset bucket will not be generated and will be undefined and there will be no asset bucket.
In any other case there is an asset bucket.

I will update to None - no assets are used in this product as well.

/**
* Product stack asset bucket.
*
* @default - None
Copy link
Contributor

Choose a reason for hiding this comment

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

I would update the docstring to be more descriptive. As a user I want to know should I pass
something here or not? When would I want to provide my own bucket and what is the behavior if I
don't

/**
* The asset bucket of a product created via product stack.
* @atrribute
* @default - None
Copy link
Contributor

Choose a reason for hiding this comment

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

Something like None - no assets are used in this product

/**
* Name of s3 asset bucket deployed
*
* @default - None
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can be more descriptive here since you know what the generated name will be (or atleast
the format).

* A Service Catalog product stack asset bucket, which is similar in form to an Amazon S3 bucket.
* You can store multiple product stack assets and collectively deploy them to S3.
*/
export class ProductStackAssetBucket extends Construct {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should extends s3.Bucket.

Comment on lines 32 to 35
if (!this.assetBucket) {
const parentStack = (this.stack as ProductStack)._getParentStack();
this.assetBucket = new ProductStackAssetBucket(parentStack, `ProductStackAssetBucket${hashValues(this.stack.stackName)}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure how I feel about the way we are creating the asset bucket here. What if we just created
the asset bucket by default as part of the product stack?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you mean we create a ProductStackAssetBucket regardless of if the user is using an asset or not.
I don't that is a good idea since we would be creating resources that will not be needed (S3-deployment also deploys a lambda). Furthermore, a user could be unintentionally create a bunch of S3 Buckets (since it is one per product-stack) and fill up their S3 Bucket limit capacity.

}

(this.stack as ProductStack)._setAssetBucket(this.assetBucket._getBucket());
return this.assetBucket._addAsset(_asset);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is where we should handle the asset deployment, rather than in the bucket construct.

@@ -16,7 +25,17 @@ export class ProductStackSynthesizer extends cdk.StackSynthesizer {
}

public addFileAsset(_asset: cdk.FileAssetSource): cdk.FileAssetLocation {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
public addFileAsset(_asset: cdk.FileAssetSource): cdk.FileAssetLocation {
public addFileAsset(asset: cdk.FileAssetSource): cdk.FileAssetLocation {

protected addBucketPermissionsToSharedAccounts() {
if (this.sharedAccounts.length > 0) {
for (const bucket of this.assetBuckets) {
bucket.grantRead(new iam.CompositePrincipal(...this.sharedAccounts.map(account => new iam.AccountPrincipal(account))),
Copy link
Contributor

Choose a reason for hiding this comment

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

How are you granting access on the other side? The IAM role that gets from these buckets needs
access to be granted access to the bucket in its princial policy.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in my other comment, but there is not much more we can do. We made it as easy as possible but we don't have access to the accounts it is being shared with, it is up to the Admin to configure these spoke accounts.

@@ -1,8 +1,9 @@
import * as path from 'path';
Copy link
Contributor

Choose a reason for hiding this comment

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

This integration test only tests half of the scenario. It confirms that we can publish to the
bucket, but how do we know that we can then deploy one of these products?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The same can be said about any of the other existing integration test. There exist validation in Service Catalog to validate the template before it can be created but it can't check everything. We can't provision the product in CDK code and even then trying to provision it would probably fall in the scope of a provision-product construct.
I'm not sure if is the products job to check if a Product is provisionable, Service Catalog allows us to create a Product regardless of if its deployable or not. We also do our best in unit test to check the generated template is as expected.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is different though than existing functionality. In this PR we are adding functionality outside of service catalog. This PR is completely useless if the consumer cannot access the assets in the bucket and we have no test to assert that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey Cory, I refactored ProductStackAssetBucket to extend S3.Bucket as suggested as well as implemented the other comments.
I also added additional unit test to check Bucket Name and Bucket Policy Permissions are correct in template when shared.
If we can catch that the bucket is correct and the permissions are correct then the product should be deployable and the bucket should be acessable. If this is still not enough, please advise what what other test we can add (I don't think provisioning it is an option).

@wanjacki
Copy link
Contributor Author

I have a couple of big concerns with this PR.

1. We need an integration test that tests creating a product with assets _and_ provisioning a
   product with assets.

2. I'm not sure about how you are currently handling the asset buckets. Each individual product will
   get it's own asset bucket? What about having a single bucket that the user needs to create
   themselves? A bucket per product seems like it will lead to more work on the consumer side (if
   you want to provision product ABC then add a policy to your role with access to bucket ABC).
  1. We can't provision a product directly in CDK and there has been no precedent for having to provision a product in any of the other integration test.
  2. Yes we are limited to one asset bucket Product Stack if we are generating for the user. It is not trivial to implement it on a portfolio level and the asset itself are tied to Products not Portfolios. As a workaround we allow users to create their own asset bucket, this asset bucket can be used for multiple Product Stacks and bypasses this restriction. We grant users that the admin shares their portfolio/product with permissions to read the Bucket. Any further policy that might be needed would have to be setup and managed by the Admin (Hub) to Shared Accounts (Spoke) anyways.

@mergify mergify bot dismissed corymhall’s stale review September 29, 2022 20:44

Pull request has been modified.

@corymhall
Copy link
Contributor

@wanjacki I would recommend going through the RFC process for this feature. There are a lot of design considerations that we are not yet agreed on. The biggest thing for me is that we have to consider the entire experience (publishing & consuming).

Copy link
Contributor

@corymhall corymhall left a comment

Choose a reason for hiding this comment

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

Putting back in request changes.

…nal unit test for bucket name and permission sharing.
@mergify mergify bot dismissed corymhall’s stale review September 30, 2022 16:51

Pull request has been modified.

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildv2Project1C6BFA3F-wQm2hXv2jqQv
  • Commit ID: 0b84503
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@TheRealAmazonKendra
Copy link
Contributor

@wanjacki I would recommend going through the RFC process for this feature. There are a lot of design considerations that we are not yet agreed on. The biggest thing for me is that we have to consider the entire experience (publishing & consuming).

+1 on this comment. I'm going to convert this into a draft until we have an approved RFC for this.

@TheRealAmazonKendra TheRealAmazonKendra marked this pull request as draft October 2, 2022 05:52
Copy link
Contributor

@TheRealAmazonKendra TheRealAmazonKendra left a comment

Choose a reason for hiding this comment

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

Putting in changes requested to accurately reflect status.

@aws-cdk-automation
Copy link
Collaborator

This PR has been in the CHANGES REQUESTED state for 3 weeks, and looks abandoned. To keep this PR from being closed, please continue work on it. If not, it will automatically be closed in a week.

@aws-cdk-automation
Copy link
Collaborator

This PR has been deemed to be abandoned, and will be automatically closed. Please create a new PR for these changes if you think this decision has been made in error.

@aws-cdk-automation aws-cdk-automation added the closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. label Oct 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-for-staleness This issue was automatically closed because it hadn't received any attention in a while. effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

(servicecatalog): ProductStack does not support Assets
6 participants