Use nested CF template for Task Execution Role

Refactor templates to show how to use Nested CF templates
to avoid code repetition among the recipes.

Change-Id: I87fedafaf621dd158e53a80e44f4dc0d77219230
diff --git a/Makefile.common b/Makefile.common
index 37ae390..e5bf82a 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -4,4 +4,8 @@
 
 cluster-keys:
 	aws ec2 describe-key-pairs --region $(AWS_REGION) --key-names $(CLUSTER_KEYS) > /dev/null 2>&1 || \
-		aws ec2 create-key-pair --region $(AWS_REGION) --key-name $(CLUSTER_KEYS) --query 'KeyMaterial' --output text > $(CLUSTER_KEYS).pem
\ No newline at end of file
+		aws ec2 create-key-pair --region $(AWS_REGION) --key-name $(CLUSTER_KEYS) --query 'KeyMaterial' --output text > $(CLUSTER_KEYS).pem
+
+upload-common-templates:
+	export AWS_PAGER=; aws s3api head-bucket --bucket $(TEMPLATE_BUCKET_NAME) 2>/dev/null || aws s3api create-bucket --bucket $(TEMPLATE_BUCKET_NAME)
+	aws s3 cp ../common-templates/cf-gerrit-task-execution-role.yml s3://$(TEMPLATE_BUCKET_NAME)/
diff --git a/common-templates/cf-gerrit-task-execution-role.yml b/common-templates/cf-gerrit-task-execution-role.yml
new file mode 100644
index 0000000..889111e
--- /dev/null
+++ b/common-templates/cf-gerrit-task-execution-role.yml
@@ -0,0 +1,45 @@
+
+AWSTemplateFormatVersion: '2010-09-09'
+Description: Deploy a service into an ECS cluster behind a public load balancer.
+
+Resources:
+    # This is a role which is used by the ECS tasks themselves.
+    ECSTaskExecutionRole:
+      Type: AWS::IAM::Role
+      Properties:
+        AssumeRolePolicyDocument:
+          Statement:
+          - Effect: Allow
+            Principal:
+              Service: [ecs-tasks.amazonaws.com]
+            Action:
+              - sts:AssumeRole
+        Path: /
+        Policies:
+          - PolicyName: AmazonECSTaskExecutionRolePolicy
+            PolicyDocument:
+              Statement:
+              - Effect: Allow
+                Action:
+                  # Allow the ECS Tasks to download images from ECR
+                  - 'ecr:GetAuthorizationToken'
+                  - 'ecr:BatchCheckLayerAvailability'
+                  - 'ecr:GetDownloadUrlForLayer'
+                  - 'ecr:BatchGetImage'
+                  # Allow the ECS tasks to upload logs to CloudWatch
+                  - 'logs:CreateLogStream'
+                  - 'logs:PutLogEvents'
+                Resource: '*'
+          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
+            PolicyDocument:
+              Statement:
+              - Effect: Allow
+                Action:
+                  # Allow the ECS Tasks to get SSH Keys
+                  - 'secretsmanager:GetSecretValue'
+                  - 'kms:Decrypt'
+                Resource: '*'
+
+Outputs:
+  TaskExecutionRoleRef:
+    Value: !Ref ECSTaskExecutionRole
diff --git a/common.env b/common.env
index 0c3f973..371577f 100644
--- a/common.env
+++ b/common.env
@@ -23,3 +23,6 @@
 SYSLOG_HEAD_SHA1=$(shell find $(SYSLOG_IMAGE_DIR) -type f -exec cat {} \; | shasum | cut -c 1-20)
 
 IMAGE_TAG=$(GERRIT_VERSION).$(GERRIT_PATCH)-$(HEAD_SHA1)
+
+# Nested templates bucket
+TEMPLATE_BUCKET_NAME=aws-gerrit-cf-templates
diff --git a/dual-master/Makefile b/dual-master/Makefile
index 6c0280a..88e8ff4 100644
--- a/dual-master/Makefile
+++ b/dual-master/Makefile
@@ -15,7 +15,8 @@
 				service-lb wait-for-service-lb-deletion wait-for-service-lb-creation \
 				gerrit-build gerrit-publish haproxy-publish syslog-sidecar-publish
 
-create-all: gerrit-publish haproxy-publish syslog-sidecar-publish \
+create-all: upload-common-templates \
+						gerrit-publish haproxy-publish syslog-sidecar-publish \
 						cluster wait-for-cluster-creation \
 						service-slave service-master-1 \
 						wait-for-service-master-1-creation wait-for-service-slave-creation \
diff --git a/dual-master/cf-service-lb.yml b/dual-master/cf-service-lb.yml
index 16c0b81..c4d8acc 100644
--- a/dual-master/cf-service-lb.yml
+++ b/dual-master/cf-service-lb.yml
@@ -93,8 +93,8 @@
         Type: AWS::ECS::TaskDefinition
         Properties:
             Family: !Sub '${LBServiceName}TaskDefinition'
-            TaskRoleArn: !Ref ECSTaskExecutionRole
-            ExecutionRoleArn: !Ref ECSTaskExecutionRole
+            TaskRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
+            ExecutionRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
             NetworkMode: bridge
             ContainerDefinitions:
                 - Name: !Ref LBServiceName
@@ -135,41 +135,11 @@
                         awslogs-region: !Ref AWS::Region
                         awslogs-stream-prefix: !Ref EnvironmentName
 
-    # This is a role which is used by the ECS tasks themselves.
-    ECSTaskExecutionRole:
-      Type: AWS::IAM::Role
+    ECSTaskExecutionRoleStack:
+      Type: AWS::CloudFormation::Stack
       Properties:
-        AssumeRolePolicyDocument:
-          Statement:
-          - Effect: Allow
-            Principal:
-              Service: [ecs-tasks.amazonaws.com]
-            Action: ['sts:AssumeRole']
-        Path: /
-        Policies:
-          - PolicyName: AmazonECSTaskExecutionRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to download images from ECR
-                  - 'ecr:GetAuthorizationToken'
-                  - 'ecr:BatchCheckLayerAvailability'
-                  - 'ecr:GetDownloadUrlForLayer'
-                  - 'ecr:BatchGetImage'
-                  # Allow the ECS tasks to upload logs to CloudWatch
-                  - 'logs:CreateLogStream'
-                  - 'logs:PutLogEvents'
-                Resource: '*'
-          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to get SSH Keys
-                  - 'secretsmanager:GetSecretValue'
-                  - 'kms:Decrypt'
-                Resource: '*'
+        TemplateURL: https://aws-gerrit-cf-templates.s3.amazonaws.com/cf-gerrit-task-execution-role.yml
+        TimeoutInMinutes: '5'
 
     LoadBalancer:
         Type: AWS::ElasticLoadBalancingV2::LoadBalancer
diff --git a/dual-master/cf-service-master.yml b/dual-master/cf-service-master.yml
index 2089e8d..548b19e 100644
--- a/dual-master/cf-service-master.yml
+++ b/dual-master/cf-service-master.yml
@@ -130,8 +130,8 @@
         Type: AWS::ECS::TaskDefinition
         Properties:
             Family: !Join ['', [!Ref GerritServiceName, TaskDefinition]]
-            TaskRoleArn: !Ref ECSTaskExecutionRole
-            ExecutionRoleArn: !Ref ECSTaskExecutionRole
+            TaskRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
+            ExecutionRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
             NetworkMode: bridge
             ContainerDefinitions:
                 - Name: !Ref GerritServiceName
@@ -284,41 +284,11 @@
             Port: !Ref SSHHostPort
             Protocol: TCP
 
-    # This is a role which is used by the ECS tasks themselves.
-    ECSTaskExecutionRole:
-      Type: AWS::IAM::Role
+    ECSTaskExecutionRoleStack:
+      Type: AWS::CloudFormation::Stack
       Properties:
-        AssumeRolePolicyDocument:
-          Statement:
-          - Effect: Allow
-            Principal:
-              Service: [ecs-tasks.amazonaws.com]
-            Action: ['sts:AssumeRole']
-        Path: /
-        Policies:
-          - PolicyName: AmazonECSTaskExecutionRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to download images from ECR
-                  - 'ecr:GetAuthorizationToken'
-                  - 'ecr:BatchCheckLayerAvailability'
-                  - 'ecr:GetDownloadUrlForLayer'
-                  - 'ecr:BatchGetImage'
-                  # Allow the ECS tasks to upload logs to CloudWatch
-                  - 'logs:CreateLogStream'
-                  - 'logs:PutLogEvents'
-                Resource: '*'
-          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to get SSH Keys
-                  - 'secretsmanager:GetSecretValue'
-                  - 'kms:Decrypt'
-                Resource: '*'
+        TemplateURL: https://aws-gerrit-cf-templates.s3.amazonaws.com/cf-gerrit-task-execution-role.yml
+        TimeoutInMinutes: '5'
 
 Outputs:
   PublicLoadBalancerDNSName:
diff --git a/dual-master/cf-service-slave.yml b/dual-master/cf-service-slave.yml
index c03e973..6965e79 100644
--- a/dual-master/cf-service-slave.yml
+++ b/dual-master/cf-service-slave.yml
@@ -135,8 +135,8 @@
         Type: AWS::ECS::TaskDefinition
         Properties:
             Family: !Join ['', [!Ref GerritServiceName, TaskDefinition]]
-            TaskRoleArn: !Ref ECSTaskExecutionRole
-            ExecutionRoleArn: !Ref ECSTaskExecutionRole
+            TaskRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
+            ExecutionRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
             NetworkMode: bridge
             ContainerDefinitions:
                 - Name: !Ref GerritServiceName
@@ -373,41 +373,12 @@
             HostedZoneId: !GetAtt 'LoadBalancer.CanonicalHostedZoneID'
             EvaluateTargetHealth: False
 
-    # This is a role which is used by the ECS tasks themselves.
-    ECSTaskExecutionRole:
-      Type: AWS::IAM::Role
+    ECSTaskExecutionRoleStack:
+      Type: AWS::CloudFormation::Stack
       Properties:
-        AssumeRolePolicyDocument:
-          Statement:
-          - Effect: Allow
-            Principal:
-              Service: [ecs-tasks.amazonaws.com]
-            Action: ['sts:AssumeRole']
-        Path: /
-        Policies:
-          - PolicyName: AmazonECSTaskExecutionRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to download images from ECR
-                  - 'ecr:GetAuthorizationToken'
-                  - 'ecr:BatchCheckLayerAvailability'
-                  - 'ecr:GetDownloadUrlForLayer'
-                  - 'ecr:BatchGetImage'
-                  # Allow the ECS tasks to upload logs to CloudWatch
-                  - 'logs:CreateLogStream'
-                  - 'logs:PutLogEvents'
-                Resource: '*'
-          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to get SSH Keys
-                  - 'secretsmanager:GetSecretValue'
-                  - 'kms:Decrypt'
-                Resource: '*'
+        TemplateURL: https://aws-gerrit-cf-templates.s3.amazonaws.com/cf-gerrit-task-execution-role.yml
+        TimeoutInMinutes: '5'
+
 Outputs:
   PublicLoadBalancerDNSName:
     Description: The DNS name of the external load balancer
diff --git a/master-slave/Makefile b/master-slave/Makefile
index 0c487d0..b4986ef 100644
--- a/master-slave/Makefile
+++ b/master-slave/Makefile
@@ -14,7 +14,8 @@
 				wait-for-cluster-deletion wait-for-service-master-deletion wait-for-dns-routing-deletion \
 				gerrit-build gerrit-publish
 
-create-all: gerrit-publish git-daemon-publish git-ssh-publish \
+create-all: upload-common-templates \
+						gerrit-publish git-daemon-publish git-ssh-publish \
 						cluster wait-for-cluster-creation \
 						service-slave service-master \
 						wait-for-service-master-creation wait-for-service-slave-creation \
diff --git a/master-slave/cf-service-master.yml b/master-slave/cf-service-master.yml
index 68f1bf8..e2a6135 100644
--- a/master-slave/cf-service-master.yml
+++ b/master-slave/cf-service-master.yml
@@ -104,8 +104,8 @@
         Type: AWS::ECS::TaskDefinition
         Properties:
             Family: !Join ['', [!Ref GerritServiceName, TaskDefinition]]
-            TaskRoleArn: !Ref ECSTaskExecutionRole
-            ExecutionRoleArn: !Ref ECSTaskExecutionRole
+            TaskRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
+            ExecutionRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
             NetworkMode: bridge
             ContainerDefinitions:
                 - Name: !Ref GerritServiceName
@@ -251,41 +251,12 @@
             Port: !Ref SSHPort
             Protocol: TCP
 
-    # This is a role which is used by the ECS tasks themselves.
-    ECSTaskExecutionRole:
-      Type: AWS::IAM::Role
+    ECSTaskExecutionRoleStack:
+      Type: AWS::CloudFormation::Stack
       Properties:
-        AssumeRolePolicyDocument:
-          Statement:
-          - Effect: Allow
-            Principal:
-              Service: [ecs-tasks.amazonaws.com]
-            Action: ['sts:AssumeRole']
-        Path: /
-        Policies:
-          - PolicyName: AmazonECSTaskExecutionRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to download images from ECR
-                  - 'ecr:GetAuthorizationToken'
-                  - 'ecr:BatchCheckLayerAvailability'
-                  - 'ecr:GetDownloadUrlForLayer'
-                  - 'ecr:BatchGetImage'
-                  # Allow the ECS tasks to upload logs to CloudWatch
-                  - 'logs:CreateLogStream'
-                  - 'logs:PutLogEvents'
-                Resource: '*'
-          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to get SSH Keys
-                  - 'secretsmanager:GetSecretValue'
-                  - 'kms:Decrypt'
-                Resource: '*'
+        TemplateURL: https://aws-gerrit-cf-templates.s3.amazonaws.com/cf-gerrit-task-execution-role.yml
+        TimeoutInMinutes: '5'
+
 Outputs:
   PublicLoadBalancerDNSName:
     Description: The DNS name of the external load balancer
diff --git a/master-slave/cf-service-slave.yml b/master-slave/cf-service-slave.yml
index c03e973..6965e79 100644
--- a/master-slave/cf-service-slave.yml
+++ b/master-slave/cf-service-slave.yml
@@ -135,8 +135,8 @@
         Type: AWS::ECS::TaskDefinition
         Properties:
             Family: !Join ['', [!Ref GerritServiceName, TaskDefinition]]
-            TaskRoleArn: !Ref ECSTaskExecutionRole
-            ExecutionRoleArn: !Ref ECSTaskExecutionRole
+            TaskRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
+            ExecutionRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
             NetworkMode: bridge
             ContainerDefinitions:
                 - Name: !Ref GerritServiceName
@@ -373,41 +373,12 @@
             HostedZoneId: !GetAtt 'LoadBalancer.CanonicalHostedZoneID'
             EvaluateTargetHealth: False
 
-    # This is a role which is used by the ECS tasks themselves.
-    ECSTaskExecutionRole:
-      Type: AWS::IAM::Role
+    ECSTaskExecutionRoleStack:
+      Type: AWS::CloudFormation::Stack
       Properties:
-        AssumeRolePolicyDocument:
-          Statement:
-          - Effect: Allow
-            Principal:
-              Service: [ecs-tasks.amazonaws.com]
-            Action: ['sts:AssumeRole']
-        Path: /
-        Policies:
-          - PolicyName: AmazonECSTaskExecutionRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to download images from ECR
-                  - 'ecr:GetAuthorizationToken'
-                  - 'ecr:BatchCheckLayerAvailability'
-                  - 'ecr:GetDownloadUrlForLayer'
-                  - 'ecr:BatchGetImage'
-                  # Allow the ECS tasks to upload logs to CloudWatch
-                  - 'logs:CreateLogStream'
-                  - 'logs:PutLogEvents'
-                Resource: '*'
-          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to get SSH Keys
-                  - 'secretsmanager:GetSecretValue'
-                  - 'kms:Decrypt'
-                Resource: '*'
+        TemplateURL: https://aws-gerrit-cf-templates.s3.amazonaws.com/cf-gerrit-task-execution-role.yml
+        TimeoutInMinutes: '5'
+
 Outputs:
   PublicLoadBalancerDNSName:
     Description: The DNS name of the external load balancer
diff --git a/single-master/Makefile b/single-master/Makefile
index b053f53..fca4d15 100644
--- a/single-master/Makefile
+++ b/single-master/Makefile
@@ -12,7 +12,8 @@
 				wait-for-cluster-deletion wait-for-service-deletion wait-for-dns-routing-deletion \
 				gerrit-build gerrit-publish
 
-create-all: gerrit-publish \
+create-all: upload-common-templates \
+						gerrit-publish \
 						cluster wait-for-cluster-creation \
 						service wait-for-service-creation \
 						dns-routing wait-for-dns-routing-creation
diff --git a/single-master/cf-service.yml b/single-master/cf-service.yml
index 80a06dc..0f7cd92 100644
--- a/single-master/cf-service.yml
+++ b/single-master/cf-service.yml
@@ -97,8 +97,8 @@
         Type: AWS::ECS::TaskDefinition
         Properties:
             Family: !Join ['', [!Ref GerritServiceName, TaskDefinition]]
-            TaskRoleArn: !Ref ECSTaskExecutionRole
-            ExecutionRoleArn: !Ref ECSTaskExecutionRole
+            TaskRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
+            ExecutionRoleArn: !GetAtt ECSTaskExecutionRoleStack.Outputs.TaskExecutionRoleRef
             NetworkMode: bridge
             ContainerDefinitions:
                 - Name: !Ref GerritServiceName
@@ -241,41 +241,12 @@
             Port: !Ref SSHPort
             Protocol: TCP
 
-    # This is a role which is used by the ECS tasks themselves.
-    ECSTaskExecutionRole:
-      Type: AWS::IAM::Role
+    ECSTaskExecutionRoleStack:
+      Type: AWS::CloudFormation::Stack
       Properties:
-        AssumeRolePolicyDocument:
-          Statement:
-          - Effect: Allow
-            Principal:
-              Service: [ecs-tasks.amazonaws.com]
-            Action: ['sts:AssumeRole']
-        Path: /
-        Policies:
-          - PolicyName: AmazonECSTaskExecutionRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to download images from ECR
-                  - 'ecr:GetAuthorizationToken'
-                  - 'ecr:BatchCheckLayerAvailability'
-                  - 'ecr:GetDownloadUrlForLayer'
-                  - 'ecr:BatchGetImage'
-                  # Allow the ECS tasks to upload logs to CloudWatch
-                  - 'logs:CreateLogStream'
-                  - 'logs:PutLogEvents'
-                Resource: '*'
-          - PolicyName: AmazonECSTaskSecretManagerRolePolicy
-            PolicyDocument:
-              Statement:
-              - Effect: Allow
-                Action:
-                  # Allow the ECS Tasks to get SSH Keys
-                  - 'secretsmanager:GetSecretValue'
-                  - 'kms:Decrypt'
-                Resource: '*'
+        TemplateURL: https://aws-gerrit-cf-templates.s3.amazonaws.com/cf-gerrit-task-execution-role.yml
+        TimeoutInMinutes: '5'
+
 Outputs:
   PublicLoadBalancerDNSName:
     Description: The DNS name of the external load balancer