-
Notifications
You must be signed in to change notification settings - Fork 4k
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: support for cross-account CodePipelines #1924
feat: support for cross-account CodePipelines #1924
Conversation
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.
A few comments following an initial pass.
packages/@aws-cdk/aws-cloudformation/test/test.pipeline-actions.ts
Outdated
Show resolved
Hide resolved
packages/@aws-cdk/cdk/lib/cloudformation/cross-account-region-token.ts
Outdated
Show resolved
Hide resolved
resource: 'project', | ||
resourceName: this.physicalName, | ||
})), this).toString(); | ||
this.projectName = new cdk.CrossAccountRegionPhysicalNameToken(resource.projectName, this).toString(); |
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 don't understand why this has to be a different class from CrossAccountRegionPhysicalArnToken
. Is the difference that the second one knows that obj.physicalName
exists, but the first one doesn't? Because that doesn't seem strong enough of a reason to make two classes to me, especially given that the second one seems like it could be written as:
new cdk.CrossEnvironmentIdentifier(resource.projectName, () => this.physicalName).toString();
…ve an encryption key. This is a prerequisite for having a nice cross-account experience (see aws#1924).
…ve an encryption key. This is a prerequisite for having a nice cross-account experience (see aws#1924).
35c00c0
to
9fc7006
Compare
b2ebde2
to
c440f86
Compare
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.
Initial partial pass. Let's do another iteration and I'll continue the review.
Thanks for the review @eladb ! One question: how do you see the migration to the 'new' way of specifying a physical name ( Also, should we do it for all L2s at the same time, or should we migrate gradually, module-by-module? |
Something I forgot to comment about: I think the physical name prop should be “bucketName” and not “physicalName”. The type denotes that it’s a physical name so there is no additional benefit in adding another prop. Which I believe answers your question: this is our last chance to “rip the bandaid”, and we should do it across the entire library through an awslint rule. |
(But I would still do it in a subsequent PR) |
I'm actually not a huge fan of the "Physical names" is a concept in our domain, it's present in the CDK docs, etc. I feel like calling the property that way has value (I think a name is much more important than the type, especially in dynamically-typed languages) - it reinforces that the concepts and code use a shared terminology. Just my two cents. If you feel strongly that it should remain EDIT: it also make it trivial to answer the question "Which property is the physical name?" for every resource (and a related one, which is: what resources don't have a physical name?). |
c440f86
to
85108d7
Compare
Implemented some (not all) of Elad's comments. |
|
||
let actionRole = this.crossAccountActionRoles.get(resourceStack); | ||
if (!actionRole) { | ||
actionRole = new iam.Role(resourceStack, this.node.id + 'ActionRole', { |
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.
Should this also be this.node.uniqueId
instead of just this.node.id
?
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.
probably.
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.
Hmmm... on second thought, these are per-resource Stack unique, and the Pipeline ID makes it per-Pipeline unique... maybe leave it as this.node.id
?
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 if there are two pipelines with the same id?
The latest batch of changes should be close to merge ready, the significant part that is missing are the name changes of the static factory methods of |
/** | ||
* The ARN of the resource when referenced from the same CloudFormation template. | ||
*/ | ||
readonly resourceSimpleArn: string; |
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.
why are these called "simple"?
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.
Those are the non-cross environments variants (so, those that result in Ref
and/or Fn::GetAtt
).
I'm open to having a better name for them.
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 think just arn
and name
are sufficient. These are the only ARNs and names in this Props...
* A physical name that will be automatically assigned at deploy time. | ||
* This is the default you don't specify a physical name. | ||
*/ | ||
public static deployTime(): PhysicalName { |
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 do have a feeling that since there will be cases where users won't have control over how underlying resources are configured, and those will be configured without cross: true
, then they would want to be able to override the default "auto" behavior. That's why I am proposing to merge deployTime
and deployTimeOrAssigned
into a single method with config. This will enable us to provide facilities for users to basically modify the default behavior of some scope:
PhysicalName.allowCrossEnvWithinThisScope(this); // this is "Construct"
new Bucket(this, 'MyBucket'); // implies `deploy-time-or-assigned`.
AWS resources are messy. Their intrinsic physical name has different names for different resources (usually either "name" or "ID"). I want to make sure that the prop that assigns this name is the sameas the attribute property that can be used to retrieve it, and there are sometimes many attributes (could be I feel strongly that we should use consistent terminology between the prop and the attribute and we've settled on a pretty strict convention for attribute names (always start with the type name, etc), so I think we should stay with As for discovery: we now have your beautiful nice type |
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.
Sorry for derailing the discussion further, but I just had a stroke of insight leading me to no longer agree to do fully automatic auto-naming. I think it's too risky. I forgot whether we already discussed this, and rejected the concerns?
Good news is, it would get rid of the token magic, simplifying the whole thing a lot.
* A physical name that will be automatically assigned at deploy time. | ||
* This is the default you don't specify a physical name. | ||
*/ | ||
public static deployTime(): PhysicalName { |
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.
FWIW, Aspects could totally cover the use case you're thinking of there, Elad.
This change adds support for expressing CodePipelines that are cross-account in the CDK.
There is a lot of things happening in this PR, as in order to support this functionality, changes were needed at the framework level. A summary:
1.
CrossEnvironmentToken
andResourceIdentifiers
I've added a new Token,
CrossEnvironmentToken
, that allows references across accounts and/or regions. I've also added a helper class,ResourceIdentifiers
, that encapsulates using the new Token.ResourceIdentifiers
are mean to be used inside our L2s. Both of these live in@aws-cdk/cdk
.2. Added the concept of a physical name
I've created a new class,
PhysicalName
, that encompasses our strategies for assigning physical names. I've added the option to pass a physical name when creating S3 Buckets, IAM Roles and CodeBuild Projects (if the API is deemed acceptable, we would need to make changes to other L2s as well of course).The "old" ways of passing a physical name (
bucketName
,roleName
, etc.) have been kept for now, but we might want to consider removing them in favor ofphysicalName
.3. Added facilities for automatically generating physical names
Added a new class,
PhysicalNameGenerator
, that creates physical names at synthesis time. Added it to theResource
class, so that particular resources can override the strategy (used for S3 Buckets, for example). As bothIResource
andResource
were previously empty, this uncovered a lot of incorrect inheritance hierarchies in our Constructs, where an interface extendedIResource
, but the implementation class extendedConstruct
, which now failed whenIResource
has members - fixed those as well.4. Changed some implicit sub resources to the new physical naming scheme
To facilitate cross-environment usage, the Bucket for a CodePipeline and a Role for CodeBuild Project are now created with
PhysicalName.deployTimeOrAssigned()
.5. Changes in the CodePipeline Construct
The CodePipeline Construct detects if a resource is from a different account, and automatically generates a bootstrap Role with the correct permissions if it is.
All in all, the changes allow for the following cross-environment customer experience with CodePipeline:
which is exactly the same as creating a non-cross account Pipeline.
Pull Request Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license.