Skip to content

Commit

Permalink
Merge pull request #390 from nestorsalceda/anchore-falco
Browse files Browse the repository at this point in the history
Add integration between Falco and Anchore
  • Loading branch information
bencer authored Jul 12, 2018
2 parents c5523d8 + 46b0fd8 commit ec0c109
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 0 deletions.
13 changes: 13 additions & 0 deletions integrations/anchore-falco/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM python:3-stretch

RUN pip install pipenv

WORKDIR /app

ADD Pipfile /app/Pipfile
ADD Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy

ADD . /app

CMD ["python", "main.py"]
16 changes: 16 additions & 0 deletions integrations/anchore-falco/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]
doublex-expects = "==0.7.0rc2"
doublex = "*"
mamba = "*"
expects = "*"

[packages]
requests = "*"

[requires]
python_version = "3.6"
156 changes: 156 additions & 0 deletions integrations/anchore-falco/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

89 changes: 89 additions & 0 deletions integrations/anchore-falco/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Create Falco rule from Anchore policy result

This integration creates a rule for Sysdig Falco based on Anchore policy result.
So that when we will try to run an image which has a ```stop``` final action result
in Anchore, Falco will alert us.

## Getting started

### Prerequisites

For running this integration you will need:

* Python 3.6
* pipenv
* An [anchore-engine](https://github.com/anchore/anchore-engine) running

### Configuration

This integration uses the [same environment variables that anchore-cli](https://github.com/anchore/anchore-cli#configuring-the-anchore-cli):

* ANCHORE_CLI_USER: The user used to conect to anchore-engine. By default is ```admin```
* ANCHORE_CLI_PASS: The password used to connect to anchore-engine.
* ANCHORE_CLI_URL: The url where anchore-engine listens. Make sure does not end with a slash. By default is ```http://localhost:8228/v1```
* ANCHORE_CLI_SSL_VERIFY: Flag for enabling if HTTP client verifies SSL. By default is ```true```

### Running

This is a Python program which generates a Falco rule based on anchore-engine
information:

```
pipenv run python main.py
```

And this will output something like:


```yaml
- macro: anchore_stop_policy_evaluation_containers
condition: container.image.id in ("8626492fecd368469e92258dfcafe055f636cb9cbc321a5865a98a0a6c99b8dd", "e86d9bb526efa0b0401189d8df6e3856d0320a3d20045c87b4e49c8a8bdb22c1")

- rule: Run Anchore Containers with Stop Policy Evaluation
desc: Detect containers which does not receive a positive Policy Evaluation from Anchore Engine.

condition: evt.type=execve and proc.vpid=1 and container and anchore_stop_policy_evaluation_containers
output: A stop policy evaluation container from anchore has started (%container.info image=%container.image)
priority: INFO
tags: [container]
```
You can save that output to ```/etc/falco/rules.d/anchore-integration-rules.yaml```
and Falco will start checking this rule.

As long as information in anchore-engine can change, it's a good idea to run this
integration **periodically** and keep the rule synchronized with anchore-engine
policy evaluation result.

## Tests

As long as there are contract tests with anchore-engine, it needs a working
anchore-engine and its environment variables.

```
pipenv install -d
pipenv run mamba --format=documentation
```
## Docker support
### Build the image
```
docker build -t sysdig/anchore-falco .
```
### Running the image
An image exists on DockerHub, its name is ```sysdig/anchore-falco```.
So you can run directly with Docker:
```
docker run --rm -e ANCHORE_CLI_USER=<user-for-custom-anchore-engine> \
-e ANCHORE_CLI_PASS=<passsword-for-user-for-custom-anchore-engine> \
-e ANCHORE_CLI_URL=http://<custom-anchore-engine-host>:8228/v1 \
sysdig/anchore-falco
```
And this will output the Falco rule based on *custom-anchore-engine-host*.
25 changes: 25 additions & 0 deletions integrations/anchore-falco/actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import string

FALCO_RULE_TEMPLATE = string.Template('''
- macro: anchore_stop_policy_evaluation_containers
condition: container.image.id in ($images)
- rule: Run Anchore Containers with Stop Policy Evaluation
desc: Detect containers which does not receive a positive Policy Evaluation from Anchore Engine.
condition: evt.type=execve and proc.vpid=1 and container and anchore_stop_policy_evaluation_containers
output: A stop policy evaluation container from anchore has started (%container.info image=%container.image)
priority: INFO
tags: [container]
''')


class CreateFalcoRuleFromAnchoreStopPolicyResults:
def __init__(self, anchore_client):
self._anchore_client = anchore_client

def run(self):
images = self._anchore_client.get_images_with_policy_result('stop')

images = ['"{}"'.format(image) for image in images]
return FALCO_RULE_TEMPLATE.substitute(images=', '.join(images))
39 changes: 39 additions & 0 deletions integrations/anchore-falco/infrastructure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import requests


class AnchoreClient:
def __init__(self, user, password, url, ssl_verify):
self._user = user
self._password = password
self._url = url
self._ssl_verify = ssl_verify

def get_images_with_policy_result(self, policy_result):
results = []
for image in self._get_all_images():
final_action = self._evaluate_image(image)

if final_action == 'stop':
results.append(image['image_id'])

return results

def _get_all_images(self):
response = self._do_get_request(self._url + '/images')
return [
{
'image_id': image['image_detail'][0]['imageId'],
'image_digest': image['image_detail'][0]['imageDigest'],
'full_tag': image['image_detail'][0]['fulltag']
} for image in response.json()]

def _do_get_request(self, url):
return requests.get(url,
auth=(self._user, self._password),
verify=self._ssl_verify,
headers={'Content-Type': 'application/json'})

def _evaluate_image(self, image):
response = self._do_get_request(self._url + '/images/{}/check?tag={}'.format(image['image_digest'], image['full_tag']))
if response.status_code == 200:
return response.json()[0][image['image_digest']][image['full_tag']][0]['detail']['result']['final_action']
21 changes: 21 additions & 0 deletions integrations/anchore-falco/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import os

import actions, infrastructure


def main():
anchore_client = infrastructure.AnchoreClient(
os.environ.get('ANCHORE_CLI_USER', 'admin'),
os.environ['ANCHORE_CLI_PASS'],
os.environ.get('ANCHORE_CLI_URL', 'http://localhost:8228/v1'),
os.environ.get('ANCHORE_CLI_SSL_VERIFY', True)
)
action = actions.CreateFalcoRuleFromAnchoreStopPolicyResults(anchore_client)

result = action.run()

print(result)


if __name__ == '__main__':
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from mamba import description, it, before
from expects import expect, contain

from doublex import Stub, when

import actions
import infrastructure


with description(actions.CreateFalcoRuleFromAnchoreStopPolicyResults) as self:
with before.each:
self.anchore_client = Stub(infrastructure.AnchoreClient)
self.action = actions.CreateFalcoRuleFromAnchoreStopPolicyResults(self.anchore_client)

with it('queries Anchore Server for images with Stop as policy results'):
image_id = 'any image id'
when(self.anchore_client).get_images_with_policy_result('stop').returns([image_id])

result = self.action.run()

expect(result).to(contain(image_id))
Loading

0 comments on commit ec0c109

Please sign in to comment.