From 893554e0f02c5636c6c4fbb669de40bb946b62b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 13:44:02 +0200 Subject: [PATCH 01/13] Add README for the kubernetes response engine --- kubernetes-response-engine/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 kubernetes-response-engine/README.md diff --git a/kubernetes-response-engine/README.md b/kubernetes-response-engine/README.md new file mode 100644 index 00000000000..6343027bc7c --- /dev/null +++ b/kubernetes-response-engine/README.md @@ -0,0 +1,27 @@ +# Kubernetes Response Engine for Sysdig Falco + +The goal of this project is to create a response engine for Kubernetes which is +able to execute playbooks to different types of security threats in our +cointainer fleet alerted by Falco. + +There are several principles which guides our decisions (in no particular order): + +* Real time responses to a security threat: We need to react as soon as possible. +* Deployment independence: Each playbook is independent of others. +* Open Source Software: We want to use and promote OSS. +* Write rock solid code: Each playbook is tested. + +## Alert lifecycle outline + +An alert travels by our system, these are the typical stages for an alert: + +1. *Falco* detects an alert in one container which belongs to our fleet +2. *Falco* sends the alert to *NATS* using a topic compound by "falco.." +3. *NATS* delivers message to its subscribers through *Kubeless* infrastructure +4. *Kubeless* receives the alert and pass it to inner *Playbook* +6. *Playbook* performs its inner action: Stopping the container, Sending an alert to Slack ... + +## Glossary + +* *Alert*: Falco sends alerts +* *Playbook*: Each piece of Python code which is run when an alert is received From 26ca8661621dc5008c83a8cf40eb92f2bd6ae8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 13:44:32 +0200 Subject: [PATCH 02/13] Add nats output for Falco --- .../falco-nats/.gitignore | 1 + .../falco-nats/Dockerfile | 5 + .../falco-nats/Makefile | 12 +++ kubernetes-response-engine/falco-nats/main.go | 100 ++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 kubernetes-response-engine/falco-nats/.gitignore create mode 100644 kubernetes-response-engine/falco-nats/Dockerfile create mode 100644 kubernetes-response-engine/falco-nats/Makefile create mode 100644 kubernetes-response-engine/falco-nats/main.go diff --git a/kubernetes-response-engine/falco-nats/.gitignore b/kubernetes-response-engine/falco-nats/.gitignore new file mode 100644 index 00000000000..7ee62ab86f5 --- /dev/null +++ b/kubernetes-response-engine/falco-nats/.gitignore @@ -0,0 +1 @@ +falco-nats diff --git a/kubernetes-response-engine/falco-nats/Dockerfile b/kubernetes-response-engine/falco-nats/Dockerfile new file mode 100644 index 00000000000..47f264a34a4 --- /dev/null +++ b/kubernetes-response-engine/falco-nats/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest + +COPY ./falco-nats /bin/ + +CMD ["/bin/falco-nats"] diff --git a/kubernetes-response-engine/falco-nats/Makefile b/kubernetes-response-engine/falco-nats/Makefile new file mode 100644 index 00000000000..9303ee0549c --- /dev/null +++ b/kubernetes-response-engine/falco-nats/Makefile @@ -0,0 +1,12 @@ +build: + GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s" -o falco-nats main.go + +deps: + go get -u github.com/nats-io/go-nats + +clean: + rm falco-nats + +docker: build + docker build -t sysdig/falco-nats . + docker push sysdig/falco-nats diff --git a/kubernetes-response-engine/falco-nats/main.go b/kubernetes-response-engine/falco-nats/main.go new file mode 100644 index 00000000000..6639d2a2028 --- /dev/null +++ b/kubernetes-response-engine/falco-nats/main.go @@ -0,0 +1,100 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build ignore + +package main + +import ( + "bufio" + "encoding/json" + "flag" + "github.com/nats-io/go-nats" + "log" + "os" + "regexp" + "strings" +) + +var slugRegularExpression = regexp.MustCompile("[^a-z0-9]+") + +func main() { + var urls = flag.String("s", "nats://nats.nats-io.svc.cluster.local:4222", "The nats server URLs (separated by comma)") + var pipePath = flag.String("f", "/var/run/falco/nats", "The named pipe path") + + log.SetFlags(0) + flag.Usage = usage + flag.Parse() + + nc, err := nats.Connect(*urls) + if err != nil { + log.Fatal(err) + } + defer nc.Close() + + pipe, err := os.OpenFile(*pipePath, os.O_RDONLY, 0600) + if err != nil { + log.Fatal(err) + } + + log.Printf("Opened pipe %s", *pipePath) + + reader := bufio.NewReader(pipe) + scanner := bufio.NewScanner(reader) + + log.Printf("Scanning %s", *pipePath) + + for scanner.Scan() { + msg := []byte(scanner.Text()) + + subj, err := subjectAndRuleSlug(msg) + if err != nil { + log.Fatal(err) + } + nc.Publish(subj, msg) + nc.Flush() + + if err := nc.LastError(); err != nil { + log.Fatal(err) + } else { + log.Printf("Published [%s] : '%s'\n", subj, msg) + } + } +} + +func usage() { + log.Fatalf("Usage: nats-pub [-s server (%s)] \n", nats.DefaultURL) +} + +type parsedAlert struct { + Priority string `json:"priority"` + Rule string `json:"rule"` +} + +func subjectAndRuleSlug(alert []byte) (string, error) { + var result parsedAlert + err := json.Unmarshal(alert, &result) + + if err != nil { + return "", err + } + + subject := "falco." + result.Priority + "." + slugify(result.Rule) + subject = strings.ToLower(subject) + + return subject, nil +} + +func slugify(input string) string { + return strings.Trim(slugRegularExpression.ReplaceAllString(strings.ToLower(input), "_"), "_") +} From 526f32b54bf11869359c14628993cd1cf13f855a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 16:22:58 +0200 Subject: [PATCH 03/13] Add a README for falco-nats output --- .../falco-nats/README.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 kubernetes-response-engine/falco-nats/README.md diff --git a/kubernetes-response-engine/falco-nats/README.md b/kubernetes-response-engine/falco-nats/README.md new file mode 100644 index 00000000000..5e32e319ab4 --- /dev/null +++ b/kubernetes-response-engine/falco-nats/README.md @@ -0,0 +1,27 @@ +# NATS output for Sysdig Falco + +As Falco does not support a NATS output natively, we have created this small +golang utility wich reads Falco alerts from a named pipe and sends them to a +NATS server. + +This utility is designed to being run in a sidecar container in the same +Pod as Falco. + +## Configuration + +You have a [complete Kubernetes manifest available](https://github.com/draios/falco/tree/kubernetes-response-engine/deployment/falco-daemonset.yaml) for future reading. + +Take a look at sidecar container and to the initContainers directive which +craetes the shared pipe between containers. + +### Container image + +You have this adapter available as a container image. Its name is *sysdig/falco-nats*. + +### Parameters Reference + +* -s: Specifies the NATS server URL where message will be published. By default + is: *nats://nats.nats-io.svc.cluster.local:4222* + +* -f: Specifies the named pipe path where Falco publishes its alerts. By default + is: */var/run/falco/nats* From 4867c47d4b4d96a39909896c316ffb1d46864bfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 16:41:56 +0200 Subject: [PATCH 04/13] Upload playbooks code --- .../playbooks/.gitignore | 104 +++++ kubernetes-response-engine/playbooks/Pipfile | 19 + .../playbooks/Pipfile.lock | 367 ++++++++++++++++++ .../playbooks/delete.py | 16 + .../playbooks/deploy_playbook | 68 ++++ .../playbooks/isolate.py | 16 + .../playbooks/playbooks/__init__.py | 101 +++++ .../playbooks/playbooks/infrastructure.py | 74 ++++ kubernetes-response-engine/playbooks/setup.py | 11 + kubernetes-response-engine/playbooks/slack.py | 16 + .../infrastructure/kubernetes_client_spec.py | 65 ++++ .../specs/infrastructure/slack_client_spec.py | 16 + .../add_message_to_slack_playbook_spec.py | 62 +++ .../playbooks/delete_pod_playbook_spec.py | 22 ++ .../network_isolate_pod_playbook_spec.py | 22 ++ .../playbooks/taint_node_playbook_spec.py | 34 ++ .../playbooks/specs/support/deployment.yaml | 10 + kubernetes-response-engine/playbooks/taint.py | 19 + 18 files changed, 1042 insertions(+) create mode 100644 kubernetes-response-engine/playbooks/.gitignore create mode 100644 kubernetes-response-engine/playbooks/Pipfile create mode 100644 kubernetes-response-engine/playbooks/Pipfile.lock create mode 100644 kubernetes-response-engine/playbooks/delete.py create mode 100755 kubernetes-response-engine/playbooks/deploy_playbook create mode 100644 kubernetes-response-engine/playbooks/isolate.py create mode 100644 kubernetes-response-engine/playbooks/playbooks/__init__.py create mode 100644 kubernetes-response-engine/playbooks/playbooks/infrastructure.py create mode 100644 kubernetes-response-engine/playbooks/setup.py create mode 100644 kubernetes-response-engine/playbooks/slack.py create mode 100644 kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py create mode 100644 kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py create mode 100644 kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py create mode 100644 kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py create mode 100644 kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py create mode 100644 kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py create mode 100644 kubernetes-response-engine/playbooks/specs/support/deployment.yaml create mode 100644 kubernetes-response-engine/playbooks/taint.py diff --git a/kubernetes-response-engine/playbooks/.gitignore b/kubernetes-response-engine/playbooks/.gitignore new file mode 100644 index 00000000000..894a44cc066 --- /dev/null +++ b/kubernetes-response-engine/playbooks/.gitignore @@ -0,0 +1,104 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/kubernetes-response-engine/playbooks/Pipfile b/kubernetes-response-engine/playbooks/Pipfile new file mode 100644 index 00000000000..4fd0be60390 --- /dev/null +++ b/kubernetes-response-engine/playbooks/Pipfile @@ -0,0 +1,19 @@ +[[source]] +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[dev-packages] +mamba = "*" +expects = "*" +doublex = "*" +doublex-expects = "==0.7.0rc2" + +[packages] +kubernetes = "*" +requests = "*" +"e1839a8" = {path = ".", editable = true} +maya = "*" + +[requires] +python_version = "3.6" diff --git a/kubernetes-response-engine/playbooks/Pipfile.lock b/kubernetes-response-engine/playbooks/Pipfile.lock new file mode 100644 index 00000000000..23ff0d7bd13 --- /dev/null +++ b/kubernetes-response-engine/playbooks/Pipfile.lock @@ -0,0 +1,367 @@ +{ + "_meta": { + "hash": { + "sha256": "00ca5a9cb1f462d534a06bca990e987e75a05b7baf6ba5ddac529f03312135e6" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.6" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "cachetools": { + "hashes": [ + "sha256:90f1d559512fc073483fe573ef5ceb39bf6ad3d39edc98dc55178a2b2b176fa3", + "sha256:d1c398969c478d336f767ba02040fa22617333293fb0b8968e79b16028dfee35" + ], + "version": "==2.1.0" + }, + "certifi": { + "hashes": [ + "sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7", + "sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0" + ], + "version": "==2018.4.16" + }, + "chardet": { + "hashes": [ + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691" + ], + "version": "==3.0.4" + }, + "dateparser": { + "hashes": [ + "sha256:940828183c937bcec530753211b70f673c0a9aab831e43273489b310538dff86", + "sha256:b452ef8b36cd78ae86a50721794bc674aa3994e19b570f7ba92810f4e0a2ae03" + ], + "version": "==0.7.0" + }, + "e1839a8": { + "editable": true, + "path": "." + }, + "google-auth": { + "hashes": [ + "sha256:1745c9066f698eac3da99cef082914495fb71bc09597ba7626efbbb64c4acc57", + "sha256:82a34e1a59ad35f01484d283d2a36b7a24c8c404a03a71b3afddd0a4d31e169f" + ], + "version": "==1.5.0" + }, + "humanize": { + "hashes": [ + "sha256:a43f57115831ac7c70de098e6ac46ac13be00d69abbf60bdcac251344785bb19" + ], + "version": "==0.5.1" + }, + "idna": { + "hashes": [ + "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e", + "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16" + ], + "version": "==2.7" + }, + "ipaddress": { + "hashes": [ + "sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794", + "sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c" + ], + "version": "==1.0.22" + }, + "kubernetes": { + "hashes": [ + "sha256:b370ab4abd925309db69a14a4723487948e9a83de60ca92782ec14992b741c89", + "sha256:c80dcf531deca2037105df09c933355c80830ffbf9e496b5e6a3967ac6809ef7" + ], + "index": "pypi", + "version": "==6.0.0" + }, + "maya": { + "hashes": [ + "sha256:6f63bc69aa77309fc220bc02618da8701a21da87c2e7a747ee5ccd56a907c3a5", + "sha256:f526bc8596d993f4bd9755668f66aaf61d635bb4149e084d4a2bc0ebe42aa0b6" + ], + "index": "pypi", + "version": "==0.5.0" + }, + "oauthlib": { + "hashes": [ + "sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162", + "sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b" + ], + "version": "==2.1.0" + }, + "pendulum": { + "hashes": [ + "sha256:4173ce3e81ad0d9d61dbce86f4286c43a26a398270df6a0a89f501f0c28ad27d", + "sha256:56a347d0457859c84b8cdba161fc37c7df5db9b3becec7881cd770e9d2058b3c", + "sha256:738878168eb26e5446da5d1f7b3312ae993a542061be8882099c00ef4866b1a2", + "sha256:95536b33ae152e3c831eb236c1bf9ac9dcfb3b5b98fdbe8e9e601eab6c373897", + "sha256:c04fcf955e622e97e405e5f6d1b1f4a7adc69d79d82f3609643de69283170d6d", + "sha256:dd6500d27bb7ccc029d497da4f9bd09549bd3c0ea276dad894ea2fdf309e83f3", + "sha256:ddaf97a061eb5e2ae37857a8cb548e074125017855690d20e443ad8d9f31e164", + "sha256:e7df37447824f9af0b58c7915a4caf349926036afd86ad38e7529a6b2f8fc34b", + "sha256:e9732b8bb214fad2c72ddcbfec07542effa8a8b704e174347ede1ff8dc679cce", + "sha256:f4eee1e1735487d9d25cc435c519fd4380cb1f82cde3ebad1efbc2fc30deca5b" + ], + "version": "==1.5.1" + }, + "pyasn1": { + "hashes": [ + "sha256:2f57960dc7a2820ea5a1782b872d974b639aa3b448ac6628d1ecc5d0fe3986f2", + "sha256:3651774ca1c9726307560792877db747ba5e8a844ea1a41feb7670b319800ab3", + "sha256:602fda674355b4701acd7741b2be5ac188056594bf1eecf690816d944e52905e", + "sha256:8fb265066eac1d3bb5015c6988981b009ccefd294008ff7973ed5f64335b0f2d", + "sha256:9334cb427609d2b1e195bb1e251f99636f817d7e3e1dffa150cb3365188fb992", + "sha256:9a15cc13ff6bf5ed29ac936ca941400be050dff19630d6cd1df3fb978ef4c5ad", + "sha256:a66dcda18dbf6e4663bde70eb30af3fc4fe1acb2d14c4867a861681887a5f9a2", + "sha256:ba77f1e8d7d58abc42bfeddd217b545fdab4c1eeb50fd37c2219810ad56303bf", + "sha256:cdc8eb2eaafb56de66786afa6809cd9db2df1b3b595dcb25aa5b9dc61189d40a", + "sha256:d01fbba900c80b42af5c3fe1a999acf61e27bf0e452e0f1ef4619065e57622da", + "sha256:f281bf11fe204f05859225ec2e9da7a7c140b65deccd8a4eb0bc75d0bd6949e0", + "sha256:fb81622d8f3509f0026b0683fe90fea27be7284d3826a5f2edf97f69151ab0fc" + ], + "version": "==0.4.3" + }, + "pyasn1-modules": { + "hashes": [ + "sha256:041e9fbafac548d095f5b6c3b328b80792f006196e15a232b731a83c93d59493", + "sha256:0cdca76a68dcb701fff58c397de0ef9922b472b1cb3ea9695ca19d03f1869787", + "sha256:0cea139045c38f84abaa803bcb4b5e8775ea12a42af10019d942f227acc426c3", + "sha256:0f2e50d20bc670be170966638fa0ae603f0bc9ed6ebe8e97a6d1d4cef30cc889", + "sha256:47fb6757ab78fe966e7c58b2030b546854f78416d653163f0ce9290cf2278e8b", + "sha256:598a6004ec26a8ab40a39ea955068cf2a3949ad9c0030da970f2e1ca4c9f1cc9", + "sha256:72fd8b0c11191da088147c6e4678ec53e573923ecf60b57eeac9e97433e09fc2", + "sha256:854700bbdd01394e2ada9c1bfbd0ed9f5d0c551350dbbd023e88b11d2771ae06", + "sha256:af00ea8f2022b6287dc375b2c70f31ab5af83989fc6fe9eacd4976ce26cd7ccc", + "sha256:b1f395cae2d669e0830cb023aa86f9f283b7a9aa32317d7f80d8e78aa2745812", + "sha256:c6747146e95d2b14cc2a8399b2b0bde3f93778f8f9ec704690d2b589c376c137", + "sha256:f53fe5bcebdf318f51399b250fe8325ef3a26d927f012cc0c8e0f9e9af7f9deb" + ], + "version": "==0.2.1" + }, + "python-dateutil": { + "hashes": [ + "sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0", + "sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8" + ], + "version": "==2.7.3" + }, + "pytz": { + "hashes": [ + "sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555", + "sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749" + ], + "version": "==2018.4" + }, + "pytzdata": { + "hashes": [ + "sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622", + "sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5" + ], + "version": "==2018.5" + }, + "pyyaml": { + "hashes": [ + "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", + "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", + "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", + "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", + "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", + "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", + "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7", + "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", + "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", + "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", + "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", + "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", + "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", + "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269" + ], + "version": "==3.12" + }, + "regex": { + "hashes": [ + "sha256:0201b4cb42f03842a75044a3d08b62a79114f753b33ee421182c631d9f5c81f5", + "sha256:204524604456e3e0e25c3f24da4efc43db78edfe7623f1049e03d3aa51ddda48", + "sha256:24c0e838bde42fe9d4d5650e75bff2d4bb5867968fb9409331dbe39154f6e8e2", + "sha256:4360143da844cd985effb7fb9af04beaa2d371ab13e4a1996424aa2f6fbfb877", + "sha256:4b8c6fd44dbd46cdbf755c20a7b9dedb32b8d15b707a0e470dfa66ba5df00a35", + "sha256:4fb5622987f3863cfa76c40ab3338a7dc8ed2bac236bb53e638b21ea397a3252", + "sha256:5eebefef6e3d97e4c1f9f77eac6555c32ed3afbd769955a9f7339256a4d50d6c", + "sha256:7222204c6acb9e52688678ec7306b2dfd84df68bc8eb251be74fec4e9dd85bf9", + "sha256:809cbbcbe291cf7bc9cf6aeac6a9a400a71318292d0a2a07effaf4b4782203a0", + "sha256:9c9075c727afec23eab196be51737eedb00cd67bb4a2e0170fa8dc65163838f3", + "sha256:a105b1d7287d412e8fe99959c1b80f7cbd76184b6466d63579b6d256a406a76e", + "sha256:c3d9cfd214a3e5a25f2da9817c389e32069e210b067ebb901e10f3270da9b259", + "sha256:c3ebfb5ec2dd750f7861734b25ea7d5ae89d6f33b427cccf3cafa36a1511d862", + "sha256:c670acd71d975b0c91579d40ae7f703d0daa1c871f12e46394a2c7be0ec8e217", + "sha256:e371482ee3e6e5ca19ea83cdfc84bf69cac230e3cb1073c8c3bebf3f143cd7a5" + ], + "version": "==2018.6.9" + }, + "requests": { + "hashes": [ + "sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1", + "sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a" + ], + "index": "pypi", + "version": "==2.19.1" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:8886bfec5ad7afb391ed5443b1f697c6f4ae98d0e5620839d8b4499c032ada3f", + "sha256:e21232e2465808c0e892e0e4dbb8c2faafec16ac6dc067dd546e9b466f3deac8", + "sha256:fe3282f48fb134ee0035712159f5429215459407f6d5484013343031ff1a400d" + ], + "version": "==1.0.0" + }, + "rsa": { + "hashes": [ + "sha256:25df4e10c263fb88b5ace923dd84bf9aa7f5019687b5e55382ffcdb8bede9db5", + "sha256:43f682fea81c452c98d09fc316aae12de6d30c4b5c84226642cf8f8fd1c93abd" + ], + "version": "==3.4.2" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + }, + "snaptime": { + "hashes": [ + "sha256:e3f1eb89043d58d30721ab98cb65023f1a4c2740e3b197704298b163c92d508b" + ], + "version": "==0.2.4" + }, + "tzlocal": { + "hashes": [ + "sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e" + ], + "version": "==1.5.1" + }, + "urllib3": { + "hashes": [ + "sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf", + "sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5" + ], + "version": "==1.23" + }, + "websocket-client": { + "hashes": [ + "sha256:18f1170e6a1b5463986739d9fd45c4308b0d025c1b2f9b88788d8f69e8a5eb4a", + "sha256:db70953ae4a064698b27ae56dcad84d0ee68b7b43cb40940f537738f38f510c1" + ], + "version": "==0.48.0" + } + }, + "develop": { + "args": { + "hashes": [ + "sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814" + ], + "version": "==0.1.0" + }, + "clint": { + "hashes": [ + "sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa" + ], + "version": "==0.5.1" + }, + "coverage": { + "hashes": [ + "sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba", + "sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed", + "sha256:104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a", + "sha256:15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd", + "sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640", + "sha256:1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2", + "sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162", + "sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508", + "sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249", + "sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694", + "sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a", + "sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287", + "sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1", + "sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000", + "sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1", + "sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e", + "sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5", + "sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062", + "sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba", + "sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc", + "sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc", + "sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99", + "sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653", + "sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c", + "sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558", + "sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f", + "sha256:9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4", + "sha256:ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91", + "sha256:b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d", + "sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9", + "sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd", + "sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d", + "sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6", + "sha256:e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77", + "sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80", + "sha256:f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e" + ], + "version": "==4.5.1" + }, + "doublex": { + "hashes": [ + "sha256:062af49d9e4148bc47b7512d3fdc8e145dea4671d074ffd54b2464a19d3757ab" + ], + "index": "pypi", + "version": "==1.8.4" + }, + "doublex-expects": { + "hashes": [ + "sha256:5421bd92319c77ccc5a81d595d06e9c9f7f670de342b33e8007a81e70f9fade8" + ], + "index": "pypi", + "version": "==0.7.0rc2" + }, + "expects": { + "hashes": [ + "sha256:37538d7b0fa9c0d53e37d07b0e8c07d89754d3deec1f0f8ed1be27f4f10363dd" + ], + "index": "pypi", + "version": "==0.8.0" + }, + "mamba": { + "hashes": [ + "sha256:63e70a8666039cf143a255000e23f29be4ea4b5b8169f2b053f94eb73a2ea9e2" + ], + "index": "pypi", + "version": "==0.9.3" + }, + "pyhamcrest": { + "hashes": [ + "sha256:6b672c02fdf7470df9674ab82263841ce8333fb143f32f021f6cb26f0e512420", + "sha256:7a4bdade0ed98c699d728191a058a60a44d2f9c213c51e2dd1e6fb42f2c6128a", + "sha256:8ffaa0a53da57e89de14ced7185ac746227a8894dbd5a3c718bf05ddbd1d56cd", + "sha256:bac0bea7358666ce52e3c6c85139632ed89f115e9af52d44b3c36e0bf8cf16a9", + "sha256:f30e9a310bcc1808de817a92e95169ffd16b60cbc5a016a49c8d0e8ababfae79" + ], + "version": "==1.9.0" + }, + "six": { + "hashes": [ + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9", + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb" + ], + "version": "==1.11.0" + } + } +} diff --git a/kubernetes-response-engine/playbooks/delete.py b/kubernetes-response-engine/playbooks/delete.py new file mode 100644 index 00000000000..1efecb6b767 --- /dev/null +++ b/kubernetes-response-engine/playbooks/delete.py @@ -0,0 +1,16 @@ +import sys +import os.path +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)))) + +import os +import playbooks +from playbooks import infrastructure + + +playbook = playbooks.DeletePod( + infrastructure.KubernetesClient() +) + + +def handler(event, context): + playbook.run(event['data']) diff --git a/kubernetes-response-engine/playbooks/deploy_playbook b/kubernetes-response-engine/playbooks/deploy_playbook new file mode 100755 index 00000000000..766cee3700a --- /dev/null +++ b/kubernetes-response-engine/playbooks/deploy_playbook @@ -0,0 +1,68 @@ +#!/bin/bash +# +# Deploys a playbook + +set -e + +function usage() { + cat< requirements.txt + +zip "${playbook}".zip -r playbooks/*.py "${playbook}".py + +kubeless function deploy --from-file "${playbook}".zip \ + --dependencies requirements.txt \ + --env "$(join , ${environment[*]})" \ + --runtime python3.6 \ + --handler "${playbook}".handler \ + falco-"${playbook}" + +rm requirements.txt ${playbook}.zip + +for index in ${!topics[*]}; do + kubeless trigger nats create falco-"${playbook}"-trigger-"${index}" \ + --function-selector created-by=kubeless,function=falco-${playbook} \ + --trigger-topic "${topics[$index]}" +done diff --git a/kubernetes-response-engine/playbooks/isolate.py b/kubernetes-response-engine/playbooks/isolate.py new file mode 100644 index 00000000000..b529c46b011 --- /dev/null +++ b/kubernetes-response-engine/playbooks/isolate.py @@ -0,0 +1,16 @@ +import sys +import os.path +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)))) + +import os +import playbooks +from playbooks import infrastructure + + +playbook = playbooks.NetworkIsolatePod( + infrastructure.KubernetesClient() +) + + +def handler(event, context): + playbook.run(event['data']) diff --git a/kubernetes-response-engine/playbooks/playbooks/__init__.py b/kubernetes-response-engine/playbooks/playbooks/__init__.py new file mode 100644 index 00000000000..0259b9e53de --- /dev/null +++ b/kubernetes-response-engine/playbooks/playbooks/__init__.py @@ -0,0 +1,101 @@ +import maya + + +class DeletePod: + def __init__(self, k8s_client): + self._k8s_client = k8s_client + + def run(self, alert): + pod_name = alert['output_fields']['k8s.pod.name'] + + self._k8s_client.delete_pod(pod_name) + + +class AddMessageToSlack: + def __init__(self, slack_client): + self._slack_client = slack_client + + def run(self, alert): + message = self._build_slack_message(alert) + self._slack_client.post_message(message) + + return message + + def _build_slack_message(self, alert): + return { + 'text': self._output(alert), + 'attachments': [{ + 'color': self._color_from(alert['priority']), + 'fields': [ + { + 'title': 'Rule', + 'value': alert['rule'], + 'short': False + }, + { + 'title': 'Priority', + 'value': alert['priority'], + 'short': True + }, + { + 'title': 'Time', + 'value': str(maya.parse(alert['time'])), + 'short': True + }, + { + 'title': 'Kubernetes Pod Name', + 'value': alert['output_fields']['k8s.pod.name'], + 'short': True + }, + { + 'title': 'Container Id', + 'value': alert['output_fields']['container.id'], + 'short': True + } + ] + }] + } + + def _output(self, alert): + output = alert['output'].split(': ')[1] + priority_plus_whitespace_length = len(alert['priority']) + 1 + + return output[priority_plus_whitespace_length:] + + _COLORS = { + 'Emergency': '#b12737', + 'Alert': '#f24141', + 'Critical': '#fc7335', + 'Error': '#f28143', + 'Warning': '#f9c414', + 'Notice': '#397ec3', + 'Informational': '#8fc0e7', + 'Debug': '#8fc0e7', + } + + def _color_from(self, priority): + return self._COLORS.get(priority, '#eeeeee') + + +class TaintNode: + def __init__(self, k8s_client, key, value, effect): + self._k8s_client = k8s_client + self._key = key + self._value = value + self._effect = effect + + def run(self, alert): + pod = alert['output_fields']['k8s.pod.name'] + node = self._k8s_client.find_node_running_pod(pod) + + self._k8s_client.taint_node(node, self._key, self._value, self._effect) + + +class NetworkIsolatePod: + def __init__(self, k8s_client): + self._k8s_client = k8s_client + + def run(self, alert): + pod = alert['output_fields']['k8s.pod.name'] + + self._k8s_client.add_label_to_pod(pod, 'isolated', 'true') diff --git a/kubernetes-response-engine/playbooks/playbooks/infrastructure.py b/kubernetes-response-engine/playbooks/playbooks/infrastructure.py new file mode 100644 index 00000000000..5f48516913e --- /dev/null +++ b/kubernetes-response-engine/playbooks/playbooks/infrastructure.py @@ -0,0 +1,74 @@ +import os +import json + +from kubernetes import client, config +import requests + + +class KubernetesClient: + def __init__(self): + if 'KUBERNETES_LOAD_KUBE_CONFIG' in os.environ: + config.load_kube_config() + else: + config.load_incluster_config() + + self._v1 = client.CoreV1Api() + + def delete_pod(self, name): + namespace = self._find_pod_namespace(name) + body = client.V1DeleteOptions() + self._v1.delete_namespaced_pod(name=name, + namespace=namespace, + body=body) + + def exists_pod(self, name): + response = self._v1.list_pod_for_all_namespaces(watch=False) + for item in response.items: + if item.metadata.name == name: + if item.metadata.deletion_timestamp is None: + return True + + return False + + def _find_pod_namespace(self, name): + response = self._v1.list_pod_for_all_namespaces(watch=False) + for item in response.items: + if item.metadata.name == name: + return item.metadata.namespace + + def find_node_running_pod(self, name): + response = self._v1.list_pod_for_all_namespaces(watch=False) + for item in response.items: + if item.metadata.name == name: + return item.spec.node_name + + def taint_node(self, name, key, value, effect): + body = client.V1Node( + spec=client.V1NodeSpec( + taints=[ + client.V1Taint(key=key, value=value, effect=effect) + ] + ) + ) + + return self._v1.patch_node(name, body) + + def add_label_to_pod(self, name, label, value): + namespace = self._find_pod_namespace(name) + + body = client.V1Pod( + metadata=client.V1ObjectMeta( + labels={label: value} + ) + ) + + return self._v1.patch_namespaced_pod(name, namespace, body) + + +class SlackClient: + def __init__(self, slack_webhook_url): + self._slack_webhook_url = slack_webhook_url + + def post_message(self, message): + requests.post(self._slack_webhook_url, + data=json.dumps(message)) diff --git a/kubernetes-response-engine/playbooks/setup.py b/kubernetes-response-engine/playbooks/setup.py new file mode 100644 index 00000000000..22ac249ebd6 --- /dev/null +++ b/kubernetes-response-engine/playbooks/setup.py @@ -0,0 +1,11 @@ +from setuptools import setup + +setup(name='playbooks', + version='0.1', + description='A set of playbooks for Falco alerts', + url='http://github.com/draios/falco-playbooks', + author='Néstor Salceda', + author_email='nestor.salceda@sysdig.com', + license='', + packages=['playbooks'], + zip_safe=False) diff --git a/kubernetes-response-engine/playbooks/slack.py b/kubernetes-response-engine/playbooks/slack.py new file mode 100644 index 00000000000..a09431acc8f --- /dev/null +++ b/kubernetes-response-engine/playbooks/slack.py @@ -0,0 +1,16 @@ +import sys +import os.path +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)))) + +import os +import playbooks +from playbooks import infrastructure + + +playbook = playbooks.AddMessageToSlack( + infrastructure.SlackClient(os.environ['SLACK_WEBHOOK_URL']) +) + + +def handler(event, context): + playbook.run(event['data']) diff --git a/kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py b/kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py new file mode 100644 index 00000000000..6e3a2aae4be --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py @@ -0,0 +1,65 @@ +from mamba import description, context, it, before +from expects import expect, be_false, be_true, start_with, equal, have_key + +import subprocess +import os.path + +from playbooks import infrastructure + + +with description(infrastructure.KubernetesClient) as self: + with before.each: + self.kubernetes_client = infrastructure.KubernetesClient() + + with context('when checking if a pod exists'): + with before.each: + self._create_nginx_pod() + + with context('and pod exists'): + with it('returns true'): + expect(self.kubernetes_client.exists_pod('nginx')).to(be_true) + + with context('and pod does not exist'): + with it('returns false'): + self.kubernetes_client.delete_pod('nginx') + + expect(self.kubernetes_client.exists_pod('nginx')).to(be_false) + + with it('finds node running pod'): + self._create_nginx_pod() + + node = self.kubernetes_client.find_node_running_pod('nginx') + + expect(node).to(start_with('gke-sysdig-work-default-pool')) + + with it('taints node'): + self._create_nginx_pod() + + node_name = self.kubernetes_client.find_node_running_pod('nginx') + + node = self.kubernetes_client.taint_node(node_name, + 'playbooks', + 'true', + 'NoSchedule') + + expect(node.spec.taints[0].effect).to(equal('NoSchedule')) + expect(node.spec.taints[0].key).to(equal('playbooks')) + expect(node.spec.taints[0].value).to(equal('true')) + + with it('adds labels to a pod'): + self._create_nginx_pod() + + pod = self.kubernetes_client.add_label_to_pod('nginx', + 'testing', + 'true') + + expect(pod.metadata.labels).to(have_key('testing', 'true')) + + def _create_nginx_pod(self): + current_directory = os.path.dirname(os.path.realpath(__file__)) + pod_manifesto = os.path.join(current_directory, + '..', + 'support', + 'deployment.yaml') + + subprocess.run(['kubectl', 'create', '-f', pod_manifesto]) diff --git a/kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py b/kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py new file mode 100644 index 00000000000..bfdd9e41c02 --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py @@ -0,0 +1,16 @@ +from mamba import description, it + +import os + +from playbooks import infrastructure + + +with description(infrastructure.SlackClient) as self: + with it('posts a message to #kubeless-demo channel'): + slack_client = infrastructure.SlackClient(os.environ['SLACK_WEBHOOK_URL']) + + message = { + 'text': 'Hello from Python! :metal:' + } + + slack_client.post_message(message) diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py b/kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py new file mode 100644 index 00000000000..c8f6420a87e --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py @@ -0,0 +1,62 @@ +from mamba import description, it, before, context +from expects import expect, have_key, have_keys, contain + +from doublex import Spy +from doublex_expects import have_been_called_with + +from playbooks import infrastructure +import playbooks + + + +with description(playbooks.AddMessageToSlack) as self: + with before.each: + self.slack_client = Spy(infrastructure.SlackClient) + self.playbook = playbooks.AddMessageToSlack(self.slack_client) + + with context('when publishing a message to slack'): + with before.each: + self.alert = { + "output": "10:22:15.576767292: Notice Unexpected setuid call by non-sudo, non-root program (user=bin cur_uid=2 parent=event_generator command=event_generator uid=root) k8s.pod=falco-event-generator-6fd89678f9-cdkvz container=1c76f49f40b4", + "output_fields": { + "container.id": "1c76f49f40b4", + "evt.arg.uid": "root", + "evt.time": 1527157335576767292, + "k8s.pod.name": "falco-event-generator-6fd89678f9-cdkvz", + "proc.cmdline": "event_generator ", + "proc.pname": "event_generator", + "user.name": "bin", + "user.uid": 2 + }, + "priority": "Notice", + "rule": "Non sudo setuid", + "time": "2018-05-24T10:22:15.576767292Z" + } + + self.message = self.playbook.run(self.alert) + + with it('publishes message to slack'): + expect(self.slack_client.post_message).to(have_been_called_with(self.message)) + + with it('includes falco output'): + falco_output = 'Unexpected setuid call by non-sudo, non-root program (user=bin cur_uid=2 parent=event_generator command=event_generator uid=root) k8s.pod=falco-event-generator-6fd89678f9-cdkvz container=1c76f49f40b4' + + expect(self.message).to(have_key('text', falco_output)) + + with it('includes color based on priority'): + expect(self.message['attachments'][0]).to(have_key('color')) + + with it('includes priority'): + expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Priority', value='Notice'))) + + with it('includes rule name'): + expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Rule', value='Non sudo setuid'))) + + with it('includes time when alert happened'): + expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Time', value='Thu, 24 May 2018 10:22:15 GMT'))) + + with it('includes kubernetes pod name'): + expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Kubernetes Pod Name', value='falco-event-generator-6fd89678f9-cdkvz'))) + + with it('includes container id'): + expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Container Id', value='1c76f49f40b4'))) diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py b/kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py new file mode 100644 index 00000000000..e7d193a66d6 --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py @@ -0,0 +1,22 @@ +from mamba import description, it, before +from expects import expect + +from doublex import Spy +from doublex_expects import have_been_called_with + +from playbooks import infrastructure +import playbooks + + +with description(playbooks.DeletePod) as self: + with before.each: + self.k8s_client = Spy(infrastructure.KubernetesClient) + self.playbook = playbooks.DeletePod(self.k8s_client) + + with it('deletes a pod'): + pod_name = 'a pod name' + alert = {'output_fields': {'k8s.pod.name': pod_name}} + + self.playbook.run(alert) + + expect(self.k8s_client.delete_pod).to(have_been_called_with(pod_name)) diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py b/kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py new file mode 100644 index 00000000000..fe06ec6cb30 --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py @@ -0,0 +1,22 @@ +from mamba import description, it, before +from expects import expect + +from doublex import Spy +from doublex_expects import have_been_called + +from playbooks import infrastructure +import playbooks + + +with description(playbooks.NetworkIsolatePod) as self: + with before.each: + self.k8s_client = Spy(infrastructure.KubernetesClient) + self.playbook = playbooks.NetworkIsolatePod(self.k8s_client) + + with it('adds isolation label to pod'): + pod_name = 'any pod name' + alert = {'output_fields': {'k8s.pod.name': pod_name}} + + self.playbook.run(alert) + + expect(self.k8s_client.add_label_to_pod).to(have_been_called) diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py b/kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py new file mode 100644 index 00000000000..5abd9dc3456 --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py @@ -0,0 +1,34 @@ +from mamba import description, it, before +from expects import expect + +from doublex import Spy, when +from doublex_expects import have_been_called_with + +from playbooks import infrastructure +import playbooks + + +with description(playbooks.TaintNode) as self: + with before.each: + self.k8s_client = Spy(infrastructure.KubernetesClient) + self.key = 'falco/alert' + self.value = 'true' + self.effect = 'NoSchedule' + self.playbook = playbooks.TaintNode(self.k8s_client, + self.key, + self.value, + self.effect) + + with it('taints the node'): + pod_name = 'any pod name' + alert = {'output_fields': {'k8s.pod.name': pod_name}} + + node = 'any node' + when(self.k8s_client).find_node_running_pod(pod_name).returns(node) + + self.playbook.run(alert) + + expect(self.k8s_client.taint_node).to(have_been_called_with(node, + self.key, + self.value, + self.effect)) diff --git a/kubernetes-response-engine/playbooks/specs/support/deployment.yaml b/kubernetes-response-engine/playbooks/specs/support/deployment.yaml new file mode 100644 index 00000000000..94a108f718d --- /dev/null +++ b/kubernetes-response-engine/playbooks/specs/support/deployment.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx:latest + ports: + - containerPort: 80 diff --git a/kubernetes-response-engine/playbooks/taint.py b/kubernetes-response-engine/playbooks/taint.py new file mode 100644 index 00000000000..ed0811e01bb --- /dev/null +++ b/kubernetes-response-engine/playbooks/taint.py @@ -0,0 +1,19 @@ +import sys +import os.path +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)))) + +import os +import playbooks +from playbooks import infrastructure + + +playbook = playbooks.TaintNode( + infrastructure.KubernetesClient(), + os.environ.get('TAINT_KEY', 'falco/alert'), + os.environ.get('TAINT_VALUE', 'true'), + os.environ.get('TAINT_EFFECT', 'NoSchedule') +) + + +def handler(event, context): + playbook.run(event['data']) From 66ba09ea3b890ed9c861245d68d0e008d40d939d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 17:38:26 +0200 Subject: [PATCH 05/13] Add a README for playbooks --- .../playbooks/README.md | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 kubernetes-response-engine/playbooks/README.md diff --git a/kubernetes-response-engine/playbooks/README.md b/kubernetes-response-engine/playbooks/README.md new file mode 100644 index 00000000000..e3868501dda --- /dev/null +++ b/kubernetes-response-engine/playbooks/README.md @@ -0,0 +1,164 @@ +# Playbooks + +Following [owasp ideas](https://owaspsummit.org/Working-Sessions/Security-Playbooks/index.html), +playbooks are workflows and prescriptive instructions on how to handle specific +Security activities or incidents. + +Being more specific, playbooks are actions that are going to be executed when +Falco finds a weird behavior in our Kubernetes cluster. We have implemented +them with Python and we have found that several Serverless concepts fits well +with playbooks, so we use [Kubeless](https://kubeless.io/) for its deployment. + +## Requirements + +* A working Kubernetes cluster +* [kubeless cli executable](https://kubeless.io/docs/quick-start/) +* Python 3.6 +* pipenv + +## Deploying a playbook + +Deploying a playbook involves a couple of components, the function that is going +to be with Kubeless and a trigger for that function. + +We have automated those steps in a generic script *deploy_playbook* who packages +the reaction and its dependencies, uploads to Kubernetes and creates the kubeless +trigger. + +``` +./deploy_playbook -p slack -e SLACK_WEBHOOK_URL="https://..." -t "falco.error.*" -t "falco.info.*" +``` + +### Parameters + +* -p: The playbook to deploy, it must match with the top-level script. In this + example *slack.py* that contains the wiring between playbooks and Kubeless + functions + +* -e: Sets configuration settings for Playbook. In this case the URL where we + have to post messages. You can specify multiple *-e* flags. + +* -t: Topic to susbcribe. You can specify multiple *-t* flags and a trigger + will be created for each topic, so when we receive a message in that topic, + our function will be ran. In this case, playbook will be run when a + falco.error or falco.info alert is raised. + +### Kubeless 101 + +Under the hood, there are several useful commands for checking function state with kubeless. + + +We can retrieve all functions deployed in our cluster: +``` +kubeless function list +``` + +And we can see several interesting stats about a function usage: +``` +kubeless function top +``` + +And we can see bindings between functions and NATS topics: +``` +kubeless trigger nats list +``` + +### Undeploying a function + +You have to delete every component using kubeless cli tool. + +Generally, it takes 2 steps: Remove the triggers and remove the function. + +Remove the triggers: +``` +kubeless trigger nats delete trigger-name +``` + +If you have deployed with the script, trigger-name look like: +*falco--trigger-* where index is the index of the topic created. +Anyway, you can list all triggers and select the name. + + +Remove the function: +``` +kubeless function delete function-name +``` + +If you have deployed with the script, the function name will start with *falco-*, +but you can list all functions and select its name. + +## Testing + +One of the goals of the project was that playbooks were tested. + +You can execute the tests with: + +``` +pipenv --three install -d +export KUBERNETES_LOAD_KUBE_CONFIG=1 +pipenv run mamba --format=documentation +``` + +The first line install development tools, which includes test runner and assertions. +The second one tells Kubernetes Client to use the same configuration than kubectl and +the third one runs the test. + +The tests under *specs/infrastructure* runs against a real Kubernetes cluster, +but the *spec/reactions* can be run without any kind of infrastructure. + +## Available Playbooks + +### Delete a Pod + +This playbook kills a pod using Kubernetes API + +``` +./deploy_playbook -p delete -t "falco.notice.terminal_shell_in_container" +``` + +In this example, everytime we receive a *Terminal shell in container* alert from +Falco, that pod will be deleted. + +### Send message to Slack + +This playbook posts a message to Slack + +``` +./deploy_playbook -p slack -t "falco.error.*" -e SLACK_WEBHOOK_URL="https://..." +``` + +#### Parameters + +* SLACK_WEBHOOK_URL: This is the webhook used for posting messages in Slack + +In this example, when Falco raises an error we will be notified in Slack + +### Taint a Node + +This playbook taints the node which where pod is running. + +``` +$ ./deploy_playbook -p taint -t “falco.notice.contact_k8s_api_server_from_container” +``` + +#### Parameters: +* TAINT_KEY: This is the taint key. Default value: ‘falco/alert’ +* TAINT_VALUE: This is the taint value. Default value: ‘true’ +* TAINT_EFFECT: This is the taint effect. Default value: ‘NoSchedule’ + +In this example, we avoid scheduling in the node which originates the Contact +K8S API server from container. But we can use a more aggresive approach and +use -e TAINT_EFFECT=NoExecute + +### Network isolate a Pod + +This reaction denies all ingress/egress traffic from a Pod. It's intended to +be used with Calico or other similar projects for managing networking in +Kubernetes. + +``` +./deploy_playbook -p isolate -t “falco.notice.write_below_binary_dir” -t “falco.error.write_below_etc” +``` + +So as soon as we notice someone wrote under /bin (and additional binaries) or +/etc, we disconnect that pod. It's like a trap for our attackers. From 19d251ef4b650850ff111320eb98a28d3743b6ae Mon Sep 17 00:00:00 2001 From: Jorge Salamero Sanz Date: Tue, 10 Jul 2018 18:08:54 +0200 Subject: [PATCH 06/13] Update README.md --- kubernetes-response-engine/README.md | 31 ++++++++++------------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/kubernetes-response-engine/README.md b/kubernetes-response-engine/README.md index 6343027bc7c..86747c31727 100644 --- a/kubernetes-response-engine/README.md +++ b/kubernetes-response-engine/README.md @@ -1,27 +1,18 @@ # Kubernetes Response Engine for Sysdig Falco -The goal of this project is to create a response engine for Kubernetes which is -able to execute playbooks to different types of security threats in our -cointainer fleet alerted by Falco. +A response engine for Falco that allows to process security events executing playbooks to respond to security threats. -There are several principles which guides our decisions (in no particular order): +## Architecture -* Real time responses to a security threat: We need to react as soon as possible. -* Deployment independence: Each playbook is independent of others. -* Open Source Software: We want to use and promote OSS. -* Write rock solid code: Each playbook is tested. - -## Alert lifecycle outline - -An alert travels by our system, these are the typical stages for an alert: - -1. *Falco* detects an alert in one container which belongs to our fleet -2. *Falco* sends the alert to *NATS* using a topic compound by "falco.." -3. *NATS* delivers message to its subscribers through *Kubeless* infrastructure -4. *Kubeless* receives the alert and pass it to inner *Playbook* -6. *Playbook* performs its inner action: Stopping the container, Sending an alert to Slack ... +* *[Falco](https://sysdig.com/opensource/falco/)* monitors containers and processes behavior to alert when something outside our policy takes place. +* *falco-nats* forwards the alert to a message broker service into a topic compound by `falco..`. +* *[NATS](https://nats.io/)*, our message broker, delivers the alert to any subscribers to the different topics. +* *[Kubeless](https://kubeless.io/)*, a FaaS framework that runs in Kubernetes, receives the security events and executes the configured playbooks. ## Glossary -* *Alert*: Falco sends alerts -* *Playbook*: Each piece of Python code which is run when an alert is received +* *Security event*: Alert sent by Falco when a configured rule matches the behaviour on that host. +* *Playbook*: Each piece code executed when an alert is received to respond to that threat in an automated way, some examples include: + - sending an alert to Slack + - stop the pod killing the container + - taint the specific node where the pod is running From 8b82a08148a16e1091e056005216cfb61011dcca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 18:11:04 +0200 Subject: [PATCH 07/13] Add Kubernetes manifests for deploying Nats + Falco + Kubeless --- .../deployment/Makefile | 13 + .../deployment/falco-config/falco.yaml | 102 ++ .../falco-config/falco_rules.local.yaml | 38 + .../deployment/falco-config/falco_rules.yaml | 1540 +++++++++++++++++ .../deployment/falco/falco-account.yaml | 29 + .../deployment/falco/falco-daemonset.yaml | 84 + .../falco/falco-event-generator.yaml | 18 + .../kubeless/kubeless-namespace.yaml | 5 + .../kubeless/kubeless-v1.0.0-alpha.6.yaml | 369 ++++ .../kubeless/nats-v1.0.0-alpha.6.yaml | 74 + .../deployment/nats/deployment-rbac.yaml | 82 + .../deployment/nats/nats-cluster.yaml | 8 + .../deployment/network-policy.yaml | 11 + 13 files changed, 2373 insertions(+) create mode 100644 kubernetes-response-engine/deployment/Makefile create mode 100644 kubernetes-response-engine/deployment/falco-config/falco.yaml create mode 100644 kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml create mode 100644 kubernetes-response-engine/deployment/falco-config/falco_rules.yaml create mode 100644 kubernetes-response-engine/deployment/falco/falco-account.yaml create mode 100644 kubernetes-response-engine/deployment/falco/falco-daemonset.yaml create mode 100644 kubernetes-response-engine/deployment/falco/falco-event-generator.yaml create mode 100644 kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml create mode 100644 kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml create mode 100644 kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml create mode 100644 kubernetes-response-engine/deployment/nats/deployment-rbac.yaml create mode 100644 kubernetes-response-engine/deployment/nats/nats-cluster.yaml create mode 100644 kubernetes-response-engine/deployment/network-policy.yaml diff --git a/kubernetes-response-engine/deployment/Makefile b/kubernetes-response-engine/deployment/Makefile new file mode 100644 index 00000000000..df2c4cb049d --- /dev/null +++ b/kubernetes-response-engine/deployment/Makefile @@ -0,0 +1,13 @@ +deploy: + kubectl apply -f nats/ + kubectl create configmap falco-config --from-file=falco-config/ || true + kubectl apply -f falco/ + kubectl apply -f kubeless/ + kubectl apply -f network-policy.yaml + +clean: + kubectl delete -f kubeless/ + kubectl delete configmap falco-config + kubectl delete -f falco/ + kubectl delete -f nats/ + kubectl delete -f network-policy.yaml diff --git a/kubernetes-response-engine/deployment/falco-config/falco.yaml b/kubernetes-response-engine/deployment/falco-config/falco.yaml new file mode 100644 index 00000000000..9ce40534524 --- /dev/null +++ b/kubernetes-response-engine/deployment/falco-config/falco.yaml @@ -0,0 +1,102 @@ +# File(s) or Directories containing Falco rules, loaded at startup. +# The name "rules_file" is only for backwards compatibility. +# If the entry is a file, it will be read directly. If the entry is a directory, +# every file in that directory will be read, in alphabetical order. +# +# falco_rules.yaml ships with the falco package and is overridden with +# every new software version. falco_rules.local.yaml is only created +# if it doesn't exist. If you want to customize the set of rules, add +# your customizations to falco_rules.local.yaml. +# +# The files will be read in the order presented here, so make sure if +# you have overrides they appear in later files. +rules_file: + - /etc/falco/falco_rules.yaml + - /etc/falco/falco_rules.local.yaml + - /etc/falco/rules.d + +# Whether to output events in json or text +json_output: true + +# When using json output, whether or not to include the "output" property +# itself (e.g. "File below a known binary directory opened for writing +# (user=root ....") in the json output. +json_include_output_property: true + +# Send information logs to stderr and/or syslog Note these are *not* security +# notification logs! These are just Falco lifecycle (and possibly error) logs. +log_stderr: true +log_syslog: true + +# Minimum log level to include in logs. Note: these levels are +# separate from the priority field of rules. This refers only to the +# log level of falco's internal logging. Can be one of "emergency", +# "alert", "critical", "error", "warning", "notice", "info", "debug". +log_level: info + +# Minimum rule priority level to load and run. All rules having a +# priority more severe than this level will be loaded/run. Can be one +# of "emergency", "alert", "critical", "error", "warning", "notice", +# "info", "debug". +priority: debug + +# Whether or not output to any of the output channels below is +# buffered. Defaults to true +buffered_outputs: true + +# A throttling mechanism implemented as a token bucket limits the +# rate of falco notifications. This throttling is controlled by the following configuration +# options: +# - rate: the number of tokens (i.e. right to send a notification) +# gained per second. Defaults to 1. +# - max_burst: the maximum number of tokens outstanding. Defaults to 1000. +# +# With these defaults, falco could send up to 1000 notifications after +# an initial quiet period, and then up to 1 notification per second +# afterward. It would gain the full burst back after 1000 seconds of +# no activity. + +outputs: + rate: 1 + max_burst: 1000 + +# Where security notifications should go. +# Multiple outputs can be enabled. + +syslog_output: + enabled: true + +# If keep_alive is set to true, the file will be opened once and +# continuously written to, with each output message on its own +# line. If keep_alive is set to false, the file will be re-opened +# for each output message. +# +# Also, the file will be closed and reopened if falco is signaled with +# SIGUSR1. + +file_output: + enabled: true + keep_alive: true + filename: /var/run/falco/nats + +stdout_output: + enabled: true + +# Possible additional things you might want to do with program output: +# - send to a slack webhook: +# program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXX" +# - logging (alternate method than syslog): +# program: logger -t falco-test +# - send over a network connection: +# program: nc host.example.com 80 + +# If keep_alive is set to true, the program will be started once and +# continuously written to, with each output message on its own +# line. If keep_alive is set to false, the program will be re-spawned +# for each output message. +# +# Also, the program will be closed and reopened if falco is signaled with +# SIGUSR1. + + + diff --git a/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml b/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml new file mode 100644 index 00000000000..8c6e89fee3f --- /dev/null +++ b/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml @@ -0,0 +1,38 @@ +#################### +# Your custom rules! +#################### + +# Add new rules, like this one +# - rule: The program "sudo" is run in a container +# desc: An event will trigger every time you run sudo in a container +# condition: evt.type = execve and evt.dir=< and container.id != host and proc.name = sudo +# output: "Sudo run in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline)" +# priority: ERROR +# tags: [users, container] + +# Or override/append to any rule, macro, or list from the Default Rules + +- macro: node_app_frontend + condition: k8s.ns.name = node-app and k8s.pod.label.role = frontend and k8s.pod.label.app = node-app + +- rule: Detect crypto miners using the Stratum protocol + desc: Miners typically specify the mining pool to connect to with a URI that begins with 'stratum+tcp' + condition: node_app_frontend and spawned_process and container.id != host and proc.cmdline contains stratum+tcp + output: Possible miner ran inside a container (command=%proc.cmdline %container.info) + priority: CRITICAL + +- list: miner_ports + items: [ + 3333, 4444, 8333, 7777, 7778, 3357, + 3335, 8899, 8888, 5730, 5588, 8118, + 6099, 9332, 1 + ] + +- macro: miner_port_connection + condition: fd.sport in (miner_ports) + +- rule: Detect outbound connections to common miner pool ports + desc: Miners typically connect to miner pools on common ports. + condition: node_app_frontend and outbound and miner_port_connection + output: "Outbound connection to common miner port (command=%proc.cmdline port=%fd.rport %container.info)" + priority: CRITICAL \ No newline at end of file diff --git a/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml b/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml new file mode 100644 index 00000000000..58f4ea43d23 --- /dev/null +++ b/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml @@ -0,0 +1,1540 @@ +# Currently disabled as read/write are ignored syscalls. The nearly +# similar open_write/open_read check for files being opened for +# reading/writing. +# - macro: write +# condition: (syscall.type=write and fd.type in (file, directory)) +# - macro: read +# condition: (syscall.type=read and evt.dir=> and fd.type in (file, directory)) + +- macro: open_write + condition: (evt.type=open or evt.type=openat) and evt.is_open_write=true and fd.typechar='f' and fd.num>=0 + +- macro: open_read + condition: (evt.type=open or evt.type=openat) and evt.is_open_read=true and fd.typechar='f' and fd.num>=0 + +- macro: never_true + condition: (evt.num=0) + +- macro: always_true + condition: (evt.num=>0) + +# In some cases, such as dropped system call events, information about +# the process name may be missing. For some rules that really depend +# on the identity of the process performing an action such as opening +# a file, etc., we require that the process name be known. +- macro: proc_name_exists + condition: (proc.name!="") + +- macro: rename + condition: evt.type in (rename, renameat) +- macro: mkdir + condition: evt.type = mkdir +- macro: remove + condition: evt.type in (rmdir, unlink, unlinkat) + +- macro: modify + condition: rename or remove + +- macro: spawned_process + condition: evt.type = execve and evt.dir=< + +# File categories +- macro: bin_dir + condition: fd.directory in (/bin, /sbin, /usr/bin, /usr/sbin) + +- macro: bin_dir_mkdir + condition: > + (evt.arg[1] startswith /bin/ or + evt.arg[1] startswith /sbin/ or + evt.arg[1] startswith /usr/bin/ or + evt.arg[1] startswith /usr/sbin/) + +- macro: bin_dir_rename + condition: > + evt.arg[1] startswith /bin/ or + evt.arg[1] startswith /sbin/ or + evt.arg[1] startswith /usr/bin/ or + evt.arg[1] startswith /usr/sbin/ + +- macro: etc_dir + condition: fd.name startswith /etc/ + +# This detects writes immediately below / or any write anywhere below /root +- macro: root_dir + condition: ((fd.directory=/ or fd.name startswith /root) and fd.name contains "/") + +- list: shell_binaries + items: [bash, csh, ksh, sh, tcsh, zsh, dash] + +- list: shell_mgmt_binaries + items: [add-shell, remove-shell] + +- macro: shell_procs + condition: (proc.name in (shell_binaries)) + +- list: coreutils_binaries + items: [ + truncate, sha1sum, numfmt, fmt, fold, uniq, cut, who, + groups, csplit, sort, expand, printf, printenv, unlink, tee, chcon, stat, + basename, split, nice, "yes", whoami, sha224sum, hostid, users, stdbuf, + base64, unexpand, cksum, od, paste, nproc, pathchk, sha256sum, wc, test, + comm, arch, du, factor, sha512sum, md5sum, tr, runcon, env, dirname, + tsort, join, shuf, install, logname, pinky, nohup, expr, pr, tty, timeout, + tail, "[", seq, sha384sum, nl, head, id, mkfifo, sum, dircolors, ptx, shred, + tac, link, chroot, vdir, chown, touch, ls, dd, uname, "true", pwd, date, + chgrp, chmod, mktemp, cat, mknod, sync, ln, "false", rm, mv, cp, echo, + readlink, sleep, stty, mkdir, df, dir, rmdir, touch + ] + +# dpkg -L login | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," +- list: login_binaries + items: [ + login, systemd, '"(systemd)"', systemd-logind, su, + nologin, faillog, lastlog, newgrp, sg + ] + +# dpkg -L passwd | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," +- list: passwd_binaries + items: [ + shadowconfig, grpck, pwunconv, grpconv, pwck, + groupmod, vipw, pwconv, useradd, newusers, cppw, chpasswd, usermod, + groupadd, groupdel, grpunconv, chgpasswd, userdel, chage, chsh, + gpasswd, chfn, expiry, passwd, vigr, cpgr + ] + +# repoquery -l shadow-utils | grep bin | xargs ls -ld | grep -v '^d' | +# awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," +- list: shadowutils_binaries + items: [ + chage, gpasswd, lastlog, newgrp, sg, adduser, deluser, chpasswd, + groupadd, groupdel, addgroup, delgroup, groupmems, groupmod, grpck, grpconv, grpunconv, + newusers, pwck, pwconv, pwunconv, useradd, userdel, usermod, vigr, vipw, unix_chkpwd + ] + +- list: sysdigcloud_binaries + items: [setup-backend, dragent, sdchecks] + +- list: docker_binaries + items: [docker, dockerd, exe, docker-compose, docker-entrypoi, docker-runc-cur, docker-current] + +- list: k8s_binaries + items: [hyperkube, skydns, kube2sky, exechealthz] + +- list: lxd_binaries + items: [lxd, lxcfs] + +- list: http_server_binaries + items: [nginx, httpd, httpd-foregroun, lighttpd, apache, apache2] + +- list: db_server_binaries + items: [mysqld, postgres, sqlplus] + +- list: mysql_mgmt_binaries + items: [mysql_install_d, mysql_ssl_rsa_s] + +- list: postgres_mgmt_binaries + items: [pg_dumpall, pg_ctl, pg_lsclusters, pg_ctlcluster] + +- list: db_mgmt_binaries + items: [mysql_mgmt_binaries, postgres_mgmt_binaries] + +- list: nosql_server_binaries + items: [couchdb, memcached, redis-server, rabbitmq-server, mongod] + +- list: gitlab_binaries + items: [gitlab-shell, gitlab-mon, gitlab-runner-b, git] + +- macro: server_procs + condition: proc.name in (http_server_binaries, db_server_binaries, docker_binaries, sshd) + +# The explicit quotes are needed to avoid the - characters being +# interpreted by the filter expression. +- list: rpm_binaries + items: [dnf, rpm, rpmkey, yum, '"75-system-updat"', rhsmcertd-worke, subscription-ma, + repoquery, rpmkeys, rpmq, yum-cron, yum-config-mana, yum-debug-dump, + abrt-action-sav, rpmdb_stat] + +- macro: rpm_procs + condition: proc.name in (rpm_binaries) or proc.name in (salt-minion) + +- list: deb_binaries + items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, apt, apt-get, aptitude, + frontend, preinst, add-apt-reposit, apt-auto-remova, apt-key, + apt-listchanges, unattended-upgr, apt-add-reposit + ] + +# The truncated dpkg-preconfigu is intentional, process names are +# truncated at the sysdig level. +- list: package_mgmt_binaries + items: [rpm_binaries, deb_binaries, update-alternat, gem, pip, sane-utils.post] + +- macro: package_mgmt_procs + condition: proc.name in (package_mgmt_binaries) + +- macro: run_by_package_mgmt_binaries + condition: proc.aname in (package_mgmt_binaries, needrestart) + +- list: ssl_mgmt_binaries + items: [ca-certificates] + +- list: dhcp_binaries + items: [dhclient, dhclient-script] + +# A canonical set of processes that run other programs with different +# privileges or as a different user. +- list: userexec_binaries + items: [sudo, su, suexec] + +- list: known_setuid_binaries + items: [ + sshd, dbus-daemon-lau, ping, ping6, critical-stack-, pmmcli, + filemng, PassengerAgent, bwrap, osdetect, nginxmng, sw-engine-fpm, + start-stop-daem + ] + +- list: user_mgmt_binaries + items: [login_binaries, passwd_binaries, shadowutils_binaries] + +- list: dev_creation_binaries + items: [blkid, rename_device, update_engine, sgdisk] + +- list: hids_binaries + items: [aide] + +- list: vpn_binaries + items: [openvpn] + +- list: nomachine_binaries + items: [nxexec, nxnode.bin, nxserver.bin, nxclient.bin] + +- macro: system_procs + condition: proc.name in (coreutils_binaries, user_mgmt_binaries) + +- list: mail_binaries + items: [ + sendmail, sendmail-msp, postfix, procmail, exim4, + pickup, showq, mailq, dovecot, imap-login, imap, + mailmng-core, pop3-login, dovecot-lda, pop3 + ] + +- list: mail_config_binaries + items: [ + update_conf, parse_mc, makemap_hash, newaliases, update_mk, update_tlsm4, + update_db, update_mc, ssmtp.postinst, mailq, postalias, postfix.config., + postfix.config, postfix-script + ] + +- list: sensitive_file_names + items: [/etc/shadow, /etc/sudoers, /etc/pam.conf] + +- macro: sensitive_files + condition: > + fd.name startswith /etc and + (fd.name in (sensitive_file_names) + or fd.directory in (/etc/sudoers.d, /etc/pam.d)) + +# Indicates that the process is new. Currently detected using time +# since process was started, using a threshold of 5 seconds. +- macro: proc_is_new + condition: proc.duration <= 5000000000 + +# Network +- macro: inbound + condition: > + (((evt.type in (accept,listen) and evt.dir=<)) or + (fd.typechar = 4 or fd.typechar = 6) and + (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and + (evt.rawres >= 0 or evt.res = EINPROGRESS)) + +- macro: outbound + condition: > + (((evt.type = connect and evt.dir=<)) or + (fd.typechar = 4 or fd.typechar = 6) and + (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and + (evt.rawres >= 0 or evt.res = EINPROGRESS)) + +# Very similar to inbound/outbound, but combines the tests together +# for efficiency. +- macro: inbound_outbound + condition: > + (((evt.type in (accept,listen,connect) and evt.dir=<)) or + (fd.typechar = 4 or fd.typechar = 6) and + (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and + (evt.rawres >= 0 or evt.res = EINPROGRESS)) + +- macro: ssh_port + condition: fd.sport=22 + +# In a local/user rules file, you could override this macro to +# enumerate the servers for which ssh connections are allowed. For +# example, you might have a ssh gateway host for which ssh connections +# are allowed. +# +# In the main falco rules file, there isn't any way to know the +# specific hosts for which ssh access is allowed, so this macro just +# repeats ssh_port, which effectively allows ssh from all hosts. In +# the overridden macro, the condition would look something like +# "fd.sip="a.b.c.d" or fd.sip="e.f.g.h" or ..." +- macro: allowed_ssh_hosts + condition: ssh_port + +- rule: Disallowed SSH Connection + desc: Detect any new ssh connection to a host other than those in an allowed group of hosts + condition: (inbound_outbound) and ssh_port and not allowed_ssh_hosts + output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name) + priority: NOTICE + tags: [network] + +# Use this to test whether the event occurred within a container. + +# When displaying container information in the output field, use +# %container.info, without any leading term (file=%fd.name +# %container.info user=%user.name, and not file=%fd.name +# container=%container.info user=%user.name). The output will change +# based on the context and whether or not -pk/-pm/-pc was specified on +# the command line. +- macro: container + condition: container.id != host + +- macro: interactive + condition: > + ((proc.aname=sshd and proc.name != sshd) or + proc.name=systemd-logind or proc.name=login) + +- list: cron_binaries + items: [anacron, cron, crond, crontab] + +# https://github.com/liske/needrestart +- list: needrestart_binaries + items: [needrestart, 10-dpkg, 20-rpm, 30-pacman] + +# Possible scripts run by sshkit +- list: sshkit_script_binaries + items: [10_etc_sudoers., 10_passwd_group] + +- list: plesk_binaries + items: [sw-engine, sw-engine-fpm, sw-engine-kv, filemng, f2bmng] + +# System users that should never log into a system. Consider adding your own +# service users (e.g. 'apache' or 'mysqld') here. +- macro: system_users + condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data) + +# These macros will be removed soon. Only keeping them to maintain +# compatiblity with some widely used rules files. +# Begin Deprecated +- macro: parent_ansible_running_python + condition: (proc.pname in (python, pypy) and proc.pcmdline contains ansible) + +- macro: parent_bro_running_python + condition: (proc.pname=python and proc.cmdline contains /usr/share/broctl) + +- macro: parent_python_running_denyhosts + condition: > + (proc.cmdline startswith "denyhosts.py /usr/bin/denyhosts.py" or + (proc.pname=python and + (proc.pcmdline contains /usr/sbin/denyhosts or + proc.pcmdline contains /usr/local/bin/denyhosts.py))) + +- macro: parent_python_running_sdchecks + condition: > + (proc.pname in (python, python2.7) and + (proc.pcmdline contains /opt/draios/bin/sdchecks)) + +- macro: parent_linux_image_upgrade_script + condition: proc.pname startswith linux-image- + +- macro: parent_java_running_echo + condition: (proc.pname=java and proc.cmdline startswith "sh -c echo") + +- macro: parent_scripting_running_builds + condition: > + (proc.pname in (php,php5-fpm,php-fpm7.1,python,ruby,ruby2.3,ruby2.1,node,conda) and ( + proc.cmdline startswith "sh -c git" or + proc.cmdline startswith "sh -c date" or + proc.cmdline startswith "sh -c /usr/bin/g++" or + proc.cmdline startswith "sh -c /usr/bin/gcc" or + proc.cmdline startswith "sh -c gcc" or + proc.cmdline startswith "sh -c if type gcc" or + proc.cmdline startswith "sh -c cd '/var/www/edi/';LC_ALL=en_US.UTF-8 git" or + proc.cmdline startswith "sh -c /var/www/edi/bin/sftp.sh" or + proc.cmdline startswith "sh -c /usr/src/app/crxlsx/bin/linux/crxlsx" or + proc.cmdline startswith "sh -c make parent" or + proc.cmdline startswith "node /jenkins/tools" or + proc.cmdline startswith "sh -c '/usr/bin/node'" or + proc.cmdline startswith "sh -c stty -a |" or + proc.pcmdline startswith "node /opt/nodejs/bin/yarn" or + proc.pcmdline startswith "node /usr/local/bin/yarn" or + proc.pcmdline startswith "node /root/.config/yarn" or + proc.pcmdline startswith "node /opt/yarn/bin/yarn.js")) + + +- macro: httpd_writing_ssl_conf + condition: > + (proc.pname=run-httpd and + (proc.cmdline startswith "sed -ri" or proc.cmdline startswith "sed -i") and + (fd.name startswith /etc/httpd/conf.d/ or fd.name startswith /etc/httpd/conf)) + +- macro: parent_Xvfb_running_xkbcomp + condition: (proc.pname=Xvfb and proc.cmdline startswith 'sh -c "/usr/bin/xkbcomp"') + +- macro: parent_nginx_running_serf + condition: (proc.pname=nginx and proc.cmdline startswith "sh -c serf") + +- macro: parent_node_running_npm + condition: (proc.pcmdline startswith "node /usr/local/bin/npm" or + proc.pcmdline startswith "node /usr/local/nodejs/bin/npm" or + proc.pcmdline startswith "node /opt/rh/rh-nodejs6/root/usr/bin/npm") + +- macro: parent_java_running_sbt + condition: (proc.pname=java and proc.pcmdline contains sbt-launch.jar) + +- list: known_container_shell_spawn_cmdlines + items: [] + +- list: known_shell_spawn_binaries + items: [] + +- macro: shell_spawning_containers + condition: (container.image startswith jenkins or + container.image startswith gitlab/gitlab-ce or + container.image startswith gitlab/gitlab-ee) + +## End Deprecated + +- macro: ansible_running_python + condition: (proc.name in (python, pypy) and proc.cmdline contains ansible) + +- macro: chef_running_yum_dump + condition: (proc.name=python and proc.cmdline contains yum-dump.py) + +- macro: python_running_denyhosts + condition: > + (proc.name=python and + (proc.cmdline contains /usr/sbin/denyhosts or + proc.cmdline contains /usr/local/bin/denyhosts.py)) + +# Qualys seems to run a variety of shell subprocesses, at various +# levels. This checks at a few levels without the cost of a full +# proc.aname, which traverses the full parent heirarchy. +- macro: run_by_qualys + condition: > + (proc.pname=qualys-cloud-ag or + proc.aname[2]=qualys-cloud-ag or + proc.aname[3]=qualys-cloud-ag or + proc.aname[4]=qualys-cloud-ag) + +- macro: run_by_sumologic_securefiles + condition: > + ((proc.cmdline="usermod -a -G sumologic_collector" or + proc.cmdline="groupadd sumologic_collector") and + (proc.pname=secureFiles.sh and proc.aname[2]=java)) + +- macro: run_by_yum + condition: ((proc.pname=sh and proc.aname[2]=yum) or + (proc.aname[2]=sh and proc.aname[3]=yum)) + +- macro: run_by_ms_oms + condition: > + (proc.aname[3] startswith omsagent- or + proc.aname[3] startswith scx-) + +- macro: run_by_google_accounts_daemon + condition: > + (proc.aname[1] startswith google_accounts or + proc.aname[2] startswith google_accounts) + +# Chef is similar. +- macro: run_by_chef + condition: (proc.aname[2]=chef_command_wr or proc.aname[3]=chef_command_wr or + proc.aname[2]=chef-client or proc.aname[3]=chef-client or + proc.name=chef-client) + +- macro: run_by_adclient + condition: (proc.aname[2]=adclient or proc.aname[3]=adclient or proc.aname[4]=adclient) + +- macro: run_by_centrify + condition: (proc.aname[2]=centrify or proc.aname[3]=centrify or proc.aname[4]=centrify) + +- macro: run_by_puppet + condition: (proc.aname[2]=puppet or proc.aname[3]=puppet) + +# Also handles running semi-indirectly via scl +- macro: run_by_foreman + condition: > + (user.name=foreman and + (proc.pname in (rake, ruby, scl) and proc.aname[5] in (tfm-rake,tfm-ruby)) or + (proc.pname=scl and proc.aname[2] in (tfm-rake,tfm-ruby))) + +- macro: java_running_sdjagent + condition: proc.name=java and proc.cmdline contains sdjagent.jar + +- macro: kubelet_running_loopback + condition: (proc.pname=kubelet and proc.name=loopback) + +- macro: python_mesos_marathon_scripting + condition: (proc.pcmdline startswith "python3 /marathon-lb/marathon_lb.py") + +- macro: splunk_running_forwarder + condition: (proc.pname=splunkd and proc.cmdline startswith "sh -c /opt/splunkforwarder") + +- macro: parent_supervise_running_multilog + condition: (proc.name=multilog and proc.pname=supervise) + +- macro: supervise_writing_status + condition: (proc.name in (supervise,svc) and fd.name startswith "/etc/sb/") + +- macro: pki_realm_writing_realms + condition: (proc.cmdline startswith "bash /usr/local/lib/pki/pki-realm" and fd.name startswith /etc/pki/realms) + +- macro: htpasswd_writing_passwd + condition: (proc.name=htpasswd and fd.name=/etc/nginx/.htpasswd) + +- macro: lvprogs_writing_lvm_archive + condition: (proc.name in (dmeventd,lvcreate) and (fd.name startswith /etc/lvm/archive or + fd.name startswith /etc/lvm/backup)) +- macro: ovsdb_writing_openvswitch + condition: (proc.name=ovsdb-server and fd.directory=/etc/openvswitch) + +- macro: perl_running_plesk + condition: (proc.cmdline startswith "perl /opt/psa/admin/bin/plesk_agent_manager" or + proc.pcmdline startswith "perl /opt/psa/admin/bin/plesk_agent_manager") + +- macro: perl_running_updmap + condition: (proc.cmdline startswith "perl /usr/bin/updmap") + +- macro: perl_running_centrifydc + condition: (proc.cmdline startswith "perl /usr/share/centrifydc") + +- macro: parent_ucf_writing_conf + condition: (proc.pname=ucf and proc.aname[2]=frontend) + +- macro: consul_template_writing_conf + condition: > + ((proc.name=consul-template and fd.name startswith /etc/haproxy) or + (proc.name=reload.sh and proc.aname[2]=consul-template and fd.name startswith /etc/ssl)) + +- macro: countly_writing_nginx_conf + condition: (proc.cmdline startswith "nodejs /opt/countly/bin" and fd.name startswith /etc/nginx) + +- macro: ms_oms_writing_conf + condition: > + ((proc.name in (omiagent,omsagent,in_heartbeat_r*,omsadmin.sh,PerformInventor) + or proc.pname in (omi.postinst,omsconfig.posti,scx.postinst,omsadmin.sh,omiagent)) + and (fd.name startswith /etc/opt/omi or fd.name startswith /etc/opt/microsoft/omsagent)) + +- macro: ms_scx_writing_conf + condition: (proc.name in (GetLinuxOS.sh) and fd.name startswith /etc/opt/microsoft/scx) + +- macro: azure_scripts_writing_conf + condition: (proc.pname startswith "bash /var/lib/waagent/" and fd.name startswith /etc/azure) + +- macro: azure_networkwatcher_writing_conf + condition: (proc.name in (NetworkWatcherA) and fd.name=/etc/init.d/AzureNetworkWatcherAgent) + +- macro: couchdb_writing_conf + condition: (proc.name=beam.smp and proc.cmdline contains couchdb and fd.name startswith /etc/couchdb) + +- macro: update_texmf_writing_conf + condition: (proc.name=update-texmf and fd.name startswith /etc/texmf) + +- macro: slapadd_writing_conf + condition: (proc.name=slapadd and fd.name startswith /etc/ldap) + +- macro: symantec_writing_conf + condition: > + ((proc.name=symcfgd and fd.name startswith /etc/symantec) or + (proc.name=navdefutil and fd.name=/etc/symc-defutils.conf)) + +- macro: liveupdate_writing_conf + condition: (proc.cmdline startswith "java LiveUpdate" and fd.name in (/etc/liveupdate.conf, /etc/Product.Catalog.JavaLiveUpdate)) + +- macro: sosreport_writing_files + condition: > + (proc.name=urlgrabber-ext- and proc.aname[3]=sosreport and + (fd.name startswith /etc/pkt/nssdb or fd.name startswith /etc/pki/nssdb)) + +- macro: selinux_writing_conf + condition: (proc.name in (semodule,genhomedircon,sefcontext_comp) and fd.name startswith /etc/selinux) + +- list: veritas_binaries + items: [vxconfigd, sfcache, vxclustadm, vxdctl, vxprint, vxdmpadm, vxdisk, vxdg, vxassist, vxtune] + +- macro: veritas_driver_script + condition: (proc.cmdline startswith "perl /opt/VRTSsfmh/bin/mh_driver.pl") + +- macro: veritas_progs + condition: (proc.name in (veritas_binaries) or veritas_driver_script) + +- macro: veritas_writing_config + condition: (veritas_progs and fd.name startswith /etc/vx) + +- macro: nginx_writing_conf + condition: (proc.name=nginx and fd.name startswith /etc/nginx) + +- macro: nginx_writing_certs + condition: > + (((proc.name=openssl and proc.pname=nginx-launch.sh) or proc.name=nginx-launch.sh) and fd.name startswith /etc/nginx/certs) + +- macro: chef_client_writing_conf + condition: (proc.pcmdline startswith "chef-client /opt/gitlab" and fd.name startswith /etc/gitlab) + +- macro: centrify_writing_krb + condition: (proc.name in (adjoin,addns) and fd.name startswith /etc/krb5) + +- macro: cockpit_writing_conf + condition: > + ((proc.pname=cockpit-kube-la or proc.aname[2]=cockpit-kube-la) + and fd.name startswith /etc/cockpit) + +- macro: ipsec_writing_conf + condition: (proc.name=start-ipsec.sh and fd.directory=/etc/ipsec) + +- macro: exe_running_docker_save + condition: (proc.cmdline startswith "exe /var/lib/docker" and proc.pname in (dockerd, docker)) + +- macro: python_running_get_pip + condition: (proc.cmdline startswith "python get-pip.py") + +- macro: python_running_ms_oms + condition: (proc.cmdline startswith "python /var/lib/waagent/") + +- macro: gugent_writing_guestagent_log + condition: (proc.name=gugent and fd.name=GuestAgent.log) + +- rule: Write below binary dir + desc: an attempt to write to any file below a set of binary directories + condition: > + bin_dir and evt.dir = < and open_write + and not package_mgmt_procs + and not exe_running_docker_save + and not python_running_get_pip + and not python_running_ms_oms + output: > + File below a known binary directory opened for writing (user=%user.name + command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2]) + priority: ERROR + tags: [filesystem] + +- list: safe_etc_dirs + items: [/etc/cassandra, /etc/ssl/certs/java, /etc/logstash, /etc/nginx/conf.d, /etc/container_environment, /etc/hrmconfig] + +- macro: fluentd_writing_conf_files + condition: (proc.name=start-fluentd and fd.name in (/etc/fluent/fluent.conf, /etc/td-agent/td-agent.conf)) + +- macro: qualys_writing_conf_files + condition: (proc.name=qualys-cloud-ag and fd.name=/etc/qualys/cloud-agent/qagent-log.conf) + +- macro: git_writing_nssdb + condition: (proc.name=git-remote-http and fd.directory=/etc/pki/nssdb) + +- macro: plesk_writing_keys + condition: (proc.name in (plesk_binaries) and fd.name startswith /etc/sw/keys) + +- macro: plesk_install_writing_apache_conf + condition: (proc.cmdline startswith "bash -hB /usr/lib/plesk-9.0/services/webserver.apache configure" + and fd.name="/etc/apache2/apache2.conf.tmp") + +- macro: plesk_running_mktemp + condition: (proc.name=mktemp and proc.aname[3] in (plesk_binaries)) + +- macro: networkmanager_writing_resolv_conf + condition: proc.aname[2]=nm-dispatcher and fd.name=/etc/resolv.conf + +- macro: add_shell_writing_shells_tmp + condition: (proc.name=add-shell and fd.name=/etc/shells.tmp) + +- macro: duply_writing_exclude_files + condition: (proc.name=touch and proc.pcmdline startswith "bash /usr/bin/duply" and fd.name startswith "/etc/duply") + +- macro: xmlcatalog_writing_files + condition: (proc.name=update-xmlcatal and fd.directory=/etc/xml) + +- macro: datadog_writing_conf + condition: ((proc.cmdline startswith "python /opt/datadog-agent" or + proc.cmdline startswith "entrypoint.sh /entrypoint.sh datadog start" or + proc.cmdline startswith "agent.py /opt/datadog-agent") + and fd.name startswith "/etc/dd-agent") + +- macro: curl_writing_pki_db + condition: (proc.name=curl and fd.directory=/etc/pki/nssdb) + +- macro: haproxy_writing_conf + condition: ((proc.name in (update-haproxy-,haproxy_reload.) or proc.pname in (update-haproxy-,haproxy_reload,haproxy_reload.)) + and (fd.name=/etc/openvpn/client.map or fd.name startswith /etc/haproxy)) + +- macro: java_writing_conf + condition: (proc.name=java and fd.name=/etc/.java/.systemPrefs/.system.lock) + +- macro: rabbitmq_writing_conf + condition: (proc.name=rabbitmq-server and fd.directory=/etc/rabbitmq) + +- macro: rook_writing_conf + condition: (proc.name=toolbox.sh and container.image startswith rook/toolbox + and fd.directory=/etc/ceph) + +- macro: httpd_writing_conf_logs + condition: (proc.name=httpd and fd.name startswith /etc/httpd/) + +- macro: mysql_writing_conf + condition: ((proc.name=start-mysql.sh or proc.pname=start-mysql.sh) and fd.name startswith /etc/mysql) + +- macro: openvpn_writing_conf + condition: (proc.name in (openvpn,openvpn-entrypo) and fd.name startswith /etc/openvpn) + +- macro: php_handlers_writing_conf + condition: (proc.name=php_handlers_co and fd.name=/etc/psa/php_versions.json) + +- macro: sed_writing_temp_file + condition: > + ((proc.aname[3]=cron_start.sh and fd.name startswith /etc/security/sed) or + (proc.name=sed and (fd.name startswith /etc/apt/sources.list.d/sed or + fd.name startswith /etc/apt/sed or + fd.name startswith /etc/apt/apt.conf.d/sed))) + +- macro: cron_start_writing_pam_env + condition: (proc.cmdline="bash /usr/sbin/start-cron" and fd.name=/etc/security/pam_env.conf) + +# In some cases dpkg-reconfigur runs commands that modify /etc. Not +# putting the full set of package management programs yet. +- macro: dpkg_scripting + condition: (proc.aname[2] in (dpkg-reconfigur, dpkg-preconfigu)) + +# Add conditions to this macro (probably in a separate file, +# overwriting this macro) to allow for specific combinations of +# programs writing below specific directories below +# /etc. fluentd_writing_conf_files is a good example to follow, as it +# specifies both the program doing the writing as well as the specific +# files it is allowed to modify. +# +# In this file, it just takes one of the programs in the base macro +# and repeats it. + +- macro: user_known_write_etc_conditions + condition: proc.name=confd + +- macro: write_etc_common + condition: > + etc_dir and evt.dir = < and open_write + and proc_name_exists + and not proc.name in (passwd_binaries, shadowutils_binaries, sysdigcloud_binaries, + package_mgmt_binaries, ssl_mgmt_binaries, dhcp_binaries, + dev_creation_binaries, shell_mgmt_binaries, + mail_config_binaries, + sshkit_script_binaries, + ldconfig.real, ldconfig, confd, gpg, insserv, + apparmor_parser, update-mime, tzdata.config, tzdata.postinst, + systemd, systemd-machine, systemd-sysuser, + debconf-show, rollerd, bind9.postinst, sv, + gen_resolvconf., update-ca-certi, certbot, runsv, + qualys-cloud-ag, locales.postins, nomachine_binaries, + adclient, certutil, crlutil, pam-auth-update, parallels_insta, + openshift-launc, update-rc.d) + and not proc.pname in (sysdigcloud_binaries, mail_config_binaries, hddtemp.postins, sshkit_script_binaries, locales.postins, deb_binaries, dhcp_binaries) + and not fd.name pmatch (safe_etc_dirs) + and not fd.name in (/etc/container_environment.sh, /etc/container_environment.json, /etc/motd, /etc/motd.svc) + and not exe_running_docker_save + and not ansible_running_python + and not python_running_denyhosts + and not fluentd_writing_conf_files + and not user_known_write_etc_conditions + and not run_by_centrify + and not run_by_adclient + and not qualys_writing_conf_files + and not git_writing_nssdb + and not plesk_writing_keys + and not plesk_install_writing_apache_conf + and not plesk_running_mktemp + and not networkmanager_writing_resolv_conf + and not run_by_chef + and not add_shell_writing_shells_tmp + and not duply_writing_exclude_files + and not xmlcatalog_writing_files + and not parent_supervise_running_multilog + and not supervise_writing_status + and not pki_realm_writing_realms + and not htpasswd_writing_passwd + and not lvprogs_writing_lvm_archive + and not ovsdb_writing_openvswitch + and not datadog_writing_conf + and not curl_writing_pki_db + and not haproxy_writing_conf + and not java_writing_conf + and not dpkg_scripting + and not parent_ucf_writing_conf + and not rabbitmq_writing_conf + and not rook_writing_conf + and not php_handlers_writing_conf + and not sed_writing_temp_file + and not cron_start_writing_pam_env + and not httpd_writing_conf_logs + and not mysql_writing_conf + and not openvpn_writing_conf + and not consul_template_writing_conf + and not countly_writing_nginx_conf + and not ms_oms_writing_conf + and not ms_scx_writing_conf + and not azure_scripts_writing_conf + and not azure_networkwatcher_writing_conf + and not couchdb_writing_conf + and not update_texmf_writing_conf + and not slapadd_writing_conf + and not symantec_writing_conf + and not liveupdate_writing_conf + and not sosreport_writing_files + and not selinux_writing_conf + and not veritas_writing_config + and not nginx_writing_conf + and not nginx_writing_certs + and not chef_client_writing_conf + and not centrify_writing_krb + and not cockpit_writing_conf + and not ipsec_writing_conf + and not httpd_writing_ssl_conf + +- rule: Write below etc + desc: an attempt to write to any file below /etc + condition: write_etc_common + output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])" + priority: ERROR + tags: [filesystem] + +- list: known_root_files + items: [/root/.monit.state, /root/.auth_tokens, /root/.bash_history, /root/.ash_history, /root/.aws/credentials, + /root/.viminfo.tmp, /root/.lesshst, /root/.bzr.log, /root/.gitconfig.lock, /root/.babel.json, /root/.localstack, + /root/.node_repl_history, /root/.mongorc.js, /root/.dbshell, /root/.augeas/history, /root/.rnd] + +- list: known_root_directories + items: [/root/.oracle_jre_usage, /root/.ssh, /root/.subversion, /root/.nami] + +- macro: known_root_conditions + condition: (fd.name startswith /root/orcexec. + or fd.name startswith /root/.m2 + or fd.name startswith /root/.npm + or fd.name startswith /root/.pki + or fd.name startswith /root/.ivy2 + or fd.name startswith /root/.config/Cypress + or fd.name startswith /root/.config/pulse + or fd.name startswith /root/.config/configstore + or fd.name startswith /root/jenkins/workspace + or fd.name startswith /root/.jenkins + or fd.name startswith /root/.cache + or fd.name startswith /root/.sbt + or fd.name startswith /root/.java + or fd.name startswith /root/.glide + or fd.name startswith /root/.sonar + or fd.name startswith /root/.v8flag + or fd.name startswith /root/infaagent + or fd.name startswith /root/.local/lib/python + or fd.name startswith /root/.pm2 + or fd.name startswith /root/.gnupg + or fd.name startswith /root/.pgpass + or fd.name startswith /root/.theano + or fd.name startswith /root/.gradle + or fd.name startswith /root/.android + or fd.name startswith /root/.ansible + or fd.name startswith /root/.crashlytics + or fd.name startswith /root/.dbus + or fd.name startswith /root/.composer + or fd.name startswith /root/.gconf + or fd.name startswith /root/.nv) + +- rule: Write below root + desc: an attempt to write to any file directly below / or /root + condition: > + root_dir and evt.dir = < and open_write + and not fd.name in (known_root_files) + and not fd.directory in (known_root_directories) + and not exe_running_docker_save + and not gugent_writing_guestagent_log + and not known_root_conditions + output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name)" + priority: ERROR + tags: [filesystem] + +- macro: cmp_cp_by_passwd + condition: proc.name in (cmp, cp) and proc.pname in (passwd, run-parts) + +- rule: Read sensitive file trusted after startup + desc: > + an attempt to read any sensitive file (e.g. files containing user/password/authentication + information) by a trusted program after startup. Trusted programs might read these files + at startup to load initial state, but not afterwards. + condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd" + output: > + Sensitive file opened for reading by trusted program after startup (user=%user.name + command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2]) + priority: WARNING + tags: [filesystem] + +- list: read_sensitive_file_binaries + items: [ + iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, sshd, + vsftpd, systemd, mysql_install_d, psql, screen, debconf-show, sa-update, + pam-auth-update, /usr/sbin/spamd, polkit-agent-he, lsattr, file, sosreport, + scxcimservera, adclient, rtvscand, cockpit-session + ] + +# Add conditions to this macro (probably in a separate file, +# overwriting this macro) to allow for specific combinations of +# programs accessing sensitive files. +# fluentd_writing_conf_files is a good example to follow, as it +# specifies both the program doing the writing as well as the specific +# files it is allowed to modify. +# +# In this file, it just takes one of the macros in the base rule +# and repeats it. + +- macro: user_read_sensitive_file_conditions + condition: cmp_cp_by_passwd + +- rule: Read sensitive file untrusted + desc: > + an attempt to read any sensitive file (e.g. files containing user/password/authentication + information). Exceptions are made for known trusted programs. + condition: > + sensitive_files and open_read + and proc_name_exists + and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries, + cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries, + vpn_binaries, mail_config_binaries, nomachine_binaries, sshkit_script_binaries, + in.proftpd, mandb, salt-minion, postgres_mgmt_binaries) + and not cmp_cp_by_passwd + and not ansible_running_python + and not proc.cmdline contains /usr/bin/mandb + and not run_by_qualys + and not run_by_chef + and not user_read_sensitive_file_conditions + and not perl_running_plesk + and not perl_running_updmap + and not veritas_driver_script + and not perl_running_centrifydc + output: > + Sensitive file opened for reading by non-trusted program (user=%user.name program=%proc.name + command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]) + priority: WARNING + tags: [filesystem] + +# Only let rpm-related programs write to the rpm database +- rule: Write below rpm database + desc: an attempt to write to the rpm database by any non-rpm related program + condition: fd.name startswith /var/lib/rpm and open_write and not rpm_procs and not ansible_running_python and not chef_running_yum_dump + output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name)" + priority: ERROR + tags: [filesystem, software_mgmt] + +- macro: postgres_running_wal_e + condition: (proc.pname=postgres and proc.cmdline startswith "sh -c envdir /etc/wal-e.d/env /usr/local/bin/wal-e") + +- macro: redis_running_prepost_scripts + condition: (proc.aname[2]=redis-server and (proc.cmdline contains "redis-server.post-up.d" or proc.cmdline contains "redis-server.pre-up.d")) + +- macro: rabbitmq_running_scripts + condition: > + (proc.pname=beam.smp and + (proc.cmdline startswith "sh -c exec ps" or + proc.cmdline startswith "sh -c exec inet_gethost" or + proc.cmdline= "sh -s unix:cmd" or + proc.cmdline= "sh -c exec /bin/sh -s unix:cmd 2>&1")) + +- macro: rabbitmqctl_running_scripts + condition: (proc.aname[2]=rabbitmqctl and proc.cmdline startswith "sh -c ") + +- rule: DB program spawned process + desc: > + a database-server related program spawned a new process other than itself. + This shouldn\'t occur and is a follow on from some SQL injection attacks. + condition: > + proc.pname in (db_server_binaries) + and spawned_process + and not proc.name in (db_server_binaries) + and not postgres_running_wal_e + output: > + Database-related program spawned process other than itself (user=%user.name + program=%proc.cmdline parent=%proc.pname) + priority: NOTICE + tags: [process, database] + +- rule: Modify binary dirs + desc: an attempt to modify any file below a set of binary directories. + condition: (bin_dir_rename) and modify and not package_mgmt_procs and not exe_running_docker_save + output: > + File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline + operation=%evt.type file=%fd.name %evt.args) + priority: ERROR + tags: [filesystem] + +- rule: Mkdir binary dirs + desc: an attempt to create a directory below a set of binary directories. + condition: mkdir and bin_dir_mkdir and not package_mgmt_procs + output: > + Directory below known binary directory created (user=%user.name + command=%proc.cmdline directory=%evt.arg.path) + priority: ERROR + tags: [filesystem] + +# This list allows for easy additions to the set of commands allowed +# to change thread namespace without having to copy and override the +# entire change thread namespace rule. +- list: user_known_change_thread_namespace_binaries + items: [] + +- rule: Change thread namespace + desc: > + an attempt to change a program/thread\'s namespace (commonly done + as a part of creating a container) by calling setns. + condition: > + evt.type = setns + and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries, sysdig, nsenter) + and not proc.name in (user_known_change_thread_namespace_binaries) + and not proc.name startswith "runc:" + and not proc.pname in (sysdigcloud_binaries) + and not java_running_sdjagent + and not kubelet_running_loopback + output: > + Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline + parent=%proc.pname %container.info) + priority: NOTICE + tags: [process] + +# The binaries in this list and their descendents are *not* allowed +# spawn shells. This includes the binaries spawning shells directly as +# well as indirectly. For example, apache -> php/perl for +# mod_{php,perl} -> some shell is also not allowed, because the shell +# has apache as an ancestor. + +- list: protected_shell_spawning_binaries + items: [ + http_server_binaries, db_server_binaries, nosql_server_binaries, mail_binaries, + fluentd, flanneld, splunkd, consul, smbd, runsv, PM2 + ] + +- macro: parent_java_running_zookeeper + condition: (proc.pname=java and proc.pcmdline contains org.apache.zookeeper.server) + +- macro: parent_java_running_kafka + condition: (proc.pname=java and proc.pcmdline contains kafka.Kafka) + +- macro: parent_java_running_elasticsearch + condition: (proc.pname=java and proc.pcmdline contains org.elasticsearch.bootstrap.Elasticsearch) + +- macro: parent_java_running_activemq + condition: (proc.pname=java and proc.pcmdline contains activemq.jar) + +- macro: parent_java_running_cassandra + condition: (proc.pname=java and (proc.pcmdline contains "-Dcassandra.config.loader" or proc.pcmdline contains org.apache.cassandra.service.CassandraDaemon)) + +- macro: parent_java_running_jboss_wildfly + condition: (proc.pname=java and proc.pcmdline contains org.jboss) + +- macro: parent_java_running_glassfish + condition: (proc.pname=java and proc.pcmdline contains com.sun.enterprise.glassfish) + +- macro: parent_java_running_hadoop + condition: (proc.pname=java and proc.pcmdline contains org.apache.hadoop) + +- macro: parent_java_running_datastax + condition: (proc.pname=java and proc.pcmdline contains com.datastax) + +- macro: nginx_starting_nginx + condition: (proc.pname=nginx and proc.cmdline contains "/usr/sbin/nginx -c /etc/nginx/nginx.conf") + +- macro: nginx_running_aws_s3_cp + condition: (proc.pname=nginx and proc.cmdline startswith "sh -c /usr/local/bin/aws s3 cp") + +- macro: consul_running_net_scripts + condition: (proc.pname=consul and (proc.cmdline startswith "sh -c curl" or proc.cmdline startswith "sh -c nc")) + +- macro: consul_running_alert_checks + condition: (proc.pname=consul and proc.cmdline startswith "sh -c /bin/consul-alerts") + +- macro: serf_script + condition: (proc.cmdline startswith "sh -c serf") + +- macro: check_process_status + condition: (proc.cmdline startswith "sh -c kill -0 ") + +# In some cases, you may want to consider node processes run directly +# in containers as protected shell spawners. Examples include using +# pm2-docker or pm2 start some-app.js --no-daemon-mode as the direct +# entrypoint of the container, and when the node app is a long-lived +# server using something like express. +# +# However, there are other uses of node related to build pipelines for +# which node is not really a server but instead a general scripting +# tool. In these cases, shells are very likely and in these cases you +# don't want to consider node processes protected shell spawners. +# +# We have to choose one of these cases, so we consider node processes +# as unprotected by default. If you want to consider any node process +# run in a container as a protected shell spawner, override the below +# macro to remove the "never_true" clause, which allows it to take effect. +- macro: possibly_node_in_container + condition: (never_true and (proc.pname=node and proc.aname[3]=docker-containe)) + +- macro: protected_shell_spawner + condition: > + (proc.aname in (protected_shell_spawning_binaries) + or parent_java_running_zookeeper + or parent_java_running_kafka + or parent_java_running_elasticsearch + or parent_java_running_activemq + or parent_java_running_cassandra + or parent_java_running_jboss_wildfly + or parent_java_running_glassfish + or parent_java_running_hadoop + or parent_java_running_datastax + or possibly_node_in_container) + +- list: mesos_shell_binaries + items: [mesos-docker-ex, mesos-slave, mesos-health-ch] + +# Note that runsv is both in protected_shell_spawner and the +# exclusions by pname. This means that runsv can itself spawn shells +# (the ./run and ./finish scripts), but the processes runsv can not +# spawn shells. +- rule: Run shell untrusted + desc: an attempt to spawn a shell below a non-shell application. Specific applications are monitored. + condition: > + spawned_process + and shell_procs + and proc.pname exists + and protected_shell_spawner + and not proc.pname in (shell_binaries, gitlab_binaries, cron_binaries, user_known_shell_spawn_binaries, + needrestart_binaries, + mesos_shell_binaries, + erl_child_setup, exechealthz, + PM2, PassengerWatchd, c_rehash, svlogd, logrotate, hhvm, serf, + lb-controller, nvidia-installe, runsv, statsite, erlexec) + and not proc.cmdline in (known_shell_spawn_cmdlines) + and not proc.aname in (unicorn_launche) + and not consul_running_net_scripts + and not consul_running_alert_checks + and not nginx_starting_nginx + and not nginx_running_aws_s3_cp + and not run_by_package_mgmt_binaries + and not serf_script + and not check_process_status + and not run_by_foreman + and not python_mesos_marathon_scripting + and not splunk_running_forwarder + and not postgres_running_wal_e + and not redis_running_prepost_scripts + and not rabbitmq_running_scripts + and not rabbitmqctl_running_scripts + and not user_shell_container_exclusions + output: > + Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname + cmdline=%proc.cmdline pcmdline=%proc.pcmdline gparent=%proc.aname[2] ggparent=%proc.aname[3] + gggparent=%proc.aname[4] ggggparent=%proc.aname[5]) + priority: DEBUG + tags: [shell] + +- macro: trusted_containers + condition: (container.image startswith sysdig/agent or + (container.image startswith sysdig/falco and + not container.image startswith sysdig/falco-event-generator) or + container.image startswith quay.io/sysdig or + container.image startswith sysdig/sysdig or + container.image startswith gcr.io/google_containers/hyperkube or + container.image startswith quay.io/coreos/flannel or + container.image startswith gcr.io/google_containers/kube-proxy or + container.image startswith calico/node or + container.image startswith rook/toolbox or + container.image startswith registry.access.redhat.com/openshift3/logging-fluentd or + container.image startswith registry.access.redhat.com/openshift3/logging-elasticsearch or + container.image startswith registry.access.redhat.com/openshift3/metrics-cassandra or + container.image startswith openshift3/ose-sti-builder or + container.image startswith registry.access.redhat.com/openshift3/ose-sti-builder or + container.image startswith cloudnativelabs/kube-router or + container.image startswith "consul:" or + container.image startswith mesosphere/mesos-slave or + container.image startswith istio/proxy_ or + container.image startswith datadog/docker-dd-agent) + +# Add conditions to this macro (probably in a separate file, +# overwriting this macro) to specify additional containers that are +# trusted and therefore allowed to run privileged. +# +# In this file, it just takes one of the images in trusted_containers +# and repeats it. +- macro: user_trusted_containers + condition: (container.image startswith sysdig/agent) + +# Add conditions to this macro (probably in a separate file, +# overwriting this macro) to specify additional containers that are +# allowed to perform sensitive mounts. +# +# In this file, it just takes one of the images in trusted_containers +# and repeats it. +- macro: user_sensitive_mount_containers + condition: (container.image startswith sysdig/agent) + +- rule: Launch Privileged Container + desc: Detect the initial process started in a privileged container. Exceptions are made for known trusted images. + condition: > + evt.type=execve and proc.vpid=1 and container + and container.privileged=true + and not trusted_containers + and not user_trusted_containers + output: Privileged container started (user=%user.name command=%proc.cmdline %container.info image=%container.image) + priority: INFO + tags: [container, cis] + +# For now, only considering a full mount of /etc as +# sensitive. Ideally, this would also consider all subdirectories +# below /etc as well, but the globbing mechanism used by sysdig +# doesn't allow exclusions of a full pattern, only single characters. +- macro: sensitive_mount + condition: (container.mount.dest[/proc*] != "N/A" or + container.mount.dest[/var/run/docker.sock] != "N/A" or + container.mount.dest[/] != "N/A" or + container.mount.dest[/etc] != "N/A" or + container.mount.dest[/root*] != "N/A") + +# The steps libcontainer performs to set up the root program for a container are: +# - clone + exec self to a program runc:[0:PARENT] +# - clone a program runc:[1:CHILD] which sets up all the namespaces +# - clone a second program runc:[2:INIT] + exec to the root program. +# The parent of runc:[2:INIT] is runc:0:PARENT] +# As soon as 1:CHILD is created, 0:PARENT exits, so there's a race +# where at the time 2:INIT execs the root program, 0:PARENT might have +# already exited, or might still be around. So we handle both. +# We also let runc:[1:CHILD] count as the parent process, which can occur +# when we lose events and lose track of state. + +- macro: container_entrypoint + condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe)) + +- rule: Launch Sensitive Mount Container + desc: > + Detect the initial process started by a container that has a mount from a sensitive host directory + (i.e. /proc). Exceptions are made for known trusted images. + condition: > + evt.type=execve and proc.vpid=1 and container + and sensitive_mount + and not trusted_containers + and not user_sensitive_mount_containers + output: Container with sensitive mount started (user=%user.name command=%proc.cmdline %container.info image=%container.image mounts=%container.mounts) + priority: INFO + tags: [container, cis] + +# In a local/user rules file, you could override this macro to +# explicitly enumerate the container images that you want to run in +# your environment. In this main falco rules file, there isn't any way +# to know all the containers that can run, so any container is +# alllowed, by using a filter that is guaranteed to evaluate to true +# (the same proc.vpid=1 that's in the Launch Disallowed Container +# rule). In the overridden macro, the condition would look something +# like (container.image startswith vendor/container-1 or +# container.image startswith vendor/container-2 or ...) + +- macro: allowed_containers + condition: (proc.vpid=1) + +- rule: Launch Disallowed Container + desc: > + Detect the initial process started by a container that is not in a list of allowed containers. + condition: evt.type=execve and proc.vpid=1 and container and not allowed_containers + output: Container started and not in allowed list (user=%user.name command=%proc.cmdline %container.info image=%container.image) + priority: WARNING + tags: [container] + +# Anything run interactively by root +# - condition: evt.type != switch and user.name = root and proc.name != sshd and interactive +# output: "Interactive root (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" +# priority: WARNING + +- rule: System user interactive + desc: an attempt to run interactive commands by a system (i.e. non-login) user + condition: spawned_process and system_users and interactive + output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)" + priority: INFO + tags: [users] + +- rule: Terminal shell in container + desc: A shell was used as the entrypoint/exec point into a container with an attached terminal. + condition: > + spawned_process and container + and shell_procs and proc.tty != 0 + and container_entrypoint + output: > + A shell was spawned in a container with an attached terminal (user=%user.name %container.info + shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty) + priority: NOTICE + tags: [container, shell] + +# For some container types (mesos), there isn't a container image to +# work with, and the container name is autogenerated, so there isn't +# any stable aspect of the software to work with. In this case, we +# fall back to allowing certain command lines. + +- list: known_shell_spawn_cmdlines + items: [ + '"sh -c uname -p 2> /dev/null"', + '"sh -c uname -s 2>&1"', + '"sh -c uname -r 2>&1"', + '"sh -c uname -v 2>&1"', + '"sh -c uname -a 2>&1"', + '"sh -c ruby -v 2>&1"', + '"sh -c getconf CLK_TCK"', + '"sh -c getconf PAGESIZE"', + '"sh -c LC_ALL=C LANG=C /sbin/ldconfig -p 2>/dev/null"', + '"sh -c LANG=C /sbin/ldconfig -p 2>/dev/null"', + '"sh -c /sbin/ldconfig -p 2>/dev/null"', + '"sh -c stty -a 2>/dev/null"', + '"sh -c stty -a < /dev/tty"', + '"sh -c stty -g < /dev/tty"', + '"sh -c node index.js"', + '"sh -c node index"', + '"sh -c node ./src/start.js"', + '"sh -c node app.js"', + '"sh -c node -e \"require(''nan'')\""', + '"sh -c node -e \"require(''nan'')\")"', + '"sh -c node $NODE_DEBUG_OPTION index.js "', + '"sh -c crontab -l 2"', + '"sh -c lsb_release -a"', + '"sh -c lsb_release -is 2>/dev/null"', + '"sh -c whoami"', + '"sh -c node_modules/.bin/bower-installer"', + '"sh -c /bin/hostname -f 2> /dev/null"', + '"sh -c locale -a"', + '"sh -c -t -i"', + '"sh -c openssl version"', + '"bash -c id -Gn kafadmin"', + '"sh -c /bin/sh -c ''date +%%s''"' + ] + +# This list allows for easy additions to the set of commands allowed +# to run shells in containers without having to without having to copy +# and override the entire run shell in container macro. Once +# https://github.com/draios/falco/issues/255 is fixed this will be a +# bit easier, as someone could append of any of the existing lists. +- list: user_known_shell_spawn_binaries + items: [] + +# This macro allows for easy additions to the set of commands allowed +# to run shells in containers without having to override the entire +# rule. Its default value is an expression that always is false, which +# becomes true when the "not ..." in the rule is applied. +- macro: user_shell_container_exclusions + condition: (never_true) + +- macro: login_doing_dns_lookup + condition: (proc.name=login and fd.l4proto=udp and fd.sport=53) + +# sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets +# systemd can listen on ports to launch things like sshd on demand +- rule: System procs network activity + desc: any network activity performed by system binaries that are not expected to send or receive any network traffic + condition: > + (fd.sockfamily = ip and system_procs) + and (inbound_outbound) + and not proc.name in (systemd, hostid) + and not login_doing_dns_lookup + output: > + Known system binary sent/received network traffic + (user=%user.name command=%proc.cmdline connection=%fd.name) + priority: NOTICE + tags: [network] + +- list: openvpn_udp_ports + items: [1194, 1197, 1198, 8080, 9201] + +- list: l2tp_udp_ports + items: [500, 1701, 4500, 10000] + +- list: statsd_ports + items: [8125] + +- list: ntp_ports + items: [123] + +# Some applications will connect a udp socket to an address only to +# test connectivity. Assuming the udp connect works, they will follow +# up with a tcp connect that actually sends/receives data. +# +# With that in mind, we listed a few commonly seen ports here to avoid +# some false positives. In addition, we make the main rule opt-in, so +# it's disabled by default. + +- list: test_connect_ports + items: [0, 9, 80, 3306] + +- macro: do_unexpected_udp_check + condition: (never_true) + +- list: expected_udp_ports + items: [53, openvpn_udp_ports, l2tp_udp_ports, statsd_ports, ntp_ports, test_connect_ports] + +- macro: expected_udp_traffic + condition: fd.port in (expected_udp_ports) + +- rule: Unexpected UDP Traffic + desc: UDP traffic not on port 53 (DNS) or other commonly used ports + condition: (inbound_outbound) and do_unexpected_udp_check and fd.l4proto=udp and not expected_udp_traffic + output: > + Unexpected UDP Traffic Seen + (user=%user.name command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args) + priority: NOTICE + tags: [network] + +# With the current restriction on system calls handled by falco +# (e.g. excluding read/write/sendto/recvfrom/etc, this rule won't +# trigger). +# - rule: Ssh error in syslog +# desc: any ssh errors (failed logins, disconnects, ...) sent to syslog +# condition: syslog and ssh_error_message and evt.dir = < +# output: "sshd sent error message to syslog (error=%evt.buffer)" +# priority: WARNING + +- macro: somebody_becoming_themself + condition: ((user.name=nobody and evt.arg.uid=nobody) or + (user.name=www-data and evt.arg.uid=www-data) or + (user.name=_apt and evt.arg.uid=_apt) or + (user.name=postfix and evt.arg.uid=postfix) or + (user.name=pki-agent and evt.arg.uid=pki-agent) or + (user.name=pki-acme and evt.arg.uid=pki-acme) or + (user.name=nfsnobody and evt.arg.uid=nfsnobody) or + (user.name=postgres and evt.arg.uid=postgres)) + +- macro: nrpe_becoming_nagios + condition: (proc.name=nrpe and evt.arg.uid=nagios) + +# In containers, the user name might be for a uid that exists in the +# container but not on the host. (See +# https://github.com/draios/sysdig/issues/954). So in that case, allow +# a setuid. +- macro: known_user_in_container + condition: (container and user.name != "N/A") + +# sshd, mail programs attempt to setuid to root even when running as non-root. Excluding here to avoid meaningless FPs +- rule: Non sudo setuid + desc: > + an attempt to change users by calling setuid. sudo/su are excluded. users "root" and "nobody" + suing to itself are also excluded, as setuid calls typically involve dropping privileges. + condition: > + evt.type=setuid and evt.dir=> + and (known_user_in_container or not container) + and not user.name=root and not somebody_becoming_themself + and not proc.name in (known_setuid_binaries, userexec_binaries, mail_binaries, docker_binaries, + nomachine_binaries) + and not java_running_sdjagent + and not nrpe_becoming_nagios + output: > + Unexpected setuid call by non-sudo, non-root program (user=%user.name cur_uid=%user.uid parent=%proc.pname + command=%proc.cmdline uid=%evt.arg.uid) + priority: NOTICE + tags: [users] + +- rule: User mgmt binaries + desc: > + activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. + Activity in containers is also excluded--some containers create custom users on top + of a base linux distribution at startup. + Some innocuous commandlines that don't actually change anything are excluded. + condition: > + spawned_process and proc.name in (user_mgmt_binaries) and + not proc.name in (su, sudo, lastlog, nologin, unix_chkpwd) and not container and + not proc.pname in (cron_binaries, systemd, systemd.postins, udev.postinst, run-parts) and + not proc.cmdline startswith "passwd -S" and + not proc.cmdline startswith "useradd -D" and + not proc.cmdline startswith "systemd --version" and + not run_by_qualys and + not run_by_sumologic_securefiles and + not run_by_yum and + not run_by_ms_oms and + not run_by_google_accounts_daemon + output: > + User management binary command run outside of container + (user=%user.name command=%proc.cmdline parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]) + priority: NOTICE + tags: [host, users] + +- list: allowed_dev_files + items: [ + /dev/null, /dev/stdin, /dev/stdout, /dev/stderr, + /dev/random, /dev/urandom, /dev/console, /dev/kmsg + ] + +# (we may need to add additional checks against false positives, see: +# https://bugs.launchpad.net/ubuntu/+source/rkhunter/+bug/86153) +- rule: Create files below dev + desc: creating any files below /dev other than known programs that manage devices. Some rootkits hide files in /dev. + condition: > + fd.directory = /dev and + (evt.type = creat or (evt.type = open and evt.arg.flags contains O_CREAT)) + and not proc.name in (dev_creation_binaries) + and not fd.name in (allowed_dev_files) + and not fd.name startswith /dev/tty + output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)" + priority: ERROR + tags: [filesystem] + + +# In a local/user rules file, you could override this macro to +# explicitly enumerate the container images that you want to allow +# access to EC2 metadata. In this main falco rules file, there isn't +# any way to know all the containers that should have access, so any +# container is alllowed, by repeating the "container" macro. In the +# overridden macro, the condition would look something like +# (container.image startswith vendor/container-1 or container.image +# startswith vendor/container-2 or ...) +- macro: ec2_metadata_containers + condition: container + +# On EC2 instances, 169.254.169.254 is a special IP used to fetch +# metadata about the instance. It may be desirable to prevent access +# to this IP from containers. +- rule: Contact EC2 Instance Metadata Service From Container + desc: Detect attempts to contact the EC2 Instance Metadata Service from a container + condition: outbound and fd.sip="169.254.169.254" and container and not ec2_metadata_containers + output: Outbound connection to EC2 instance metadata service (command=%proc.cmdline connection=%fd.name %container.info image=%container.image) + priority: NOTICE + tags: [network, aws, container] + +# In a local/user rules file, you should override this macro with the +# IP address of your k8s api server. The IP 1.2.3.4 is a placeholder +# IP that is not likely to be seen in practice. +- macro: k8s_api_server + condition: (fd.sip="1.2.3.4" and fd.sport=8080) + +# In a local/user rules file, list the container images that are +# allowed to contact the K8s API Server from within a container. This +# might cover cases where the K8s infrastructure itself is running +# within a container. +- macro: k8s_containers + condition: > + (container.image startswith gcr.io/google_containers/hyperkube-amd64 or + container.image startswith gcr.io/google_containers/kube2sky or + container.image startswith sysdig/agent or + container.image startswith sysdig/falco or + container.image startswith sysdig/sysdig) + +- rule: Contact K8S API Server From Container + desc: Detect attempts to contact the K8S API Server from a container + condition: outbound and k8s_api_server and container and not k8s_containers + output: Unexpected connection to K8s API Server from container (command=%proc.cmdline %container.info image=%container.image connection=%fd.name) + priority: NOTICE + tags: [network, k8s, container] + +# In a local/user rules file, list the container images that are +# allowed to contact NodePort services from within a container. This +# might cover cases where the K8s infrastructure itself is running +# within a container. +# +# By default, all containers are allowed to contact NodePort services. +- macro: nodeport_containers + condition: container + +- rule: Unexpected K8s NodePort Connection + desc: Detect attempts to use K8s NodePorts from a container + condition: (inbound_outbound) and fd.sport >= 30000 and fd.sport <= 32767 and container and not nodeport_containers + output: Unexpected K8s NodePort Connection (command=%proc.cmdline connection=%fd.name) + priority: NOTICE + tags: [network, k8s, container] + +# Application rules have moved to application_rules.yaml. Please look +# there if you want to enable them by adding to +# falco_rules.local.yaml. + diff --git a/kubernetes-response-engine/deployment/falco/falco-account.yaml b/kubernetes-response-engine/deployment/falco/falco-account.yaml new file mode 100644 index 00000000000..9d611519522 --- /dev/null +++ b/kubernetes-response-engine/deployment/falco/falco-account.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: falco-account +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: falco-cluster-role +rules: + - apiGroups: ["extensions",""] + resources: ["nodes","namespaces","pods","replicationcontrollers","services","events","configmaps"] + verbs: ["get","list","watch"] + - nonResourceURLs: ["/healthz", "/healthz/*"] + verbs: ["get"] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: falco-cluster-role-binding + namespace: default +subjects: + - kind: ServiceAccount + name: falco-account + namespace: default +roleRef: + kind: ClusterRole + name: falco-cluster-role + apiGroup: rbac.authorization.k8s.io diff --git a/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml b/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml new file mode 100644 index 00000000000..ecc4dcdb96e --- /dev/null +++ b/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml @@ -0,0 +1,84 @@ +apiVersion: extensions/v1beta1 +kind: DaemonSet +metadata: + name: falco + labels: + name: falco-daemonset + app: demo +spec: + template: + metadata: + labels: + name: falco + app: demo + role: security + spec: + serviceAccount: falco-account + containers: + - name: falco-nats + image: sysdig/falco-nats:latest + imagePullPolicy: Always + volumeMounts: + - mountPath: /var/run/falco/ + name: shared-pipe + - name: falco + image: sysdig/falco:latest + securityContext: + privileged: true + args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes", "-pk", "-U"] + volumeMounts: + - mountPath: /var/run/falco/ + name: shared-pipe + readOnly: false + - mountPath: /host/var/run/docker.sock + name: docker-socket + readOnly: true + - mountPath: /host/dev + name: dev-fs + readOnly: true + - mountPath: /host/proc + name: proc-fs + readOnly: true + - mountPath: /host/boot + name: boot-fs + readOnly: true + - mountPath: /host/lib/modules + name: lib-modules + readOnly: true + - mountPath: /host/usr + name: usr-fs + readOnly: true + - mountPath: /etc/falco + name: falco-config + initContainers: + - name: init-pipe + image: busybox + command: ['mkfifo','/var/run/falco/nats'] + volumeMounts: + - mountPath: /var/run/falco/ + name: shared-pipe + readOnly: false + volumes: + - name: shared-pipe + emptyDir: {} + - name: docker-socket + hostPath: + path: /var/run/docker.sock + - name: dev-fs + hostPath: + path: /dev + - name: proc-fs + hostPath: + path: /proc + - name: boot-fs + hostPath: + path: /boot + - name: lib-modules + hostPath: + path: /lib/modules + - name: usr-fs + hostPath: + path: /usr + - name: falco-config + configMap: + name: falco-config diff --git a/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml b/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml new file mode 100644 index 00000000000..0b6500d5742 --- /dev/null +++ b/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml @@ -0,0 +1,18 @@ +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: falco-event-generator + labels: + name: falco-event-generator + app: demo +spec: + replicas: 1 + template: + metadata: + labels: + name: falco-event-generator + app: demo + spec: + containers: + - name: falco-event-generator + image: sysdig/falco-event-generator:latest diff --git a/kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml b/kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml new file mode 100644 index 00000000000..ceb8374e14b --- /dev/null +++ b/kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: kubeless diff --git a/kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml b/kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml new file mode 100644 index 00000000000..570b9b274b2 --- /dev/null +++ b/kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml @@ -0,0 +1,369 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: controller-acct + namespace: kubeless +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: kubeless-controller-deployer +rules: +- apiGroups: + - "" + resources: + - services + - configmaps + verbs: + - create + - get + - delete + - list + - update + - patch +- apiGroups: + - apps + - extensions + resources: + - deployments + verbs: + - create + - get + - delete + - list + - update + - patch +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - delete +- apiGroups: + - "" + resourceNames: + - kubeless-registry-credentials + resources: + - secrets + verbs: + - get +- apiGroups: + - kubeless.io + resources: + - functions + - httptriggers + - cronjobtriggers + verbs: + - get + - list + - watch + - update + - delete +- apiGroups: + - batch + resources: + - cronjobs + - jobs + verbs: + - create + - get + - delete + - deletecollection + - list + - update + - patch +- apiGroups: + - autoscaling + resources: + - horizontalpodautoscalers + verbs: + - create + - get + - delete + - list + - update + - patch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list +- apiGroups: + - monitoring.coreos.com + resources: + - alertmanagers + - prometheuses + - servicemonitors + verbs: + - '*' +- apiGroups: + - extensions + resources: + - ingresses + verbs: + - create + - get + - list + - update + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: kubeless-controller-deployer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kubeless-controller-deployer +subjects: +- kind: ServiceAccount + name: controller-acct + namespace: kubeless +--- +apiVersion: apiextensions.k8s.io/v1beta1 +description: Kubernetes Native Serverless Framework +kind: CustomResourceDefinition +metadata: + name: functions.kubeless.io +spec: + group: kubeless.io + names: + kind: Function + plural: functions + singular: function + scope: Namespaced + version: v1beta1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +description: CRD object for HTTP trigger type +kind: CustomResourceDefinition +metadata: + name: httptriggers.kubeless.io +spec: + group: kubeless.io + names: + kind: HTTPTrigger + plural: httptriggers + singular: httptrigger + scope: Namespaced + version: v1beta1 +--- +apiVersion: apiextensions.k8s.io/v1beta1 +description: CRD object for HTTP trigger type +kind: CustomResourceDefinition +metadata: + name: cronjobtriggers.kubeless.io +spec: + group: kubeless.io + names: + kind: CronJobTrigger + plural: cronjobtriggers + singular: cronjobtrigger + scope: Namespaced + version: v1beta1 +--- +apiVersion: v1 +data: + builder-image: kubeless/function-image-builder:v1.0.0-alpha.6 + builder-image-secret: "" + deployment: '{}' + enable-build-step: "false" + function-registry-tls-verify: "true" + ingress-enabled: "false" + provision-image: kubeless/unzip@sha256:f162c062973cca05459834de6ed14c039d45df8cdb76097f50b028a1621b3697 + provision-image-secret: "" + runtime-images: |- + [ + { + "ID": "python", + "compiled": false, + "versions": [ + { + "name": "python27", + "version": "2.7", + "runtimeImage": "kubeless/python@sha256:07cfb0f3d8b6db045dc317d35d15634d7be5e436944c276bf37b1c630b03add8", + "initImage": "python:2.7" + }, + { + "name": "python34", + "version": "3.4", + "runtimeImage": "kubeless/python@sha256:f19640c547a3f91dbbfb18c15b5e624029b4065c1baf2892144e07c36f0a7c8f", + "initImage": "python:3.4" + }, + { + "name": "python36", + "version": "3.6", + "runtimeImage": "kubeless/python@sha256:0c9f8f727d42625a4e25230cfe612df7488b65f283e7972f84108d87e7443d72", + "initImage": "python:3.6" + } + ], + "depName": "requirements.txt", + "fileNameSuffix": ".py" + }, + { + "ID": "nodejs", + "compiled": false, + "versions": [ + { + "name": "node6", + "version": "6", + "runtimeImage": "kubeless/nodejs@sha256:013facddb0f66c150844192584d823d7dfb2b5b8d79fd2ae98439c86685da657", + "initImage": "node:6.10" + }, + { + "name": "node8", + "version": "8", + "runtimeImage": "kubeless/nodejs@sha256:b155d7e20e333044b60009c12a25a97c84eed610f2a3d9d314b47449dbdae0e5", + "initImage": "node:8" + } + ], + "depName": "package.json", + "fileNameSuffix": ".js" + }, + { + "ID": "nodejs_distroless", + "compiled": false, + "versions": [ + { + "name": "node8", + "version": "8", + "runtimeImage": "henrike42/kubeless/runtimes/nodejs/distroless:0.0.2", + "initImage": "node:8" + } + ], + "depName": "package.json", + "fileNameSuffix": ".js" + }, + { + "ID": "ruby", + "compiled": false, + "versions": [ + { + "name": "ruby24", + "version": "2.4", + "runtimeImage": "kubeless/ruby@sha256:01665f1a32fe4fab4195af048627857aa7b100e392ae7f3e25a44bd296d6f105", + "initImage": "bitnami/ruby:2.4" + } + ], + "depName": "Gemfile", + "fileNameSuffix": ".rb" + }, + { + "ID": "php", + "compiled": false, + "versions": [ + { + "name": "php72", + "version": "7.2", + "runtimeImage": "kubeless/php@sha256:9b86066b2640bedcd88acb27f43dfaa2b338f0d74d9d91131ea781402f7ec8ec", + "initImage": "composer:1.6" + } + ], + "depName": "composer.json", + "fileNameSuffix": ".php" + }, + { + "ID": "go", + "compiled": true, + "versions": [ + { + "name": "go1.10", + "version": "1.10", + "runtimeImage": "kubeless/go@sha256:e2fd49f09b6ff8c9bac6f1592b3119ea74237c47e2955a003983e08524cb3ae5", + "initImage": "kubeless/go-init@sha256:983b3f06452321a2299588966817e724d1a9c24be76cf1b12c14843efcdff502" + } + ], + "depName": "Gopkg.toml", + "fileNameSuffix": ".go" + }, + { + "ID": "dotnetcore", + "compiled": true, + "versions": [ + { + "name": "dotnetcore2.0", + "version": "2.0", + "runtimeImage": "allantargino/kubeless-dotnetcore@sha256:1699b07d9fc0276ddfecc2f823f272d96fd58bbab82d7e67f2fd4982a95aeadc", + "initImage": "allantargino/aspnetcore-build@sha256:0d60f845ff6c9c019362a68b87b3920f3eb2d32f847f2d75e4d190cc0ce1d81c" + } + ], + "depName": "project.csproj", + "fileNameSuffix": ".cs" + }, + { + "ID": "java", + "compiled": true, + "versions": [ + { + "name": "java1.8", + "version": "1.8", + "runtimeImage": "kubeless/java@sha256:debf9502545f4c0e955eb60fabb45748c5d98ed9365c4a508c07f38fc7fefaac", + "initImage": "kubeless/java-init@sha256:7e5e4376d3ab76c336d4830c9ed1b7f9407415feca49b8c2bf013e279256878f" + } + ], + "depName": "pom.xml", + "fileNameSuffix": ".java" + }, + { + "ID": "ballerina", + "compiled": true, + "versions": [ + { + "name": "ballerina0.975.0", + "version": "0.975.0", + "runtimeImage": "kubeless/ballerina@sha256:83e51423972f4b0d6b419bee0b4afb3bb87d2bf1b604ebc4366c430e7cc28a35", + "initImage": "kubeless/ballerina-init@sha256:05857ce439a7e290f9d86f8cb38ea3b574670c0c0e91af93af06686fa21ecf4f" + } + ], + "depName": "", + "fileNameSuffix": ".bal" + } + ] + service-type: ClusterIP +kind: ConfigMap +metadata: + name: kubeless-config + namespace: kubeless +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + labels: + kubeless: controller + name: kubeless-controller-manager + namespace: kubeless +spec: + selector: + matchLabels: + kubeless: controller + template: + metadata: + labels: + kubeless: controller + spec: + containers: + - env: + - name: KUBELESS_INGRESS_ENABLED + valueFrom: + configMapKeyRef: + key: ingress-enabled + name: kubeless-config + - name: KUBELESS_SERVICE_TYPE + valueFrom: + configMapKeyRef: + key: service-type + name: kubeless-config + - name: KUBELESS_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: KUBELESS_CONFIG + value: kubeless-config + image: bitnami/kubeless-controller-manager:v1.0.0-alpha.6 + imagePullPolicy: IfNotPresent + name: kubeless-controller-manager + serviceAccountName: controller-acct diff --git a/kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml b/kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml new file mode 100644 index 00000000000..049b61c5f66 --- /dev/null +++ b/kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml @@ -0,0 +1,74 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: nats-controller-deployer +rules: +- apiGroups: + - "" + resources: + - services + - configmaps + verbs: + - get + - list +- apiGroups: + - kubeless.io + resources: + - functions + - natstriggers + verbs: + - get + - list + - watch + - update + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: nats-controller-deployer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nats-controller-deployer +subjects: +- kind: ServiceAccount + name: controller-acct + namespace: kubeless +--- +apiVersion: apiextensions.k8s.io/v1beta1 +description: CRD object for NATS trigger type +kind: CustomResourceDefinition +metadata: + name: natstriggers.kubeless.io +spec: + group: kubeless.io + names: + kind: NATSTrigger + plural: natstriggers + singular: natstrigger + scope: Namespaced + version: v1beta1 +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + labels: + kubeless: nats-trigger-controller + name: nats-trigger-controller + namespace: kubeless +spec: + selector: + matchLabels: + kubeless: nats-trigger-controller + template: + metadata: + labels: + kubeless: nats-trigger-controller + spec: + containers: + - image: bitnami/nats-trigger-controller:v1.0.0-alpha.6 + imagePullPolicy: IfNotPresent + name: nats-trigger-controller + serviceAccountName: controller-acct diff --git a/kubernetes-response-engine/deployment/nats/deployment-rbac.yaml b/kubernetes-response-engine/deployment/nats/deployment-rbac.yaml new file mode 100644 index 00000000000..fdd05108b97 --- /dev/null +++ b/kubernetes-response-engine/deployment/nats/deployment-rbac.yaml @@ -0,0 +1,82 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: nats-io +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: nats-operator + namespace: nats-io +--- +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: nats-operator + namespace: nats-io +spec: + replicas: 1 + selector: + matchLabels: + name: nats-operator + template: + metadata: + labels: + name: nats-operator + spec: + serviceAccountName: nats-operator + containers: + - name: nats-operator + image: connecteverything/nats-operator:0.2.2-v1alpha2 + imagePullPolicy: Always + env: + - name: MY_POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: MY_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: nats-io:nats-operator-binding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nats-io:nats-operator +subjects: +- kind: ServiceAccount + name: nats-operator + namespace: nats-io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: nats-io:nats-operator +rules: +# Allow creating CRDs +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: ["*"] +# Allow all actions on NatsClusters +- apiGroups: + - nats.io + resources: + - natsclusters + verbs: ["*"] +# Allow actions on basic Kubernetes objects +- apiGroups: [""] + resources: + - configmaps + - secrets + - pods + - services + - endpoints + - events + verbs: ["*"] diff --git a/kubernetes-response-engine/deployment/nats/nats-cluster.yaml b/kubernetes-response-engine/deployment/nats/nats-cluster.yaml new file mode 100644 index 00000000000..83056935582 --- /dev/null +++ b/kubernetes-response-engine/deployment/nats/nats-cluster.yaml @@ -0,0 +1,8 @@ +apiVersion: "nats.io/v1alpha2" +kind: "NatsCluster" +metadata: + name: "nats" + namespace: "nats-io" +spec: + size: 3 + version: "1.1.0" diff --git a/kubernetes-response-engine/deployment/network-policy.yaml b/kubernetes-response-engine/deployment/network-policy.yaml new file mode 100644 index 00000000000..d9d4ed12450 --- /dev/null +++ b/kubernetes-response-engine/deployment/network-policy.yaml @@ -0,0 +1,11 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: isolate +spec: + podSelector: + matchLabels: + isolated: 'true' + policyTypes: + - Ingress + - Egress From 42285687d48de198442c0cbefecc7201ee57fe73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 18:16:57 +0200 Subject: [PATCH 08/13] Add a README for Kubernetes infrastructure --- .../deployment/README.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 kubernetes-response-engine/deployment/README.md diff --git a/kubernetes-response-engine/deployment/README.md b/kubernetes-response-engine/deployment/README.md new file mode 100644 index 00000000000..3d97606e93f --- /dev/null +++ b/kubernetes-response-engine/deployment/README.md @@ -0,0 +1,20 @@ +# Kubernetes Manifests for Kubernetes Response Engine + +In this directory are the manifests for creating required infrastructure in the +Kubernetes cluster + +## Deploy + +For deploying NATS, Falco + Falco-NATS output and Kubeless just run default Makefile target: + +``` +make +``` + +## Clean + +You can clean your cluster with: + +``` +make clean +``` From 46405510e20757dc5254265144b66f0a8389966c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Tue, 10 Jul 2018 18:19:20 +0200 Subject: [PATCH 09/13] Update link target --- kubernetes-response-engine/falco-nats/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubernetes-response-engine/falco-nats/README.md b/kubernetes-response-engine/falco-nats/README.md index 5e32e319ab4..86fd51065ba 100644 --- a/kubernetes-response-engine/falco-nats/README.md +++ b/kubernetes-response-engine/falco-nats/README.md @@ -9,7 +9,7 @@ Pod as Falco. ## Configuration -You have a [complete Kubernetes manifest available](https://github.com/draios/falco/tree/kubernetes-response-engine/deployment/falco-daemonset.yaml) for future reading. +You have a [complete Kubernetes manifest available](https://github.com/draios/falco/tree/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml) for future reading. Take a look at sidecar container and to the initContainers directive which craetes the shared pipe between containers. From 95435142701def9a7162603d63067e097aeb3e82 Mon Sep 17 00:00:00 2001 From: Jorge Salamero Sanz Date: Tue, 10 Jul 2018 18:29:02 +0200 Subject: [PATCH 10/13] Update README.md --- kubernetes-response-engine/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kubernetes-response-engine/README.md b/kubernetes-response-engine/README.md index 86747c31727..5f8e83e70dd 100644 --- a/kubernetes-response-engine/README.md +++ b/kubernetes-response-engine/README.md @@ -4,7 +4,7 @@ A response engine for Falco that allows to process security events executing pla ## Architecture -* *[Falco](https://sysdig.com/opensource/falco/)* monitors containers and processes behavior to alert when something outside our policy takes place. +* *[Falco](https://sysdig.com/opensource/falco/)* monitors containers and processes to alert on unexpected behavior. This is defined through the runtime policy built from multiple rules that define what the system should and shouldn't do. * *falco-nats* forwards the alert to a message broker service into a topic compound by `falco..`. * *[NATS](https://nats.io/)*, our message broker, delivers the alert to any subscribers to the different topics. * *[Kubeless](https://kubeless.io/)*, a FaaS framework that runs in Kubernetes, receives the security events and executes the configured playbooks. From bebdff3d6761cb473ba7f2f8b1787d6e9b62a9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Wed, 11 Jul 2018 17:18:56 +0200 Subject: [PATCH 11/13] This rule does not add any value to the integration It was just an example for cryptomining. --- .../falco-config/falco_rules.local.yaml | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml b/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml index 8c6e89fee3f..3c8e3bb5aa8 100644 --- a/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml +++ b/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml @@ -11,28 +11,3 @@ # tags: [users, container] # Or override/append to any rule, macro, or list from the Default Rules - -- macro: node_app_frontend - condition: k8s.ns.name = node-app and k8s.pod.label.role = frontend and k8s.pod.label.app = node-app - -- rule: Detect crypto miners using the Stratum protocol - desc: Miners typically specify the mining pool to connect to with a URI that begins with 'stratum+tcp' - condition: node_app_frontend and spawned_process and container.id != host and proc.cmdline contains stratum+tcp - output: Possible miner ran inside a container (command=%proc.cmdline %container.info) - priority: CRITICAL - -- list: miner_ports - items: [ - 3333, 4444, 8333, 7777, 7778, 3357, - 3335, 8899, 8888, 5730, 5588, 8118, - 6099, 9332, 1 - ] - -- macro: miner_port_connection - condition: fd.sport in (miner_ports) - -- rule: Detect outbound connections to common miner pool ports - desc: Miners typically connect to miner pools on common ports. - condition: node_app_frontend and outbound and miner_port_connection - output: "Outbound connection to common miner port (command=%proc.cmdline port=%fd.rport %container.info)" - priority: CRITICAL \ No newline at end of file From 3afe04629a49e476856f06026a6a9afc1a7e2e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Wed, 11 Jul 2018 17:49:25 +0200 Subject: [PATCH 12/13] Move kubernetes_response_engine under integrations A top level directory for this integration could led to confussion. --- .../kubernetes-response-engine}/README.md | 0 .../kubernetes-response-engine}/deployment/Makefile | 0 .../kubernetes-response-engine}/deployment/README.md | 0 .../deployment/falco-config/falco.yaml | 0 .../deployment/falco-config/falco_rules.local.yaml | 0 .../deployment/falco-config/falco_rules.yaml | 0 .../deployment/falco/falco-account.yaml | 0 .../deployment/falco/falco-daemonset.yaml | 0 .../deployment/falco/falco-event-generator.yaml | 0 .../deployment/kubeless/kubeless-namespace.yaml | 0 .../deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml | 0 .../deployment/kubeless/nats-v1.0.0-alpha.6.yaml | 0 .../deployment/nats/deployment-rbac.yaml | 0 .../kubernetes-response-engine}/deployment/nats/nats-cluster.yaml | 0 .../kubernetes-response-engine}/deployment/network-policy.yaml | 0 .../kubernetes-response-engine}/falco-nats/.gitignore | 0 .../kubernetes-response-engine}/falco-nats/Dockerfile | 0 .../kubernetes-response-engine}/falco-nats/Makefile | 0 .../kubernetes-response-engine}/falco-nats/README.md | 0 .../kubernetes-response-engine}/falco-nats/main.go | 0 .../kubernetes-response-engine}/playbooks/.gitignore | 0 .../kubernetes-response-engine}/playbooks/Pipfile | 0 .../kubernetes-response-engine}/playbooks/Pipfile.lock | 0 .../kubernetes-response-engine}/playbooks/README.md | 0 .../kubernetes-response-engine}/playbooks/delete.py | 0 .../kubernetes-response-engine}/playbooks/deploy_playbook | 0 .../kubernetes-response-engine}/playbooks/isolate.py | 0 .../kubernetes-response-engine}/playbooks/playbooks/__init__.py | 0 .../playbooks/playbooks/infrastructure.py | 0 .../kubernetes-response-engine}/playbooks/setup.py | 0 .../kubernetes-response-engine}/playbooks/slack.py | 0 .../playbooks/specs/infrastructure/kubernetes_client_spec.py | 0 .../playbooks/specs/infrastructure/slack_client_spec.py | 0 .../specs/playbooks/add_message_to_slack_playbook_spec.py | 0 .../playbooks/specs/playbooks/delete_pod_playbook_spec.py | 0 .../specs/playbooks/network_isolate_pod_playbook_spec.py | 0 .../playbooks/specs/playbooks/taint_node_playbook_spec.py | 0 .../playbooks/specs/support/deployment.yaml | 0 .../kubernetes-response-engine}/playbooks/taint.py | 0 39 files changed, 0 insertions(+), 0 deletions(-) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/README.md (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/Makefile (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/README.md (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/falco-config/falco.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/falco-config/falco_rules.local.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/falco-config/falco_rules.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/falco/falco-account.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/falco/falco-daemonset.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/falco/falco-event-generator.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/kubeless/kubeless-namespace.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/kubeless/nats-v1.0.0-alpha.6.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/nats/deployment-rbac.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/nats/nats-cluster.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/deployment/network-policy.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/falco-nats/.gitignore (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/falco-nats/Dockerfile (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/falco-nats/Makefile (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/falco-nats/README.md (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/falco-nats/main.go (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/.gitignore (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/Pipfile (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/Pipfile.lock (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/README.md (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/delete.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/deploy_playbook (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/isolate.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/playbooks/__init__.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/playbooks/infrastructure.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/setup.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/slack.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/infrastructure/kubernetes_client_spec.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/infrastructure/slack_client_spec.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/playbooks/delete_pod_playbook_spec.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/playbooks/taint_node_playbook_spec.py (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/specs/support/deployment.yaml (100%) rename {kubernetes-response-engine => integrations/kubernetes-response-engine}/playbooks/taint.py (100%) diff --git a/kubernetes-response-engine/README.md b/integrations/kubernetes-response-engine/README.md similarity index 100% rename from kubernetes-response-engine/README.md rename to integrations/kubernetes-response-engine/README.md diff --git a/kubernetes-response-engine/deployment/Makefile b/integrations/kubernetes-response-engine/deployment/Makefile similarity index 100% rename from kubernetes-response-engine/deployment/Makefile rename to integrations/kubernetes-response-engine/deployment/Makefile diff --git a/kubernetes-response-engine/deployment/README.md b/integrations/kubernetes-response-engine/deployment/README.md similarity index 100% rename from kubernetes-response-engine/deployment/README.md rename to integrations/kubernetes-response-engine/deployment/README.md diff --git a/kubernetes-response-engine/deployment/falco-config/falco.yaml b/integrations/kubernetes-response-engine/deployment/falco-config/falco.yaml similarity index 100% rename from kubernetes-response-engine/deployment/falco-config/falco.yaml rename to integrations/kubernetes-response-engine/deployment/falco-config/falco.yaml diff --git a/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml b/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml similarity index 100% rename from kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml rename to integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml diff --git a/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml b/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml similarity index 100% rename from kubernetes-response-engine/deployment/falco-config/falco_rules.yaml rename to integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml diff --git a/kubernetes-response-engine/deployment/falco/falco-account.yaml b/integrations/kubernetes-response-engine/deployment/falco/falco-account.yaml similarity index 100% rename from kubernetes-response-engine/deployment/falco/falco-account.yaml rename to integrations/kubernetes-response-engine/deployment/falco/falco-account.yaml diff --git a/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml b/integrations/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml similarity index 100% rename from kubernetes-response-engine/deployment/falco/falco-daemonset.yaml rename to integrations/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml diff --git a/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml b/integrations/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml similarity index 100% rename from kubernetes-response-engine/deployment/falco/falco-event-generator.yaml rename to integrations/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml diff --git a/kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml b/integrations/kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml similarity index 100% rename from kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml rename to integrations/kubernetes-response-engine/deployment/kubeless/kubeless-namespace.yaml diff --git a/kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml b/integrations/kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml similarity index 100% rename from kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml rename to integrations/kubernetes-response-engine/deployment/kubeless/kubeless-v1.0.0-alpha.6.yaml diff --git a/kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml b/integrations/kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml similarity index 100% rename from kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml rename to integrations/kubernetes-response-engine/deployment/kubeless/nats-v1.0.0-alpha.6.yaml diff --git a/kubernetes-response-engine/deployment/nats/deployment-rbac.yaml b/integrations/kubernetes-response-engine/deployment/nats/deployment-rbac.yaml similarity index 100% rename from kubernetes-response-engine/deployment/nats/deployment-rbac.yaml rename to integrations/kubernetes-response-engine/deployment/nats/deployment-rbac.yaml diff --git a/kubernetes-response-engine/deployment/nats/nats-cluster.yaml b/integrations/kubernetes-response-engine/deployment/nats/nats-cluster.yaml similarity index 100% rename from kubernetes-response-engine/deployment/nats/nats-cluster.yaml rename to integrations/kubernetes-response-engine/deployment/nats/nats-cluster.yaml diff --git a/kubernetes-response-engine/deployment/network-policy.yaml b/integrations/kubernetes-response-engine/deployment/network-policy.yaml similarity index 100% rename from kubernetes-response-engine/deployment/network-policy.yaml rename to integrations/kubernetes-response-engine/deployment/network-policy.yaml diff --git a/kubernetes-response-engine/falco-nats/.gitignore b/integrations/kubernetes-response-engine/falco-nats/.gitignore similarity index 100% rename from kubernetes-response-engine/falco-nats/.gitignore rename to integrations/kubernetes-response-engine/falco-nats/.gitignore diff --git a/kubernetes-response-engine/falco-nats/Dockerfile b/integrations/kubernetes-response-engine/falco-nats/Dockerfile similarity index 100% rename from kubernetes-response-engine/falco-nats/Dockerfile rename to integrations/kubernetes-response-engine/falco-nats/Dockerfile diff --git a/kubernetes-response-engine/falco-nats/Makefile b/integrations/kubernetes-response-engine/falco-nats/Makefile similarity index 100% rename from kubernetes-response-engine/falco-nats/Makefile rename to integrations/kubernetes-response-engine/falco-nats/Makefile diff --git a/kubernetes-response-engine/falco-nats/README.md b/integrations/kubernetes-response-engine/falco-nats/README.md similarity index 100% rename from kubernetes-response-engine/falco-nats/README.md rename to integrations/kubernetes-response-engine/falco-nats/README.md diff --git a/kubernetes-response-engine/falco-nats/main.go b/integrations/kubernetes-response-engine/falco-nats/main.go similarity index 100% rename from kubernetes-response-engine/falco-nats/main.go rename to integrations/kubernetes-response-engine/falco-nats/main.go diff --git a/kubernetes-response-engine/playbooks/.gitignore b/integrations/kubernetes-response-engine/playbooks/.gitignore similarity index 100% rename from kubernetes-response-engine/playbooks/.gitignore rename to integrations/kubernetes-response-engine/playbooks/.gitignore diff --git a/kubernetes-response-engine/playbooks/Pipfile b/integrations/kubernetes-response-engine/playbooks/Pipfile similarity index 100% rename from kubernetes-response-engine/playbooks/Pipfile rename to integrations/kubernetes-response-engine/playbooks/Pipfile diff --git a/kubernetes-response-engine/playbooks/Pipfile.lock b/integrations/kubernetes-response-engine/playbooks/Pipfile.lock similarity index 100% rename from kubernetes-response-engine/playbooks/Pipfile.lock rename to integrations/kubernetes-response-engine/playbooks/Pipfile.lock diff --git a/kubernetes-response-engine/playbooks/README.md b/integrations/kubernetes-response-engine/playbooks/README.md similarity index 100% rename from kubernetes-response-engine/playbooks/README.md rename to integrations/kubernetes-response-engine/playbooks/README.md diff --git a/kubernetes-response-engine/playbooks/delete.py b/integrations/kubernetes-response-engine/playbooks/delete.py similarity index 100% rename from kubernetes-response-engine/playbooks/delete.py rename to integrations/kubernetes-response-engine/playbooks/delete.py diff --git a/kubernetes-response-engine/playbooks/deploy_playbook b/integrations/kubernetes-response-engine/playbooks/deploy_playbook similarity index 100% rename from kubernetes-response-engine/playbooks/deploy_playbook rename to integrations/kubernetes-response-engine/playbooks/deploy_playbook diff --git a/kubernetes-response-engine/playbooks/isolate.py b/integrations/kubernetes-response-engine/playbooks/isolate.py similarity index 100% rename from kubernetes-response-engine/playbooks/isolate.py rename to integrations/kubernetes-response-engine/playbooks/isolate.py diff --git a/kubernetes-response-engine/playbooks/playbooks/__init__.py b/integrations/kubernetes-response-engine/playbooks/playbooks/__init__.py similarity index 100% rename from kubernetes-response-engine/playbooks/playbooks/__init__.py rename to integrations/kubernetes-response-engine/playbooks/playbooks/__init__.py diff --git a/kubernetes-response-engine/playbooks/playbooks/infrastructure.py b/integrations/kubernetes-response-engine/playbooks/playbooks/infrastructure.py similarity index 100% rename from kubernetes-response-engine/playbooks/playbooks/infrastructure.py rename to integrations/kubernetes-response-engine/playbooks/playbooks/infrastructure.py diff --git a/kubernetes-response-engine/playbooks/setup.py b/integrations/kubernetes-response-engine/playbooks/setup.py similarity index 100% rename from kubernetes-response-engine/playbooks/setup.py rename to integrations/kubernetes-response-engine/playbooks/setup.py diff --git a/kubernetes-response-engine/playbooks/slack.py b/integrations/kubernetes-response-engine/playbooks/slack.py similarity index 100% rename from kubernetes-response-engine/playbooks/slack.py rename to integrations/kubernetes-response-engine/playbooks/slack.py diff --git a/kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py b/integrations/kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py similarity index 100% rename from kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py rename to integrations/kubernetes-response-engine/playbooks/specs/infrastructure/kubernetes_client_spec.py diff --git a/kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py b/integrations/kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py similarity index 100% rename from kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py rename to integrations/kubernetes-response-engine/playbooks/specs/infrastructure/slack_client_spec.py diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py b/integrations/kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py similarity index 100% rename from kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py rename to integrations/kubernetes-response-engine/playbooks/specs/playbooks/add_message_to_slack_playbook_spec.py diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py b/integrations/kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py similarity index 100% rename from kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py rename to integrations/kubernetes-response-engine/playbooks/specs/playbooks/delete_pod_playbook_spec.py diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py b/integrations/kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py similarity index 100% rename from kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py rename to integrations/kubernetes-response-engine/playbooks/specs/playbooks/network_isolate_pod_playbook_spec.py diff --git a/kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py b/integrations/kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py similarity index 100% rename from kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py rename to integrations/kubernetes-response-engine/playbooks/specs/playbooks/taint_node_playbook_spec.py diff --git a/kubernetes-response-engine/playbooks/specs/support/deployment.yaml b/integrations/kubernetes-response-engine/playbooks/specs/support/deployment.yaml similarity index 100% rename from kubernetes-response-engine/playbooks/specs/support/deployment.yaml rename to integrations/kubernetes-response-engine/playbooks/specs/support/deployment.yaml diff --git a/kubernetes-response-engine/playbooks/taint.py b/integrations/kubernetes-response-engine/playbooks/taint.py similarity index 100% rename from kubernetes-response-engine/playbooks/taint.py rename to integrations/kubernetes-response-engine/playbooks/taint.py From bed360497e0c9d37d7786f2d518d7057e8dec3e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Salceda?= Date: Wed, 11 Jul 2018 17:52:11 +0200 Subject: [PATCH 13/13] Remove repeated configurations and other stuff As long as this PR merged, this is not needed: https://github.com/kubernetes/charts/pull/6600 --- .../deployment/Makefile | 4 - .../deployment/falco-config/falco.yaml | 102 -- .../falco-config/falco_rules.local.yaml | 13 - .../deployment/falco-config/falco_rules.yaml | 1540 ----------------- .../deployment/falco/falco-account.yaml | 29 - .../deployment/falco/falco-daemonset.yaml | 84 - .../falco/falco-event-generator.yaml | 18 - 7 files changed, 1790 deletions(-) delete mode 100644 integrations/kubernetes-response-engine/deployment/falco-config/falco.yaml delete mode 100644 integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml delete mode 100644 integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml delete mode 100644 integrations/kubernetes-response-engine/deployment/falco/falco-account.yaml delete mode 100644 integrations/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml delete mode 100644 integrations/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml diff --git a/integrations/kubernetes-response-engine/deployment/Makefile b/integrations/kubernetes-response-engine/deployment/Makefile index df2c4cb049d..c02c718c167 100644 --- a/integrations/kubernetes-response-engine/deployment/Makefile +++ b/integrations/kubernetes-response-engine/deployment/Makefile @@ -1,13 +1,9 @@ deploy: kubectl apply -f nats/ - kubectl create configmap falco-config --from-file=falco-config/ || true - kubectl apply -f falco/ kubectl apply -f kubeless/ kubectl apply -f network-policy.yaml clean: kubectl delete -f kubeless/ - kubectl delete configmap falco-config - kubectl delete -f falco/ kubectl delete -f nats/ kubectl delete -f network-policy.yaml diff --git a/integrations/kubernetes-response-engine/deployment/falco-config/falco.yaml b/integrations/kubernetes-response-engine/deployment/falco-config/falco.yaml deleted file mode 100644 index 9ce40534524..00000000000 --- a/integrations/kubernetes-response-engine/deployment/falco-config/falco.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# File(s) or Directories containing Falco rules, loaded at startup. -# The name "rules_file" is only for backwards compatibility. -# If the entry is a file, it will be read directly. If the entry is a directory, -# every file in that directory will be read, in alphabetical order. -# -# falco_rules.yaml ships with the falco package and is overridden with -# every new software version. falco_rules.local.yaml is only created -# if it doesn't exist. If you want to customize the set of rules, add -# your customizations to falco_rules.local.yaml. -# -# The files will be read in the order presented here, so make sure if -# you have overrides they appear in later files. -rules_file: - - /etc/falco/falco_rules.yaml - - /etc/falco/falco_rules.local.yaml - - /etc/falco/rules.d - -# Whether to output events in json or text -json_output: true - -# When using json output, whether or not to include the "output" property -# itself (e.g. "File below a known binary directory opened for writing -# (user=root ....") in the json output. -json_include_output_property: true - -# Send information logs to stderr and/or syslog Note these are *not* security -# notification logs! These are just Falco lifecycle (and possibly error) logs. -log_stderr: true -log_syslog: true - -# Minimum log level to include in logs. Note: these levels are -# separate from the priority field of rules. This refers only to the -# log level of falco's internal logging. Can be one of "emergency", -# "alert", "critical", "error", "warning", "notice", "info", "debug". -log_level: info - -# Minimum rule priority level to load and run. All rules having a -# priority more severe than this level will be loaded/run. Can be one -# of "emergency", "alert", "critical", "error", "warning", "notice", -# "info", "debug". -priority: debug - -# Whether or not output to any of the output channels below is -# buffered. Defaults to true -buffered_outputs: true - -# A throttling mechanism implemented as a token bucket limits the -# rate of falco notifications. This throttling is controlled by the following configuration -# options: -# - rate: the number of tokens (i.e. right to send a notification) -# gained per second. Defaults to 1. -# - max_burst: the maximum number of tokens outstanding. Defaults to 1000. -# -# With these defaults, falco could send up to 1000 notifications after -# an initial quiet period, and then up to 1 notification per second -# afterward. It would gain the full burst back after 1000 seconds of -# no activity. - -outputs: - rate: 1 - max_burst: 1000 - -# Where security notifications should go. -# Multiple outputs can be enabled. - -syslog_output: - enabled: true - -# If keep_alive is set to true, the file will be opened once and -# continuously written to, with each output message on its own -# line. If keep_alive is set to false, the file will be re-opened -# for each output message. -# -# Also, the file will be closed and reopened if falco is signaled with -# SIGUSR1. - -file_output: - enabled: true - keep_alive: true - filename: /var/run/falco/nats - -stdout_output: - enabled: true - -# Possible additional things you might want to do with program output: -# - send to a slack webhook: -# program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXX" -# - logging (alternate method than syslog): -# program: logger -t falco-test -# - send over a network connection: -# program: nc host.example.com 80 - -# If keep_alive is set to true, the program will be started once and -# continuously written to, with each output message on its own -# line. If keep_alive is set to false, the program will be re-spawned -# for each output message. -# -# Also, the program will be closed and reopened if falco is signaled with -# SIGUSR1. - - - diff --git a/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml b/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml deleted file mode 100644 index 3c8e3bb5aa8..00000000000 --- a/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.local.yaml +++ /dev/null @@ -1,13 +0,0 @@ -#################### -# Your custom rules! -#################### - -# Add new rules, like this one -# - rule: The program "sudo" is run in a container -# desc: An event will trigger every time you run sudo in a container -# condition: evt.type = execve and evt.dir=< and container.id != host and proc.name = sudo -# output: "Sudo run in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline)" -# priority: ERROR -# tags: [users, container] - -# Or override/append to any rule, macro, or list from the Default Rules diff --git a/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml b/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml deleted file mode 100644 index 58f4ea43d23..00000000000 --- a/integrations/kubernetes-response-engine/deployment/falco-config/falco_rules.yaml +++ /dev/null @@ -1,1540 +0,0 @@ -# Currently disabled as read/write are ignored syscalls. The nearly -# similar open_write/open_read check for files being opened for -# reading/writing. -# - macro: write -# condition: (syscall.type=write and fd.type in (file, directory)) -# - macro: read -# condition: (syscall.type=read and evt.dir=> and fd.type in (file, directory)) - -- macro: open_write - condition: (evt.type=open or evt.type=openat) and evt.is_open_write=true and fd.typechar='f' and fd.num>=0 - -- macro: open_read - condition: (evt.type=open or evt.type=openat) and evt.is_open_read=true and fd.typechar='f' and fd.num>=0 - -- macro: never_true - condition: (evt.num=0) - -- macro: always_true - condition: (evt.num=>0) - -# In some cases, such as dropped system call events, information about -# the process name may be missing. For some rules that really depend -# on the identity of the process performing an action such as opening -# a file, etc., we require that the process name be known. -- macro: proc_name_exists - condition: (proc.name!="") - -- macro: rename - condition: evt.type in (rename, renameat) -- macro: mkdir - condition: evt.type = mkdir -- macro: remove - condition: evt.type in (rmdir, unlink, unlinkat) - -- macro: modify - condition: rename or remove - -- macro: spawned_process - condition: evt.type = execve and evt.dir=< - -# File categories -- macro: bin_dir - condition: fd.directory in (/bin, /sbin, /usr/bin, /usr/sbin) - -- macro: bin_dir_mkdir - condition: > - (evt.arg[1] startswith /bin/ or - evt.arg[1] startswith /sbin/ or - evt.arg[1] startswith /usr/bin/ or - evt.arg[1] startswith /usr/sbin/) - -- macro: bin_dir_rename - condition: > - evt.arg[1] startswith /bin/ or - evt.arg[1] startswith /sbin/ or - evt.arg[1] startswith /usr/bin/ or - evt.arg[1] startswith /usr/sbin/ - -- macro: etc_dir - condition: fd.name startswith /etc/ - -# This detects writes immediately below / or any write anywhere below /root -- macro: root_dir - condition: ((fd.directory=/ or fd.name startswith /root) and fd.name contains "/") - -- list: shell_binaries - items: [bash, csh, ksh, sh, tcsh, zsh, dash] - -- list: shell_mgmt_binaries - items: [add-shell, remove-shell] - -- macro: shell_procs - condition: (proc.name in (shell_binaries)) - -- list: coreutils_binaries - items: [ - truncate, sha1sum, numfmt, fmt, fold, uniq, cut, who, - groups, csplit, sort, expand, printf, printenv, unlink, tee, chcon, stat, - basename, split, nice, "yes", whoami, sha224sum, hostid, users, stdbuf, - base64, unexpand, cksum, od, paste, nproc, pathchk, sha256sum, wc, test, - comm, arch, du, factor, sha512sum, md5sum, tr, runcon, env, dirname, - tsort, join, shuf, install, logname, pinky, nohup, expr, pr, tty, timeout, - tail, "[", seq, sha384sum, nl, head, id, mkfifo, sum, dircolors, ptx, shred, - tac, link, chroot, vdir, chown, touch, ls, dd, uname, "true", pwd, date, - chgrp, chmod, mktemp, cat, mknod, sync, ln, "false", rm, mv, cp, echo, - readlink, sleep, stty, mkdir, df, dir, rmdir, touch - ] - -# dpkg -L login | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," -- list: login_binaries - items: [ - login, systemd, '"(systemd)"', systemd-logind, su, - nologin, faillog, lastlog, newgrp, sg - ] - -# dpkg -L passwd | grep bin | xargs ls -ld | grep -v '^d' | awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," -- list: passwd_binaries - items: [ - shadowconfig, grpck, pwunconv, grpconv, pwck, - groupmod, vipw, pwconv, useradd, newusers, cppw, chpasswd, usermod, - groupadd, groupdel, grpunconv, chgpasswd, userdel, chage, chsh, - gpasswd, chfn, expiry, passwd, vigr, cpgr - ] - -# repoquery -l shadow-utils | grep bin | xargs ls -ld | grep -v '^d' | -# awk '{print $9}' | xargs -L 1 basename | tr "\\n" "," -- list: shadowutils_binaries - items: [ - chage, gpasswd, lastlog, newgrp, sg, adduser, deluser, chpasswd, - groupadd, groupdel, addgroup, delgroup, groupmems, groupmod, grpck, grpconv, grpunconv, - newusers, pwck, pwconv, pwunconv, useradd, userdel, usermod, vigr, vipw, unix_chkpwd - ] - -- list: sysdigcloud_binaries - items: [setup-backend, dragent, sdchecks] - -- list: docker_binaries - items: [docker, dockerd, exe, docker-compose, docker-entrypoi, docker-runc-cur, docker-current] - -- list: k8s_binaries - items: [hyperkube, skydns, kube2sky, exechealthz] - -- list: lxd_binaries - items: [lxd, lxcfs] - -- list: http_server_binaries - items: [nginx, httpd, httpd-foregroun, lighttpd, apache, apache2] - -- list: db_server_binaries - items: [mysqld, postgres, sqlplus] - -- list: mysql_mgmt_binaries - items: [mysql_install_d, mysql_ssl_rsa_s] - -- list: postgres_mgmt_binaries - items: [pg_dumpall, pg_ctl, pg_lsclusters, pg_ctlcluster] - -- list: db_mgmt_binaries - items: [mysql_mgmt_binaries, postgres_mgmt_binaries] - -- list: nosql_server_binaries - items: [couchdb, memcached, redis-server, rabbitmq-server, mongod] - -- list: gitlab_binaries - items: [gitlab-shell, gitlab-mon, gitlab-runner-b, git] - -- macro: server_procs - condition: proc.name in (http_server_binaries, db_server_binaries, docker_binaries, sshd) - -# The explicit quotes are needed to avoid the - characters being -# interpreted by the filter expression. -- list: rpm_binaries - items: [dnf, rpm, rpmkey, yum, '"75-system-updat"', rhsmcertd-worke, subscription-ma, - repoquery, rpmkeys, rpmq, yum-cron, yum-config-mana, yum-debug-dump, - abrt-action-sav, rpmdb_stat] - -- macro: rpm_procs - condition: proc.name in (rpm_binaries) or proc.name in (salt-minion) - -- list: deb_binaries - items: [dpkg, dpkg-preconfigu, dpkg-reconfigur, apt, apt-get, aptitude, - frontend, preinst, add-apt-reposit, apt-auto-remova, apt-key, - apt-listchanges, unattended-upgr, apt-add-reposit - ] - -# The truncated dpkg-preconfigu is intentional, process names are -# truncated at the sysdig level. -- list: package_mgmt_binaries - items: [rpm_binaries, deb_binaries, update-alternat, gem, pip, sane-utils.post] - -- macro: package_mgmt_procs - condition: proc.name in (package_mgmt_binaries) - -- macro: run_by_package_mgmt_binaries - condition: proc.aname in (package_mgmt_binaries, needrestart) - -- list: ssl_mgmt_binaries - items: [ca-certificates] - -- list: dhcp_binaries - items: [dhclient, dhclient-script] - -# A canonical set of processes that run other programs with different -# privileges or as a different user. -- list: userexec_binaries - items: [sudo, su, suexec] - -- list: known_setuid_binaries - items: [ - sshd, dbus-daemon-lau, ping, ping6, critical-stack-, pmmcli, - filemng, PassengerAgent, bwrap, osdetect, nginxmng, sw-engine-fpm, - start-stop-daem - ] - -- list: user_mgmt_binaries - items: [login_binaries, passwd_binaries, shadowutils_binaries] - -- list: dev_creation_binaries - items: [blkid, rename_device, update_engine, sgdisk] - -- list: hids_binaries - items: [aide] - -- list: vpn_binaries - items: [openvpn] - -- list: nomachine_binaries - items: [nxexec, nxnode.bin, nxserver.bin, nxclient.bin] - -- macro: system_procs - condition: proc.name in (coreutils_binaries, user_mgmt_binaries) - -- list: mail_binaries - items: [ - sendmail, sendmail-msp, postfix, procmail, exim4, - pickup, showq, mailq, dovecot, imap-login, imap, - mailmng-core, pop3-login, dovecot-lda, pop3 - ] - -- list: mail_config_binaries - items: [ - update_conf, parse_mc, makemap_hash, newaliases, update_mk, update_tlsm4, - update_db, update_mc, ssmtp.postinst, mailq, postalias, postfix.config., - postfix.config, postfix-script - ] - -- list: sensitive_file_names - items: [/etc/shadow, /etc/sudoers, /etc/pam.conf] - -- macro: sensitive_files - condition: > - fd.name startswith /etc and - (fd.name in (sensitive_file_names) - or fd.directory in (/etc/sudoers.d, /etc/pam.d)) - -# Indicates that the process is new. Currently detected using time -# since process was started, using a threshold of 5 seconds. -- macro: proc_is_new - condition: proc.duration <= 5000000000 - -# Network -- macro: inbound - condition: > - (((evt.type in (accept,listen) and evt.dir=<)) or - (fd.typechar = 4 or fd.typechar = 6) and - (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and - (evt.rawres >= 0 or evt.res = EINPROGRESS)) - -- macro: outbound - condition: > - (((evt.type = connect and evt.dir=<)) or - (fd.typechar = 4 or fd.typechar = 6) and - (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and - (evt.rawres >= 0 or evt.res = EINPROGRESS)) - -# Very similar to inbound/outbound, but combines the tests together -# for efficiency. -- macro: inbound_outbound - condition: > - (((evt.type in (accept,listen,connect) and evt.dir=<)) or - (fd.typechar = 4 or fd.typechar = 6) and - (fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and - (evt.rawres >= 0 or evt.res = EINPROGRESS)) - -- macro: ssh_port - condition: fd.sport=22 - -# In a local/user rules file, you could override this macro to -# enumerate the servers for which ssh connections are allowed. For -# example, you might have a ssh gateway host for which ssh connections -# are allowed. -# -# In the main falco rules file, there isn't any way to know the -# specific hosts for which ssh access is allowed, so this macro just -# repeats ssh_port, which effectively allows ssh from all hosts. In -# the overridden macro, the condition would look something like -# "fd.sip="a.b.c.d" or fd.sip="e.f.g.h" or ..." -- macro: allowed_ssh_hosts - condition: ssh_port - -- rule: Disallowed SSH Connection - desc: Detect any new ssh connection to a host other than those in an allowed group of hosts - condition: (inbound_outbound) and ssh_port and not allowed_ssh_hosts - output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name) - priority: NOTICE - tags: [network] - -# Use this to test whether the event occurred within a container. - -# When displaying container information in the output field, use -# %container.info, without any leading term (file=%fd.name -# %container.info user=%user.name, and not file=%fd.name -# container=%container.info user=%user.name). The output will change -# based on the context and whether or not -pk/-pm/-pc was specified on -# the command line. -- macro: container - condition: container.id != host - -- macro: interactive - condition: > - ((proc.aname=sshd and proc.name != sshd) or - proc.name=systemd-logind or proc.name=login) - -- list: cron_binaries - items: [anacron, cron, crond, crontab] - -# https://github.com/liske/needrestart -- list: needrestart_binaries - items: [needrestart, 10-dpkg, 20-rpm, 30-pacman] - -# Possible scripts run by sshkit -- list: sshkit_script_binaries - items: [10_etc_sudoers., 10_passwd_group] - -- list: plesk_binaries - items: [sw-engine, sw-engine-fpm, sw-engine-kv, filemng, f2bmng] - -# System users that should never log into a system. Consider adding your own -# service users (e.g. 'apache' or 'mysqld') here. -- macro: system_users - condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data) - -# These macros will be removed soon. Only keeping them to maintain -# compatiblity with some widely used rules files. -# Begin Deprecated -- macro: parent_ansible_running_python - condition: (proc.pname in (python, pypy) and proc.pcmdline contains ansible) - -- macro: parent_bro_running_python - condition: (proc.pname=python and proc.cmdline contains /usr/share/broctl) - -- macro: parent_python_running_denyhosts - condition: > - (proc.cmdline startswith "denyhosts.py /usr/bin/denyhosts.py" or - (proc.pname=python and - (proc.pcmdline contains /usr/sbin/denyhosts or - proc.pcmdline contains /usr/local/bin/denyhosts.py))) - -- macro: parent_python_running_sdchecks - condition: > - (proc.pname in (python, python2.7) and - (proc.pcmdline contains /opt/draios/bin/sdchecks)) - -- macro: parent_linux_image_upgrade_script - condition: proc.pname startswith linux-image- - -- macro: parent_java_running_echo - condition: (proc.pname=java and proc.cmdline startswith "sh -c echo") - -- macro: parent_scripting_running_builds - condition: > - (proc.pname in (php,php5-fpm,php-fpm7.1,python,ruby,ruby2.3,ruby2.1,node,conda) and ( - proc.cmdline startswith "sh -c git" or - proc.cmdline startswith "sh -c date" or - proc.cmdline startswith "sh -c /usr/bin/g++" or - proc.cmdline startswith "sh -c /usr/bin/gcc" or - proc.cmdline startswith "sh -c gcc" or - proc.cmdline startswith "sh -c if type gcc" or - proc.cmdline startswith "sh -c cd '/var/www/edi/';LC_ALL=en_US.UTF-8 git" or - proc.cmdline startswith "sh -c /var/www/edi/bin/sftp.sh" or - proc.cmdline startswith "sh -c /usr/src/app/crxlsx/bin/linux/crxlsx" or - proc.cmdline startswith "sh -c make parent" or - proc.cmdline startswith "node /jenkins/tools" or - proc.cmdline startswith "sh -c '/usr/bin/node'" or - proc.cmdline startswith "sh -c stty -a |" or - proc.pcmdline startswith "node /opt/nodejs/bin/yarn" or - proc.pcmdline startswith "node /usr/local/bin/yarn" or - proc.pcmdline startswith "node /root/.config/yarn" or - proc.pcmdline startswith "node /opt/yarn/bin/yarn.js")) - - -- macro: httpd_writing_ssl_conf - condition: > - (proc.pname=run-httpd and - (proc.cmdline startswith "sed -ri" or proc.cmdline startswith "sed -i") and - (fd.name startswith /etc/httpd/conf.d/ or fd.name startswith /etc/httpd/conf)) - -- macro: parent_Xvfb_running_xkbcomp - condition: (proc.pname=Xvfb and proc.cmdline startswith 'sh -c "/usr/bin/xkbcomp"') - -- macro: parent_nginx_running_serf - condition: (proc.pname=nginx and proc.cmdline startswith "sh -c serf") - -- macro: parent_node_running_npm - condition: (proc.pcmdline startswith "node /usr/local/bin/npm" or - proc.pcmdline startswith "node /usr/local/nodejs/bin/npm" or - proc.pcmdline startswith "node /opt/rh/rh-nodejs6/root/usr/bin/npm") - -- macro: parent_java_running_sbt - condition: (proc.pname=java and proc.pcmdline contains sbt-launch.jar) - -- list: known_container_shell_spawn_cmdlines - items: [] - -- list: known_shell_spawn_binaries - items: [] - -- macro: shell_spawning_containers - condition: (container.image startswith jenkins or - container.image startswith gitlab/gitlab-ce or - container.image startswith gitlab/gitlab-ee) - -## End Deprecated - -- macro: ansible_running_python - condition: (proc.name in (python, pypy) and proc.cmdline contains ansible) - -- macro: chef_running_yum_dump - condition: (proc.name=python and proc.cmdline contains yum-dump.py) - -- macro: python_running_denyhosts - condition: > - (proc.name=python and - (proc.cmdline contains /usr/sbin/denyhosts or - proc.cmdline contains /usr/local/bin/denyhosts.py)) - -# Qualys seems to run a variety of shell subprocesses, at various -# levels. This checks at a few levels without the cost of a full -# proc.aname, which traverses the full parent heirarchy. -- macro: run_by_qualys - condition: > - (proc.pname=qualys-cloud-ag or - proc.aname[2]=qualys-cloud-ag or - proc.aname[3]=qualys-cloud-ag or - proc.aname[4]=qualys-cloud-ag) - -- macro: run_by_sumologic_securefiles - condition: > - ((proc.cmdline="usermod -a -G sumologic_collector" or - proc.cmdline="groupadd sumologic_collector") and - (proc.pname=secureFiles.sh and proc.aname[2]=java)) - -- macro: run_by_yum - condition: ((proc.pname=sh and proc.aname[2]=yum) or - (proc.aname[2]=sh and proc.aname[3]=yum)) - -- macro: run_by_ms_oms - condition: > - (proc.aname[3] startswith omsagent- or - proc.aname[3] startswith scx-) - -- macro: run_by_google_accounts_daemon - condition: > - (proc.aname[1] startswith google_accounts or - proc.aname[2] startswith google_accounts) - -# Chef is similar. -- macro: run_by_chef - condition: (proc.aname[2]=chef_command_wr or proc.aname[3]=chef_command_wr or - proc.aname[2]=chef-client or proc.aname[3]=chef-client or - proc.name=chef-client) - -- macro: run_by_adclient - condition: (proc.aname[2]=adclient or proc.aname[3]=adclient or proc.aname[4]=adclient) - -- macro: run_by_centrify - condition: (proc.aname[2]=centrify or proc.aname[3]=centrify or proc.aname[4]=centrify) - -- macro: run_by_puppet - condition: (proc.aname[2]=puppet or proc.aname[3]=puppet) - -# Also handles running semi-indirectly via scl -- macro: run_by_foreman - condition: > - (user.name=foreman and - (proc.pname in (rake, ruby, scl) and proc.aname[5] in (tfm-rake,tfm-ruby)) or - (proc.pname=scl and proc.aname[2] in (tfm-rake,tfm-ruby))) - -- macro: java_running_sdjagent - condition: proc.name=java and proc.cmdline contains sdjagent.jar - -- macro: kubelet_running_loopback - condition: (proc.pname=kubelet and proc.name=loopback) - -- macro: python_mesos_marathon_scripting - condition: (proc.pcmdline startswith "python3 /marathon-lb/marathon_lb.py") - -- macro: splunk_running_forwarder - condition: (proc.pname=splunkd and proc.cmdline startswith "sh -c /opt/splunkforwarder") - -- macro: parent_supervise_running_multilog - condition: (proc.name=multilog and proc.pname=supervise) - -- macro: supervise_writing_status - condition: (proc.name in (supervise,svc) and fd.name startswith "/etc/sb/") - -- macro: pki_realm_writing_realms - condition: (proc.cmdline startswith "bash /usr/local/lib/pki/pki-realm" and fd.name startswith /etc/pki/realms) - -- macro: htpasswd_writing_passwd - condition: (proc.name=htpasswd and fd.name=/etc/nginx/.htpasswd) - -- macro: lvprogs_writing_lvm_archive - condition: (proc.name in (dmeventd,lvcreate) and (fd.name startswith /etc/lvm/archive or - fd.name startswith /etc/lvm/backup)) -- macro: ovsdb_writing_openvswitch - condition: (proc.name=ovsdb-server and fd.directory=/etc/openvswitch) - -- macro: perl_running_plesk - condition: (proc.cmdline startswith "perl /opt/psa/admin/bin/plesk_agent_manager" or - proc.pcmdline startswith "perl /opt/psa/admin/bin/plesk_agent_manager") - -- macro: perl_running_updmap - condition: (proc.cmdline startswith "perl /usr/bin/updmap") - -- macro: perl_running_centrifydc - condition: (proc.cmdline startswith "perl /usr/share/centrifydc") - -- macro: parent_ucf_writing_conf - condition: (proc.pname=ucf and proc.aname[2]=frontend) - -- macro: consul_template_writing_conf - condition: > - ((proc.name=consul-template and fd.name startswith /etc/haproxy) or - (proc.name=reload.sh and proc.aname[2]=consul-template and fd.name startswith /etc/ssl)) - -- macro: countly_writing_nginx_conf - condition: (proc.cmdline startswith "nodejs /opt/countly/bin" and fd.name startswith /etc/nginx) - -- macro: ms_oms_writing_conf - condition: > - ((proc.name in (omiagent,omsagent,in_heartbeat_r*,omsadmin.sh,PerformInventor) - or proc.pname in (omi.postinst,omsconfig.posti,scx.postinst,omsadmin.sh,omiagent)) - and (fd.name startswith /etc/opt/omi or fd.name startswith /etc/opt/microsoft/omsagent)) - -- macro: ms_scx_writing_conf - condition: (proc.name in (GetLinuxOS.sh) and fd.name startswith /etc/opt/microsoft/scx) - -- macro: azure_scripts_writing_conf - condition: (proc.pname startswith "bash /var/lib/waagent/" and fd.name startswith /etc/azure) - -- macro: azure_networkwatcher_writing_conf - condition: (proc.name in (NetworkWatcherA) and fd.name=/etc/init.d/AzureNetworkWatcherAgent) - -- macro: couchdb_writing_conf - condition: (proc.name=beam.smp and proc.cmdline contains couchdb and fd.name startswith /etc/couchdb) - -- macro: update_texmf_writing_conf - condition: (proc.name=update-texmf and fd.name startswith /etc/texmf) - -- macro: slapadd_writing_conf - condition: (proc.name=slapadd and fd.name startswith /etc/ldap) - -- macro: symantec_writing_conf - condition: > - ((proc.name=symcfgd and fd.name startswith /etc/symantec) or - (proc.name=navdefutil and fd.name=/etc/symc-defutils.conf)) - -- macro: liveupdate_writing_conf - condition: (proc.cmdline startswith "java LiveUpdate" and fd.name in (/etc/liveupdate.conf, /etc/Product.Catalog.JavaLiveUpdate)) - -- macro: sosreport_writing_files - condition: > - (proc.name=urlgrabber-ext- and proc.aname[3]=sosreport and - (fd.name startswith /etc/pkt/nssdb or fd.name startswith /etc/pki/nssdb)) - -- macro: selinux_writing_conf - condition: (proc.name in (semodule,genhomedircon,sefcontext_comp) and fd.name startswith /etc/selinux) - -- list: veritas_binaries - items: [vxconfigd, sfcache, vxclustadm, vxdctl, vxprint, vxdmpadm, vxdisk, vxdg, vxassist, vxtune] - -- macro: veritas_driver_script - condition: (proc.cmdline startswith "perl /opt/VRTSsfmh/bin/mh_driver.pl") - -- macro: veritas_progs - condition: (proc.name in (veritas_binaries) or veritas_driver_script) - -- macro: veritas_writing_config - condition: (veritas_progs and fd.name startswith /etc/vx) - -- macro: nginx_writing_conf - condition: (proc.name=nginx and fd.name startswith /etc/nginx) - -- macro: nginx_writing_certs - condition: > - (((proc.name=openssl and proc.pname=nginx-launch.sh) or proc.name=nginx-launch.sh) and fd.name startswith /etc/nginx/certs) - -- macro: chef_client_writing_conf - condition: (proc.pcmdline startswith "chef-client /opt/gitlab" and fd.name startswith /etc/gitlab) - -- macro: centrify_writing_krb - condition: (proc.name in (adjoin,addns) and fd.name startswith /etc/krb5) - -- macro: cockpit_writing_conf - condition: > - ((proc.pname=cockpit-kube-la or proc.aname[2]=cockpit-kube-la) - and fd.name startswith /etc/cockpit) - -- macro: ipsec_writing_conf - condition: (proc.name=start-ipsec.sh and fd.directory=/etc/ipsec) - -- macro: exe_running_docker_save - condition: (proc.cmdline startswith "exe /var/lib/docker" and proc.pname in (dockerd, docker)) - -- macro: python_running_get_pip - condition: (proc.cmdline startswith "python get-pip.py") - -- macro: python_running_ms_oms - condition: (proc.cmdline startswith "python /var/lib/waagent/") - -- macro: gugent_writing_guestagent_log - condition: (proc.name=gugent and fd.name=GuestAgent.log) - -- rule: Write below binary dir - desc: an attempt to write to any file below a set of binary directories - condition: > - bin_dir and evt.dir = < and open_write - and not package_mgmt_procs - and not exe_running_docker_save - and not python_running_get_pip - and not python_running_ms_oms - output: > - File below a known binary directory opened for writing (user=%user.name - command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2]) - priority: ERROR - tags: [filesystem] - -- list: safe_etc_dirs - items: [/etc/cassandra, /etc/ssl/certs/java, /etc/logstash, /etc/nginx/conf.d, /etc/container_environment, /etc/hrmconfig] - -- macro: fluentd_writing_conf_files - condition: (proc.name=start-fluentd and fd.name in (/etc/fluent/fluent.conf, /etc/td-agent/td-agent.conf)) - -- macro: qualys_writing_conf_files - condition: (proc.name=qualys-cloud-ag and fd.name=/etc/qualys/cloud-agent/qagent-log.conf) - -- macro: git_writing_nssdb - condition: (proc.name=git-remote-http and fd.directory=/etc/pki/nssdb) - -- macro: plesk_writing_keys - condition: (proc.name in (plesk_binaries) and fd.name startswith /etc/sw/keys) - -- macro: plesk_install_writing_apache_conf - condition: (proc.cmdline startswith "bash -hB /usr/lib/plesk-9.0/services/webserver.apache configure" - and fd.name="/etc/apache2/apache2.conf.tmp") - -- macro: plesk_running_mktemp - condition: (proc.name=mktemp and proc.aname[3] in (plesk_binaries)) - -- macro: networkmanager_writing_resolv_conf - condition: proc.aname[2]=nm-dispatcher and fd.name=/etc/resolv.conf - -- macro: add_shell_writing_shells_tmp - condition: (proc.name=add-shell and fd.name=/etc/shells.tmp) - -- macro: duply_writing_exclude_files - condition: (proc.name=touch and proc.pcmdline startswith "bash /usr/bin/duply" and fd.name startswith "/etc/duply") - -- macro: xmlcatalog_writing_files - condition: (proc.name=update-xmlcatal and fd.directory=/etc/xml) - -- macro: datadog_writing_conf - condition: ((proc.cmdline startswith "python /opt/datadog-agent" or - proc.cmdline startswith "entrypoint.sh /entrypoint.sh datadog start" or - proc.cmdline startswith "agent.py /opt/datadog-agent") - and fd.name startswith "/etc/dd-agent") - -- macro: curl_writing_pki_db - condition: (proc.name=curl and fd.directory=/etc/pki/nssdb) - -- macro: haproxy_writing_conf - condition: ((proc.name in (update-haproxy-,haproxy_reload.) or proc.pname in (update-haproxy-,haproxy_reload,haproxy_reload.)) - and (fd.name=/etc/openvpn/client.map or fd.name startswith /etc/haproxy)) - -- macro: java_writing_conf - condition: (proc.name=java and fd.name=/etc/.java/.systemPrefs/.system.lock) - -- macro: rabbitmq_writing_conf - condition: (proc.name=rabbitmq-server and fd.directory=/etc/rabbitmq) - -- macro: rook_writing_conf - condition: (proc.name=toolbox.sh and container.image startswith rook/toolbox - and fd.directory=/etc/ceph) - -- macro: httpd_writing_conf_logs - condition: (proc.name=httpd and fd.name startswith /etc/httpd/) - -- macro: mysql_writing_conf - condition: ((proc.name=start-mysql.sh or proc.pname=start-mysql.sh) and fd.name startswith /etc/mysql) - -- macro: openvpn_writing_conf - condition: (proc.name in (openvpn,openvpn-entrypo) and fd.name startswith /etc/openvpn) - -- macro: php_handlers_writing_conf - condition: (proc.name=php_handlers_co and fd.name=/etc/psa/php_versions.json) - -- macro: sed_writing_temp_file - condition: > - ((proc.aname[3]=cron_start.sh and fd.name startswith /etc/security/sed) or - (proc.name=sed and (fd.name startswith /etc/apt/sources.list.d/sed or - fd.name startswith /etc/apt/sed or - fd.name startswith /etc/apt/apt.conf.d/sed))) - -- macro: cron_start_writing_pam_env - condition: (proc.cmdline="bash /usr/sbin/start-cron" and fd.name=/etc/security/pam_env.conf) - -# In some cases dpkg-reconfigur runs commands that modify /etc. Not -# putting the full set of package management programs yet. -- macro: dpkg_scripting - condition: (proc.aname[2] in (dpkg-reconfigur, dpkg-preconfigu)) - -# Add conditions to this macro (probably in a separate file, -# overwriting this macro) to allow for specific combinations of -# programs writing below specific directories below -# /etc. fluentd_writing_conf_files is a good example to follow, as it -# specifies both the program doing the writing as well as the specific -# files it is allowed to modify. -# -# In this file, it just takes one of the programs in the base macro -# and repeats it. - -- macro: user_known_write_etc_conditions - condition: proc.name=confd - -- macro: write_etc_common - condition: > - etc_dir and evt.dir = < and open_write - and proc_name_exists - and not proc.name in (passwd_binaries, shadowutils_binaries, sysdigcloud_binaries, - package_mgmt_binaries, ssl_mgmt_binaries, dhcp_binaries, - dev_creation_binaries, shell_mgmt_binaries, - mail_config_binaries, - sshkit_script_binaries, - ldconfig.real, ldconfig, confd, gpg, insserv, - apparmor_parser, update-mime, tzdata.config, tzdata.postinst, - systemd, systemd-machine, systemd-sysuser, - debconf-show, rollerd, bind9.postinst, sv, - gen_resolvconf., update-ca-certi, certbot, runsv, - qualys-cloud-ag, locales.postins, nomachine_binaries, - adclient, certutil, crlutil, pam-auth-update, parallels_insta, - openshift-launc, update-rc.d) - and not proc.pname in (sysdigcloud_binaries, mail_config_binaries, hddtemp.postins, sshkit_script_binaries, locales.postins, deb_binaries, dhcp_binaries) - and not fd.name pmatch (safe_etc_dirs) - and not fd.name in (/etc/container_environment.sh, /etc/container_environment.json, /etc/motd, /etc/motd.svc) - and not exe_running_docker_save - and not ansible_running_python - and not python_running_denyhosts - and not fluentd_writing_conf_files - and not user_known_write_etc_conditions - and not run_by_centrify - and not run_by_adclient - and not qualys_writing_conf_files - and not git_writing_nssdb - and not plesk_writing_keys - and not plesk_install_writing_apache_conf - and not plesk_running_mktemp - and not networkmanager_writing_resolv_conf - and not run_by_chef - and not add_shell_writing_shells_tmp - and not duply_writing_exclude_files - and not xmlcatalog_writing_files - and not parent_supervise_running_multilog - and not supervise_writing_status - and not pki_realm_writing_realms - and not htpasswd_writing_passwd - and not lvprogs_writing_lvm_archive - and not ovsdb_writing_openvswitch - and not datadog_writing_conf - and not curl_writing_pki_db - and not haproxy_writing_conf - and not java_writing_conf - and not dpkg_scripting - and not parent_ucf_writing_conf - and not rabbitmq_writing_conf - and not rook_writing_conf - and not php_handlers_writing_conf - and not sed_writing_temp_file - and not cron_start_writing_pam_env - and not httpd_writing_conf_logs - and not mysql_writing_conf - and not openvpn_writing_conf - and not consul_template_writing_conf - and not countly_writing_nginx_conf - and not ms_oms_writing_conf - and not ms_scx_writing_conf - and not azure_scripts_writing_conf - and not azure_networkwatcher_writing_conf - and not couchdb_writing_conf - and not update_texmf_writing_conf - and not slapadd_writing_conf - and not symantec_writing_conf - and not liveupdate_writing_conf - and not sosreport_writing_files - and not selinux_writing_conf - and not veritas_writing_config - and not nginx_writing_conf - and not nginx_writing_certs - and not chef_client_writing_conf - and not centrify_writing_krb - and not cockpit_writing_conf - and not ipsec_writing_conf - and not httpd_writing_ssl_conf - -- rule: Write below etc - desc: an attempt to write to any file below /etc - condition: write_etc_common - output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])" - priority: ERROR - tags: [filesystem] - -- list: known_root_files - items: [/root/.monit.state, /root/.auth_tokens, /root/.bash_history, /root/.ash_history, /root/.aws/credentials, - /root/.viminfo.tmp, /root/.lesshst, /root/.bzr.log, /root/.gitconfig.lock, /root/.babel.json, /root/.localstack, - /root/.node_repl_history, /root/.mongorc.js, /root/.dbshell, /root/.augeas/history, /root/.rnd] - -- list: known_root_directories - items: [/root/.oracle_jre_usage, /root/.ssh, /root/.subversion, /root/.nami] - -- macro: known_root_conditions - condition: (fd.name startswith /root/orcexec. - or fd.name startswith /root/.m2 - or fd.name startswith /root/.npm - or fd.name startswith /root/.pki - or fd.name startswith /root/.ivy2 - or fd.name startswith /root/.config/Cypress - or fd.name startswith /root/.config/pulse - or fd.name startswith /root/.config/configstore - or fd.name startswith /root/jenkins/workspace - or fd.name startswith /root/.jenkins - or fd.name startswith /root/.cache - or fd.name startswith /root/.sbt - or fd.name startswith /root/.java - or fd.name startswith /root/.glide - or fd.name startswith /root/.sonar - or fd.name startswith /root/.v8flag - or fd.name startswith /root/infaagent - or fd.name startswith /root/.local/lib/python - or fd.name startswith /root/.pm2 - or fd.name startswith /root/.gnupg - or fd.name startswith /root/.pgpass - or fd.name startswith /root/.theano - or fd.name startswith /root/.gradle - or fd.name startswith /root/.android - or fd.name startswith /root/.ansible - or fd.name startswith /root/.crashlytics - or fd.name startswith /root/.dbus - or fd.name startswith /root/.composer - or fd.name startswith /root/.gconf - or fd.name startswith /root/.nv) - -- rule: Write below root - desc: an attempt to write to any file directly below / or /root - condition: > - root_dir and evt.dir = < and open_write - and not fd.name in (known_root_files) - and not fd.directory in (known_root_directories) - and not exe_running_docker_save - and not gugent_writing_guestagent_log - and not known_root_conditions - output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name)" - priority: ERROR - tags: [filesystem] - -- macro: cmp_cp_by_passwd - condition: proc.name in (cmp, cp) and proc.pname in (passwd, run-parts) - -- rule: Read sensitive file trusted after startup - desc: > - an attempt to read any sensitive file (e.g. files containing user/password/authentication - information) by a trusted program after startup. Trusted programs might read these files - at startup to load initial state, but not afterwards. - condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd" - output: > - Sensitive file opened for reading by trusted program after startup (user=%user.name - command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2]) - priority: WARNING - tags: [filesystem] - -- list: read_sensitive_file_binaries - items: [ - iptables, ps, lsb_release, check-new-relea, dumpe2fs, accounts-daemon, sshd, - vsftpd, systemd, mysql_install_d, psql, screen, debconf-show, sa-update, - pam-auth-update, /usr/sbin/spamd, polkit-agent-he, lsattr, file, sosreport, - scxcimservera, adclient, rtvscand, cockpit-session - ] - -# Add conditions to this macro (probably in a separate file, -# overwriting this macro) to allow for specific combinations of -# programs accessing sensitive files. -# fluentd_writing_conf_files is a good example to follow, as it -# specifies both the program doing the writing as well as the specific -# files it is allowed to modify. -# -# In this file, it just takes one of the macros in the base rule -# and repeats it. - -- macro: user_read_sensitive_file_conditions - condition: cmp_cp_by_passwd - -- rule: Read sensitive file untrusted - desc: > - an attempt to read any sensitive file (e.g. files containing user/password/authentication - information). Exceptions are made for known trusted programs. - condition: > - sensitive_files and open_read - and proc_name_exists - and not proc.name in (user_mgmt_binaries, userexec_binaries, package_mgmt_binaries, - cron_binaries, read_sensitive_file_binaries, shell_binaries, hids_binaries, - vpn_binaries, mail_config_binaries, nomachine_binaries, sshkit_script_binaries, - in.proftpd, mandb, salt-minion, postgres_mgmt_binaries) - and not cmp_cp_by_passwd - and not ansible_running_python - and not proc.cmdline contains /usr/bin/mandb - and not run_by_qualys - and not run_by_chef - and not user_read_sensitive_file_conditions - and not perl_running_plesk - and not perl_running_updmap - and not veritas_driver_script - and not perl_running_centrifydc - output: > - Sensitive file opened for reading by non-trusted program (user=%user.name program=%proc.name - command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]) - priority: WARNING - tags: [filesystem] - -# Only let rpm-related programs write to the rpm database -- rule: Write below rpm database - desc: an attempt to write to the rpm database by any non-rpm related program - condition: fd.name startswith /var/lib/rpm and open_write and not rpm_procs and not ansible_running_python and not chef_running_yum_dump - output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name)" - priority: ERROR - tags: [filesystem, software_mgmt] - -- macro: postgres_running_wal_e - condition: (proc.pname=postgres and proc.cmdline startswith "sh -c envdir /etc/wal-e.d/env /usr/local/bin/wal-e") - -- macro: redis_running_prepost_scripts - condition: (proc.aname[2]=redis-server and (proc.cmdline contains "redis-server.post-up.d" or proc.cmdline contains "redis-server.pre-up.d")) - -- macro: rabbitmq_running_scripts - condition: > - (proc.pname=beam.smp and - (proc.cmdline startswith "sh -c exec ps" or - proc.cmdline startswith "sh -c exec inet_gethost" or - proc.cmdline= "sh -s unix:cmd" or - proc.cmdline= "sh -c exec /bin/sh -s unix:cmd 2>&1")) - -- macro: rabbitmqctl_running_scripts - condition: (proc.aname[2]=rabbitmqctl and proc.cmdline startswith "sh -c ") - -- rule: DB program spawned process - desc: > - a database-server related program spawned a new process other than itself. - This shouldn\'t occur and is a follow on from some SQL injection attacks. - condition: > - proc.pname in (db_server_binaries) - and spawned_process - and not proc.name in (db_server_binaries) - and not postgres_running_wal_e - output: > - Database-related program spawned process other than itself (user=%user.name - program=%proc.cmdline parent=%proc.pname) - priority: NOTICE - tags: [process, database] - -- rule: Modify binary dirs - desc: an attempt to modify any file below a set of binary directories. - condition: (bin_dir_rename) and modify and not package_mgmt_procs and not exe_running_docker_save - output: > - File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline - operation=%evt.type file=%fd.name %evt.args) - priority: ERROR - tags: [filesystem] - -- rule: Mkdir binary dirs - desc: an attempt to create a directory below a set of binary directories. - condition: mkdir and bin_dir_mkdir and not package_mgmt_procs - output: > - Directory below known binary directory created (user=%user.name - command=%proc.cmdline directory=%evt.arg.path) - priority: ERROR - tags: [filesystem] - -# This list allows for easy additions to the set of commands allowed -# to change thread namespace without having to copy and override the -# entire change thread namespace rule. -- list: user_known_change_thread_namespace_binaries - items: [] - -- rule: Change thread namespace - desc: > - an attempt to change a program/thread\'s namespace (commonly done - as a part of creating a container) by calling setns. - condition: > - evt.type = setns - and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries, sysdig, nsenter) - and not proc.name in (user_known_change_thread_namespace_binaries) - and not proc.name startswith "runc:" - and not proc.pname in (sysdigcloud_binaries) - and not java_running_sdjagent - and not kubelet_running_loopback - output: > - Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline - parent=%proc.pname %container.info) - priority: NOTICE - tags: [process] - -# The binaries in this list and their descendents are *not* allowed -# spawn shells. This includes the binaries spawning shells directly as -# well as indirectly. For example, apache -> php/perl for -# mod_{php,perl} -> some shell is also not allowed, because the shell -# has apache as an ancestor. - -- list: protected_shell_spawning_binaries - items: [ - http_server_binaries, db_server_binaries, nosql_server_binaries, mail_binaries, - fluentd, flanneld, splunkd, consul, smbd, runsv, PM2 - ] - -- macro: parent_java_running_zookeeper - condition: (proc.pname=java and proc.pcmdline contains org.apache.zookeeper.server) - -- macro: parent_java_running_kafka - condition: (proc.pname=java and proc.pcmdline contains kafka.Kafka) - -- macro: parent_java_running_elasticsearch - condition: (proc.pname=java and proc.pcmdline contains org.elasticsearch.bootstrap.Elasticsearch) - -- macro: parent_java_running_activemq - condition: (proc.pname=java and proc.pcmdline contains activemq.jar) - -- macro: parent_java_running_cassandra - condition: (proc.pname=java and (proc.pcmdline contains "-Dcassandra.config.loader" or proc.pcmdline contains org.apache.cassandra.service.CassandraDaemon)) - -- macro: parent_java_running_jboss_wildfly - condition: (proc.pname=java and proc.pcmdline contains org.jboss) - -- macro: parent_java_running_glassfish - condition: (proc.pname=java and proc.pcmdline contains com.sun.enterprise.glassfish) - -- macro: parent_java_running_hadoop - condition: (proc.pname=java and proc.pcmdline contains org.apache.hadoop) - -- macro: parent_java_running_datastax - condition: (proc.pname=java and proc.pcmdline contains com.datastax) - -- macro: nginx_starting_nginx - condition: (proc.pname=nginx and proc.cmdline contains "/usr/sbin/nginx -c /etc/nginx/nginx.conf") - -- macro: nginx_running_aws_s3_cp - condition: (proc.pname=nginx and proc.cmdline startswith "sh -c /usr/local/bin/aws s3 cp") - -- macro: consul_running_net_scripts - condition: (proc.pname=consul and (proc.cmdline startswith "sh -c curl" or proc.cmdline startswith "sh -c nc")) - -- macro: consul_running_alert_checks - condition: (proc.pname=consul and proc.cmdline startswith "sh -c /bin/consul-alerts") - -- macro: serf_script - condition: (proc.cmdline startswith "sh -c serf") - -- macro: check_process_status - condition: (proc.cmdline startswith "sh -c kill -0 ") - -# In some cases, you may want to consider node processes run directly -# in containers as protected shell spawners. Examples include using -# pm2-docker or pm2 start some-app.js --no-daemon-mode as the direct -# entrypoint of the container, and when the node app is a long-lived -# server using something like express. -# -# However, there are other uses of node related to build pipelines for -# which node is not really a server but instead a general scripting -# tool. In these cases, shells are very likely and in these cases you -# don't want to consider node processes protected shell spawners. -# -# We have to choose one of these cases, so we consider node processes -# as unprotected by default. If you want to consider any node process -# run in a container as a protected shell spawner, override the below -# macro to remove the "never_true" clause, which allows it to take effect. -- macro: possibly_node_in_container - condition: (never_true and (proc.pname=node and proc.aname[3]=docker-containe)) - -- macro: protected_shell_spawner - condition: > - (proc.aname in (protected_shell_spawning_binaries) - or parent_java_running_zookeeper - or parent_java_running_kafka - or parent_java_running_elasticsearch - or parent_java_running_activemq - or parent_java_running_cassandra - or parent_java_running_jboss_wildfly - or parent_java_running_glassfish - or parent_java_running_hadoop - or parent_java_running_datastax - or possibly_node_in_container) - -- list: mesos_shell_binaries - items: [mesos-docker-ex, mesos-slave, mesos-health-ch] - -# Note that runsv is both in protected_shell_spawner and the -# exclusions by pname. This means that runsv can itself spawn shells -# (the ./run and ./finish scripts), but the processes runsv can not -# spawn shells. -- rule: Run shell untrusted - desc: an attempt to spawn a shell below a non-shell application. Specific applications are monitored. - condition: > - spawned_process - and shell_procs - and proc.pname exists - and protected_shell_spawner - and not proc.pname in (shell_binaries, gitlab_binaries, cron_binaries, user_known_shell_spawn_binaries, - needrestart_binaries, - mesos_shell_binaries, - erl_child_setup, exechealthz, - PM2, PassengerWatchd, c_rehash, svlogd, logrotate, hhvm, serf, - lb-controller, nvidia-installe, runsv, statsite, erlexec) - and not proc.cmdline in (known_shell_spawn_cmdlines) - and not proc.aname in (unicorn_launche) - and not consul_running_net_scripts - and not consul_running_alert_checks - and not nginx_starting_nginx - and not nginx_running_aws_s3_cp - and not run_by_package_mgmt_binaries - and not serf_script - and not check_process_status - and not run_by_foreman - and not python_mesos_marathon_scripting - and not splunk_running_forwarder - and not postgres_running_wal_e - and not redis_running_prepost_scripts - and not rabbitmq_running_scripts - and not rabbitmqctl_running_scripts - and not user_shell_container_exclusions - output: > - Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname - cmdline=%proc.cmdline pcmdline=%proc.pcmdline gparent=%proc.aname[2] ggparent=%proc.aname[3] - gggparent=%proc.aname[4] ggggparent=%proc.aname[5]) - priority: DEBUG - tags: [shell] - -- macro: trusted_containers - condition: (container.image startswith sysdig/agent or - (container.image startswith sysdig/falco and - not container.image startswith sysdig/falco-event-generator) or - container.image startswith quay.io/sysdig or - container.image startswith sysdig/sysdig or - container.image startswith gcr.io/google_containers/hyperkube or - container.image startswith quay.io/coreos/flannel or - container.image startswith gcr.io/google_containers/kube-proxy or - container.image startswith calico/node or - container.image startswith rook/toolbox or - container.image startswith registry.access.redhat.com/openshift3/logging-fluentd or - container.image startswith registry.access.redhat.com/openshift3/logging-elasticsearch or - container.image startswith registry.access.redhat.com/openshift3/metrics-cassandra or - container.image startswith openshift3/ose-sti-builder or - container.image startswith registry.access.redhat.com/openshift3/ose-sti-builder or - container.image startswith cloudnativelabs/kube-router or - container.image startswith "consul:" or - container.image startswith mesosphere/mesos-slave or - container.image startswith istio/proxy_ or - container.image startswith datadog/docker-dd-agent) - -# Add conditions to this macro (probably in a separate file, -# overwriting this macro) to specify additional containers that are -# trusted and therefore allowed to run privileged. -# -# In this file, it just takes one of the images in trusted_containers -# and repeats it. -- macro: user_trusted_containers - condition: (container.image startswith sysdig/agent) - -# Add conditions to this macro (probably in a separate file, -# overwriting this macro) to specify additional containers that are -# allowed to perform sensitive mounts. -# -# In this file, it just takes one of the images in trusted_containers -# and repeats it. -- macro: user_sensitive_mount_containers - condition: (container.image startswith sysdig/agent) - -- rule: Launch Privileged Container - desc: Detect the initial process started in a privileged container. Exceptions are made for known trusted images. - condition: > - evt.type=execve and proc.vpid=1 and container - and container.privileged=true - and not trusted_containers - and not user_trusted_containers - output: Privileged container started (user=%user.name command=%proc.cmdline %container.info image=%container.image) - priority: INFO - tags: [container, cis] - -# For now, only considering a full mount of /etc as -# sensitive. Ideally, this would also consider all subdirectories -# below /etc as well, but the globbing mechanism used by sysdig -# doesn't allow exclusions of a full pattern, only single characters. -- macro: sensitive_mount - condition: (container.mount.dest[/proc*] != "N/A" or - container.mount.dest[/var/run/docker.sock] != "N/A" or - container.mount.dest[/] != "N/A" or - container.mount.dest[/etc] != "N/A" or - container.mount.dest[/root*] != "N/A") - -# The steps libcontainer performs to set up the root program for a container are: -# - clone + exec self to a program runc:[0:PARENT] -# - clone a program runc:[1:CHILD] which sets up all the namespaces -# - clone a second program runc:[2:INIT] + exec to the root program. -# The parent of runc:[2:INIT] is runc:0:PARENT] -# As soon as 1:CHILD is created, 0:PARENT exits, so there's a race -# where at the time 2:INIT execs the root program, 0:PARENT might have -# already exited, or might still be around. So we handle both. -# We also let runc:[1:CHILD] count as the parent process, which can occur -# when we lose events and lose track of state. - -- macro: container_entrypoint - condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe)) - -- rule: Launch Sensitive Mount Container - desc: > - Detect the initial process started by a container that has a mount from a sensitive host directory - (i.e. /proc). Exceptions are made for known trusted images. - condition: > - evt.type=execve and proc.vpid=1 and container - and sensitive_mount - and not trusted_containers - and not user_sensitive_mount_containers - output: Container with sensitive mount started (user=%user.name command=%proc.cmdline %container.info image=%container.image mounts=%container.mounts) - priority: INFO - tags: [container, cis] - -# In a local/user rules file, you could override this macro to -# explicitly enumerate the container images that you want to run in -# your environment. In this main falco rules file, there isn't any way -# to know all the containers that can run, so any container is -# alllowed, by using a filter that is guaranteed to evaluate to true -# (the same proc.vpid=1 that's in the Launch Disallowed Container -# rule). In the overridden macro, the condition would look something -# like (container.image startswith vendor/container-1 or -# container.image startswith vendor/container-2 or ...) - -- macro: allowed_containers - condition: (proc.vpid=1) - -- rule: Launch Disallowed Container - desc: > - Detect the initial process started by a container that is not in a list of allowed containers. - condition: evt.type=execve and proc.vpid=1 and container and not allowed_containers - output: Container started and not in allowed list (user=%user.name command=%proc.cmdline %container.info image=%container.image) - priority: WARNING - tags: [container] - -# Anything run interactively by root -# - condition: evt.type != switch and user.name = root and proc.name != sshd and interactive -# output: "Interactive root (%user.name %proc.name %evt.dir %evt.type %evt.args %fd.name)" -# priority: WARNING - -- rule: System user interactive - desc: an attempt to run interactive commands by a system (i.e. non-login) user - condition: spawned_process and system_users and interactive - output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)" - priority: INFO - tags: [users] - -- rule: Terminal shell in container - desc: A shell was used as the entrypoint/exec point into a container with an attached terminal. - condition: > - spawned_process and container - and shell_procs and proc.tty != 0 - and container_entrypoint - output: > - A shell was spawned in a container with an attached terminal (user=%user.name %container.info - shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty) - priority: NOTICE - tags: [container, shell] - -# For some container types (mesos), there isn't a container image to -# work with, and the container name is autogenerated, so there isn't -# any stable aspect of the software to work with. In this case, we -# fall back to allowing certain command lines. - -- list: known_shell_spawn_cmdlines - items: [ - '"sh -c uname -p 2> /dev/null"', - '"sh -c uname -s 2>&1"', - '"sh -c uname -r 2>&1"', - '"sh -c uname -v 2>&1"', - '"sh -c uname -a 2>&1"', - '"sh -c ruby -v 2>&1"', - '"sh -c getconf CLK_TCK"', - '"sh -c getconf PAGESIZE"', - '"sh -c LC_ALL=C LANG=C /sbin/ldconfig -p 2>/dev/null"', - '"sh -c LANG=C /sbin/ldconfig -p 2>/dev/null"', - '"sh -c /sbin/ldconfig -p 2>/dev/null"', - '"sh -c stty -a 2>/dev/null"', - '"sh -c stty -a < /dev/tty"', - '"sh -c stty -g < /dev/tty"', - '"sh -c node index.js"', - '"sh -c node index"', - '"sh -c node ./src/start.js"', - '"sh -c node app.js"', - '"sh -c node -e \"require(''nan'')\""', - '"sh -c node -e \"require(''nan'')\")"', - '"sh -c node $NODE_DEBUG_OPTION index.js "', - '"sh -c crontab -l 2"', - '"sh -c lsb_release -a"', - '"sh -c lsb_release -is 2>/dev/null"', - '"sh -c whoami"', - '"sh -c node_modules/.bin/bower-installer"', - '"sh -c /bin/hostname -f 2> /dev/null"', - '"sh -c locale -a"', - '"sh -c -t -i"', - '"sh -c openssl version"', - '"bash -c id -Gn kafadmin"', - '"sh -c /bin/sh -c ''date +%%s''"' - ] - -# This list allows for easy additions to the set of commands allowed -# to run shells in containers without having to without having to copy -# and override the entire run shell in container macro. Once -# https://github.com/draios/falco/issues/255 is fixed this will be a -# bit easier, as someone could append of any of the existing lists. -- list: user_known_shell_spawn_binaries - items: [] - -# This macro allows for easy additions to the set of commands allowed -# to run shells in containers without having to override the entire -# rule. Its default value is an expression that always is false, which -# becomes true when the "not ..." in the rule is applied. -- macro: user_shell_container_exclusions - condition: (never_true) - -- macro: login_doing_dns_lookup - condition: (proc.name=login and fd.l4proto=udp and fd.sport=53) - -# sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets -# systemd can listen on ports to launch things like sshd on demand -- rule: System procs network activity - desc: any network activity performed by system binaries that are not expected to send or receive any network traffic - condition: > - (fd.sockfamily = ip and system_procs) - and (inbound_outbound) - and not proc.name in (systemd, hostid) - and not login_doing_dns_lookup - output: > - Known system binary sent/received network traffic - (user=%user.name command=%proc.cmdline connection=%fd.name) - priority: NOTICE - tags: [network] - -- list: openvpn_udp_ports - items: [1194, 1197, 1198, 8080, 9201] - -- list: l2tp_udp_ports - items: [500, 1701, 4500, 10000] - -- list: statsd_ports - items: [8125] - -- list: ntp_ports - items: [123] - -# Some applications will connect a udp socket to an address only to -# test connectivity. Assuming the udp connect works, they will follow -# up with a tcp connect that actually sends/receives data. -# -# With that in mind, we listed a few commonly seen ports here to avoid -# some false positives. In addition, we make the main rule opt-in, so -# it's disabled by default. - -- list: test_connect_ports - items: [0, 9, 80, 3306] - -- macro: do_unexpected_udp_check - condition: (never_true) - -- list: expected_udp_ports - items: [53, openvpn_udp_ports, l2tp_udp_ports, statsd_ports, ntp_ports, test_connect_ports] - -- macro: expected_udp_traffic - condition: fd.port in (expected_udp_ports) - -- rule: Unexpected UDP Traffic - desc: UDP traffic not on port 53 (DNS) or other commonly used ports - condition: (inbound_outbound) and do_unexpected_udp_check and fd.l4proto=udp and not expected_udp_traffic - output: > - Unexpected UDP Traffic Seen - (user=%user.name command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args) - priority: NOTICE - tags: [network] - -# With the current restriction on system calls handled by falco -# (e.g. excluding read/write/sendto/recvfrom/etc, this rule won't -# trigger). -# - rule: Ssh error in syslog -# desc: any ssh errors (failed logins, disconnects, ...) sent to syslog -# condition: syslog and ssh_error_message and evt.dir = < -# output: "sshd sent error message to syslog (error=%evt.buffer)" -# priority: WARNING - -- macro: somebody_becoming_themself - condition: ((user.name=nobody and evt.arg.uid=nobody) or - (user.name=www-data and evt.arg.uid=www-data) or - (user.name=_apt and evt.arg.uid=_apt) or - (user.name=postfix and evt.arg.uid=postfix) or - (user.name=pki-agent and evt.arg.uid=pki-agent) or - (user.name=pki-acme and evt.arg.uid=pki-acme) or - (user.name=nfsnobody and evt.arg.uid=nfsnobody) or - (user.name=postgres and evt.arg.uid=postgres)) - -- macro: nrpe_becoming_nagios - condition: (proc.name=nrpe and evt.arg.uid=nagios) - -# In containers, the user name might be for a uid that exists in the -# container but not on the host. (See -# https://github.com/draios/sysdig/issues/954). So in that case, allow -# a setuid. -- macro: known_user_in_container - condition: (container and user.name != "N/A") - -# sshd, mail programs attempt to setuid to root even when running as non-root. Excluding here to avoid meaningless FPs -- rule: Non sudo setuid - desc: > - an attempt to change users by calling setuid. sudo/su are excluded. users "root" and "nobody" - suing to itself are also excluded, as setuid calls typically involve dropping privileges. - condition: > - evt.type=setuid and evt.dir=> - and (known_user_in_container or not container) - and not user.name=root and not somebody_becoming_themself - and not proc.name in (known_setuid_binaries, userexec_binaries, mail_binaries, docker_binaries, - nomachine_binaries) - and not java_running_sdjagent - and not nrpe_becoming_nagios - output: > - Unexpected setuid call by non-sudo, non-root program (user=%user.name cur_uid=%user.uid parent=%proc.pname - command=%proc.cmdline uid=%evt.arg.uid) - priority: NOTICE - tags: [users] - -- rule: User mgmt binaries - desc: > - activity by any programs that can manage users, passwords, or permissions. sudo and su are excluded. - Activity in containers is also excluded--some containers create custom users on top - of a base linux distribution at startup. - Some innocuous commandlines that don't actually change anything are excluded. - condition: > - spawned_process and proc.name in (user_mgmt_binaries) and - not proc.name in (su, sudo, lastlog, nologin, unix_chkpwd) and not container and - not proc.pname in (cron_binaries, systemd, systemd.postins, udev.postinst, run-parts) and - not proc.cmdline startswith "passwd -S" and - not proc.cmdline startswith "useradd -D" and - not proc.cmdline startswith "systemd --version" and - not run_by_qualys and - not run_by_sumologic_securefiles and - not run_by_yum and - not run_by_ms_oms and - not run_by_google_accounts_daemon - output: > - User management binary command run outside of container - (user=%user.name command=%proc.cmdline parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4]) - priority: NOTICE - tags: [host, users] - -- list: allowed_dev_files - items: [ - /dev/null, /dev/stdin, /dev/stdout, /dev/stderr, - /dev/random, /dev/urandom, /dev/console, /dev/kmsg - ] - -# (we may need to add additional checks against false positives, see: -# https://bugs.launchpad.net/ubuntu/+source/rkhunter/+bug/86153) -- rule: Create files below dev - desc: creating any files below /dev other than known programs that manage devices. Some rootkits hide files in /dev. - condition: > - fd.directory = /dev and - (evt.type = creat or (evt.type = open and evt.arg.flags contains O_CREAT)) - and not proc.name in (dev_creation_binaries) - and not fd.name in (allowed_dev_files) - and not fd.name startswith /dev/tty - output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)" - priority: ERROR - tags: [filesystem] - - -# In a local/user rules file, you could override this macro to -# explicitly enumerate the container images that you want to allow -# access to EC2 metadata. In this main falco rules file, there isn't -# any way to know all the containers that should have access, so any -# container is alllowed, by repeating the "container" macro. In the -# overridden macro, the condition would look something like -# (container.image startswith vendor/container-1 or container.image -# startswith vendor/container-2 or ...) -- macro: ec2_metadata_containers - condition: container - -# On EC2 instances, 169.254.169.254 is a special IP used to fetch -# metadata about the instance. It may be desirable to prevent access -# to this IP from containers. -- rule: Contact EC2 Instance Metadata Service From Container - desc: Detect attempts to contact the EC2 Instance Metadata Service from a container - condition: outbound and fd.sip="169.254.169.254" and container and not ec2_metadata_containers - output: Outbound connection to EC2 instance metadata service (command=%proc.cmdline connection=%fd.name %container.info image=%container.image) - priority: NOTICE - tags: [network, aws, container] - -# In a local/user rules file, you should override this macro with the -# IP address of your k8s api server. The IP 1.2.3.4 is a placeholder -# IP that is not likely to be seen in practice. -- macro: k8s_api_server - condition: (fd.sip="1.2.3.4" and fd.sport=8080) - -# In a local/user rules file, list the container images that are -# allowed to contact the K8s API Server from within a container. This -# might cover cases where the K8s infrastructure itself is running -# within a container. -- macro: k8s_containers - condition: > - (container.image startswith gcr.io/google_containers/hyperkube-amd64 or - container.image startswith gcr.io/google_containers/kube2sky or - container.image startswith sysdig/agent or - container.image startswith sysdig/falco or - container.image startswith sysdig/sysdig) - -- rule: Contact K8S API Server From Container - desc: Detect attempts to contact the K8S API Server from a container - condition: outbound and k8s_api_server and container and not k8s_containers - output: Unexpected connection to K8s API Server from container (command=%proc.cmdline %container.info image=%container.image connection=%fd.name) - priority: NOTICE - tags: [network, k8s, container] - -# In a local/user rules file, list the container images that are -# allowed to contact NodePort services from within a container. This -# might cover cases where the K8s infrastructure itself is running -# within a container. -# -# By default, all containers are allowed to contact NodePort services. -- macro: nodeport_containers - condition: container - -- rule: Unexpected K8s NodePort Connection - desc: Detect attempts to use K8s NodePorts from a container - condition: (inbound_outbound) and fd.sport >= 30000 and fd.sport <= 32767 and container and not nodeport_containers - output: Unexpected K8s NodePort Connection (command=%proc.cmdline connection=%fd.name) - priority: NOTICE - tags: [network, k8s, container] - -# Application rules have moved to application_rules.yaml. Please look -# there if you want to enable them by adding to -# falco_rules.local.yaml. - diff --git a/integrations/kubernetes-response-engine/deployment/falco/falco-account.yaml b/integrations/kubernetes-response-engine/deployment/falco/falco-account.yaml deleted file mode 100644 index 9d611519522..00000000000 --- a/integrations/kubernetes-response-engine/deployment/falco/falco-account.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: falco-account ---- -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: falco-cluster-role -rules: - - apiGroups: ["extensions",""] - resources: ["nodes","namespaces","pods","replicationcontrollers","services","events","configmaps"] - verbs: ["get","list","watch"] - - nonResourceURLs: ["/healthz", "/healthz/*"] - verbs: ["get"] ---- -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1beta1 -metadata: - name: falco-cluster-role-binding - namespace: default -subjects: - - kind: ServiceAccount - name: falco-account - namespace: default -roleRef: - kind: ClusterRole - name: falco-cluster-role - apiGroup: rbac.authorization.k8s.io diff --git a/integrations/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml b/integrations/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml deleted file mode 100644 index ecc4dcdb96e..00000000000 --- a/integrations/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml +++ /dev/null @@ -1,84 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: DaemonSet -metadata: - name: falco - labels: - name: falco-daemonset - app: demo -spec: - template: - metadata: - labels: - name: falco - app: demo - role: security - spec: - serviceAccount: falco-account - containers: - - name: falco-nats - image: sysdig/falco-nats:latest - imagePullPolicy: Always - volumeMounts: - - mountPath: /var/run/falco/ - name: shared-pipe - - name: falco - image: sysdig/falco:latest - securityContext: - privileged: true - args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes", "-pk", "-U"] - volumeMounts: - - mountPath: /var/run/falco/ - name: shared-pipe - readOnly: false - - mountPath: /host/var/run/docker.sock - name: docker-socket - readOnly: true - - mountPath: /host/dev - name: dev-fs - readOnly: true - - mountPath: /host/proc - name: proc-fs - readOnly: true - - mountPath: /host/boot - name: boot-fs - readOnly: true - - mountPath: /host/lib/modules - name: lib-modules - readOnly: true - - mountPath: /host/usr - name: usr-fs - readOnly: true - - mountPath: /etc/falco - name: falco-config - initContainers: - - name: init-pipe - image: busybox - command: ['mkfifo','/var/run/falco/nats'] - volumeMounts: - - mountPath: /var/run/falco/ - name: shared-pipe - readOnly: false - volumes: - - name: shared-pipe - emptyDir: {} - - name: docker-socket - hostPath: - path: /var/run/docker.sock - - name: dev-fs - hostPath: - path: /dev - - name: proc-fs - hostPath: - path: /proc - - name: boot-fs - hostPath: - path: /boot - - name: lib-modules - hostPath: - path: /lib/modules - - name: usr-fs - hostPath: - path: /usr - - name: falco-config - configMap: - name: falco-config diff --git a/integrations/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml b/integrations/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml deleted file mode 100644 index 0b6500d5742..00000000000 --- a/integrations/kubernetes-response-engine/deployment/falco/falco-event-generator.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: extensions/v1beta1 -kind: Deployment -metadata: - name: falco-event-generator - labels: - name: falco-event-generator - app: demo -spec: - replicas: 1 - template: - metadata: - labels: - name: falco-event-generator - app: demo - spec: - containers: - - name: falco-event-generator - image: sysdig/falco-event-generator:latest