diff --git a/ql/lib/codeql/iac/aws/CloudFormation.qll b/ql/lib/codeql/iac/aws/CloudFormation.qll index f041753..2c03a43 100644 --- a/ql/lib/codeql/iac/aws/CloudFormation.qll +++ b/ql/lib/codeql/iac/aws/CloudFormation.qll @@ -158,4 +158,365 @@ module CloudFormation { // ) } } -} + class LambdaFunction extends Resource { + LambdaFunction() { this.getType() = "AWS::Lambda::Function" } + + override string toString() { result = "CloudFormation Lambda Function" } + + /** + * Get the Lambda function runtime. + */ + string getRuntime() { + result = this.getProperties().getProperty("Runtime").(YamlString).getValue() + } + /** + * get principal + */ + string getPrincipal() { + result = this.getProperties().getProperty("Principal").(YamlString).getValue() + } + + } + + class EC2SecurityGroup extends Resource { + EC2SecurityGroup() { this.getType() = "AWS::EC2::SecurityGroup" } + + override string toString() { result = "CloudFormation EC2 Security Group" } + + /** + * Get the security group egress rules. + */ + YamlNode getSgEgress() { + result = this.getProperties().getProperty("SecurityGroupEgress") + } + YamlNode getEgressCidrIp() { + result = this.getSgEgress().getAChildNode().(YamlMapping).lookup("CidrIp") + } + YamlNode getEgressFromPort() { + result = this.getSgEgress().getAChildNode().(YamlMapping).lookup("FromPort") + } + YamlNode getEgressToPort() { + result = this.getSgEgress().getAChildNode().(YamlMapping).lookup("ToPort") + } + YamlNode getEgressDesc() { + result = this.getSgEgress().getAChildNode().(YamlMapping).lookup("Description") + } + + /** + * Get the security group ingress rules. + */ + YamlNode getSgIngress() { + result = this.getProperties().getProperty("SecurityGroupIngress") + } + YamlNode getIngressCidrIp() { + result = this.getSgIngress().getAChildNode().(YamlMapping).lookup("CidrIp") + } + YamlNode getIngressFromPort() { + result = this.getSgIngress().getAChildNode().(YamlMapping).lookup("FromPort") + } + YamlNode getIngressToPort() { + result = this.getSgIngress().getAChildNode().(YamlMapping).lookup("ToPort") + } + YamlNode getIngressDesc() { + result = this.getSgIngress().getAChildNode().(YamlMapping).lookup("Description") + } + } + + class EC2SecurityGroupEgress extends Resource { + EC2SecurityGroupEgress() { this.getType() = "AWS::EC2::SecurityGroupEgress" } + + override string toString() { result = "CloudFormation EC2 Security Group Egress" } + + /** + * Get the security group ingress CIDR IP. + */ + YamlNode getCidrIp() { + result = this.getProperties().getProperty("CidrIp") + } + + /** + * Get the security group ingress from port. + */ + YamlNode getFromPort() { + result = this.getProperties().getProperty("FromPort") + } + YamlNode getToPort() { + result = this.getProperties().getProperty("ToPort") + } + } + + + + class EC2SecurityGroupIngress extends Resource { + EC2SecurityGroupIngress() { this.getType() = "AWS::EC2::SecurityGroupIngress" } + + override string toString() { result = "CloudFormation EC2 Security Group Ingress" } + + /** + * Get the security group ingress CIDR IP. + */ + YamlNode getCidrIp() { + result = this.getProperties().getProperty("CidrIp") + } + + /** + * Get the security group ingress from port. + */ + YamlNode getFromPort() { + result = this.getProperties().getProperty("FromPort") + } + YamlNode getToPort() { + result = this.getProperties().getProperty("ToPort") + } + } + + class IAMRole extends Resource { + IAMRole() { this.getType() = "AWS::IAM::Role" } + + override string toString() { result = "CloudFormation IAM Role" } + + string getProperty(string key) { result = this.getProperties().getProperty(key).toString() } + + /** + * Get the IAM role policies. + */ + IAMStatement getPolicy() { + result = this.getProperties().getProperty("Policies").getAChild().getAChild() + + /* + exists(YamlNode policies + | policies = this.getProperties().getAChildNode() + | result = policies and policies.toString() = "Statement" ) + */ + } + } + class IAMStatement extends YamlNode { + IAMStatement(){ this.getAChild().toString() = "Statement"} + + YamlNode getAction() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Action") + } + YamlNode getEffect() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Effect") + } + YamlNode getResource() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Resource") + } + } + + class ECSService extends Resource { + ECSService() { this.getType() = "AWS::ECS::Service" } + YamlNode getNetworkConfiguration() { + result = this.getProperties().getProperty("NetworkConfiguration") + } + + /** + * Get ecs service platform version + */ + YamlNode getPlatformVersion() { + result = this.getProperties().getProperty("PlatformVersion") + } + + TaskDefinition getTaskDefinition() { + result = this.getProperties().getProperty("TaskDefinition") + } + } + + class ECSTaskSet extends Resource { + ECSTaskSet() { this.getType() = "AWS::ECS::TaskSet" } + + override string toString() { result = "CloudFormation ECS Task Set" } + + /** + * Get the task set network configuration. + */ + YamlNode getNetworkConfiguration() { + result = this.getProperties().getProperty("NetworkConfiguration") + } + + YamlNode getAssignPublicIp() { + result = this.getNetworkConfiguration().getAChild().(YamlMapping).lookup("AssignPublicIp") + } + } + + class ECSNetworkConfiguration extends YamlNode { + ECSNetworkConfiguration() { this.getAChild().toString() = "NetworkConfiguration" } + + YamlNode getAwsvpcConfiguration() { + result = this.getAChild().(YamlMapping).lookup("AwsvpcConfiguration") + } + YamlNode getAssignPublicIp() { + result = this.getAwsvpcConfiguration().(YamlMapping).lookup("AssignPublicIp") + } + } + + class TaskDefinition extends Resource { + TaskDefinition() { this.getType() = "AWS::ECS::TaskDefinition" } + + override string toString() { result = "CloudFormation ECS Task Definition" } + + /** + * Get the task definition container definitions. + */ + ContainerDefinition getContainerDefinitions() { + result = this.getProperties().getProperty("ContainerDefinitions") + } + /** + * Get network mode + */ + YamlNode getNetworkMode() { + result = this.getProperties().getProperty("NetworkMode") + } + + /** + * get PidMode + * + */ + YamlNode getPidMode() { + result = this.getProperties().getProperty("PidMode") + } + /** + * get IPCMode + */ + YamlNode getIpcMode() { + result = this.getProperties().getProperty("IpcMode") + } + /** + * get Volumes + */ + YamlNode getVolumes() { + result = this.getProperties().getProperty("Volumes") + } + /** + * get PlacementConstraints + */ + YamlNode getPlacementConstraints() { + result = this.getProperties().getProperty("PlacementConstraints") + } + /** + * get RequiresCompatibilities + */ + YamlNode getRequiresCompatibilities() { + result = this.getProperties().getProperty("RequiresCompatibilities") + } + /** + * get Cpu + */ + YamlNode getCpu() { + result = this.getProperties().getProperty("Cpu") + } + /** + * get Memory + */ + YamlNode getMemory() { + result = this.getProperties().getProperty("Memory") + } + /** + * get ExecutionRoleArn + */ + YamlNode getExecutionRoleArn() { + result = this.getProperties().getProperty("ExecutionRoleArn") + } + + /** + * get logConfiguration + */ + YamlNode getLogConfiguration() { + result = this.getProperties().getProperty("LogConfiguration") + } + + /** + * get Secrets from ContainerDefinitions + */ + YamlNode getSecrets() { + result = this.getContainerDefinitions().getAChild().(YamlMapping).lookup("Secrets") + } + YamlNode getRuntimePlatform() { + result = this.getProperties().getProperty("RuntimePlatform").(YamlMapping).lookup("OperatingSystemFamily") + } + } + + class ECSCluster extends Resource { + ECSCluster() { this.getType() = "AWS::ECS::Cluster" } + + override string toString() { result = "CloudFormation ECS Cluster" } + + /** checks if container insights is enabled in container settings */ + YamlNode getContainerInsights() { + result = this.getProperties().getProperty("ClusterSettings").getAChild().(YamlMapping).lookup("Value") + } + } + + class ContainerDefinition extends YamlNode + { + ContainerDefinition() { this.getAChild().toString() = "ContainerDefinitions" } + + YamlNode getName() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Name") + } + + YamlNode getNetworkConfiguration() { + result = this.getAChild().getAChild().(YamlMapping).lookup("NetworkConfiguration") + } + YamlNode getnetworkconfigurationAwsvpcConfiguration() { + result = this.getAChild().getAChild().(YamlMapping).lookup("AwsvpcConfiguration") + } + YamlNode getImage() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Image") + } + YamlNode getMemory() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Memory") + } + YamlNode getMemoryReservation() { + result = this.getAChild().getAChild().(YamlMapping).lookup("MemoryReservation") + } + YamlNode getCpu() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Cpu") + } + YamlNode getEssential() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Essential") + } + YamlNode getPortMappings() { + result = this.getAChild().getAChild().(YamlMapping).lookup("PortMappings") + } + YamlNode getVolumesFrom() { + result = this.getAChild().getAChild().(YamlMapping).lookup("VolumesFrom") + } + YamlNode getEnvironment() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Environment") + } + YamlNode getSecrets() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Secrets") + } + YamlNode getLogConfiguration() { + result = this.getAChild().getAChild().(YamlMapping).lookup("LogConfiguration") + } + YamlNode getHealthCheck() { + result = this.getAChild().getAChild().(YamlMapping).lookup("HealthCheck") + } + YamlNode getEntryPoint() { + result = this.getAChild().getAChild().(YamlMapping).lookup("EntryPoint") + } + YamlNode getCommand() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Command") + } + YamlNode getWorkingDirectory() { + result = this.getAChild().getAChild().(YamlMapping).lookup("WorkingDirectory") + } + string getPrivileged() { + result = this.getAChild().getAChild().(YamlMapping).lookup("Privileged").toString() + } + + string getReadOnlyRootFilesystem() { + result = this.getAChild().getAChild().(YamlMapping).lookup("ReadOnlyRootFilesystem").toString() + } + YamlNode getLinuxParametersCapabilities() { + result = this.getAChild().getAChild().(YamlMapping).lookup("LinuxParameters") + } + + YamlNode getUser() { + result = this.getAChild().getAChild().(YamlMapping).lookup("User") + } + } + +} \ No newline at end of file diff --git a/ql/src/security/CloudFormation/ECS/ContainerInsights.ql b/ql/src/security/CloudFormation/ECS/ContainerInsights.ql new file mode 100644 index 0000000..04eb162 --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/ContainerInsights.ql @@ -0,0 +1,18 @@ +/** + * @name ECS clusters should use Container Insights + * @kind problem + * @problem.severity warning + * @id iac/ecs/container-insights + * @tags security + * aws/ecs/12 + * NIST/800-53/AU-6(3) + * NIST/800-53/AU-6(4) + * NIST/800-53/CA-7 + * NIST/800-53/SI-2 + */ + +import iac + +from CloudFormation::ECSCluster cluster +where not cluster.getContainerInsights().toString() = "'enabled'" +select cluster, "ECS Cluster should have cluster settings enabled" \ No newline at end of file diff --git a/ql/src/security/CloudFormation/ECS/LatestVersion.ql b/ql/src/security/CloudFormation/ECS/LatestVersion.ql new file mode 100644 index 0000000..16daf67 --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/LatestVersion.ql @@ -0,0 +1,33 @@ +/** + * @name ECS Fargate services should run on the latest Fargate platform version + * @kind problem + * @problem.severity warning + * @id iac/ecs/latest-version + * @tags security + * experimental + * aws/ecs/10 + * NIST/800-53/SI-2 + * NIST/800-53/SI-2(2) + * NIST/800-53/SI-2(4) + * NIST/800-53/SI-2(5) + * PCI-DSS/4.0.1 + * PCI-DSS/6.3.3 + * + */ + +// need to figure out how to make !Ref to be recognized, then and this should be possible to be used properly, used as "Experimental for now +import iac +from CloudFormation::ECSService ecs, CloudFormation::TaskDefinition td +//where ecs.getPlatformVersion().toString() = ["'LATEST'", "'1.4.0'"] or ecs.getPlatformVersion().toString() = ["'LATEST'", "'1.0.0'"] +//where td.getRuntimePlatform().toString() = "'LINUX'" or td.getRuntimePlatform().toString() = "'WINDOWS'" +where + ((ecs.getPlatformVersion().toString() = ["'LATEST'", "'1.4.0'"] or not exists(ecs.getPlatformVersion())) + and + (td.getRuntimePlatform().toString() ="'LINUX'" or not exists(td.getRuntimePlatform())) ) + or + ((ecs.getPlatformVersion().toString() = ["'LATEST'", "'1.0.0'"] or not exists(ecs.getPlatformVersion())) + and + (exists(td.getRuntimePlatform()) and td.getRuntimePlatform().toString() !="'LINUX'")) + +select td, "ContainerDefinitions must have a log configuration" + diff --git a/ql/src/security/CloudFormation/ECS/LogConfiguration.ql b/ql/src/security/CloudFormation/ECS/LogConfiguration.ql new file mode 100644 index 0000000..91ce3ef --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/LogConfiguration.ql @@ -0,0 +1,25 @@ +/** + * @name ECS task definitions should have a logging configuration + * @kind problem + * @problem.severity warning + * @id iac/ecs/log-configuration + * @tags security + * aws/ecs/9 + * NIST/800-53/AC-4(26) + * NIST/800-53/AU-10 + * NIST/800-53/AU-12 + * NIST/800-53/AU-2 + * NIST/800-53/AU-3 + * NIST/800-53/AU-6(3) + * NIST/800-53/AU-6(4) + * NIST/800-53/CA-7 + * NIST/800-53/SC-7(9) + * NIST/800-53/SI-7(8) + */ + +import iac + +from CloudFormation::ContainerDefinition cd +where not exists(cd.getLogConfiguration()) +select cd, "ContainerDefinitions must have a log configuration" + diff --git a/ql/src/security/CloudFormation/ECS/NetworkMode.ql b/ql/src/security/CloudFormation/ECS/NetworkMode.ql new file mode 100644 index 0000000..242a12d --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/NetworkMode.ql @@ -0,0 +1,25 @@ +/** + * @name Amazon ECS task definitions should have secure networking modes and user definitions. + * @kind problem + * @problem.severity warning + * @id iac/ecs/networkmode + * @tags security + * experimental + * /aws/config/ecs/1 + * /NIST/800-53/AC-2(1) + * /NIST/800-53/AC-3 + * /NIST/800-53/AC-3(15) + * /NIST/800-53/AC-3(7) + * /NIST/800-53/AC-5 + * /NIST/800-53/AC-6 + */ + +import iac + +//Check for NetworkMode to not be host in taskdefinition, this is very much experimental -> Experimental +from CloudFormation::ContainerDefinition cd, CloudFormation::TaskDefinition td +where + (cd.getUser().toString() = "'root'" or cd.getPrivileged() = "true") and + td.getNetworkMode().toString() = "'host'" +select td, + "ContainerDefinitions must not run as root or be privileged when networkmode Host is used" diff --git a/ql/src/security/CloudFormation/ECS/NonPriv.ql b/ql/src/security/CloudFormation/ECS/NonPriv.ql new file mode 100644 index 0000000..b1562aa --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/NonPriv.ql @@ -0,0 +1,20 @@ +/** + * @name ECS containers should run as non-privileged + * @kind problem + * @problem.severity warning + * @id iac/ecs/non-priv + * @tags security + * aws/ecs/4 + * NIST/800-53/AC-2(1) + * NIST/800-53/AC-3 + * NIST/800-53/AC-3(15) + * NIST/800-53/AC-3(7) + * NIST/800-53/AC-5 + * NIST/800-53/AC-6 + */ + +import iac + +from CloudFormation::ContainerDefinition cd +where not cd.getPrivileged() = "false" +select cd, "ContainerDefinitions must be explictly configured privileged mode to false" diff --git a/ql/src/security/CloudFormation/ECS/PidMode.ql b/ql/src/security/CloudFormation/ECS/PidMode.ql new file mode 100644 index 0000000..7f63d05 --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/PidMode.ql @@ -0,0 +1,16 @@ +/** + * @name ECS task definitions should not share the host's process namespace + * @kind problem + * @problem.severity warning + * @id iac/ecs/pidmode + * @tags security + * aws/ecs/3 + * NIST/800-53/CA-9(1) + * NIST/800-53/CM-2 + */ + +import iac + +from CloudFormation::TaskDefinition td +where not td.getPidMode().toString() = "task" +select td, "PidMode should be \"task\" for ECS tasks" diff --git a/ql/src/security/CloudFormation/ECS/PublicIP.ql b/ql/src/security/CloudFormation/ECS/PublicIP.ql new file mode 100644 index 0000000..e697e73 --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/PublicIP.ql @@ -0,0 +1,30 @@ +/** + * @name ECS task sets should not automatically assign public IP addresses + * @kind problem + * @problem.severity warning + * @id iac/ecs/assignpublicip + * @tags security + * aws/ecs/2 + * NIST/800-53/AC-21 + * NIST/800-53/AC-3 + * NIST/800-53/AC-3(7) + * NIST/800-53/AC-4 + * NIST/800-53/AC-4(21) + * NIST/800-53/AC-6 + * NIST/800-53/SC-7 + * NIST/800-53/SC-7(11) + * NIST/800-53/SC-7(16) + * NIST/800-53/SC-7(20) + * NIST/800-53/SC-7(21) + * NIST/800-53/SC-7(3) + * NIST/800-53/SC-7(4) + * NIST/800-53/SC-7(9) + * PCI-DSS/4.0.1 + * PCI-DSS/1.4.4 + */ + +import iac + +from CloudFormation::ECSNetworkConfiguration ecsnetwork +where not ecsnetwork.getAssignPublicIp().toString() = ["'DISABLED'","DISABLED"] +select ecsnetwork.getAssignPublicIp(), "AssignPublicIp should be \"DISABLED\" for ECS tasks" \ No newline at end of file diff --git a/ql/src/security/CloudFormation/ECS/PublicIPTaskSet.ql b/ql/src/security/CloudFormation/ECS/PublicIPTaskSet.ql new file mode 100644 index 0000000..a37772e --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/PublicIPTaskSet.ql @@ -0,0 +1,17 @@ +/** + * @name ECS task sets should not automatically assign public IP addresses + * @kind problem + * @problem.severity warning + * @id iac/ecs/assign-publicip-taskset + * @tags security + * cloudformation + * aws/ecs/16 + * PCI-DSS/4.0.1 + * PCI-DSS/1.4.4 + */ + +import iac + +from CloudFormation::ECSTaskSet ts +//where not ts.getAssignPublicIp().toString() = ["'DISABLED'","DISABLED"] +select ts, "AssignPublicIp must be \"DISABLED\" for ECS tasks" diff --git a/ql/src/security/CloudFormation/ECS/ReadOnlyRootFileSystem.ql b/ql/src/security/CloudFormation/ECS/ReadOnlyRootFileSystem.ql new file mode 100644 index 0000000..df01aaf --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/ReadOnlyRootFileSystem.ql @@ -0,0 +1,20 @@ +/** + * @name ECS containers should be limited to read-only access to root filesystems + * @kind problem + * @problem.severity warning + * @id iac/ecs/read-only-root-filesystem + * @tags security + * aws/ecs/5 + * NIST/800-53/AC-2(1) + * NIST/800-53/AC-3 + * NIST/800-53/AC-3(15) + * NIST/800-53/AC-3(7) + * NIST/800-53/AC-5 + * NIST/800-53/AC-6 + */ + +import iac + +from CloudFormation::ContainerDefinition cd +where not cd.getReadOnlyRootFilesystem() = "true" +select cd, "Containers must have explictly only read only root filesystem" diff --git a/ql/src/security/CloudFormation/ECS/Secrets.ql b/ql/src/security/CloudFormation/ECS/Secrets.ql new file mode 100644 index 0000000..2dbbac5 --- /dev/null +++ b/ql/src/security/CloudFormation/ECS/Secrets.ql @@ -0,0 +1,20 @@ +/** + * @name Secrets should not be passed as container environment variables + * @kind problem + * @problem.severity warning + * @id iac/ecs/secrets + * @tags security + * aws/ecs/8 + * NIST/800-53/AC-2(1) + * NIST/800-53/AC-3 + * NIST/800-53/AC-3(15) + * NIST/800-53/AC-3(7) + * NIST/800-53/AC-5 + * NIST/800-53/AC-6 + */ + +import iac + +from CloudFormation::ContainerDefinition cd +//where cd.getSecrets().getAChild().getAChild().toString() = ["'AWS_ACCESS_KEY_ID'", "'AWS_SECRET_ACCESS_KEY'", "'ECS_ENGINE_AUTH_DATA'"] +select cd.getSecrets(), "Containers must not pass secret thorugh environment variables" diff --git a/ql/test/library-tests/aws/cloudformation/AST.expected b/ql/test/library-tests/aws/cloudformation/AST.expected index 7202c3c..16219c8 100644 --- a/ql/test/library-tests/aws/cloudformation/AST.expected +++ b/ql/test/library-tests/aws/cloudformation/AST.expected @@ -1,18 +1,61 @@ cloudformation +| IAMRole.yml:1:1:18:74 | CloudFormation Document | +| IngressEgressResources.yml:1:1:19:21 | CloudFormation Document | +| ecs.yml:1:1:92:40 | CloudFormation Document | +| lambda.yml:1:1:21:18 | CloudFormation Document | | s3.json:1:1:77:1 | CloudFormation Document | | s3.yml:1:1:42:59 | CloudFormation Document | +| securitygroup.yml:1:1:16:24 | CloudFormation Document | resources +| IAMRole.yml:5:5:18:74 | CloudFormation IAM Role | +| IngressEgressResources.yml:7:5:13:2 | CloudFormation EC2 Security Group Ingress | +| IngressEgressResources.yml:14:5:19:21 | CloudFormation EC2 Security Group Egress | +| ecs.yml:6:5:38:2 | CloudFormation ECS Task Set | +| ecs.yml:39:5:66:2 | CloudFormation ECS Task Definition | +| ecs.yml:67:5:92:40 | CloudFormation Resource | +| lambda.yml:5:5:21:18 | CloudFormation Lambda Function | | s3.json:4:21:15:9 | CloudFormation S3 Bucket | | s3.json:16:25:47:9 | CloudFormation S3 Bucket Policy | | s3.yml:4:5:12:2 | CloudFormation S3 Bucket | | s3.yml:13:5:28:28 | CloudFormation S3 Bucket Policy | +| securitygroup.yml:7:5:16:24 | CloudFormation EC2 Security Group | resourceProperties +| IAMRole.yml:7:7:18:74 | CloudFormation Resource Properties | +| IngressEgressResources.yml:9:7:13:2 | CloudFormation Resource Properties | +| IngressEgressResources.yml:16:7:19:21 | CloudFormation Resource Properties | +| ecs.yml:8:7:38:2 | CloudFormation Resource Properties | +| ecs.yml:41:7:66:2 | CloudFormation Resource Properties | +| ecs.yml:70:7:92:40 | CloudFormation Resource Properties | +| lambda.yml:7:7:21:18 | CloudFormation Resource Properties | | s3.json:6:27:12:13 | CloudFormation Resource Properties | | s3.json:18:27:46:13 | CloudFormation Resource Properties | | s3.yml:6:7:10:4 | CloudFormation Resource Properties | | s3.yml:15:7:28:28 | CloudFormation Resource Properties | +| securitygroup.yml:9:7:16:24 | CloudFormation Resource Properties | s3 | s3.json:4:21:15:9 | CloudFormation S3 Bucket | | s3.yml:4:5:12:2 | CloudFormation S3 Bucket | s3Policy | s3.yml:4:5:12:2 | CloudFormation S3 Bucket | s3.yml:13:5:28:28 | CloudFormation S3 Bucket Policy | +lambda +| lambda.yml:5:5:21:18 | CloudFormation Lambda Function | +ec2SecurityGroup +| securitygroup.yml:7:5:16:24 | CloudFormation EC2 Security Group | +ec2SecurityGroupIngress +| IngressEgressResources.yml:7:5:13:2 | CloudFormation EC2 Security Group Ingress | +ec2SecurityGroupEgress +| IngressEgressResources.yml:14:5:19:21 | CloudFormation EC2 Security Group Egress | +iamRole +| IAMRole.yml:5:5:18:74 | CloudFormation IAM Role | +iamStatement +| IAMRole.yml:9:9:16:6 | Version ... -10-17' | +| s3.yml:16:9:28:6 | Id: MyPolicy | +ecsService +| ecs.yml:67:5:92:40 | CloudFormation Resource | +ecsCluster +ecsTaskSet +| ecs.yml:6:5:38:2 | CloudFormation ECS Task Set | +taskDefinition +| ecs.yml:39:5:66:2 | CloudFormation ECS Task Definition | +containerDefinition +| ecs.yml:41:7:66:2 | CloudFormation Resource Properties | diff --git a/ql/test/library-tests/aws/cloudformation/AST.ql b/ql/test/library-tests/aws/cloudformation/AST.ql index 9180335..e0919fe 100644 --- a/ql/test/library-tests/aws/cloudformation/AST.ql +++ b/ql/test/library-tests/aws/cloudformation/AST.ql @@ -11,3 +11,17 @@ query predicate s3(CloudFormation::S3Bucket n) { any() } query predicate s3Policy(CloudFormation::S3Bucket n, CloudFormation::S3BucketPolicy p) { p = n.getBucketPolicy() } + +query predicate lambda(CloudFormation::LambdaFunction n) { any() } + +query predicate ec2SecurityGroup(CloudFormation::EC2SecurityGroup n) { any() } +query predicate ec2SecurityGroupIngress(CloudFormation::EC2SecurityGroupIngress n) { any() } +query predicate ec2SecurityGroupEgress(CloudFormation::EC2SecurityGroupEgress n) { any() } +query predicate iamRole(CloudFormation::IAMRole n) { any() } +query predicate iamStatement(CloudFormation::IAMStatement p){ any() } + +query predicate ecsService(CloudFormation::ECSService p){ any() } +query predicate ecsCluster(CloudFormation::ECSCluster p){ any() } +query predicate ecsTaskSet(CloudFormation::ECSTaskSet p){ any() } +query predicate taskDefinition(CloudFormation::TaskDefinition p){ any() } +query predicate containerDefinition(CloudFormation::ContainerDefinition p){ any() } diff --git a/ql/test/library-tests/aws/cloudformation/IAMRole.yml b/ql/test/library-tests/aws/cloudformation/IAMRole.yml new file mode 100644 index 0000000..de7cc30 --- /dev/null +++ b/ql/test/library-tests/aws/cloudformation/IAMRole.yml @@ -0,0 +1,18 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Security: Account Enable Guardduty' +Resources: + LambdaRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: SecurityGuardDutyLambdaRole + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: 'lambda.amazonaws.com' + Action: + - 'sts:AssumeRole' + Path: '/' + ManagedPolicyArns: + - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' \ No newline at end of file diff --git a/ql/test/library-tests/aws/cloudformation/IngressEgressResources.yml b/ql/test/library-tests/aws/cloudformation/IngressEgressResources.yml new file mode 100644 index 0000000..26caecb --- /dev/null +++ b/ql/test/library-tests/aws/cloudformation/IngressEgressResources.yml @@ -0,0 +1,22 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: PositionAndJourney Statistics Service + +Resources: + IngressInbound: + Type: 'AWS::EC2::SecurityGroupIngress' + Properties: + IpProtocol: tcp + CidrIp: 0.0.0.0/0 + FromPort: '6370' + ToPort: '6379' + EgressOutbound: + Type: 'AWS::EC2::SecurityGroupEgress' + Properties: + IpProtocol: tcp + CidrIp: 0.0.0.0/0 + FromPort: '6370' + ToPort: '6379' + + + diff --git a/ql/test/library-tests/aws/cloudformation/ecs.yml b/ql/test/library-tests/aws/cloudformation/ecs.yml new file mode 100644 index 0000000..c22758e --- /dev/null +++ b/ql/test/library-tests/aws/cloudformation/ecs.yml @@ -0,0 +1,92 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' +Parameters: +Resources: + TaskSet: + Type: 'AWS::ECS::TaskSet' + Properties: + Cluster: !Ref 'Cluster' + Service: !Ref 'Service' + TaskDefinition: !Ref 'TaskDefinition' + LaunchType: 'FARGATE' + NetworkConfiguration: + AwsVpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref 'SecurityGroup' + Subnets: + - !Ref 'SubnetA' + - !Ref 'SubnetB' + - !Ref 'SubnetC' + LoadBalancers: + - ContainerName: !Ref 'ContainerName' + ContainerPort: !Ref 'ContainerPort' + TargetGroupArn: !Ref 'TargetGroup' + PlatformVersion: 'LATEST' + Scale: !Ref 'Scale' + ServiceRegistries: + - ContainerName: !Ref 'ContainerName' + ContainerPort: !Ref 'ContainerPort' + RegistryArn: !Ref 'ServiceDiscoveryRegistry' + HealthCheckGracePeriodSeconds: 90 + SchedulingStrategy: 'REPLICA' + ServiceDiscovery: !Ref 'ServiceDiscovery' + + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Ref Container + Name: !Ref Component + PortMappings: + - ContainerPort: !Ref ContainerPort + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/logs' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: DummyListenerRule + Properties: + Cluster: + Fn::ImportValue: 'ecs-fargate-ws-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref PrivateA + - !Ref PrivateB + - !Ref PrivateC + ServiceName: !Ref Service + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 diff --git a/ql/test/library-tests/aws/cloudformation/lambda.yml b/ql/test/library-tests/aws/cloudformation/lambda.yml new file mode 100644 index 0000000..162edf6 --- /dev/null +++ b/ql/test/library-tests/aws/cloudformation/lambda.yml @@ -0,0 +1,21 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Security: Account Enable Guardduty' +Resources: + LambdaFunctionEnableGuardDuty: + Type: 'AWS::Lambda::Function' + Properties: + Code: + ZipFile: | + 'use strict'; + const AWS = require('aws-sdk'); + const response = require('cfn-response'); + Handler: 'index.handler' + MemorySize: 128 + Role: !GetAtt 'LambdaRole.Arn' + Runtime: 'nodejs16.x' + Tags: + - Key: 'wcar-service' + Value: 'provisioning-security-guardduty' + - Key: 'team' + Value: 'sec-ops' + Timeout: 120 \ No newline at end of file diff --git a/ql/test/library-tests/aws/cloudformation/securitygroup.yml b/ql/test/library-tests/aws/cloudformation/securitygroup.yml new file mode 100644 index 0000000..ffe3af1 --- /dev/null +++ b/ql/test/library-tests/aws/cloudformation/securitygroup.yml @@ -0,0 +1,16 @@ +AWSTemplateFormatVersion: "2010-09-09" +Metadata: + Description: 'AWS CloudFormation Template To fs2 messaging test' + +Resources: + SecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: "Vpc Security Group" + SecurityGroupEgress: + - IpProtocol: "tcp" + CidrIp: "0.0.0.0/0" + FromPort: 1337 + ToPort: 1337 + Description: "For RDS" + VpcId: !Ref VpcId diff --git a/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ContainerInsights.expected b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ContainerInsights.expected new file mode 100644 index 0000000..3ae18e1 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ContainerInsights.expected @@ -0,0 +1 @@ +| ecs.yml:41:5:47:2 | CloudFormation ECS Cluster | ECS Cluster should have cluster settings enabled | \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ContainerInsights.qlref b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ContainerInsights.qlref new file mode 100644 index 0000000..73c892c --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ContainerInsights.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/ContainerInsights.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ecs.yml new file mode 100644 index 0000000..febb0c7 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/ecs.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/something.tf b/ql/test/queries-tests/CloudFormation/ECS/ContainerInsights/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/LogConfiguration.expected b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/LogConfiguration.expected new file mode 100644 index 0000000..04b574b --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/LogConfiguration.expected @@ -0,0 +1 @@ +| ecs.yml:11:7:33:2 | CloudFormation Resource Properties | ContainerDefinitions must have a log configuration | \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/LogConfiguration.qlref b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/LogConfiguration.qlref new file mode 100644 index 0000000..725b86f --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/LogConfiguration.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/LogConfiguration.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/ecs.yml new file mode 100644 index 0000000..d885c52 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/ecs.yml @@ -0,0 +1,64 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/something.tf b/ql/test/queries-tests/CloudFormation/ECS/LogConfiguration/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/NetworkMode.expected b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/NetworkMode.expected new file mode 100644 index 0000000..7a0c9fb --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/NetworkMode.expected @@ -0,0 +1 @@ +| ecs.yml:9:5:42:2 | CloudFormation ECS Task Definition | ContainerDefinitions must not run as root or be privileged when networkmode Host is used | diff --git a/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/NetworkMode.qlref b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/NetworkMode.qlref new file mode 100644 index 0000000..e2d716c --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/NetworkMode.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/NetworkMode.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/ecs.yml new file mode 100644 index 0000000..94e5714 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/ecs.yml @@ -0,0 +1,73 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + User: 'root' + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + NetworkMode: 'host' + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/something.tf b/ql/test/queries-tests/CloudFormation/ECS/NetworkMode/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/NonPriv/NonPriv.expected b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/NonPriv.expected new file mode 100644 index 0000000..184828a --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/NonPriv.expected @@ -0,0 +1 @@ +| ecs.yml:11:7:40:2 | CloudFormation Resource Properties | ContainerDefinitions must be explictly configured privileged mode to false | \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/NonPriv/NonPriv.qlref b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/NonPriv.qlref new file mode 100644 index 0000000..1559cda --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/NonPriv.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/NonPriv.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/NonPriv/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/ecs.yml new file mode 100644 index 0000000..febb0c7 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/ecs.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/NonPriv/something.tf b/ql/test/queries-tests/CloudFormation/ECS/NonPriv/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/PidMode/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/PidMode/ecs.yml new file mode 100644 index 0000000..febb0c7 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PidMode/ecs.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/PidMode/pidmode.expected b/ql/test/queries-tests/CloudFormation/ECS/PidMode/pidmode.expected new file mode 100644 index 0000000..031a38c --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PidMode/pidmode.expected @@ -0,0 +1 @@ +| ecs.yml:9:5:40:2 | CloudFormation ECS Task Definition | PidMode should be "task" for ECS tasks | \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/PidMode/pidmode.qlref b/ql/test/queries-tests/CloudFormation/ECS/PidMode/pidmode.qlref new file mode 100644 index 0000000..984385f --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PidMode/pidmode.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/PidMode.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/PidMode/something.tf b/ql/test/queries-tests/CloudFormation/ECS/PidMode/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIP/PublicIP.expected b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/PublicIP.expected new file mode 100644 index 0000000..0c5bb23 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/PublicIP.expected @@ -0,0 +1 @@ +| ecs.yml:61:27:61:35 | 'ENABLED' | AssignPublicIp should be "DISABLED" for ECS tasks | \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIP/PublicIP.qlref b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/PublicIP.qlref new file mode 100644 index 0000000..bf35faa --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/PublicIP.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/PublicIP.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIP/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/ecs.yml new file mode 100644 index 0000000..febb0c7 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/ecs.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIP/something.tf b/ql/test/queries-tests/CloudFormation/ECS/PublicIP/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/PublicIPTaskSet.expected b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/PublicIPTaskSet.expected new file mode 100644 index 0000000..02f86ad --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/PublicIPTaskSet.expected @@ -0,0 +1 @@ +| ecs.yml:5:5:37:2 | CloudFormation ECS Task Set | AssignPublicIp must be "DISABLED" for ECS tasks | diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/PublicIPTaskSet.qlref b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/PublicIPTaskSet.qlref new file mode 100644 index 0000000..42cce83 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/PublicIPTaskSet.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/PublicIPTaskSet.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/ecs.yml new file mode 100644 index 0000000..e1a0a3b --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/ecs.yml @@ -0,0 +1,100 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' +Resources: + TaskSet: + Type: 'AWS::ECS::TaskSet' + Properties: + Cluster: !Ref 'Cluster' + Service: !Ref 'Service' + TaskDefinition: !Ref 'TaskDefinition' + LaunchType: 'FARGATE' + NetworkConfiguration: + AwsVpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref 'SecurityGroup' + Subnets: + - !Ref 'SubnetA' + - !Ref 'SubnetB' + - !Ref 'SubnetC' + LoadBalancers: + - ContainerName: !Ref 'ContainerName' + ContainerPort: !Ref 'ContainerPort' + TargetGroupArn: !Ref 'TargetGroup' + PlatformVersion: 'LATEST' + Scale: !Ref 'Scale' + ServiceRegistries: + - ContainerName: !Ref 'ContainerName' + ContainerPort: !Ref 'ContainerPort' + RegistryArn: !Ref 'ServiceDiscoveryRegistry' + HealthCheckGracePeriodSeconds: 90 + SchedulingStrategy: 'REPLICA' + ServiceDiscovery: !Ref 'ServiceDiscovery' + + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/something.tf b/ql/test/queries-tests/CloudFormation/ECS/PublicIPTaskSet/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ReadOnlyFileSystem.expected b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ReadOnlyFileSystem.expected new file mode 100644 index 0000000..c7538c6 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ReadOnlyFileSystem.expected @@ -0,0 +1 @@ +| ecs.yml:11:7:40:2 | CloudFormation Resource Properties | Containers must have explictly only read only root filesystem | \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ReadOnlyFileSystem.qlref b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ReadOnlyFileSystem.qlref new file mode 100644 index 0000000..9873b52 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ReadOnlyFileSystem.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/ReadOnlyRootFileSystem.ql \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ecs.yml new file mode 100644 index 0000000..febb0c7 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/ecs.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/something.tf b/ql/test/queries-tests/CloudFormation/ECS/ReadOnlyFileSystem/something.tf new file mode 100644 index 0000000..e69de29 diff --git a/ql/test/queries-tests/CloudFormation/ECS/Secrets/Secrets.expected b/ql/test/queries-tests/CloudFormation/ECS/Secrets/Secrets.expected new file mode 100644 index 0000000..f1a99c5 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/Secrets/Secrets.expected @@ -0,0 +1 @@ +| ecs.yml:27:13:31:6 | - Name: ... KEY_ID' | Containers must not pass secret thorugh environment variables | diff --git a/ql/test/queries-tests/CloudFormation/ECS/Secrets/Secrets.qlref b/ql/test/queries-tests/CloudFormation/ECS/Secrets/Secrets.qlref new file mode 100644 index 0000000..e7a27ce --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/Secrets/Secrets.qlref @@ -0,0 +1 @@ +security/CloudFormation/ECS/Secrets.ql diff --git a/ql/test/queries-tests/CloudFormation/ECS/Secrets/ecs.yml b/ql/test/queries-tests/CloudFormation/ECS/Secrets/ecs.yml new file mode 100644 index 0000000..febb0c7 --- /dev/null +++ b/ql/test/queries-tests/CloudFormation/ECS/Secrets/ecs.yml @@ -0,0 +1,71 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: 'Infrastructure for the ECS Fargate deployment pattern workshop service.' + +Resources: + #------------------------------------------------ + # ECS task definition + #------------------------------------------------ + ComponentTaskDefinition: + Type: 'AWS::ECS::TaskDefinition' + Properties: + ContainerDefinitions: + - Image: !Sub '${image}:${version}' + Name: !Ref Component + PortMappings: + - ContainerPort: 443 + LogConfiguration: + LogDriver: 'awslogs' + Options: + awslogs-create-group: true + awslogs-region: !Ref AWS::Region + awslogs-group: !Sub '/fargate/${Component}' + awslogs-stream-prefix: !Ref Component + Environment: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + Secrets: + # Normally mandatory (but e.g. SHORTNAME and FLAVOUR may not always be applicable) + - Name: 'AWS_ACCESS_KEY_ID' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-key-id + Name: 'AWS_SECRET_ACCESS_KEY' + ValueFrom: arn:aws:secretsmanager:region:account-id:secret:aws-secret-key + Cpu: 512 + ExecutionRoleArn: !GetAtt ComponentTaskDefinitionExecutionRole.Arn + TaskRoleArn: !GetAtt ComponentTaskDefinitionRole.Arn + Family: !Ref Component + Memory: 1024 + RequiresCompatibilities: + - 'FARGATE' + + + ClusterService: + Type: 'AWS::ECS::Cluster' + Properties: + ClusterName: !Sub 'group${UserPartition}-ecs-fargate-ws-cluster' + #------------------------------------------------ + # ECS Service + #------------------------------------------------ + ComponentEcsService: + Type: 'AWS::ECS::Service' + DependsOn: ListenerRule + Properties: + Cluster: + Fn::ImportValue: !Sub 'group$-ecs-fargate-cluster-arn' + DesiredCount: 1 + LaunchType: 'FARGATE' + LoadBalancers: + - ContainerName: !Ref Component + ContainerPort: !Ref ContainerPort + TargetGroupArn: !Ref ComponentTargetGroup + NetworkConfiguration: + AwsvpcConfiguration: + AssignPublicIp: 'ENABLED' + SecurityGroups: + - !Ref ComponentEcsServiceSecurityGroup + - !Ref CiSecurityGroupId + Subnets: + - !Ref Subnet1 + ServiceName: !Sub '${RegionalPrefix}-${Component}-${Version}-${Launch}' + TaskDefinition: !Ref ComponentTaskDefinition + PropagateTags: 'TASK_DEFINITION' + # Note: The value has been lowered from the recommended 180, for production use please choose this value wisely. + HealthCheckGracePeriodSeconds: 90 \ No newline at end of file diff --git a/ql/test/queries-tests/CloudFormation/ECS/Secrets/something.tf b/ql/test/queries-tests/CloudFormation/ECS/Secrets/something.tf new file mode 100644 index 0000000..e69de29