Repository: aws/amazon-ecs-cli-v2
Pull request #396 (2019-11-18 03:56:38)

Project Hosted Zone and Delegation Role
This change adds creates the project hosted zone
and record set in the parent hosted zone. It updates
the DNS Delegation role to only have write permissions
to this particular hosted zone.

<!-- Provide summary of changes -->

<!-- Issue number, if available. E.g. "Fixes #31", "Addresses #42, 77" -->

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.



Patch:
diff --git a/internal/pkg/deploy/cloudformation/stack/project.go b/internal/pkg/deploy/cloudformation/stack/project.go
index eeb6871f..fc2cd6b5 100644
--- a/internal/pkg/deploy/cloudformation/stack/project.go
+++ b/internal/pkg/deploy/cloudformation/stack/project.go
@@ -52,6 +52,7 @@ const (
 	projectOutputECRRepoPrefix     = "ECRRepo"
 	projectDNSDelegatedAccountsKey = "ProjectDNSDelegatedAccounts"
 	projectDomainNameKey           = "ProjectDomainName"
+	projectNameKey                 = "Project"
 )
 
 // ProjectConfigFrom takes a template file and extracts the metadata block,
@@ -132,6 +133,10 @@ func (c *ProjectStackConfig) Parameters() []*cloudformation.Parameter {
 			ParameterKey:   aws.String(projectDomainNameKey),
 			ParameterValue: aws.String(c.DomainName),
 		},
+		{
+			ParameterKey:   aws.String(projectNameKey),
+			ParameterValue: aws.String(c.Project),
+		},
 	}
 }
 
diff --git a/templates/project/project.yml b/templates/project/project.yml
index 0efbeb68..a1ced82b 100644
--- a/templates/project/project.yml
+++ b/templates/project/project.yml
@@ -13,6 +13,8 @@ Parameters:
   ProjectDomainName:
     Type: String
     Default: ""
+  ProjectName:
+    Type: String
 Conditions:
   DelegateDNS:
     !Not [!Equals [ !Ref ProjectDomainName, "" ]]
@@ -92,6 +94,7 @@ Resources:
                   - ecr:GetLifecyclePolicy
                   - ecr:TagResource
                 Resource: "*"
+
   DNSDelegationRole:
     Type: AWS::IAM::Role
     Condition: DelegateDNS
@@ -121,11 +124,37 @@ Resources:
         PolicyDocument:
           Version: "2012-10-17"
           Statement:
-              - Sid: HostedZoneChangeRecord
+              - Sid: HostedZoneReadRecords
                 Effect: Allow
                 Action:
-                  - route53:*
+                  - route53:Get*
+                  - route53:List*
                 Resource: "*"
+              - Sid: HostedZoneUpdate
+                Effect: Allow
+                Action:
+                  - route53:ChangeResourceRecordSets
+                Resource:
+                  - !Sub arn:${AWS::Partition}:route53:::hostedzone/${ProjectHostedZone}
+
+  ProjectHostedZone:
+    Type: AWS::Route53::HostedZone
+    Condition: DelegateDNS
+    Properties:
+      HostedZoneConfig:
+        Comment: !Sub "Hosted zone for ecs-cli project ${ProjectName}: ${ProjectName}.${ProjectDomainName}"
+      Name: !Sub ${ProjectName}.${ProjectDomainName}
+
+  ProjectDomainDelegationRecordSet:
+    Type: AWS::Route53::RecordSet
+    Condition: DelegateDNS
+    Properties:
+      HostedZoneName: !Sub ${ProjectDomainName}.
+      Comment: !Sub "Record for ecs-cli domain delegation for project ${ProjectDomainName}"
+      Name: !Sub ${ProjectName}.${ProjectDomainName}.
+      Type: NS
+      TTL: '900'
+      ResourceRecords: !GetAtt ProjectHostedZone.NameServers
 
 Outputs:
   ExecutionRoleARN:


Test patch:
diff --git a/internal/pkg/deploy/cloudformation/project_test.go b/internal/pkg/deploy/cloudformation/project_test.go
index 3f6f9fec..ae889821 100644
--- a/internal/pkg/deploy/cloudformation/project_test.go
+++ b/internal/pkg/deploy/cloudformation/project_test.go
@@ -1022,7 +1022,7 @@ func TestDelegateDNSPermissions(t *testing.T) {
 				return &mockCloudFormation{
 					t: t,
 					mockCreateChangeSet: func(t *testing.T, in *cloudformation.CreateChangeSetInput) (*cloudformation.CreateChangeSetOutput, error) {
-						require.Equal(t, len(in.Parameters), 4)
+						require.Equal(t, 5, len(in.Parameters))
 						return &cloudformation.CreateChangeSetOutput{
 							StackId: aws.String("stackname"),
 						}, nil
@@ -1087,7 +1087,7 @@ func TestDelegateDNSPermissions(t *testing.T) {
 				return &mockCloudFormation{
 					t: t,
 					mockCreateChangeSet: func(t *testing.T, in *cloudformation.CreateChangeSetInput) (*cloudformation.CreateChangeSetOutput, error) {
-						require.Equal(t, len(in.Parameters), 4)
+						require.Equal(t, 5, len(in.Parameters))
 						return &cloudformation.CreateChangeSetOutput{
 							StackId: aws.String("stackname"),
 						}, nil
diff --git a/internal/pkg/deploy/cloudformation/stack/project_test.go b/internal/pkg/deploy/cloudformation/stack/project_test.go
index 4efac581..19006c6b 100644
--- a/internal/pkg/deploy/cloudformation/stack/project_test.go
+++ b/internal/pkg/deploy/cloudformation/stack/project_test.go
@@ -174,6 +174,10 @@ func TestProjectParameters(t *testing.T) {
 			ParameterKey:   aws.String(projectDomainNameKey),
 			ParameterValue: aws.String("amazon.com"),
 		},
+		{
+			ParameterKey:   aws.String(projectNameKey),
+			ParameterValue: aws.String("testproject"),
+		},
 	}
 	require.ElementsMatch(t, expectedParams, proj.Parameters())
 }