-
Notifications
You must be signed in to change notification settings - Fork 90
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
RFC 0693: Property injectors #699
base: main
Are you sure you want to change the base?
Conversation
text/0693-property-injection.md
Outdated
|
||
`IPropertyInjector` - An IPropertyInjector defines a way to inject additional properties that are not specified in the props. It is specific to one Construct and operates on that Construct’s properties. This will be called `Injector` for short. | ||
|
||
`propertyInjectors` - A collection of Injectors attached to App, Stage, or Stack. Any matching Construct created in this App, Stage, or Stack will have the Injector applied to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we also agreed on that the injectors can be also attached to any construct. It can be attached to any node in the scope tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have an example of that in the FAQ. The common way is to attach them to App, Stage, or Stack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please write something to clarify that here, it confuses me every time I read it. You can try verbiage like the following:
A collection of injectors attached to the construct tree. Injectors can be attached to any construct, but in practice we expect most of them will be attached to
App
,Stage
orStack
.
That acknowledges both the genericity of the proposed solution as well as the expected use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do. thanks
Pull request has been modified.
text/0693-property-injection.md
Outdated
@@ -0,0 +1,468 @@ | |||
# Blueprint via Property Injection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This document is proposing "blueprints" and "property injection" at the same time.
I think the reader would benefit from a small definition of both terms and how they relate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try to define that in line 7.
Blueprint is a way for orgs to enforce standards by setting default values to CDK Constructs. The Blueprint standards can be shared and applied to many development teams. This is done via injecting default property values at creation time.
What is a better way to communicate this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would phrase it as something like:
This document describes the mechanism of property injection, which is ...
This mechanism allows the implementation of blueprints, which are ...
The trick is now to define "blueprints" in a way that is substantially different enough from "applied property injectors" to add descriptive value.
I wonder if that's even possible, and if it's not just distracting. It might come down to "blueprints are a branded term for a particular library of property injectors"... which... fair enough, but is that worth describing in this doc?
text/0693-property-injection.md
Outdated
|
||
`IPropertyInjector` - An IPropertyInjector defines a way to inject additional properties that are not specified in the props. It is specific to one Construct and operates on that Construct’s properties. This will be called `Injector` for short. | ||
|
||
`propertyInjectors` - A collection of Injectors attached to App, Stage, or Stack. Any matching Construct created in this App, Stage, or Stack will have the Injector applied to it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please write something to clarify that here, it confuses me every time I read it. You can try verbiage like the following:
A collection of injectors attached to the construct tree. Injectors can be attached to any construct, but in practice we expect most of them will be attached to
App
,Stage
orStack
.
That acknowledges both the genericity of the proposed solution as well as the expected use cases.
* We will add Bucket.PROPERTY_INJECTION_ID to unique identify this Construct. | ||
This is a new Property that we will add to Bucket and other supported Constructs. | ||
* This TypeScript code will set blockPublicAccess to BlockPublicAccess.BLOCK_ALL and enforceSSL to true | ||
if these properties are not specified in originalProps. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if the properties are specified? It would be great to have a warning in case both the code and injector define a value for the property. Perhaps also the ability to explicitly suppress the warning.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is up to the implementor of the Injector. For our org, we allow the builder's values to stand and only provide defaults to properties they don't specify. In this code snippet, the returned props will keep all the props the builder specified.
It is possible to use Annotation to give a warning about some prop value the builder specified. We intend to do this to warn builders that certain prop values are not recommended by our org.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do keep in mind that the current design will not make it possible for the property injector to add warnings on the construct (because when the injector executes, the construct won't exist yet!), so the best it can do is add warnings on its parent scope.
* **Tracking Issue**: [#693](https://github.com/aws/aws-cdk-rfcs/issues/693) | ||
* **API Bar Raiser**: @rix0rrr | ||
|
||
`Property injection` is a new mechanism that makes it possible to control the properties that are used to instantiate a construct via an out-of-band mechanism. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some alignment story with tools like cdk-nag?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading through the link you provided, I have a basic understand of cdk-nag. I think cdk-nag and Property Injectors are both trying to prevent builders from creating AWS resources incorrectly. cdk-nag will warn the builders about non-compliant resource creation, but does not provide remediation. Property Injectors will create resources with the correct properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this, I would need to check every layer above a construct for possible injectors to understand why behaviour is different. On the other hand, I don't really get anything compared to just having a custom construct library, as injectors still require teams to actually apply them and then not to overwrite the defaults. And if I really need to make sure that e.g. buckets are not set to public, I could instead add an Asepct that modifies all buckets to ensure that they are not public.
So for me, I don't really understand yet what this achieves that would justify the added complexity, especially since it breaks locality of code changes.
Blueprints by themselves are not a compliance enforcement mechanism; | ||
instead they are a mechanism to make it easier for developers to hit compliance targets that are already being enforced via other means. | ||
|
||
**Why do we need Blueprints?** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do Property Injectors interact with Aspects? When should I use property injectors to modify resources and when aspects? Based on the RFC so far I don't get yet why I should use injectors at all instead of just modifying the resources via Aspects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The biggest difference between Aspect
and Property Injector
is that Aspect
visits the Construct after it has been created - after the constructor completes. Property Injector
runs as the first line in the constructor so we set all the default properties before the rest of the constructor code runs.
We want to create a L2 Construct with all the default values we want, instead of updating the Properties after the Construct has been created. Sometimes, it is not possible to update a Property. For example, serverAccessLogsBucket can only be specified in BucketProps. We cannot change it once aws_s3.Bucket has been created.
|
||
### Organization Level Standardization | ||
|
||
As an org with many dev teams, we can standardize how AWS Resources are created by providing dev teams with Injectors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the teams still need to actitvely use the injector, then what's the benefit compared to just giving them a "SecureBucket" class to build upon? In both cases, the org still needs to rely on the devs to actually use the injector/construct, but with a SecureBucket at least the code would be easier to debug (anyone wondering why the bucket isn't publicly accessible needs to look just at the bucket, not go through every single Stack/Stage/App layer above to verify whether an injector exists).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One disadvantage of subclassing is that it breaks other tools like cdk-nag
. cdk-nag
checks for Bucket, but not SecureBucket subclass. Since Property Injector
is native to Bucke, cdk-nag
can work with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another tradeoff to consider when writing your own SecureBucket is the maintenance burden that comes with it. You will constantly need to sync your package that contains SecureBucket with AWS-CDK. AWS-CDK is currently at 2.182.0 and there is usually a new minor version every week. My org currently uses a subclass solution and we are very familiar with this weekly sync'ing. This is why we are moving away from a subclass solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also want to quote
Finally, keep in mind that writing your own "L2+" constructs might prevent your developers from
taking advantage of AWS CDK packages such as [AWS Solutions Constructs]
(https://docs.aws.amazon.com/solutions/latest/constructs/welcome.html) or third-party constructs
from Construct Hub. These packages are typically built on standard AWS CDK constructs and
won't be able to use your wrapper constructs.
from this doc: https://docs.aws.amazon.com/cdk/v2/guide/best-practices.html
This is a request for comments about Set Default Values to Construct Properties using PropertyInjector. See #693 for
additional details.
APIs are signed off by @{rix0rrr}.
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache-2.0 license