@@ -5,7 +5,7 @@ import ecr = require('@aws-cdk/aws-ecr');
5
5
import events = require( '@aws-cdk/aws-events' ) ;
6
6
import iam = require( '@aws-cdk/aws-iam' ) ;
7
7
import kms = require( '@aws-cdk/aws-kms' ) ;
8
- import { Aws , Construct , IResource , Lazy , PhysicalName , Resource , ResourceIdentifiers , Stack } from '@aws-cdk/cdk' ;
8
+ import { Aws , CfnResource , Construct , IResource , Lazy , PhysicalName , Resource , ResourceIdentifiers , Stack } from '@aws-cdk/cdk' ;
9
9
import { IArtifacts } from './artifacts' ;
10
10
import { BuildSpec } from './build-spec' ;
11
11
import { Cache } from './cache' ;
@@ -699,6 +699,8 @@ export class Project extends ProjectBase {
699
699
vpcConfig : this . configureVpc ( props ) ,
700
700
} ) ;
701
701
702
+ this . addVpcRequiredPermissions ( props , resource ) ;
703
+
702
704
const resourceIdentifiers = new ResourceIdentifiers ( this , {
703
705
arn : resource . attrArn ,
704
706
name : resource . refAsString ,
@@ -718,20 +720,6 @@ export class Project extends ProjectBase {
718
720
}
719
721
}
720
722
721
- /**
722
- * Add a permission only if there's a policy attached.
723
- * @param statement The permissions statement to add
724
- */
725
- public addToRoleInlinePolicy ( statement : iam . PolicyStatement ) {
726
- if ( this . role ) {
727
- const policy = new iam . Policy ( this , 'PolicyDocument' , {
728
- policyName : 'CodeBuildEC2Policy' ,
729
- statements : [ statement ]
730
- } ) ;
731
- this . role . attachInlinePolicy ( policy ) ;
732
- }
733
- }
734
-
735
723
/**
736
724
* Adds a secondary source to the Project.
737
725
*
@@ -869,31 +857,55 @@ export class Project extends ProjectBase {
869
857
}
870
858
this . _connections = new ec2 . Connections ( { securityGroups } ) ;
871
859
872
- this . addToRoleInlinePolicy ( new iam . PolicyStatement ( {
873
- resources : [ '*' ] ,
874
- actions : [
875
- 'ec2:CreateNetworkInterface' , 'ec2:DescribeNetworkInterfaces' ,
876
- 'ec2:DeleteNetworkInterface' , 'ec2:DescribeSubnets' ,
877
- 'ec2:DescribeSecurityGroups' , 'ec2:DescribeDhcpOptions' ,
878
- 'ec2:DescribeVpcs' ]
879
- } ) ) ;
880
- this . addToRolePolicy ( new iam . PolicyStatement ( {
860
+ return {
861
+ vpcId : props . vpc . vpcId ,
862
+ subnets : props . vpc . selectSubnets ( props . subnetSelection ) . subnetIds ,
863
+ securityGroupIds : this . connections . securityGroups . map ( s => s . securityGroupId )
864
+ } ;
865
+ }
866
+
867
+ private addVpcRequiredPermissions ( props : ProjectProps , project : CfnProject ) : void {
868
+ if ( ! props . vpc || ! this . role ) {
869
+ return ;
870
+ }
871
+
872
+ this . role . addToPolicy ( new iam . PolicyStatement ( {
881
873
resources : [ `arn:aws:ec2:${ Aws . region } :${ Aws . accountId } :network-interface/*` ] ,
882
874
actions : [ 'ec2:CreateNetworkInterfacePermission' ] ,
883
875
conditions : {
884
876
StringEquals : {
885
- " ec2:Subnet" : props . vpc
877
+ ' ec2:Subnet' : props . vpc
886
878
. selectSubnets ( props . subnetSelection ) . subnetIds
887
879
. map ( si => `arn:aws:ec2:${ Aws . region } :${ Aws . accountId } :subnet/${ si } ` ) ,
888
- " ec2:AuthorizedService" : " codebuild.amazonaws.com"
889
- }
890
- }
880
+ ' ec2:AuthorizedService' : ' codebuild.amazonaws.com'
881
+ } ,
882
+ } ,
891
883
} ) ) ;
892
- return {
893
- vpcId : props . vpc . vpcId ,
894
- subnets : props . vpc . selectSubnets ( props . subnetSelection ) . subnetIds ,
895
- securityGroupIds : this . connections . securityGroups . map ( s => s . securityGroupId )
896
- } ;
884
+
885
+ const policy = new iam . Policy ( this , 'PolicyDocument' , {
886
+ policyName : 'CodeBuildEC2Policy' ,
887
+ statements : [
888
+ new iam . PolicyStatement ( {
889
+ resources : [ '*' ] ,
890
+ actions : [
891
+ 'ec2:CreateNetworkInterface' ,
892
+ 'ec2:DescribeNetworkInterfaces' ,
893
+ 'ec2:DeleteNetworkInterface' ,
894
+ 'ec2:DescribeSubnets' ,
895
+ 'ec2:DescribeSecurityGroups' ,
896
+ 'ec2:DescribeDhcpOptions' ,
897
+ 'ec2:DescribeVpcs' ,
898
+ ] ,
899
+ } ) ,
900
+ ] ,
901
+ } ) ;
902
+ this . role . attachInlinePolicy ( policy ) ;
903
+
904
+ // add an explicit dependency between the EC2 Policy and this Project -
905
+ // otherwise, creating the Project fails,
906
+ // as it requires these permissions to be already attached to the Project's Role
907
+ const cfnPolicy = policy . node . findChild ( 'Resource' ) as CfnResource ;
908
+ project . addDependsOn ( cfnPolicy ) ;
897
909
}
898
910
899
911
private validateCodePipelineSettings ( artifacts : IArtifacts ) {
0 commit comments