falcosidekick

5 October 2023

In this article, Padok Security demonstrates how to implement Falco with Falcosidekick on an ECS cluster with EC2 launch type within AWS. This threat detection engine is useful for securing your ECS clusters to receive alerts in case of suspicious behavior.

Introduction to the tools

Falco

Falco is a cloud-native security solution striving to become the premier threat detection engine for Kubernetes. It identifies potential security risks in real time by closely observing and tracking the actions of various elements within your Kubernetes environment, including Nodes, Pods, Applications, and the Kubernetes API. In achieving this, Falco uses data from Linux system calls and Kubernetes Audit Logs.

If you're more interested in how Falco works, we delved into its workings in another article.

Falcosidekick

Falcosidekick is an open-source tool that retrieves all Falco events and forwards them to various possible outputs. For example, you can use Falcosidekick to receive alerts triggered by Falco on Slack or Opsgenie.

Deployment

Chosen implementation on ECS cluster with EC2 launch type

Deploying Falco with Falcosidekick on a Kubernetes cluster is very straightforward, thanks to the Helm chart "falcosecurity/falco." This Helm chart enables the deployment of a Falco instance on each node of the cluster with only a single instance of Falcosidekick that receives all the events. This schema explains the architecture on a Kubernetes cluster.

eks

In our case, we implemented Falco on an ECS cluster with EC2 launch type. In the EC2 launch type, the ECS cluster has a fleet of EC2 instances. Each EC2 instance can be likened to a node in Kubernetes on which tasks can be launched.

We've opted for a different strategy than the one explained for a Kubernetes cluster. We deploy one instance of Falco and one instance of Falcosidekick per EC2 instance.

ecs

We chose this approach because to have a single instance of Falcosidekick, we would need to establish inter-container communication across different EC2 instances. Unlike Kubernetes, there's no built-in internal DNS resolution to facilitate this communication in ECS. It is possible to implement, but it's technically more complex than the solution we've chosen. Furthermore, Falcosidekick has very low consumption, so it doesn't have much of a FinOps impact.

If you're interested in delving into inter-service communication on AWS ECS, you can refer to AWS documentation.

Terraform code

We used Terraform to deploy Falco and Falcosidekick.

  • You need to create a task definition (JSON file) that contains two containers: Falco and Falcosidekick.
[
  {
    "name": "falco",
    "image": "falcosecurity/falco:0.35.1",
    "essential": true,
    "cpu": 10,
    "memory": 512,
    "privileged": true,
    "mountPoints": [
      {
        "containerPath": "/host/var/run/docker.sock",
        "sourceVolume": "docker-socket"
      },
      {
        "containerPath": "/host/dev",
        "sourceVolume": "dev-fs"
      },
      {
        "containerPath": "/host/proc",
        "sourceVolume": "proc-fs",
        "readOnly": true
      },
      {
        "containerPath": "/host/boot",
        "sourceVolume": "boot-fs",
        "readOnly": true
      },
      {
        "containerPath": "/host/lib/modules",
        "sourceVolume": "lib-modules",
        "readOnly": true
      },
      {
        "containerPath": "/host/usr",
        "sourceVolume": "usr-fs",
        "readOnly": true
      },
      {
        "containerPath": "/host/etc",
        "sourceVolume": "etc-fs",
        "readOnly": true
      }
    ]
  },
  {
    "name": "falcosidekick",
    "image": "falcosecurity/falcosidekick:2.28.0",
    "essential": true,
    "cpu": 2,
    "memory": 126,
    "portMappings": [
      {
          "containerPort": 2801,
          "hostPort": 2801,
          "protocol": "tcp"
      }
    ],
    "environment": [
      {
          "name": "SLACK_WEBHOOKURL",
          "value": "https://hooks.slack.com/services/XXXX/YYYY/ZZZZ"
      }
    ]
  }
]

In the Falcosidekick definition, we've mapped port 2801, which needs to be accessible for Falco to send its events. We've also defined an environment variable SLACK_WEBHOOKURL to send logs to a Slack channel. You can refer to the Falcosidekick documentation for instructions on configuring other types of channel output using environment variables. You can also edit Falco configuration through environment variables in the task definition of Falco container.

  • Create an aws_ecs_cluster data to access ECS cluster from Terraform.
data "aws_ecs_cluster" "your-ecs-cluster" {
  cluster_name = "your-ecs-cluster-name"
}
  • Create an aws_ecs_task_definition resource, pointing to your task definition JSON file.
resource "aws_ecs_task_definition" "falco" {
  family                = "falco"
  container_definitions = file("path/to/your/task/definition/file.json")
  network_mode          = "host"

  volume {
    name      = "docker-socket"
    host_path = "/var/run/docker.sock"
  }

  volume {
    name      = "dev-fs"
    host_path = "/dev"
  }

  volume {
    name      = "proc-fs"
    host_path = "/proc"
  }

  volume {
    name      = "boot-fs"
    host_path = "/root"
  }

  volume {
    name      = "lib-modules"
    host_path = "/lib/modules"
  }

  volume {
    name      = "usr-fs"
    host_path = "/usr"
  }

  volume {
    name      = "etc-fs"
    host_path = "/etc"
  }

}

The "host" network mode is used to allow the containers within a task to share the network of the underlying EC2 host instance they run on. This is useful to facilitate easy communication between the Falco and Falcosidekick containers.

  • Finally, create an ECS service with the aws_ecs_service resource.
resource "aws_ecs_service" "falco" {
  name                = "falco"
  cluster             = aws_ecs_cluster.your-ecs-cluster.id
  task_definition     = aws_ecs_task_definition.falco.arn
  scheduling_strategy = "DAEMON"
}

The DAEMON scheduling strategy is used to ensure that precisely one task is launched on each EC2 instance.

Apply your terraform code and voilà! Falco should run on each of the EC2 instances within the cluster, and you should receive alerts on the configured output channel.

Custom rules

If you want to add custom rules to Falco, you can create a file (falco_rules.local.yaml) and copy it into the Falco Docker image. Here is an example of Dockerfile :

FROM falcosecurity/falco:0.35.1

COPY falco_rules.local.yaml /etc/falco/falco_rules.local.yaml

CMD ["/usr/bin/falco", "-pc"]

Then, push the Docker image in an ECR. Update the image in the task definition of the Falco container to your custom image.

Conclusion

Installing an intrusion detection system on your clusters is an excellent way to enhance the security of your infrastructure. We hope this tutorial has helped you in implementing Falco on ECS!