diff --git a/README.md b/README.md
index fe8ecb4..34de479 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,93 @@
# Sysdig Orchestrator Agent for ECS Fargate
This Terraform module deploys a Sysdig orchestrator agent for Fargate into a specified VPC.
+
+## Example
+
+The module can be created using the IDs of your VPC and two subnets capable of accessing the internet.
+
+```
+module "sysdig_orchestrator_agent" {
+ source = "../sysdig-orchestrator-agent"
+
+ name = "test-fargate-orchestrator"
+
+ vpc_id = var.my_vpc_id
+ subnet = [var.my_subnet_a, var.my_subnet_b_id]
+ access_key = var.my_sysdig_access_key
+ assign_public_ip = true # if using Internet Gateway
+}
+```
+
+The module outputs can be plugged into the Fargate workload agent data source in the [Sysdig Terraform provider](https://github.com/sysdiglabs/terraform-provider-sysdig):
+```
+data "sysdig_fargate_workload_agent" "instrumented" {
+ ...
+
+ orchestrator_host = module.sysdig_orchestrator_agent.orchestrator_host
+ orchestrator_port = module.sysdig_orchestrator_agent.orchestrator_port
+}
+```
+
+The resulting Terraform plan will have the Sysdig Orchestrator ECS service and a load balancer, as well as instrumented container JSON to use in your ECS Fargate task.
+
+
+## Requirements
+
+No requirements.
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | 3.61.0 |
+| [template](#provider\_template) | 2.2.0 |
+
+## Modules
+
+No modules.
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_cloudwatch_log_group.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
+| [aws_ecs_cluster.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |
+| [aws_ecs_service.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
+| [aws_ecs_task_definition.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |
+| [aws_iam_role.orchestrator_agent_execution_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
+| [aws_iam_role.orchestrator_agent_task_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
+| [aws_lb.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource |
+| [aws_lb_listener.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource |
+| [aws_lb_target_group.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource |
+| [aws_security_group.orchestrator_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
+| [aws_security_group_rule.orchestrator_agent_egress_rule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+| [aws_security_group_rule.orchestrator_agent_ingress_rule](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
+| [aws_region.current_region](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
+| [template_file.orchestrator_agent_container_definitions](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [access\_key](#input\_access\_key) | Sysdig access key | `string` | n/a | yes |
+| [agent\_image](#input\_agent\_image) | Orchestrator agent image | `string` | `"quay.io/sysdig/orchestrator-agent:latest"` | no |
+| [agent\_tags](#input\_agent\_tags) | Comma separated list of tags for this agent | `string` | `""` | no |
+| [assign\_public\_ip](#input\_assign\_public\_ip) | Provisions a public IP for the service. Required when using an Internet Gateway for egress. | `bool` | `false` | no |
+| [check\_collector\_certificate](#input\_check\_collector\_certificate) | Whether to check the collector certificate when connecting. Mainly for development. | `string` | `"true"` | no |
+| [collector\_host](#input\_collector\_host) | Sysdig collector host | `string` | `"collector.sysdigcloud.com"` | no |
+| [collector\_port](#input\_collector\_port) | Sysdig collector port | `string` | `"6443"` | no |
+| [default\_tags](#input\_default\_tags) | Default tags for all Sysdig Fargate Orchestrator resources | `map(string)` |
{
"Application": "sysdig",
"Module": "fargate-orchestrator-agent"
}
| no |
+| [name](#input\_name) | Identifier for module resources | `string` | `"sysdig-fargate-orchestrator"` | no |
+| [orchestrator\_port](#input\_orchestrator\_port) | Port for the workload agent to connect | `number` | `6667` | no |
+| [subnets](#input\_subnets) | A list of subnets that can access the internet and are reachable by instrumented services. The subnets must be in at least 2 different AZs. | `list(string)` | n/a | yes |
+| [tags](#input\_tags) | Extra tags for all Sysdig Fargate Orchestrator resources | `map(string)` | `{}` | no |
+| [vpc\_id](#input\_vpc\_id) | ID of the VPC where the orchestrator should be installed | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [orchestrator\_host](#output\_orchestrator\_host) | The DNS name of the orchestrator's load balancer |
+| [orchestrator\_port](#output\_orchestrator\_port) | The configured port on the orchestrator |
+
diff --git a/container-definitions/orchestrator-agent.json b/container-definitions/orchestrator-agent.json
new file mode 100644
index 0000000..19b7b4e
--- /dev/null
+++ b/container-definitions/orchestrator-agent.json
@@ -0,0 +1,47 @@
+[
+ {
+ "name": "OrchestratorAgent",
+ "image": "${agent_image}",
+ "portMappings": [
+ {
+ "hostPort": ${orchestrator_port},
+ "protocol": "tcp",
+ "containerPort": ${orchestrator_port}
+ }
+ ],
+ "environment": [
+ {
+ "name": "ACCESS_KEY",
+ "value": "${access_key}"
+ },
+ {
+ "name": "CHECK_CERTIFICATE",
+ "value": "${check_certificate}"
+ },
+ {
+ "name": "COLLECTOR",
+ "value": "${collector_host}"
+ },
+ {
+ "name": "COLLECTOR_PORT",
+ "value": "${collector_port}"
+ },
+ {
+ "name": "TAGS",
+ "value": "${agent_tags}"
+ },
+ {
+ "name": "ADDITIONAL_CONF",
+ "value": "agentino_port: ${orchestrator_port}"
+ }
+ ],
+ "logConfiguration": {
+ "logDriver": "awslogs",
+ "options": {
+ "awslogs-group": "${awslogs_group}",
+ "awslogs-region": "${awslogs_region}",
+ "awslogs-stream-prefix": "ecs"
+ }
+ }
+ }
+]
diff --git a/example/README.md b/example/README.md
new file mode 100644
index 0000000..edb9574
--- /dev/null
+++ b/example/README.md
@@ -0,0 +1,21 @@
+# Example
+
+This example uses the Sysdig Fargate Orchestrator module along with the Sysdig Terraform provider to deploy an instrumented ECS Task that is performing a suspicious activity.
+
+## Usage
+
+Initialize the state using `terraform init`
+
+Run `terraform apply`. Enter your values for the required variables.
+
+```
+terraform apply \
+ -var='name=' \
+ -var='sysdig_access_key=' \
+ -var='vpc_id=' \
+ -var='subnets=["", "", ...]
+```
+
+After a few minutes, the orchestrator and workload should be up. You can see the workload logs with `aws logs tail --follow` and the orchestrator logs using `aws logs tail -orchestrator-logs --follow`, using the value you gave Terraform for `name`.
+
+Clean up by running `terraform destroy`.
diff --git a/example/main.tf b/example/main.tf
new file mode 100644
index 0000000..9201309
--- /dev/null
+++ b/example/main.tf
@@ -0,0 +1,42 @@
+module "sysdig_orchestrator_agent" {
+ source = "../"
+
+ name = "${var.name}-orchestrator"
+
+ vpc_id = var.vpc_id
+ subnets = var.subnets
+ collector_host = "collector-staging2.sysdigcloud.com"
+ collector_port = "6443"
+ access_key = var.sysdig_access_key
+ assign_public_ip = true
+}
+
+data "sysdig_fargate_workload_agent" "instrumented" {
+ container_definitions = jsonencode([
+ {
+ "image": "quay.io/rehman0288/busyboxplus:latest",
+ "name": "busybox",
+ "EntryPoint": [
+ "watch",
+ "-n60",
+ "cat",
+ "/etc/shadow"
+ ],
+ "logConfiguration": {
+ "logDriver": "awslogs",
+ "options": {
+ "awslogs-group": var.name,
+ "awslogs-region": "us-east-1",
+ "awslogs-stream-prefix": "ecs"
+ }
+ }
+ }
+ ])
+
+ sysdig_access_key = var.sysdig_access_key
+
+ workload_agent_image = var.sysdig_workload_agent_image
+
+ orchestrator_host = module.sysdig_orchestrator_agent.orchestrator_host
+ orchestrator_port = module.sysdig_orchestrator_agent.orchestrator_port
+}
diff --git a/example/provider.tf b/example/provider.tf
new file mode 100644
index 0000000..b379679
--- /dev/null
+++ b/example/provider.tf
@@ -0,0 +1,17 @@
+terraform {
+ required_providers {
+ sysdig = {
+ source = "sysdiglabs/sysdig"
+ version = ">= 0.4.0"
+ }
+ }
+}
+
+provider "aws" {
+ region = "us-east-1"
+}
+
+provider "sysdig" {
+ sysdig_secure_api_token = var.sysdig_access_key
+}
+
diff --git a/example/service.tf b/example/service.tf
new file mode 100644
index 0000000..cecc395
--- /dev/null
+++ b/example/service.tf
@@ -0,0 +1,92 @@
+resource "aws_ecs_cluster" "example_cluster" {
+ name = var.name
+}
+
+resource "aws_cloudwatch_log_group" "example_logs" {
+ name = var.name
+}
+
+resource "aws_iam_role" "example_execution_role" {
+ assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
+
+ managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
+}
+
+resource "aws_iam_role" "example_task_role" {
+ assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
+
+ inline_policy {
+ name = "root"
+ policy = data.aws_iam_policy_document.task_policy.json
+ }
+}
+
+resource "aws_security_group" "example_security_group" {
+ description = "Allow workload to reach internet"
+ vpc_id = var.vpc_id
+}
+
+resource "aws_security_group_rule" "example_egress_rule" {
+ type = "egress"
+ protocol = "all"
+ from_port = 0
+ to_port = 0
+ cidr_blocks = [ "0.0.0.0/0" ]
+ security_group_id = aws_security_group.example_security_group.id
+}
+
+resource "aws_ecs_task_definition" "example_task_definition" {
+ family = var.name
+ task_role_arn = aws_iam_role.example_task_role.arn
+ execution_role_arn = aws_iam_role.example_execution_role.arn
+
+ cpu = "256"
+ memory = "1024"
+ network_mode = "awsvpc"
+ requires_compatibilities = ["FARGATE"]
+
+ container_definitions = data.sysdig_fargate_workload_agent.instrumented.output_container_definitions
+}
+
+resource "aws_ecs_service" "example_service" {
+ name = var.name
+
+ cluster = aws_ecs_cluster.example_cluster.id
+ task_definition = aws_ecs_task_definition.example_task_definition.arn
+ desired_count = 1
+ launch_type = "FARGATE"
+ platform_version = "1.4.0"
+
+ network_configuration {
+ subnets = var.subnets
+ security_groups = [ aws_security_group.example_security_group.id ]
+ assign_public_ip = true
+ }
+}
+
+data "aws_iam_policy_document" "assume_role_policy" {
+ statement {
+ actions = ["sts:AssumeRole"]
+
+ principals {
+ type = "Service"
+ identifiers = ["ecs-tasks.amazonaws.com"]
+ }
+ }
+}
+
+data "aws_iam_policy_document" "task_policy" {
+ statement {
+ actions = [
+ "ecr:GetAuthorizationToken",
+ "ecr:BatchCheckLayerAvailability",
+ "ecr:GetDownloadUrlForLayer",
+ "ecr:BatchGetImage",
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ]
+
+ resources = ["*"]
+ }
+}
diff --git a/example/variables.tf b/example/variables.tf
new file mode 100644
index 0000000..51b0fd5
--- /dev/null
+++ b/example/variables.tf
@@ -0,0 +1,43 @@
+#
+# Required variables
+#
+variable "name" {
+ description = "Identifier for module resources"
+ type = string
+}
+
+variable "vpc_id" {
+ description = "ID of the VPC where the orchestrator should be installed"
+ type = string
+}
+
+variable "subnets" {
+ description = "A list of subnets that can access the internet and are reachable by instrumented services. The subnets must be in at least 2 different AZs."
+ type = list(string)
+}
+
+variable "sysdig_access_key" {
+ description = "Sysdig access key"
+ type = string
+}
+
+#
+# Optional variables
+#
+variable "sysdig_workload_agent_image" {
+ description = "Workload agent image"
+ type = string
+ default = "quay.io/sysdig/workload-agent:latest"
+}
+
+variable "collector_host" {
+ description = "Sysdig collector host"
+ type = string
+ default = "collector.sysdigcloud.com"
+}
+
+variable "collector_port" {
+ description = "Sysdig collector port"
+ type = string
+ default = "6443"
+}
diff --git a/loadbalancer.tf b/loadbalancer.tf
new file mode 100644
index 0000000..1076831
--- /dev/null
+++ b/loadbalancer.tf
@@ -0,0 +1,31 @@
+resource "aws_lb" "orchestrator_agent" {
+ internal = true
+ load_balancer_type = "network"
+ ip_address_type = "ipv4"
+ subnets = var.subnets
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+resource "aws_lb_target_group" "orchestrator_agent" {
+ port = var.orchestrator_port
+ protocol = "TCP"
+ target_type = "ip"
+ deregistration_delay = 60
+ vpc_id = var.vpc_id
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+resource "aws_lb_listener" "orchestrator_agent" {
+ load_balancer_arn = aws_lb.orchestrator_agent.arn
+ port = var.orchestrator_port
+ protocol = "TCP"
+
+ default_action {
+ type = "forward"
+ target_group_arn = aws_lb_target_group.orchestrator_agent.arn
+ }
+
+ tags = merge(var.tags, var.default_tags)
+}
diff --git a/main.tf b/main.tf
new file mode 100644
index 0000000..2c52d68
--- /dev/null
+++ b/main.tf
@@ -0,0 +1,29 @@
+resource "aws_ecs_cluster" "orchestrator_agent" {
+ name = "${var.name}-cluster"
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+resource "aws_cloudwatch_log_group" "orchestrator_agent" {
+ name = "${var.name}-logs"
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+data "template_file" "orchestrator_agent_container_definitions" {
+ template = file("${path.module}/container-definitions/orchestrator-agent.json")
+
+ vars = {
+ agent_image = var.agent_image
+ access_key = var.access_key
+ collector_host = var.collector_host
+ collector_port = var.collector_port
+ agent_tags = var.agent_tags
+ check_certificate = var.check_collector_certificate
+ orchestrator_port = var.orchestrator_port
+ awslogs_region = data.aws_region.current_region.name
+ awslogs_group = "${var.name}-logs"
+ }
+}
+
+data "aws_region" "current_region" {}
diff --git a/outputs.tf b/outputs.tf
new file mode 100644
index 0000000..82fea94
--- /dev/null
+++ b/outputs.tf
@@ -0,0 +1,9 @@
+output "orchestrator_host" {
+ description = "The DNS name of the orchestrator's load balancer"
+ value = aws_lb.orchestrator_agent.dns_name
+}
+
+output "orchestrator_port" {
+ description = "The configured port on the orchestrator"
+ value = var.orchestrator_port
+}
diff --git a/roles.tf b/roles.tf
new file mode 100644
index 0000000..170fa93
--- /dev/null
+++ b/roles.tf
@@ -0,0 +1,45 @@
+resource "aws_iam_role" "orchestrator_agent_execution_role" {
+ assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
+
+ managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+resource "aws_iam_role" "orchestrator_agent_task_role" {
+ assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
+
+ inline_policy {
+ name = "root"
+ policy = data.aws_iam_policy_document.task_policy.json
+ }
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+data "aws_iam_policy_document" "assume_role_policy" {
+ statement {
+ actions = ["sts:AssumeRole"]
+
+ principals {
+ type = "Service"
+ identifiers = ["ecs-tasks.amazonaws.com"]
+ }
+ }
+}
+
+data "aws_iam_policy_document" "task_policy" {
+ statement {
+ actions = [
+ "ecr:GetAuthorizationToken",
+ "ecr:BatchCheckLayerAvailability",
+ "ecr:GetDownloadUrlForLayer",
+ "ecr:BatchGetImage",
+ "logs:CreateLogGroup",
+ "logs:CreateLogStream",
+ "logs:PutLogEvents",
+ ]
+
+ resources = ["*"]
+ }
+}
diff --git a/security-group.tf b/security-group.tf
new file mode 100644
index 0000000..72ebf6c
--- /dev/null
+++ b/security-group.tf
@@ -0,0 +1,24 @@
+resource "aws_security_group" "orchestrator_agent" {
+ description = "Allow agentino to connect"
+ vpc_id = var.vpc_id
+
+ tags = merge(var.tags, var.default_tags)
+}
+
+resource "aws_security_group_rule" "orchestrator_agent_ingress_rule" {
+ type = "ingress"
+ protocol = "tcp"
+ from_port = var.orchestrator_port
+ to_port = var.orchestrator_port
+ cidr_blocks = [ "0.0.0.0/0" ]
+ security_group_id = aws_security_group.orchestrator_agent.id
+}
+
+resource "aws_security_group_rule" "orchestrator_agent_egress_rule" {
+ type = "egress"
+ protocol = "all"
+ from_port = 0
+ to_port = 0
+ cidr_blocks = [ "0.0.0.0/0" ]
+ security_group_id = aws_security_group.orchestrator_agent.id
+}
diff --git a/service.tf b/service.tf
new file mode 100644
index 0000000..98bddd6
--- /dev/null
+++ b/service.tf
@@ -0,0 +1,25 @@
+resource "aws_ecs_service" "orchestrator_agent" {
+ name = "OrchestratorAgent"
+ cluster = aws_ecs_cluster.orchestrator_agent.id
+ task_definition = aws_ecs_task_definition.orchestrator_agent.arn
+ desired_count = 1
+ launch_type = "FARGATE"
+ platform_version = "1.4.0"
+ depends_on = [ aws_lb_listener.orchestrator_agent ]
+
+ load_balancer {
+ target_group_arn = aws_lb_target_group.orchestrator_agent.arn
+ container_name = "OrchestratorAgent"
+ container_port = var.orchestrator_port
+ }
+
+ network_configuration {
+ subnets = var.subnets
+
+ security_groups = [ aws_security_group.orchestrator_agent.id ]
+
+ assign_public_ip = var.assign_public_ip
+ }
+
+ tags = merge(var.tags, var.default_tags)
+}
diff --git a/task.tf b/task.tf
new file mode 100644
index 0000000..fa3868b
--- /dev/null
+++ b/task.tf
@@ -0,0 +1,12 @@
+resource "aws_ecs_task_definition" "orchestrator_agent" {
+ family = "${var.name}-orchestrator-agent"
+ task_role_arn = "${aws_iam_role.orchestrator_agent_task_role.arn}"
+ execution_role_arn = "${aws_iam_role.orchestrator_agent_execution_role.arn}"
+ network_mode = "awsvpc"
+ requires_compatibilities = ["FARGATE"]
+ cpu = "2048"
+ memory = "8192"
+ container_definitions = data.template_file.orchestrator_agent_container_definitions.rendered
+
+ tags = merge(var.tags, var.default_tags)
+}
diff --git a/variables.tf b/variables.tf
new file mode 100644
index 0000000..003b1ff
--- /dev/null
+++ b/variables.tf
@@ -0,0 +1,83 @@
+#
+# Required variables
+#
+variable "name" {
+ description = "Identifier for module resources"
+ type = string
+ default = "sysdig-fargate-orchestrator"
+}
+
+variable "vpc_id" {
+ description = "ID of the VPC where the orchestrator should be installed"
+ type = string
+}
+
+variable "access_key" {
+ description = "Sysdig access key"
+ type = string
+}
+
+variable "subnets" {
+ description = "A list of subnets that can access the internet and are reachable by instrumented services. The subnets must be in at least 2 different AZs."
+ type = list(string)
+}
+
+#
+# Optional variables
+#
+variable "orchestrator_port" {
+ description = "Port for the workload agent to connect"
+ type = number
+ default = 6667
+}
+
+variable "agent_image" {
+ description = "Orchestrator agent image"
+ type = string
+ default = "quay.io/sysdig/orchestrator-agent:latest"
+}
+
+variable "collector_host" {
+ description = "Sysdig collector host"
+ type = string
+ default = "collector.sysdigcloud.com"
+}
+
+variable "collector_port" {
+ description = "Sysdig collector port"
+ type = string
+ default = "6443"
+}
+
+variable "agent_tags" {
+ description = "Comma separated list of tags for this agent"
+ type = string
+ default = ""
+}
+
+variable "check_collector_certificate" {
+ description = "Whether to check the collector certificate when connecting. Mainly for development."
+ type = string
+ default = "true"
+}
+
+variable "assign_public_ip" {
+ description = "Provisions a public IP for the service. Required when using an Internet Gateway for egress."
+ type = bool
+ default = false
+}
+
+variable "tags" {
+ description = "Extra tags for all Sysdig Fargate Orchestrator resources"
+ type = map(string)
+ default = {}
+}
+
+variable "default_tags" {
+ description = "Default tags for all Sysdig Fargate Orchestrator resources"
+ type = map(string)
+ default = {
+ Application = "sysdig"
+ Module = "fargate-orchestrator-agent"
+ }
+}