Skip to content

Commit

Permalink
Terraform module for Fargate orchestrator
Browse files Browse the repository at this point in the history
  • Loading branch information
achandras authored Dec 15, 2021
2 parents 1270930 + d67ec31 commit 31bd323
Show file tree
Hide file tree
Showing 15 changed files with 610 additions and 0 deletions.
90 changes: 90 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.

<!-- BEGIN_TF_DOCS -->
## Requirements

No requirements.

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 3.61.0 |
| <a name="provider_template"></a> [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 |
|------|-------------|------|---------|:--------:|
| <a name="input_access_key"></a> [access\_key](#input\_access\_key) | Sysdig access key | `string` | n/a | yes |
| <a name="input_agent_image"></a> [agent\_image](#input\_agent\_image) | Orchestrator agent image | `string` | `"quay.io/sysdig/orchestrator-agent:latest"` | no |
| <a name="input_agent_tags"></a> [agent\_tags](#input\_agent\_tags) | Comma separated list of tags for this agent | `string` | `""` | no |
| <a name="input_assign_public_ip"></a> [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 |
| <a name="input_check_collector_certificate"></a> [check\_collector\_certificate](#input\_check\_collector\_certificate) | Whether to check the collector certificate when connecting. Mainly for development. | `string` | `"true"` | no |
| <a name="input_collector_host"></a> [collector\_host](#input\_collector\_host) | Sysdig collector host | `string` | `"collector.sysdigcloud.com"` | no |
| <a name="input_collector_port"></a> [collector\_port](#input\_collector\_port) | Sysdig collector port | `string` | `"6443"` | no |
| <a name="input_default_tags"></a> [default\_tags](#input\_default\_tags) | Default tags for all Sysdig Fargate Orchestrator resources | `map(string)` | <pre>{<br> "Application": "sysdig",<br> "Module": "fargate-orchestrator-agent"<br>}</pre> | no |
| <a name="input_name"></a> [name](#input\_name) | Identifier for module resources | `string` | `"sysdig-fargate-orchestrator"` | no |
| <a name="input_orchestrator_port"></a> [orchestrator\_port](#input\_orchestrator\_port) | Port for the workload agent to connect | `number` | `6667` | no |
| <a name="input_subnets"></a> [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 |
| <a name="input_tags"></a> [tags](#input\_tags) | Extra tags for all Sysdig Fargate Orchestrator resources | `map(string)` | `{}` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | ID of the VPC where the orchestrator should be installed | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_orchestrator_host"></a> [orchestrator\_host](#output\_orchestrator\_host) | The DNS name of the orchestrator's load balancer |
| <a name="output_orchestrator_port"></a> [orchestrator\_port](#output\_orchestrator\_port) | The configured port on the orchestrator |
<!-- END_TF_DOCS -->
47 changes: 47 additions & 0 deletions container-definitions/orchestrator-agent.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
]
21 changes: 21 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -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=<name>' \
-var='sysdig_access_key=<sysdig_access_key>' \
-var='vpc_id=<vpc_id>' \
-var='subnets=["<subnet_a>", "<subnet_b>", ...]
```

After a few minutes, the orchestrator and workload should be up. You can see the workload logs with `aws logs tail <name> --follow` and the orchestrator logs using `aws logs tail <name>-orchestrator-logs --follow`, using the value you gave Terraform for `name`.

Clean up by running `terraform destroy`.
42 changes: 42 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
17 changes: 17 additions & 0 deletions example/provider.tf
Original file line number Diff line number Diff line change
@@ -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
}

92 changes: 92 additions & 0 deletions example/service.tf
Original file line number Diff line number Diff line change
@@ -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 = ["*"]
}
}
43 changes: 43 additions & 0 deletions example/variables.tf
Original file line number Diff line number Diff line change
@@ -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"
}
31 changes: 31 additions & 0 deletions loadbalancer.tf
Original file line number Diff line number Diff line change
@@ -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)
}
Loading

0 comments on commit 31bd323

Please sign in to comment.