AWS Open Source Blog

Securing Amazon EKS Using Lambda and Falco

中文版

Intrusion and abnormality detection are important tools for stronger run-time security in applications deployed in containers on Amazon EKS clusters. In this post, Michael Ducy of Sysdig explains how Falco, a CNCF Sandbox Project, generates an alert when an abnormal application behavior is detected. AWS Lambda functions can then be configured to pass those alert messages to Slack.

Arun


Securing Amazon Elastic Container Service for Kubernetes (Amazon EKS) clusters on Amazon Web Services (AWS) can take many forms. AWS provides several options, including virtual private clouds (VPCs), which allow the traditional networking controls of Security Groups and Network ACLs. Amazon EKS also supports IAM authentication, which ties directly into the Kubernetes RBAC system. On top of these features, AWS isolates the nodes running your EKS cluster from other customers.

Even with all of these powerful features, additional security layers can still be important. Falco, an open source CNCF Sandbox project from Sysdig, detects abnormal behavior in your EKS cluster and applications deployed to that cluster, to provide an extra level of security.

Coupled with AWS services such as Amazon Simple Notification Service (Amazon SNS) and AWS Lambda, Falco actively protects your EKS cluster by deleting compromised containers, tainting EKS nodes to prevent new workloads from being scheduled, and notifying teams via a messaging system such as Slack.

Runtime Security with Falco

Falco provides runtime security for containerized applications and their underlying host systems. By instrumenting the Linux kernel of the container host, Falco is able to create an event stream from the system calls made by containers and the host. Rules can then be applied to this event stream to detect abnormal behavior.

For example, here’s a rule that detects any process attempting to read a secret after a container has already started (secrets should only be read at startup):

- macro: proc_is_new
 condition: proc.duration <= 5000000000

- rule: Read secret file after startup
 desc: >
   an attempt to read any secret file (e.g. files containing user/password/authentication
   information) Processes might read these files at startup, but not afterwards.
 condition: fd.name startswith /etc/secrets and open_read and not proc_is_new
 output: >
   Sensitive file opened for reading after startup (user=%user.name
   command=%proc.cmdline file=%fd.name)
 priority: WARNING

Falco will also pull metadata information from underlying container runtimes and orchestrators including Docker and Kubernetes. This metadata can be implemented in Falco rules to restrict certain behaviors depending on the container image, the container name, or the particular Kubernetes resource such as pod, deployment, service, or namespace.

Falco diagram
When Falco detects an abnormal event, it will fire an alert to a destination. Possible destinations include stdout, a log file, Syslog, or triggering a program that passes the alert as stdin. By leveraging a sidecar container in Kubernetes, you can expand these destinations to include messaging services like AWS Simple Notification Service (SNS). Alerts published to SNS can then trigger other services that are subscribed to the Falco alerts, such as an AWS Lambda function.

Deploying Falco with SNS Support

The easiest way to get started with Falco is to leverage the Helm chart that Falco provides. Helm is a package manager for Kubernetes that provides a rich library of applications. Helm also allows you set options for an application that are specific to your particular environment. In order to install Helm you’ll need a Helm binary for your workstation, and you’ll need to install Helm on your EKS cluster.

$ brew install kubernetes-helm # For macOS users with Homebrew installed

$ kubectl -n kube-system create sa tiller
$ kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller
$ helm init --service-account tiller

Once Helm is installed, installing Falco with SNS support is simple:

$ helm install --name sysdig-falco-1 \
--set integrations.snsOutput.enabled=true \
--set integrations.snsOutput.topic=SNS_TOPIC \
--set integrations.snsOutput.aws_access_key_id=AWS_ACCESS_KEY_ID \
--set integrations.snsOutput.aws_secret_access_key=AWS_SECRET_ACCESS_KEY \
--set integrations.snsOutput.aws_default_region=AWS_DEFAULT_REGION \
stable/falco

Adjust SNS_TOPIC, AWS_ACCESS_KEY_ID, AWS_SECRET_KEY, and AWS DEFAULT_REGION to the settings appropriate for your EKS deployment, and Falco will begin publishing any alerts to the SNS topic you’ve specified.

Creating a Role for Our Lambda Functions

EKS provides the ability to authenticate users and service accounts via AWS IAM. In order to have our Lambda function interact with EKS to delete pods or perform other actions based on a Falco alert, we will create an IAM role for a service account. Kubernetes will verify that the IAM service account is a valid user, then use the internal Kubernetes RBAC functionality to restrict what the service account can do inside our cluster.

IAM for Lambda summary screen

Here we’ve created an IAM role for our Lambda function. We then need to create a trust relationship between the IAM role and a user that has permissions to authenticate to the cluster. For this environment, we will create a user in IAM called kubernetes-response-engine. We will leave the permissions empty for the user, which will allow it to authenticate as a valid user to Kubernetes, but not create or modify objects in our AWS account. We can then map that user to the IAM role as shown below.

IAM for Lambda summary screen

We also need to create (or update) a configmap in Kubernetes for the aws-iam-authenticator to use to map our IAM role to a user Kubernetes user. This configmap may already exist if you’ve followed the AWS guide on launching worker nodes. You can run kubectl desc configmap aws-auth to get any existing configmap. If a configmap does exist, you’ll want to merge the data sections from the existing configmap and the below configmap.

apiVersion: v1
kind: ConfigMap
metadata:
 name: aws-auth
 namespace: kube-system
data:
 mapRoles: |
    - rolearn: arn:aws:iam::<ARN From IAM>:role/iam_for_lambda
      username: kubernetes-response-engine
      groups:
        - system:masters

Finally, we need to add roles to the Kubernetes RBAC system to allow the Lambda function to take action on the Kubernetes cluster. We’ve included the required yaml for the cluster roles and cluster role bindings in the Falco Github repository.

$ git clone https://github.com/falcosecurity/falco.git
$ cd integrations/kubernetes-response-engine/deployment/aws
$ kubectl apply -f cluster-role.yaml cluster-role-binding.yaml

Deploying Lambda Functions to React to Falco Alerts

Now that we’re publishing Falco alerts to an SNS topic, we can deploy Lambda functions to react to those alerts. To get started, check out the examples in the Falco GitHub repository.

After cloning the repo, navigate to the integrations/kubernetes-response-engine/playbooks directory. In order to deploy our function to Lambda, we need to package up the function and any dependencies as a zip file. Since the function is written in Python, you’ll need a basic Python environment, as well as pip and pipenv.

First, generate a requirements.txt that contains the list of Python libraries required to run your Lambda function. This can be done with pipenv:

$ pipenv lock --requirements | sed '/^-/ d' > requirements.txt

Now that the dependencies have been defined, pip can pull these dependencies down to a local directory. Since we want to push messages to Slack using Lambda, we will also copy in the slack.py function, which will fire when Falco sends an alert:

$ mkdir -p lambda
$ pip install -t lambda -r requirements.txt
$ pip install -t lambda  .
$ cp functions/slack.py lambda/

With the dependencies and function now in a single directory, all that’s left to do is create a zip file to deploy to AWS Lambda:

$ cd lambda
$ zip ../slack.zip  -r *
$ cd ..

The code is packaged up and we can create the Lambda function using the AWS CLI. You’ll need to replace the --role value with the correct ID for the role you created earlier as well as replace the Slack webhook URL with the URL for the channel to which you wish to post your Falco messages:

$ aws lambda create-function \
 --function-name falco-slack \
 --runtime python2.7 \
 --role <arn:aws:iam::XXXxxXXX:role/iam_for_lambda> \
 --environment Variables=”SLACK_WEBHOOK_URL=https://<custom_slack_app_url>” \
 --handler slack.handler \
 --zip-file fileb://./slack.zip

Deploying Functions to Act on EKS

Besides sending messages to Slack, AWS Lambda can be used to take action on your EKS clusters. You can find these functions in the integrations/kubernetes-response-engine/playbooks/functions directory.

Using the instructions above to pull the function’s dependencies, replace functions/slack.py with the function you want to deploy instead. In order to allow these Lambda functions to communicate with EKS, we’ll need to generate a kubeconfig file which contains info about our cluster.

$ aws eks update-kubeconfig --name <cluster-name> --kubeconfig lambda/kubeconfig

$ sed -i "s/command: aws-iam-authenticator/command: .\/aws-iam-authenticator/g" lambda/kubeconfig

We also need to copy in the aws-iam-authenticator which allows the Lambda function to authenticate back to IAM to operate on the EKS cluster. Then we’ll be able to create our zip file as before:

$ cp extra/aws-iam-authenticator lambda/
$ cd lambda
$ zip ../delete.zip  -r *
$ cd ..

To deploy the function, we’ll finally need to specify the location of the kubeconfig file and whether we want to load it in our function:

$ aws lambda create-function \
 --function-name falco-delete \
 --runtime python2.7 \
 --role <arn:aws:iam::XXXxxXXX:role/iam_for_lambda> \
 --environment Variables=”KUBECONFIG=kubeconfig,KUBERNETES_LOAD_KUBE_CONFIG=1” \
 --handler delete.handler \
 --zip-file fileb://./delete.zip

Tying Together SNS and Lambda

Now that we have Falco publishing to SNS and a function in Lambda to react to the alerts, we need to wire together the SNS topic and function. This can be done easily via the AWS console.

Navigate to the Lambda service and select the falco-slack function. In the designer, you can add triggers by selecting them from the left pane. Scroll down and click SNS to add the trigger. Under Configure triggers, search for the SNS topic we created earlier, ensure that Enable trigger is selected, and save the function.

setting up Falco-Slack

Triggering a Falco alert will now publish the alert to SNS, fire our Lambda function, and post the alert to Slack.

Slack alerts
Updating Function Subscriptions

The Lambda functions might not need to fire for every single event published to SNS. For instance, if a function deletes a pod, we would only want the function to fire on critical alerts. To control which alerts a function fires on, we can update the functions subscription.

In the AWS SNS console, select Subscription, then edit the filter policy for the function’s subscription.

Edit subscription filter policy

Create a JSON object and set the filter policy. Now the Lambda function will only fire when an alert of “Error” or “Warning” is received.

Get Involved with Falco

We hope this helps you integrate Falco runtime security with Amazon Web Services to build a security stack that fits your needs.

If you did find this helpful and wish to contribute to the Falco project, here are several ways to do so:

Michael Ducy

Michael Ducy

As director of community and evangelism at Sysdig, Michael Ducy is responsible for increasing adoption of Sysdig’s open source solutions. He is in charge of Falco, the behavioral activity monitoring tool from Sysdig that is quickly becoming the most popular open source container runtime security choice for cloud-native platforms built with Kubernetes, Cloud Foundry, and OpenShift.

Prior to joining Sysdig, Michael worked in community and evangelism at Chef and has held positions in systems architecture, systems engineering, and performance engineering at leading technology companies.

Michael holds an MS in computer science from the University of Chicago and an MBA from The Ohio State University.

The content and opinions in this post are those of the third-party author and AWS is not responsible for the content or accuracy of this post.

Arun Gupta

Arun Gupta

Arun Gupta is a former a Principal Open Source Technologist at Amazon Web Services. He has built and led developer communities for 12+ years at Sun, Oracle, Red Hat, and Couchbase. He has extensive speaking experience in more than 40 countries on myriad topics and is a JavaOne Rock Star for four years in a row. Gupta also founded the Devoxx4Kids chapter in the US and continues to promote technology education among children. A prolific blogger, author of several books, an avid runner, a globe trotter, a Docker Captain, a Java Champion, a JUG leader, NetBeans Dream Team member, he is easily accessible at @arungupta.