mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 19:52:08 +00:00
Compare commits
225 Commits
0.28.0
...
embed-lua-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0e3121b17c | ||
|
|
b05b252100 | ||
|
|
2df9a68140 | ||
|
|
0e52ef9971 | ||
|
|
a371a995b4 | ||
|
|
0f984c4dbe | ||
|
|
48a23121df | ||
|
|
475ed0dbeb | ||
|
|
eaccfbe82d | ||
|
|
e496c91562 | ||
|
|
cef2c2d5c1 | ||
|
|
2ee0645f25 | ||
|
|
42f8b1cd83 | ||
|
|
455be15b0b | ||
|
|
64e8feb200 | ||
|
|
eded1062cd | ||
|
|
473b94b386 | ||
|
|
226d1fb728 | ||
|
|
6319be8146 | ||
|
|
cf4672675c | ||
|
|
f035829ca2 | ||
|
|
cd471a78db | ||
|
|
65969c30f9 | ||
|
|
bb8b75a2cd | ||
|
|
b359f71511 | ||
|
|
9dcd8bccac | ||
|
|
b5667cab99 | ||
|
|
2a00a4d853 | ||
|
|
697d4427a7 | ||
|
|
bf04fed71c | ||
|
|
c005af22cc | ||
|
|
c93029ce74 | ||
|
|
076aabcea6 | ||
|
|
d8c588becf | ||
|
|
1a7611a761 | ||
|
|
7fb61ba4a3 | ||
|
|
9ab810f431 | ||
|
|
7781385769 | ||
|
|
205a8fd23b | ||
|
|
bdba37a790 | ||
|
|
19fb3458ef | ||
|
|
b0565794f5 | ||
|
|
66df790b9d | ||
|
|
749d4b4512 | ||
|
|
851033c5f4 | ||
|
|
af6f3bfeab | ||
|
|
c4d25b1d24 | ||
|
|
d434853d5f | ||
|
|
4c8e369691 | ||
|
|
b15a0458b7 | ||
|
|
d6cb8bc4bd | ||
|
|
2cc7fd9072 | ||
|
|
589829ae2f | ||
|
|
85db078dc4 | ||
|
|
23706da75e | ||
|
|
35302f6f09 | ||
|
|
375a6f66c5 | ||
|
|
e8a243d6ea | ||
|
|
7927f45d9f | ||
|
|
d9aff8d564 | ||
|
|
40e3fdd09c | ||
|
|
ba2323046a | ||
|
|
5e6f30109e | ||
|
|
f3c3de7e05 | ||
|
|
ca61f87682 | ||
|
|
113bb5cdd6 | ||
|
|
8a603c3c5d | ||
|
|
0539e948c8 | ||
|
|
5f1d04ec82 | ||
|
|
9d8fc4c8d2 | ||
|
|
09799e125d | ||
|
|
446c65007d | ||
|
|
df3728ec3f | ||
|
|
a66dda3daa | ||
|
|
eec2f5062f | ||
|
|
7dcf8f4bf7 | ||
|
|
bea91ca844 | ||
|
|
ea2ca56d5b | ||
|
|
cb51522423 | ||
|
|
9f53089bcb | ||
|
|
2a4e4d555d | ||
|
|
6a1f4f7374 | ||
|
|
98599d5e25 | ||
|
|
e7d41f8166 | ||
|
|
9075eea62f | ||
|
|
69e32f7ed1 | ||
|
|
38a7f7ada0 | ||
|
|
6a4e4eaa4f | ||
|
|
1313e77113 | ||
|
|
a1fa8edf7e | ||
|
|
d4aa7b9747 | ||
|
|
2312afe9cd | ||
|
|
6ee0b353ac | ||
|
|
28d6a293fc | ||
|
|
5ee62f66f7 | ||
|
|
b33fb6052a | ||
|
|
8448d02980 | ||
|
|
74661a7d8f | ||
|
|
e7b320b00c | ||
|
|
762500a361 | ||
|
|
8563af8a79 | ||
|
|
f7893fbd14 | ||
|
|
3b390793b9 | ||
|
|
10d47cb1f5 | ||
|
|
204892816b | ||
|
|
6156fbb4cb | ||
|
|
20b5ea8f85 | ||
|
|
cc43c721c9 | ||
|
|
230c22b674 | ||
|
|
04f3cc503c | ||
|
|
84d7020e3e | ||
|
|
0cae713412 | ||
|
|
bbbac6203c | ||
|
|
8275730bf8 | ||
|
|
de4b2fa831 | ||
|
|
943a37fcf7 | ||
|
|
3202921355 | ||
|
|
1c60dab87e | ||
|
|
044a7c153e | ||
|
|
a0f7d7cf85 | ||
|
|
bb81133201 | ||
|
|
46d5266ac8 | ||
|
|
3414ca5361 | ||
|
|
0eb170cf5f | ||
|
|
21fa6e9505 | ||
|
|
b82cbb1b59 | ||
|
|
d033868ab9 | ||
|
|
7c98d0047c | ||
|
|
c7d9b6ee7f | ||
|
|
8273e57598 | ||
|
|
b0562242e8 | ||
|
|
ca66b84e5a | ||
|
|
7c9ec9fc17 | ||
|
|
9ea43c2663 | ||
|
|
4d55847bd4 | ||
|
|
a684bec007 | ||
|
|
812aa9b566 | ||
|
|
e0f8b81692 | ||
|
|
874809351f | ||
|
|
4527228ef8 | ||
|
|
e684c95e23 | ||
|
|
2390ca447a | ||
|
|
af0e6da375 | ||
|
|
84e7d3f18f | ||
|
|
2a8c0e8bb7 | ||
|
|
f28688551c | ||
|
|
b12d37a3b8 | ||
|
|
5e027c7fe2 | ||
|
|
efbe887d6e | ||
|
|
7dcbeb1f44 | ||
|
|
93667f2d3e | ||
|
|
b5b1763d09 | ||
|
|
d6690313a0 | ||
|
|
98ce88f7ef | ||
|
|
9ff8099501 | ||
|
|
7db4778f55 | ||
|
|
7f761ade4b | ||
|
|
84257912e0 | ||
|
|
9bc942c654 | ||
|
|
8216b435cb | ||
|
|
78f710c706 | ||
|
|
1dd97c1b6f | ||
|
|
3ef5716fa2 | ||
|
|
64102078c7 | ||
|
|
9703853da8 | ||
|
|
96403fa275 | ||
|
|
acd5422b55 | ||
|
|
099c79ddde | ||
|
|
0f24448d18 | ||
|
|
1b63ad1aed | ||
|
|
b268d4d6c3 | ||
|
|
684a5d85ff | ||
|
|
58cea0c5e7 | ||
|
|
38ebc61808 | ||
|
|
535db19991 | ||
|
|
abe46a19a0 | ||
|
|
96fc8d1a27 | ||
|
|
ad82f66be3 | ||
|
|
c60fac9e34 | ||
|
|
35dc315390 | ||
|
|
62c995f309 | ||
|
|
3432551295 | ||
|
|
09e1604fe0 | ||
|
|
da7279da1d | ||
|
|
05f5aa2af3 | ||
|
|
53a1be66b0 | ||
|
|
f7b572bea5 | ||
|
|
ed59f33f3f | ||
|
|
b41acdff1c | ||
|
|
4acc089b1f | ||
|
|
591d4e500e | ||
|
|
79bdcb030b | ||
|
|
f4dba52ee2 | ||
|
|
bfc0021cdd | ||
|
|
e616f79bac | ||
|
|
4006452b1f | ||
|
|
59831b077e | ||
|
|
0d95beb1e3 | ||
|
|
2e27d5dded | ||
|
|
24f64cab33 | ||
|
|
0f36ff030e | ||
|
|
601ec5cf85 | ||
|
|
f237f277e7 | ||
|
|
2226a1508c | ||
|
|
6f64c21ad9 | ||
|
|
fd6a1d0d05 | ||
|
|
87438ec723 | ||
|
|
d0be6d96d0 | ||
|
|
aefd67eb8a | ||
|
|
6e94c37399 | ||
|
|
d3c22d3d0c | ||
|
|
366975bc3b | ||
|
|
f9692fcb82 | ||
|
|
e95ab26f33 | ||
|
|
23a611b343 | ||
|
|
2658d65373 | ||
|
|
600501e141 | ||
|
|
0df18fd786 | ||
|
|
c1da6d21b9 | ||
|
|
c4a73bdd8e | ||
|
|
28a339e4bc | ||
|
|
65a168ab5a | ||
|
|
46425b392c | ||
|
|
8b0d22dee9 | ||
|
|
a7e04fe6e6 |
@@ -13,7 +13,7 @@ jobs:
|
||||
command: apk update
|
||||
- run:
|
||||
name: Install build dependencies
|
||||
command: apk add g++ gcc cmake cmake make ncurses-dev git bash perl linux-headers autoconf automake m4 libtool elfutils-dev libelf-static patch binutils
|
||||
command: apk add g++ gcc cmake cmake make git bash perl linux-headers autoconf automake m4 libtool elfutils-dev libelf-static patch binutils
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libjq-dev libncurses-dev libyaml-cpp-dev libelf-dev cmake build-essential git -y
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libjq-dev libyaml-cpp-dev libelf-dev cmake build-essential git -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libncurses-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-generic clang llvm git -y
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-generic clang llvm git -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libncurses-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-generic clang llvm git -y
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-generic clang llvm git -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
command: apt update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install cmake build-essential clang llvm git linux-headers-generic libncurses-dev pkg-config autoconf libtool libelf-dev -y
|
||||
command: DEBIAN_FRONTEND=noninteractive apt install cmake build-essential clang llvm git linux-headers-generic pkg-config autoconf libtool libelf-dev -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
@@ -188,7 +188,7 @@ jobs:
|
||||
command: dnf update -y
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: dnf install gcc gcc-c++ git make cmake autoconf automake pkg-config patch ncurses-devel libtool elfutils-libelf-devel diffutils kernel-devel kernel-headers kernel-core clang llvm which -y
|
||||
command: dnf install gcc gcc-c++ git make cmake autoconf automake pkg-config patch libtool elfutils-libelf-devel diffutils kernel-devel kernel-headers kernel-core clang llvm which -y
|
||||
- run:
|
||||
name: Prepare project
|
||||
command: |
|
||||
@@ -292,6 +292,7 @@ jobs:
|
||||
BUILD_DIR: "/build-static"
|
||||
BUILD_TYPE: "release"
|
||||
SKIP_PACKAGES_TESTS: "true"
|
||||
SKIP_PLUGINS_TESTS: "true"
|
||||
steps:
|
||||
- setup_remote_docker
|
||||
- attach_workspace:
|
||||
@@ -303,7 +304,7 @@ jobs:
|
||||
path: /build-static/release/integration-tests-xunit
|
||||
"tests/driver-loader/integration":
|
||||
machine:
|
||||
image: ubuntu-1604:202004-01
|
||||
image: ubuntu-2004:202107-02
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: /tmp/ws
|
||||
@@ -403,7 +404,7 @@ jobs:
|
||||
name: Setup
|
||||
command: |
|
||||
apt update -y
|
||||
apt-get install apt-utils bzip2 gpg python python-pip -y
|
||||
apt-get install apt-utils bzip2 gpg python python3-pip -y
|
||||
pip install awscli
|
||||
echo $GPG_KEY | base64 -d | gpg --import
|
||||
- run:
|
||||
@@ -517,7 +518,7 @@ jobs:
|
||||
name: Setup
|
||||
command: |
|
||||
apt update -y
|
||||
apt-get install apt-utils bzip2 gpg python python-pip -y
|
||||
apt-get install apt-utils bzip2 gpg python python3-pip -y
|
||||
pip install awscli
|
||||
echo $GPG_KEY | base64 -d | gpg --import
|
||||
- run:
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
||||
<!-- Thanks for sending a pull request! Here are some tips for you:
|
||||
|
||||
1. If this is your first time, please read our contributor guidelines in the [CONTRIBUTING.md](CONTRIBUTING.md) file and learn how to compile Falco from source [here](https://falco.org/docs/source).
|
||||
1. If this is your first time, please read our contributor guidelines in the [CONTRIBUTING.md](https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md) file and learn how to compile Falco from source [here](https://falco.org/docs/source).
|
||||
2. Please label this pull request according to what type of issue you are addressing.
|
||||
3. . Please add a release note!
|
||||
4. If the PR is unfinished while opening it specify a wip in the title before the actual title, for example, "wip: my awesome feature"
|
||||
|
||||
42
ADOPTERS.md
42
ADOPTERS.md
@@ -1,5 +1,21 @@
|
||||
# Adopters
|
||||
|
||||
Known end users with notable contributions to the project include:
|
||||
* AWS
|
||||
* IBM
|
||||
* Red Hat
|
||||
|
||||
Falco is being used by numerous other companies, both large and small, to build higher layer products and services. The list includes but is not limited to:
|
||||
* Equinix Metal
|
||||
* IEEE
|
||||
* Lowes
|
||||
* Reckrut
|
||||
* Yellow Pepper
|
||||
* CTx
|
||||
* Utikal
|
||||
* Discrete Events
|
||||
* Agritech Infra
|
||||
|
||||
This is a list of production adopters of Falco (in alphabetical order):
|
||||
|
||||
* [ASAPP](https://www.asapp.com/) - ASAPP is a pushing the boundaries of fundamental artificial intelligence research. We apply our research into AI-Native® products that make organizations, in the customer experience industry, highly productive, efficient, and effective—by augmenting human activity and automating workflows. We constantly monitor our workloads against different hazards and FALCO helps us extend our threat monitoring boundaries.
|
||||
@@ -10,6 +26,8 @@ This is a list of production adopters of Falco (in alphabetical order):
|
||||
|
||||
* [Frame.io](https://frame.io/) - Frame.io is a cloud-based (SaaS) video review and collaboration platform that enables users to securely upload source media, work-in-progress edits, dailies, and more into private workspaces where they can invite their team and clients to collaborate on projects. Understanding what is running on production servers, and the context around why things are running is even more tricky now that we have further abstractions like Docker and Kubernetes. To get this needed visibility into our system, we rely on Falco. Falco's ability to collect raw system calls such as open, connect, exec, along with their arguments offer key insights on what is happening on the production system and became the foundation of our intrusion detection and alerting system.
|
||||
|
||||
* [Giant Swarm](https://www.giantswarm.io/) - Giant Swarm manages Kubernetes clusters and infrastructure for enterprises across multiple cloud providers as well as several flavors of on-premises data centers. Our platform provisions and monitors pure "vanilla" Kubernetes clusters which can be augmented with managed solutions to many common Kubernetes challenges, including security. We use Falco for anomaly detection as part of our collection of entirely open-source tools for securing our own clusters, and offer the same capabilities to our customers as part of our [managed security offering](https://docs.giantswarm.io/app-platform/apps/security/).
|
||||
|
||||
* [GitLab](https://about.gitlab.com/direction/defend/container_host_security/) - GitLab is a complete DevOps platform, delivered as a single application, fundamentally changing the way Development, Security, and Ops teams collaborate. GitLab Ultimate provides the single tool teams need to find, triage, and fix vulnerabilities in applications, services, and cloud-native environments enabling them to manage their risk. This provides them with repeatable, defensible processes that automate security and compliance policies. GitLab includes a tight integration with Falco, allowing users to defend their containerized applications from attacks while running in production.
|
||||
|
||||
* [League](https://league.com/ca/) - League provides health benefits management services to help employees understand and get the most from their benefits, and employers to provide effective, efficient plans. Falco is used to monitor our deployed services on Kubernetes, protecting against malicious access to containers which could lead to leaks of PHI or other sensitive data. The Falco alerts are logged in Stackdriver for grouping and further analysis. In the future, we're hoping for integrations with Prometheus and AlertManager as well.
|
||||
@@ -17,11 +35,21 @@ This is a list of production adopters of Falco (in alphabetical order):
|
||||
* [Logz.io](https://logz.io/) - Logz.io is a cloud observability platform for modern engineering teams. The Logz.io platform consists of three products — Log Management, Infrastructure Monitoring, and Cloud SIEM — that work together to unify the jobs of monitoring, troubleshooting, and security. We empower engineers to deliver better software by offering the world's most popular open source observability tools — the ELK Stack, Grafana, and Jaeger — in a single, easy to use, and powerful platform purpose-built for monitoring distributed cloud environments. Cloud SIEM supports data from multiple sources, including Falco's alerts, and offers useful rules and dashboards content to visualize and manage incidents across your systems in a unified UI.
|
||||
* https://logz.io/blog/k8s-security-with-falco-and-cloud-siem/
|
||||
|
||||
* [MathWorks](https://mathworks.com) - MathWorks develops mathematical computing software for engineers and scientists. MathWorks uses Falco for Kubernetes threat detection, unexpected application behavior, and maps Falco rules to their cloud infrastructure's security kill chain model. MathWorks presented their Falco use case at [KubeCon + CloudNativeCon North America 2020](https://www.youtube.com/watch?v=L-5RYBTV010).
|
||||
|
||||
* [Pocteo](https://pocteo.co) - Pocteo helps with Kubernetes adoption in enterprises by providing a variety of services such as training, consulting, auditing and mentoring. We build CI/CD pipelines the GitOps way, as well as design and run k8s clusters. Pocteo uses Falco as a runtime monitoring system to secure clients' workloads against suspicious behavior and ensure k8s pods immutability. We also use Falco to collect, process and act on security events through a response engine and serverless functions.
|
||||
|
||||
* [Preferral](https://www.preferral.com) - Preferral is a HIPAA-compliant platform for Referral Management and Online Referral Forms. Preferral streamlines the referral process for patients, specialists and their referral partners. By automating the referral process, referring practices spend less time on the phone, manual efforts are eliminated, and patients get the right care from the right specialist. Preferral leverages Falco to provide a Host Intrusion Detection System to meet their HIPPA compliance requirements.
|
||||
* https://hipaa.preferral.com/01-preferral_hipaa_compliance/
|
||||
|
||||
* [Qonto](https://qonto.com) - Qonto is a modern banking for SMEs and freelancers. Qonto provides a fully featured business account with a simplified accounting flow. Falco is used by our SecOps team to detect suspicous behaviors in our clusters.
|
||||
|
||||
* [Raft](https://goraft.tech) - Raft is a government contractor that offers cloud-native solutions across many different agencies including DoD (Department of Defense), HHS (Health and Human Services), as well as within CFPB (Consumer Finance Protection Bureau). Raft leverages Falco to detect threats in our client's Kubernetes clusters and as a Host Intrusion Detection System. Raft proudly recommends Falco across all our different projects.
|
||||
|
||||
* [Replicated](https://www.replicated.com/) - Replicated is the modern way to ship on-prem software. Replicated gives software vendors a container-based platform for easily deploying cloud native applications inside customers' environments to provide greater security and control. Replicated uses Falco as runtime security to detect threats in the Kubernetes clusters which host our critical SaaS services.
|
||||
|
||||
* [Secureworks](https://www.secureworks.com/) - Secureworks is a leading worldwide cybersecurity company with a cloud-native security product that combines the power of human intellect with security analytics to unify detection and response across cloud, network, and endpoint environments for improved security operations and outcomes. Our Taegis XDR platform and detection system processes petabytes of security relevant data to expose active threats amongst the billions of daily events from our customers. We are proud to protect our platform’s Kubernetes deployments, as well as help our customers protect their own Linux and container environments, using Falco.
|
||||
|
||||
* [Shopify](https://www.shopify.com) - Shopify is the leading multi-channel commerce platform. Merchants use Shopify to design, set up, and manage their stores across multiple sales channels, including mobile, web, social media, marketplaces, brick-and-mortar locations, and pop-up shops. The platform also provides merchants with a powerful back-office and a single view of their business, from payments to shipping. The Shopify platform was engineered for reliability and scale, making enterprise-level technology available to businesses of all sizes. Shopify uses Falco to complement its Host and Network Intrusion Detection Systems.
|
||||
|
||||
* [Sight Machine](https://www.sightmachine.com) - Sight Machine is the category leader for manufacturing analytics and used by Global 500 companies to make better, faster decisions about their operations. Sight Machine uses Falco to help enforce SOC2 compliance as well as a tool for real time security monitoring and alerting in Kubernetes.
|
||||
@@ -32,6 +60,18 @@ This is a list of production adopters of Falco (in alphabetical order):
|
||||
|
||||
* [Swissblock Technologies](https://swissblock.net/) At Swissblock we connect the dots by combining cutting-edge algorithmic trading strategies with in-depth market analysis. We route all Falco events to our control systems, both monitoring and logging. Being able to deeply analyse alerts, we can understand what is running on our Kubernetes clusters and check against security policies, specifically defined for each workload. A set of alarms notifies us in case of critical events, letting us react fast. In the near future we plan to build a little application to route Kubernetes internal events directly to Falco, fully leveraging Falco PodSecurityPolicies analyses.
|
||||
|
||||
* [Shapesecurity/F5] (https://www.shapesecurity.com/) Shapesecurity defends against application fraud attacks like Account Take Over, Credential Stuffing, Fake Accounts, etc. Required by FedRamp certification, we needed to find a FIM solution to help monitor and protect our Kubernetes clusters. Traditional FIM solutions were not scalable and not working for our environment, but with Falco we found the solution we needed. Falco's detection capabilities have helped us identify anomalous behaviour within our clusters. We leverage Sidekick (https://github.com/falcosecurity/charts/tree/master/falcosidekick) to send Falco alerts to a PubSub which in turn publishes those alerts to our SIEM (SumoLogic)
|
||||
* [Shapesecurity/F5](https://www.shapesecurity.com/) Shapesecurity defends against application fraud attacks like Account Take Over, Credential Stuffing, Fake Accounts, etc. Required by FedRamp certification, we needed to find a FIM solution to help monitor and protect our Kubernetes clusters. Traditional FIM solutions were not scalable and not working for our environment, but with Falco we found the solution we needed. Falco's detection capabilities have helped us identify anomalous behaviour within our clusters. We leverage Sidekick (https://github.com/falcosecurity/charts/tree/master/falcosidekick) to send Falco alerts to a PubSub which in turn publishes those alerts to our SIEM (SumoLogic)
|
||||
|
||||
* [Yahoo! JAPAN](https://www.yahoo.co.jp/) Yahoo! JAPAN is a leading company of internet in Japan. We build an AI Platform in our private cloud and provide it to scientists in our company. AI Platform is a multi-tenant Kubernetes environment and more flexible, faster, more efficient Machine Learning environment. Falco is used to detect unauthorized commands and malicious access and our AI Platform is monitored and alerted by Falco.
|
||||
|
||||
* [Sysdig](https://www.sysdig.com/) Sysdig originally created Falco in 2016 to detect unexpected or suspicious activity using a rules engine on top of the data that comes from the sysdig kernel system call probe. Sysdig provides tooling to help with vulnerability management, compliance, detection, incident response and forensics in Cloud-native environments. Sysdig Secure has extended Falco to include: a rule library, the ability to update macros, lists & rules via the user interface and API, automated tuning of rules, and rule creation based on profiling known system behavior. On top of the basic Falco rules, Sysdig Secure implements the concept of a "Security policy" that can comprise several rules which are evaluated for a user-defined infrastructure scope like Kubernetes namespaces, OpenShift clusters, deployment workload, cloud regions etc.
|
||||
|
||||
## Projects that use Falco libs
|
||||
|
||||
* [R6/Phoenix](https://r6security.com/) is an attack surface protection company that uses moving target defense to provide fully automated, proactive and devops friendly security to its customers. There are a set of policies you can add to enable the moving target defense capabilities. Some of them are triggered by a combination of Falco's findings. You can kill, restart and rename pods according to the ever changing policies.
|
||||
|
||||
* [SysFlow](https://sysflow.io) SysFlow is a cloud-native system telemetry framework that focuses on data abstraction, behavioral analytics, and noise reduction. At its core, SysFlow exposes a compact open telemetry format that records workload behaviors by connecting event and flow representations of process control flows, file interactions, and network communications. The resulting abstraction encodes a graph structure that enables provenance reasoning on host and container environments, and fast retrieval of security-relevant information.
|
||||
|
||||
## Adding a name
|
||||
|
||||
If you would like to add your name to this file, submit a pull request with your change.
|
||||
|
||||
130
CHANGELOG.md
130
CHANGELOG.md
@@ -1,5 +1,135 @@
|
||||
# Change Log
|
||||
|
||||
## v0.30.0
|
||||
|
||||
Released on 2021-10-01
|
||||
|
||||
### Major Changes
|
||||
|
||||
* new: add `--k8s-node` command-line options, which allows filtering by a node when requesting metadata of pods to the K8s API server [[#1671](https://github.com/falcosecurity/falco/pull/1671)] - [@leogr](https://github.com/leogr)
|
||||
* new(outputs): expose rule tags and event source in gRPC and json outputs [[#1714](https://github.com/falcosecurity/falco/pull/1714)] - [@jasondellaluce](https://github.com/jasondellaluce)
|
||||
* new(userspace/falco): add customizable metadata fetching params [[#1667](https://github.com/falcosecurity/falco/pull/1667)] - [@zuc](https://github.com/zuc)
|
||||
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* update: bump driver version to 3aa7a83bf7b9e6229a3824e3fd1f4452d1e95cb4 [[#1744](https://github.com/falcosecurity/falco/pull/1744)] - [@zuc](https://github.com/zuc)
|
||||
* docs: clarify that previous Falco drivers will remain available at https://download.falco.org and no automated cleanup is run anymore [[#1738](https://github.com/falcosecurity/falco/pull/1738)] - [@leodido](https://github.com/leodido)
|
||||
* update(outputs): add configuration option for tags in json outputs [[#1733](https://github.com/falcosecurity/falco/pull/1733)] - [@jasondellaluce](https://github.com/jasondellaluce)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix(scripts): correct standard output redirection in systemd config (DEB and RPM packages) [[#1697](https://github.com/falcosecurity/falco/pull/1697)] - [@chirabino](https://github.com/chirabino)
|
||||
* fix(scripts): correct lookup order when trying multiple `gcc` versions in the `falco-driver-loader` script [[#1716](https://github.com/falcosecurity/falco/pull/1716)] - [@Spartan-65](https://github.com/Spartan-65)
|
||||
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(list miner_domains): add new miner domains [[#1729](https://github.com/falcosecurity/falco/pull/1729)] - [@AlbertoPellitteri](https://github.com/AlbertoPellitteri)
|
||||
* rule(list https_miner_domains): add new miner domains [[#1729](https://github.com/falcosecurity/falco/pull/1729)] - [@AlbertoPellitteri](https://github.com/AlbertoPellitteri)
|
||||
|
||||
|
||||
### Non user-facing changes
|
||||
|
||||
* add Qonto as adopter [[#1717](https://github.com/falcosecurity/falco/pull/1717)] - [@Issif](https://github.com/Issif)
|
||||
* docs(proposals): proposal for a libs plugin system [[#1637](https://github.com/falcosecurity/falco/pull/1637)] - [@ldegio](https://github.com/ldegio)
|
||||
* build: remove unused `ncurses` dependency [[#1658](https://github.com/falcosecurity/falco/pull/1658)] - [@leogr](https://github.com/leogr)
|
||||
* build(.circleci): use new Debian 11 package names for python-pip [[#1712](https://github.com/falcosecurity/falco/pull/1712)] - [@zuc](https://github.com/zuc)
|
||||
* build(docker): adding libssl-dev, upstream image reference pinned to `debian:buster` [[#1719](https://github.com/falcosecurity/falco/pull/1719)] - [@michalschott](https://github.com/michalschott)
|
||||
* fix(test): avoid output_strictly_contains failures [[#1724](https://github.com/falcosecurity/falco/pull/1724)] - [@jasondellaluce](https://github.com/jasondellaluce)
|
||||
* Remove duplicate allowed ecr registry rule [[#1725](https://github.com/falcosecurity/falco/pull/1725)] - [@TomKeyte](https://github.com/TomKeyte)
|
||||
* docs(RELEASE.md): switch to 3 releases per year [[#1711](https://github.com/falcosecurity/falco/pull/1711)] - [@leogr](https://github.com/leogr)
|
||||
|
||||
|
||||
## v0.29.1
|
||||
|
||||
Released on 2021-06-29
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* update: bump the Falco engine version to version 9 [[#1675](https://github.com/falcosecurity/falco/pull/1675)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(list user_known_userfaultfd_processes): list to exclude processes known to use userfaultfd syscall [[#1675](https://github.com/falcosecurity/falco/pull/1675)] - [@leodido](https://github.com/leodido)
|
||||
* rule(macro consider_userfaultfd_activities): macro to gate the "Unprivileged Delegation of Page Faults Handling to a Userspace Process" rule [[#1675](https://github.com/falcosecurity/falco/pull/1675)] - [@leodido](https://github.com/leodido)
|
||||
* rule(Unprivileged Delegation of Page Faults Handling to a Userspace Process): new rule to detect successful unprivileged userfaultfd syscalls [[#1675](https://github.com/falcosecurity/falco/pull/1675)] - [@leodido](https://github.com/leodido)
|
||||
* rule(Linux Kernel Module Injection Detected): adding container info to the output of the rule [[#1675](https://github.com/falcosecurity/falco/pull/1675)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
### Non user-facing changes
|
||||
|
||||
* docs(release.md): update steps [[#1684](https://github.com/falcosecurity/falco/pull/1684)] - [@maxgio92](https://github.com/maxgio92)
|
||||
|
||||
|
||||
## v0.29.0
|
||||
|
||||
Released on 2021-06-21
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* update: driver version is 17f5df52a7d9ed6bb12d3b1768460def8439936d now [[#1669](https://github.com/falcosecurity/falco/pull/1669)] - [@leogr](https://github.com/leogr)
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(list miner_domains): add rx.unmineable.com for anti-miner detection [[#1676](https://github.com/falcosecurity/falco/pull/1676)] - [@fntlnz](https://github.com/fntlnz)
|
||||
* rule(Change thread namespace and Set Setuid or Setgid bit): disable by default [[#1632](https://github.com/falcosecurity/falco/pull/1632)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(list known_sa_list): add namespace-controller, statefulset-controller, disruption-controller, job-controller, horizontal-pod-autoscaler and persistent-volume-binder as allowed service accounts in the kube-system namespace [[#1659](https://github.com/falcosecurity/falco/pull/1659)] - [@sboschman](https://github.com/sboschman)
|
||||
* rule(Non sudo setuid): check user id as well in case user name info is not available [[#1665](https://github.com/falcosecurity/falco/pull/1665)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
* rule(Debugfs Launched in Privileged Container): fix typo in description [[#1657](https://github.com/falcosecurity/falco/pull/1657)] - [@Kaizhe](https://github.com/Kaizhe)
|
||||
|
||||
### Non user-facing changes
|
||||
|
||||
* Fix link to CONTRIBUTING.md in the Pull Request Template [[#1679](https://github.com/falcosecurity/falco/pull/1679)] - [@tspearconquest](https://github.com/tspearconquest)
|
||||
* fetch libs and drivers from the new repo [[#1552](https://github.com/falcosecurity/falco/pull/1552)] - [@leogr](https://github.com/leogr)
|
||||
* build(test): upgrade urllib3 to 1.26.5 [[#1666](https://github.com/falcosecurity/falco/pull/1666)] - [@leogr](https://github.com/leogr)
|
||||
* revert: add notes for 0.28.2 release [[#1663](https://github.com/falcosecurity/falco/pull/1663)] - [@maxgio92](https://github.com/maxgio92)
|
||||
* changelog: add notes for 0.28.2 release [[#1661](https://github.com/falcosecurity/falco/pull/1661)] - [@maxgio92](https://github.com/maxgio92)
|
||||
* docs(release.md): add blog announcement to post-release tasks [[#1652](https://github.com/falcosecurity/falco/pull/1652)] - [@maxgio92](https://github.com/maxgio92)
|
||||
* add Yahoo!Japan as an adopter [[#1651](https://github.com/falcosecurity/falco/pull/1651)] - [@ukitazume](https://github.com/ukitazume)
|
||||
* Add Replicated to adopters [[#1649](https://github.com/falcosecurity/falco/pull/1649)] - [@diamonwiggins](https://github.com/diamonwiggins)
|
||||
* docs(proposals): fix libs contribution name [[#1641](https://github.com/falcosecurity/falco/pull/1641)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
|
||||
## v0.28.1
|
||||
|
||||
Released on 2021-05-07
|
||||
|
||||
### Major Changes
|
||||
|
||||
* new: `--support` output now includes info about the Falco engine version [[#1581](https://github.com/falcosecurity/falco/pull/1581)] - [@mstemm](https://github.com/mstemm)
|
||||
* new: Falco outputs an alert in the unlikely situation it's receiving too many consecutive timeouts without an event [[#1622](https://github.com/falcosecurity/falco/pull/1622)] - [@leodido](https://github.com/leodido)
|
||||
* new: configuration field `syscall_event_timeouts.max_consecutive` to configure after how many consecutive timeouts without an event Falco must alert [[#1622](https://github.com/falcosecurity/falco/pull/1622)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* build: enforcing hardening flags by default [[#1604](https://github.com/falcosecurity/falco/pull/1604)] - [@leogr](https://github.com/leogr)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix: do not stop the webserver for k8s audit logs when invalid data is coming in the event to be processed [[#1617](https://github.com/falcosecurity/falco/pull/1617)] - [@fntlnz](https://github.com/fntlnz)
|
||||
|
||||
### Rule Changes
|
||||
|
||||
* rule(macro: allowed_aws_ecr_registry_root_for_eks): new macro for AWS EKS images hosted on ECR to use in rule: Launch Privileged Container [[#1640](https://github.com/falcosecurity/falco/pull/1640)] - [@ismailyenigul](https://github.com/ismailyenigul)
|
||||
* rule(macro: aws_eks_core_images): new macro for AWS EKS images hosted on ECR to use in rule: Launch Privileged Container [[#1640](https://github.com/falcosecurity/falco/pull/1640)] - [@ismailyenigul](https://github.com/ismailyenigul)
|
||||
* rule(macro: aws_eks_image_sensitive_mount): new macro for AWS EKS images hosted on ECR to use in rule: Launch Privileged Container [[#1640](https://github.com/falcosecurity/falco/pull/1640)] - [@ismailyenigul](https://github.com/ismailyenigul)
|
||||
* rule(list `falco_privileged_images`): remove deprecated Falco's OCI image repositories [[#1634](https://github.com/falcosecurity/falco/pull/1634)] - [@maxgio92](https://github.com/maxgio92)
|
||||
* rule(list `falco_sensitive_mount_images`): remove deprecated Falco's OCI image repositories [[#1634](https://github.com/falcosecurity/falco/pull/1634)] - [@maxgio92](https://github.com/maxgio92)
|
||||
* rule(macro `k8s_containers`): remove deprecated Falco's OCI image repositories [[#1634](https://github.com/falcosecurity/falco/pull/1634)] - [@maxgio92](https://github.com/maxgio92)
|
||||
* rule(macro: python_running_sdchecks): macro removed [[#1620](https://github.com/falcosecurity/falco/pull/1620)] - [@leogr](https://github.com/leogr)
|
||||
* rule(Change thread namespace): remove python_running_sdchecks exception [[#1620](https://github.com/falcosecurity/falco/pull/1620)] - [@leogr](https://github.com/leogr)
|
||||
|
||||
### Non user-facing changes
|
||||
|
||||
* urelease/docs: fix link and small refactor in the text [[#1636](https://github.com/falcosecurity/falco/pull/1636)] - [@cpanato](https://github.com/cpanato)
|
||||
* Add Secureworks to adopters [[#1629](https://github.com/falcosecurity/falco/pull/1629)] - [@dwindsor-scwx](https://github.com/dwindsor-scwx)
|
||||
* regression test for malformed k8s audit input (FAL-01-003) [[#1624](https://github.com/falcosecurity/falco/pull/1624)] - [@leodido](https://github.com/leodido)
|
||||
* Add mathworks to adopterlist [[#1621](https://github.com/falcosecurity/falco/pull/1621)] - [@natchaphon-r](https://github.com/natchaphon-r)
|
||||
* adding known users [[#1623](https://github.com/falcosecurity/falco/pull/1623)] - [@danpopSD](https://github.com/danpopSD)
|
||||
* docs: update link for HackMD community call notes [[#1614](https://github.com/falcosecurity/falco/pull/1614)] - [@leodido](https://github.com/leodido)
|
||||
|
||||
|
||||
## v0.28.0
|
||||
|
||||
Released on 2021-04-12
|
||||
|
||||
@@ -66,10 +66,17 @@ if(MINIMAL_BUILD)
|
||||
endif()
|
||||
|
||||
if(MUSL_OPTIMIZED_BUILD)
|
||||
set(MUSL_FLAGS "-static -Os")
|
||||
set(MUSL_FLAGS "-static -Os -fPIE -pie")
|
||||
endif()
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
|
||||
# explicitly set hardening flags
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set(FALCO_SECURITY_FLAGS "-Wl,-z,relro,-z,now -fstack-protector-strong")
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "release")
|
||||
set(FALCO_SECURITY_FLAGS "${FALCO_SECURITY_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||
endif()
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "${FALCO_SECURITY_FLAGS} -Wall -ggdb ${DRAIOS_FEATURE_FLAGS} ${MINIMAL_BUILD_FLAGS} ${MUSL_FLAGS}")
|
||||
|
||||
if(BUILD_WARNINGS_AS_ERRORS)
|
||||
set(CMAKE_SUPPRESSED_WARNINGS
|
||||
@@ -103,6 +110,12 @@ set(CMD_MAKE make)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
# libs
|
||||
include(falcosecurity-libs)
|
||||
|
||||
# LuaJit provided by libs
|
||||
include(luajit)
|
||||
|
||||
# jq
|
||||
include(jq)
|
||||
|
||||
@@ -118,12 +131,6 @@ ExternalProject_Add(
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
# curses
|
||||
# We pull this in because libsinsp won't build without it
|
||||
set(CURSES_NEED_NCURSES TRUE)
|
||||
find_package(Curses REQUIRED)
|
||||
message(STATUS "Found ncurses: include: ${CURSES_INCLUDE_DIR}, lib: ${CURSES_LIBRARIES}")
|
||||
|
||||
# b64
|
||||
include(b64)
|
||||
|
||||
@@ -132,14 +139,14 @@ include(yaml-cpp)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# OpenSSL
|
||||
include(OpenSSL)
|
||||
include(openssl)
|
||||
|
||||
# libcurl
|
||||
include(cURL)
|
||||
endif()
|
||||
include(curl)
|
||||
|
||||
# LuaJIT
|
||||
include(luajit)
|
||||
# civetweb
|
||||
include(civetweb)
|
||||
endif()
|
||||
|
||||
# Lpeg
|
||||
include(lpeg)
|
||||
@@ -151,51 +158,19 @@ include(libyaml)
|
||||
include(lyaml)
|
||||
|
||||
# One TBB
|
||||
set(TBB_SRC "${PROJECT_BINARY_DIR}/tbb-prefix/src/tbb")
|
||||
|
||||
message(STATUS "Using bundled tbb in '${TBB_SRC}'")
|
||||
|
||||
set(TBB_INCLUDE_DIR "${TBB_SRC}/include/")
|
||||
set(TBB_LIB "${TBB_SRC}/build/lib_release/libtbb.a")
|
||||
ExternalProject_Add(
|
||||
tbb
|
||||
URL "https://github.com/oneapi-src/oneTBB/archive/2018_U5.tar.gz"
|
||||
URL_HASH "SHA256=b8dbab5aea2b70cf07844f86fa413e549e099aa3205b6a04059ca92ead93a372"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE} tbb_build_dir=${TBB_SRC}/build tbb_build_prefix=lib extra_inc=big_iron.inc
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${TBB_LIB}
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
# civetweb
|
||||
set(CIVETWEB_SRC "${PROJECT_BINARY_DIR}/civetweb-prefix/src/civetweb/")
|
||||
set(CIVETWEB_LIB "${CIVETWEB_SRC}/install/lib/libcivetweb.a")
|
||||
set(CIVETWEB_INCLUDE_DIR "${CIVETWEB_SRC}/install/include")
|
||||
message(STATUS "Using bundled civetweb in '${CIVETWEB_SRC}'")
|
||||
ExternalProject_Add(
|
||||
civetweb
|
||||
URL "https://github.com/civetweb/civetweb/archive/v1.11.tar.gz"
|
||||
URL_HASH "SHA256=de7d5e7a2d9551d325898c71e41d437d5f7b51e754b242af897f7be96e713a42"
|
||||
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/lib
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CIVETWEB_SRC}/install/include
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" WITH_CPP=1
|
||||
BUILD_BYPRODUCTS ${CIVETWEB_LIB}
|
||||
INSTALL_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" install-lib install-headers PREFIX=${CIVETWEB_SRC}/install "WITH_CPP=1")
|
||||
endif()
|
||||
include(tbb)
|
||||
|
||||
#string-view-lite
|
||||
include(DownloadStringViewLite)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
include(zlib)
|
||||
include(cares)
|
||||
include(protobuf)
|
||||
# gRPC
|
||||
include(gRPC)
|
||||
include(grpc)
|
||||
endif()
|
||||
|
||||
# sysdig
|
||||
include(sysdig)
|
||||
|
||||
# Installation
|
||||
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}")
|
||||
|
||||
@@ -222,6 +197,7 @@ include(static-analysis)
|
||||
# Shared build variables
|
||||
set(FALCO_SINSP_LIBRARY sinsp)
|
||||
set(FALCO_SHARE_DIR share/falco)
|
||||
set(FALCO_PLUGINS_DIR ${FALCO_SHARE_DIR}/plugins)
|
||||
set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}")
|
||||
set(FALCO_BIN_DIR bin)
|
||||
|
||||
@@ -230,5 +206,7 @@ add_subdirectory(userspace/engine)
|
||||
add_subdirectory(userspace/falco)
|
||||
add_subdirectory(tests)
|
||||
|
||||
include(plugins)
|
||||
|
||||
# Packages configuration
|
||||
include(CPackConfig)
|
||||
|
||||
2
OWNERS
2
OWNERS
@@ -4,6 +4,7 @@ approvers:
|
||||
- leodido
|
||||
- mstemm
|
||||
- leogr
|
||||
- jasondellaluce
|
||||
reviewers:
|
||||
- fntlnz
|
||||
- kaizhe
|
||||
@@ -12,3 +13,4 @@ reviewers:
|
||||
- mfdii
|
||||
- mstemm
|
||||
- leogr
|
||||
- jasondellaluce
|
||||
|
||||
26
RELEASE.md
26
RELEASE.md
@@ -4,7 +4,9 @@ Our release process is mostly automated, but we still need some manual steps to
|
||||
|
||||
Changes and new features are grouped in [milestones](https://github.com/falcosecurity/falco/milestones), the milestone with the next version represents what is going to be released.
|
||||
|
||||
A release happens every two months ([as per community discussion](https://github.com/falcosecurity/community/blob/master/meeting-notes/2020-09-30.md#agenda)), and we need to assign owners for each (usually we pair a new person with an experienced one). Assignees and the due date are proposed during the [weekly community call](https://github.com/falcosecurity/community). Note that hotfix releases can happen as soon as it is needed.
|
||||
Falco releases are due to happen 3 times per year. Our current schedule sees a new release by the end of January, May, and September each year. Hotfix releases can happen whenever it's needed.
|
||||
|
||||
Moreover, we need to assign owners for each release (usually we pair a new person with an experienced one). Assignees and the due date are proposed during the [weekly community call](https://github.com/falcosecurity/community).
|
||||
|
||||
Finally, on the proposed due date the assignees for the upcoming release proceed with the processes described below.
|
||||
|
||||
@@ -15,10 +17,10 @@ Before cutting a release we need to do some homework in the Falco repository. Th
|
||||
### 1. Release notes
|
||||
- Find the previous release date (`YYYY-MM-DD`) by looking at the [Falco releases](https://github.com/falcosecurity/falco/releases)
|
||||
- Check the release note block of every PR matching the `is:pr is:merged closed:>YYYY-MM-DD` [filter](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+closed%3A%3EYYYY-MM-DD)
|
||||
- Ensure the release note block follows the [commit convention](https://github.com/falcosecurity/falco/blob/master/CONTRIBUTING.md#commit-convention), otherwise fix its content
|
||||
- Ensure the release note block follows the [commit convention](https://github.com/falcosecurity/.github/blob/master/CONTRIBUTING.md#commit-convention), otherwise fix its content
|
||||
- If the PR has no milestone, assign it to the milestone currently undergoing release
|
||||
- Check issues without a milestone (using [is:pr is:merged no:milestone closed:>YYYY-MM-DD](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYY-MM-DD) filter) and add them to the milestone currently undergoing release
|
||||
- Double-check that there are no more merged PRs without the target milestone assigned with the `is:pr is:merged no:milestone closed:>YYYY-MM-DD` [filters](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYY-MM-DD), if any, fix them
|
||||
- Check issues without a milestone (using `is:pr is:merged no:milestone closed:>YYYY-MM-DD` [filter](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYY-MM-DD) ) and add them to the milestone currently undergoing release
|
||||
- Double-check that there are no more merged PRs without the target milestone assigned with the `is:pr is:merged no:milestone closed:>YYYY-MM-DD` [filter](https://github.com/falcosecurity/falco/pulls?q=is%3Apr+is%3Amerged+no%3Amilestone+closed%3A%3EYYYY-MM-DD), if any, update those missing
|
||||
|
||||
### 2. Milestones
|
||||
|
||||
@@ -30,7 +32,7 @@ Before cutting a release we need to do some homework in the Falco repository. Th
|
||||
- If any, manually correct it then open an issue to automate version number bumping later
|
||||
- Versions table in the `README.md` updates itself automatically
|
||||
- Generate the change log using [rn2md](https://github.com/leodido/rn2md):
|
||||
- Execute `rn2md -o falcosecurity -m <version> -r falco`
|
||||
- Execute `rn2md -o falcosecurity -m <version> -r falco`
|
||||
- In case `rn2md` emits error try to generate an GitHub OAuth access token and provide it with the `-t` flag
|
||||
- Add the latest changes on top the previous `CHANGELOG.md`
|
||||
- Submit a PR with the above modifications
|
||||
@@ -52,7 +54,7 @@ Now assume `x.y.z` is the new version.
|
||||
git push origin x.y.z
|
||||
```
|
||||
|
||||
> **N.B.**: do NOT use an annotated tag
|
||||
> **N.B.**: do NOT use an annotated tag. For reference https://git-scm.com/book/en/v2/Git-Basics-Tagging
|
||||
|
||||
- Wait for the CI to complete
|
||||
|
||||
@@ -77,6 +79,10 @@ Now assume `x.y.z` is the new version.
|
||||
| `docker pull docker.io/falcosecurity/falco-driver-loader:x.y.z` |
|
||||
| `docker pull docker.io/falcosecurity/falco-no-driver:x.y.z` |
|
||||
|
||||
<changelog>
|
||||
|
||||
<!-- Substitute <changelog> with the one generated by [rn2md](https://github.com/leodido/rn2md) -->
|
||||
|
||||
### Statistics
|
||||
|
||||
| Merged PRs | Number |
|
||||
@@ -86,6 +92,10 @@ Now assume `x.y.z` is the new version.
|
||||
| Total | x |
|
||||
|
||||
<!-- Calculate stats and fill the above table -->
|
||||
|
||||
#### Release Manager <github handle>
|
||||
|
||||
<!-- Substitute Github handle with the release manager's one -->
|
||||
```
|
||||
|
||||
- Finally, publish the release!
|
||||
@@ -94,7 +104,7 @@ Now assume `x.y.z` is the new version.
|
||||
|
||||
For each release we archive the meeting notes in git for historical purposes.
|
||||
|
||||
- The notes from the Falco meetings can be [found here](https://hackmd.io/6sEAlInlSaGnLz2FnFz21A).
|
||||
- The notes from the Falco meetings can be [found here](https://hackmd.io/3qYPnZPUQLGKCzR14va_qg).
|
||||
- Note: There may be other notes from working groups that can optionally be added as well as needed.
|
||||
- Add the entire content of the document to a new file in [github.com/falcosecurity/community/tree/master/meeting-notes](https://github.com/falcosecurity/community/tree/master/meeting-notes) as a new file labeled `release-x.y.z.md`
|
||||
- Open up a pull request with the new change.
|
||||
@@ -104,5 +114,7 @@ For each release we archive the meeting notes in git for historical purposes.
|
||||
|
||||
Announce the new release to the world!
|
||||
|
||||
- Publish a blog on [Falco website](https://github.com/falcosecurity/falco-website) ([example](https://github.com/falcosecurity/falco-website/blob/master/content/en/blog/falco-0-28-1.md))
|
||||
- Send an announcement to cncf-falco-dev@lists.cncf.io (plain text, please)
|
||||
- Let folks in the slack #falco channel know about a new release came out
|
||||
- IFF the on going release introduces a **new minor version**, [archive a snapshot of the Falco website](https://github.com/falcosecurity/falco-website/blob/master/release.md#documentation-versioning)
|
||||
|
||||
@@ -48,7 +48,7 @@ set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "Apache v2.0")
|
||||
set(CPACK_RPM_PACKAGE_ARCHITECTURE, "amd64")
|
||||
set(CPACK_RPM_PACKAGE_URL "https://www.falco.org")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "dkms, kernel-devel, ncurses, systemd")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "dkms, kernel-devel, systemd")
|
||||
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_BINARY_DIR}/scripts/rpm/postinstall")
|
||||
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_BINARY_DIR}/scripts/rpm/preuninstall")
|
||||
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${CMAKE_BINARY_DIR}/scripts/rpm/postuninstall")
|
||||
|
||||
@@ -14,8 +14,8 @@ include(ExternalProject)
|
||||
|
||||
set(FAKEIT_INCLUDE ${CMAKE_BINARY_DIR}/fakeit-prefix/include)
|
||||
|
||||
set(FAKEIT_EXTERNAL_URL URL https://github.com/eranpeer/fakeit/archive/2.0.5.tar.gz URL_HASH
|
||||
SHA256=298539c773baca6ecbc28914306bba19d1008e098f8adc3ad3bb00e993ecdf15)
|
||||
set(FAKEIT_EXTERNAL_URL URL https://github.com/eranpeer/fakeit/archive/2.0.9.tar.gz URL_HASH
|
||||
SHA256=dc4ee7b17a84c959019b92c20fce6dc9426e9e170b6edf84db6cb2e188520cd7)
|
||||
|
||||
ExternalProject_Add(
|
||||
fakeit-external
|
||||
|
||||
@@ -21,7 +21,7 @@ if(NOT FALCO_VERSION)
|
||||
git_get_exact_tag(FALCO_TAG)
|
||||
if(NOT FALCO_TAG)
|
||||
# Obtain the closest tag
|
||||
git_describe(FALCO_VERSION "--always" "--tags")
|
||||
git_describe(FALCO_VERSION "--always" "--tags" "--abbrev=7")
|
||||
# Fallback version
|
||||
if(FALCO_VERSION MATCHES "NOTFOUND$")
|
||||
set(FALCO_VERSION "0.0.0")
|
||||
@@ -31,29 +31,33 @@ if(NOT FALCO_VERSION)
|
||||
else()
|
||||
# A tag has been found: use it as the Falco version
|
||||
set(FALCO_VERSION "${FALCO_TAG}")
|
||||
# Remove the starting "v" in case there is one
|
||||
string(REGEX REPLACE "^v(.*)" "\\1" FALCO_VERSION "${FALCO_TAG}")
|
||||
endif()
|
||||
# TODO(leodido) > ensure Falco version is semver before extracting parts Populate partial version variables
|
||||
string(REGEX MATCH "^(0|[1-9][0-9]*)" FALCO_VERSION_MAJOR "${FALCO_VERSION}")
|
||||
string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\..*" "\\2" FALCO_VERSION_MINOR "${FALCO_VERSION}")
|
||||
string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*).*" "\\3" FALCO_VERSION_PATCH
|
||||
"${FALCO_VERSION}")
|
||||
string(
|
||||
REGEX
|
||||
REPLACE
|
||||
"^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*).*"
|
||||
"\\5"
|
||||
FALCO_VERSION_PRERELEASE
|
||||
"${FALCO_VERSION}")
|
||||
if(FALCO_VERSION_PRERELEASE STREQUAL "${FALCO_VERSION}")
|
||||
set(FALCO_VERSION_PRERELEASE "")
|
||||
endif()
|
||||
if(NOT FALCO_VERSION_BUILD)
|
||||
string(REGEX REPLACE ".*\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)" "\\1" FALCO_VERSION_BUILD "${FALCO_VERSION}")
|
||||
endif()
|
||||
if(FALCO_VERSION_BUILD STREQUAL "${FALCO_VERSION}")
|
||||
set(FALCO_VERSION_BUILD "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Remove the starting "v" in case there is one
|
||||
string(REGEX REPLACE "^v(.*)" "\\1" FALCO_VERSION "${FALCO_VERSION}")
|
||||
|
||||
# TODO(leodido) > ensure Falco version is semver before extracting parts Populate partial version variables
|
||||
string(REGEX MATCH "^(0|[1-9][0-9]*)" FALCO_VERSION_MAJOR "${FALCO_VERSION}")
|
||||
string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\..*" "\\2" FALCO_VERSION_MINOR "${FALCO_VERSION}")
|
||||
string(REGEX REPLACE "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*).*" "\\3" FALCO_VERSION_PATCH
|
||||
"${FALCO_VERSION}")
|
||||
string(
|
||||
REGEX
|
||||
REPLACE
|
||||
"^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*).*"
|
||||
"\\5"
|
||||
FALCO_VERSION_PRERELEASE
|
||||
"${FALCO_VERSION}")
|
||||
|
||||
if(FALCO_VERSION_PRERELEASE STREQUAL "${FALCO_VERSION}")
|
||||
set(FALCO_VERSION_PRERELEASE "")
|
||||
endif()
|
||||
if(NOT FALCO_VERSION_BUILD)
|
||||
string(REGEX REPLACE ".*\\+([0-9a-zA-Z-]+(\\.[0-9a-zA-Z-]+)*)" "\\1" FALCO_VERSION_BUILD "${FALCO_VERSION}")
|
||||
endif()
|
||||
if(FALCO_VERSION_BUILD STREQUAL "${FALCO_VERSION}")
|
||||
set(FALCO_VERSION_BUILD "")
|
||||
endif()
|
||||
|
||||
message(STATUS "Falco version: ${FALCO_VERSION}")
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco 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.
|
||||
#
|
||||
mark_as_advanced(OPENSSL_BINARY)
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
message(STATUS "Found openssl: include: ${OPENSSL_INCLUDE_DIR}, lib: ${OPENSSL_LIBRARIES}")
|
||||
find_program(OPENSSL_BINARY openssl)
|
||||
if(NOT OPENSSL_BINARY)
|
||||
message(FATAL_ERROR "Couldn't find the openssl command line in PATH")
|
||||
else()
|
||||
message(STATUS "Found openssl: binary: ${OPENSSL_BINARY}")
|
||||
endif()
|
||||
else()
|
||||
mark_as_advanced(OPENSSL_BUNDLE_DIR OPENSSL_INSTALL_DIR OPENSSL_INCLUDE_DIR
|
||||
OPENSSL_LIBRARY_SSL OPENSSL_LIBRARY_CRYPTO)
|
||||
set(OPENSSL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl")
|
||||
set(OPENSSL_INSTALL_DIR "${OPENSSL_BUNDLE_DIR}/target")
|
||||
set(OPENSSL_INCLUDE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl/include")
|
||||
set(OPENSSL_LIBRARY_SSL "${OPENSSL_INSTALL_DIR}/lib/libssl.a")
|
||||
set(OPENSSL_LIBRARY_CRYPTO "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a")
|
||||
set(OPENSSL_BINARY "${OPENSSL_INSTALL_DIR}/bin/openssl")
|
||||
|
||||
message(STATUS "Using bundled openssl in '${OPENSSL_BUNDLE_DIR}'")
|
||||
|
||||
ExternalProject_Add(
|
||||
openssl
|
||||
# START CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
|
||||
URL "https://github.com/openssl/openssl/archive/OpenSSL_1_0_2n.tar.gz"
|
||||
URL_HASH "SHA256=4f4bc907caff1fee6ff8593729e5729891adcee412049153a3bb4db7625e8364"
|
||||
# END CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
|
||||
CONFIGURE_COMMAND ./config no-shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
endif()
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco 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.
|
||||
#
|
||||
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
externalproject_add(
|
||||
b64
|
||||
URL "https://github.com/libb64/libb64/archive/ce864b17ea0e24a91e77c7dd3eb2d1ac4175b3f0.tar.gz"
|
||||
URL_HASH "SHA256=d07173e66f435e5c77dbf81bd9313f8d0e4a3b4edd4105a62f4f8132ba932811"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${B64_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
@@ -1,76 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco 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.
|
||||
#
|
||||
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
find_package(CURL REQUIRED)
|
||||
message(STATUS "Found CURL: include: ${CURL_INCLUDE_DIR}, lib: ${CURL_LIBRARIES}")
|
||||
else()
|
||||
set(CURL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/curl-prefix/src/curl")
|
||||
set(CURL_INCLUDE_DIR "${CURL_BUNDLE_DIR}/include/")
|
||||
set(CURL_LIBRARIES "${CURL_BUNDLE_DIR}/lib/.libs/libcurl.a")
|
||||
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
|
||||
externalproject_add(
|
||||
curl
|
||||
DEPENDS openssl
|
||||
# START CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
|
||||
URL "https://github.com/curl/curl/releases/download/curl-7_61_0/curl-7.61.0.tar.bz2"
|
||||
URL_HASH "SHA256=5f6f336921cf5b84de56afbd08dfb70adeef2303751ffb3e570c936c6d656c9c"
|
||||
# END CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
|
||||
CONFIGURE_COMMAND
|
||||
./configure
|
||||
${CURL_SSL_OPTION}
|
||||
--disable-shared
|
||||
--enable-optimize
|
||||
--disable-curldebug
|
||||
--disable-rt
|
||||
--enable-http
|
||||
--disable-ftp
|
||||
--disable-file
|
||||
--disable-ldap
|
||||
--disable-ldaps
|
||||
--disable-rtsp
|
||||
--disable-telnet
|
||||
--disable-tftp
|
||||
--disable-pop3
|
||||
--disable-imap
|
||||
--disable-smb
|
||||
--disable-smtp
|
||||
--disable-gopher
|
||||
--disable-sspi
|
||||
--disable-ntlm-wb
|
||||
--disable-tls-srp
|
||||
--without-winssl
|
||||
--without-darwinssl
|
||||
--without-polarssl
|
||||
--without-cyassl
|
||||
--without-nss
|
||||
--without-axtls
|
||||
--without-ca-path
|
||||
--without-ca-bundle
|
||||
--without-libmetalink
|
||||
--without-librtmp
|
||||
--without-winidn
|
||||
--without-libidn2
|
||||
--without-libpsl
|
||||
--without-nghttp2
|
||||
--without-libssh2
|
||||
--disable-threaded-resolver
|
||||
--without-brotli
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
52
cmake/modules/civetweb.cmake
Normal file
52
cmake/modules/civetweb.cmake
Normal file
@@ -0,0 +1,52 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
set(CIVETWEB_SRC "${PROJECT_BINARY_DIR}/civetweb-prefix/src/civetweb/")
|
||||
set(CIVETWEB_LIB "${CIVETWEB_SRC}/install/${CMAKE_INSTALL_LIBDIR}/libcivetweb.a")
|
||||
SET(CIVETWEB_CPP_LIB "${CIVETWEB_SRC}/install/${CMAKE_INSTALL_LIBDIR}/libcivetweb-cpp.a")
|
||||
set(CIVETWEB_INCLUDE_DIR "${CIVETWEB_SRC}/install/include")
|
||||
message(STATUS "Using bundled civetweb in '${CIVETWEB_SRC}'")
|
||||
if (USE_BUNDLED_OPENSSL)
|
||||
ExternalProject_Add(
|
||||
civetweb
|
||||
DEPENDS openssl
|
||||
URL "https://github.com/civetweb/civetweb/archive/v1.15.tar.gz"
|
||||
URL_HASH "SHA256=90a533422944ab327a4fbb9969f0845d0dba05354f9cacce3a5005fa59f593b9"
|
||||
INSTALL_DIR ${CIVETWEB_SRC}/install
|
||||
CMAKE_ARGS
|
||||
-DBUILD_TESTING=off
|
||||
-DCIVETWEB_BUILD_TESTING=off
|
||||
-DCIVETWEB_ENABLE_CXX=on
|
||||
-DCIVETWEB_ENABLE_SERVER_EXECUTABLE=off
|
||||
-DCIVETWEB_ENABLE_SSL_DYNAMIC_LOADING=off
|
||||
-DCIVETWEB_SERVE_NO_FILES=on
|
||||
-DCMAKE_INSTALL_PREFIX=${CIVETWEB_SRC}/install
|
||||
-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_INSTALL_DIR}
|
||||
-DOPENSSL_USE_STATIC_LIBS:BOOL=TRUE
|
||||
BUILD_BYPRODUCTS ${CIVETWEB_LIB} ${CIVETWEB_CPP_LIB})
|
||||
else()
|
||||
ExternalProject_Add(
|
||||
civetweb
|
||||
URL "https://github.com/civetweb/civetweb/archive/v1.15.tar.gz"
|
||||
URL_HASH "SHA256=90a533422944ab327a4fbb9969f0845d0dba05354f9cacce3a5005fa59f593b9"
|
||||
INSTALL_DIR ${CIVETWEB_SRC}/install
|
||||
CMAKE_ARGS
|
||||
-DBUILD_TESTING=off
|
||||
-DCIVETWEB_BUILD_TESTING=off
|
||||
-DCIVETWEB_ENABLE_CXX=on
|
||||
-DCIVETWEB_ENABLE_SERVER_EXECUTABLE=off
|
||||
-DCIVETWEB_ENABLE_SSL_DYNAMIC_LOADING=off
|
||||
-DCIVETWEB_SERVE_NO_FILES=on
|
||||
-DCMAKE_INSTALL_PREFIX=${CIVETWEB_SRC}/install
|
||||
BUILD_BYPRODUCTS ${CIVETWEB_LIB} ${CIVETWEB_CPP_LIB})
|
||||
endif()
|
||||
@@ -12,17 +12,16 @@
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.5.1)
|
||||
|
||||
project(sysdig-repo NONE)
|
||||
project(falcosecurity-libs-repo NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
message(STATUS "Driver version: ${SYSDIG_VERSION}")
|
||||
message(STATUS "Driver version: ${FALCOSECURITY_LIBS_VERSION}")
|
||||
|
||||
ExternalProject_Add(
|
||||
sysdig
|
||||
URL "https://github.com/draios/sysdig/archive/${SYSDIG_VERSION}.tar.gz"
|
||||
URL_HASH "${SYSDIG_CHECKSUM}"
|
||||
falcosecurity-libs
|
||||
URL "https://github.com/falcosecurity/libs/archive/${FALCOSECURITY_LIBS_VERSION}.tar.gz"
|
||||
URL_HASH "${FALCOSECURITY_LIBS_CHECKSUM}"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
PATCH_COMMAND patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/libscap.patch && patch -p1 -i ${CMAKE_CURRENT_SOURCE_DIR}/patch/luajit.patch)
|
||||
TEST_COMMAND "")
|
||||
87
cmake/modules/falcosecurity-libs.cmake
Normal file
87
cmake/modules/falcosecurity-libs.cmake
Normal file
@@ -0,0 +1,87 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
set(FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/falcosecurity-libs-repo")
|
||||
set(FALCOSECURITY_LIBS_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/falcosecurity-libs-repo")
|
||||
|
||||
file(MAKE_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR})
|
||||
|
||||
if(FALCOSECURITY_LIBS_SOURCE_DIR)
|
||||
set(FALCOSECURITY_LIBS_VERSION "local")
|
||||
message(STATUS "Using local falcosecurity/libs in '${FALCOSECURITY_LIBS_SOURCE_DIR}'")
|
||||
else()
|
||||
# The falcosecurity/libs git reference (branch name, commit hash, or tag) To update falcosecurity/libs version for the next release, change the
|
||||
# default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake
|
||||
# -DFALCOSECURITY_LIBS_VERSION=dev ..`
|
||||
if(NOT FALCOSECURITY_LIBS_VERSION)
|
||||
set(FALCOSECURITY_LIBS_VERSION "bb9bee8e522fc953c2a79093d688d3d82b925e8b")
|
||||
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=ab2f18ff9c8d92dd06088ccfa73d4230fce3617613229f5afd839a37c13b0459")
|
||||
endif()
|
||||
|
||||
# cd /path/to/build && cmake /path/to/source
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -DFALCOSECURITY_LIBS_VERSION=${FALCOSECURITY_LIBS_VERSION} -DFALCOSECURITY_LIBS_CHECKSUM=${FALCOSECURITY_LIBS_CHECKSUM}
|
||||
${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR})
|
||||
|
||||
# todo(leodido, fntlnz) > use the following one when CMake version will be >= 3.13
|
||||
|
||||
# execute_process(COMMAND "${CMAKE_COMMAND}" -B ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR} WORKING_DIRECTORY
|
||||
# "${FALCOSECURITY_LIBS_CMAKE_SOURCE_DIR}")
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}")
|
||||
set(FALCOSECURITY_LIBS_SOURCE_DIR "${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR}/falcosecurity-libs-prefix/src/falcosecurity-libs")
|
||||
endif()
|
||||
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
add_definitions(-DHAS_CAPTURE)
|
||||
if(MUSL_OPTIMIZED_BUILD)
|
||||
add_definitions(-DMUSL_OPTIMIZED)
|
||||
endif()
|
||||
|
||||
set(PROBE_VERSION "${FALCOSECURITY_LIBS_VERSION}")
|
||||
set(PROBE_NAME "falco")
|
||||
set(DRIVER_PACKAGE_NAME "falco")
|
||||
set(SCAP_BPF_PROBE_ENV_VAR_NAME "FALCO_BPF_PROBE")
|
||||
set(SCAP_HOST_ROOT_ENV_VAR_NAME "HOST_ROOT")
|
||||
|
||||
if(NOT LIBSCAP_DIR)
|
||||
set(LIBSCAP_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}")
|
||||
endif()
|
||||
set(LIBSINSP_DIR "${FALCOSECURITY_LIBS_SOURCE_DIR}")
|
||||
|
||||
# explicitly disable the tests/examples of this dependency
|
||||
set(CREATE_TEST_TARGETS OFF CACHE BOOL "")
|
||||
set(BUILD_LIBSCAP_EXAMPLES OFF CACHE BOOL "")
|
||||
|
||||
# todo(leogr): although Falco does not actually depend on chisels, we need this for the lua_parser.
|
||||
# Hopefully, we can switch off this in the future
|
||||
set(WITH_CHISEL ON CACHE BOOL "")
|
||||
|
||||
set(USE_BUNDLED_TBB ON CACHE BOOL "")
|
||||
set(USE_BUNDLED_B64 ON CACHE BOOL "")
|
||||
set(USE_BUNDLED_JSONCPP ON CACHE BOOL "")
|
||||
set(USE_BUNDLED_LUAJIT ON CACHE BOOL "")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${FALCOSECURITY_LIBS_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
include(CheckSymbolExists)
|
||||
check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY)
|
||||
if(HAVE_STRLCPY)
|
||||
message(STATUS "Existing strlcpy found, will *not* use local definition by setting -DHAVE_STRLCPY.")
|
||||
add_definitions(-DHAVE_STRLCPY)
|
||||
else()
|
||||
message(STATUS "No strlcpy found, will use local definition")
|
||||
endif()
|
||||
|
||||
include(libscap)
|
||||
include(libsinsp)
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco 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.
|
||||
#
|
||||
|
||||
if(NOT USE_BUNDLED_DEPS)
|
||||
# zlib
|
||||
include(FindZLIB)
|
||||
set(ZLIB_INCLUDE "${ZLIB_INCLUDE_DIRS}")
|
||||
set(ZLIB_LIB "${ZLIB_LIBRARIES}")
|
||||
|
||||
if(ZLIB_INCLUDE AND ZLIB_LIB)
|
||||
message(STATUS "Found zlib: include: ${ZLIB_INCLUDE}, lib: ${ZLIB_LIB}")
|
||||
endif()
|
||||
|
||||
# c-ares
|
||||
mark_as_advanced(CARES_INCLUDE CARES_LIB)
|
||||
find_path(CARES_INCLUDE NAMES ares.h)
|
||||
find_library(CARES_LIB NAMES libcares.so)
|
||||
if(CARES_INCLUDE AND CARES_LIB)
|
||||
message(STATUS "Found c-ares: include: ${CARES_INCLUDE}, lib: ${CARES_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system c-ares")
|
||||
endif()
|
||||
|
||||
# protobuf
|
||||
mark_as_advanced(PROTOC PROTOBUF_INCLUDE PROTOBUF_LIB)
|
||||
find_program(PROTOC NAMES protoc)
|
||||
find_path(PROTOBUF_INCLUDE NAMES google/protobuf/message.h)
|
||||
find_library(PROTOBUF_LIB NAMES libprotobuf.so)
|
||||
if(PROTOC
|
||||
AND PROTOBUF_INCLUDE
|
||||
AND PROTOBUF_LIB)
|
||||
message(STATUS "Found protobuf: compiler: ${PROTOC}, include: ${PROTOBUF_INCLUDE}, lib: ${PROTOBUF_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system protobuf")
|
||||
endif()
|
||||
|
||||
# gpr
|
||||
mark_as_advanced(GPR_LIB)
|
||||
find_library(GPR_LIB NAMES gpr)
|
||||
|
||||
if(GPR_LIB)
|
||||
message(STATUS "Found gpr lib: ${GPR_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system gpr")
|
||||
endif()
|
||||
|
||||
# gRPC todo(fntlnz, leodido): check that gRPC version is greater or equal than 1.8.0
|
||||
mark_as_advanced(GRPC_INCLUDE GRPC_SRC
|
||||
GRPC_LIB GRPC_LIBS_ABSOLUTE GRPCPP_LIB GRPC_CPP_PLUGIN)
|
||||
find_path(GRPCXX_INCLUDE NAMES grpc++/grpc++.h)
|
||||
if(GRPCXX_INCLUDE)
|
||||
set(GRPC_INCLUDE ${GRPCXX_INCLUDE})
|
||||
unset(GRPCXX_INCLUDE CACHE)
|
||||
else()
|
||||
find_path(GRPCPP_INCLUDE NAMES grpcpp/grpcpp.h)
|
||||
set(GRPC_INCLUDE ${GRPCPP_INCLUDE})
|
||||
unset(GRPCPP_INCLUDE CACHE)
|
||||
add_definitions(-DGRPC_INCLUDE_IS_GRPCPP=1)
|
||||
endif()
|
||||
find_library(GRPC_LIB NAMES grpc)
|
||||
find_library(GRPCPP_LIB NAMES grpc++)
|
||||
if(GRPC_INCLUDE
|
||||
AND GRPC_LIB
|
||||
AND GRPCPP_LIB)
|
||||
message(STATUS "Found grpc: include: ${GRPC_INCLUDE}, C lib: ${GRPC_LIB}, C++ lib: ${GRPCPP_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system grpc")
|
||||
endif()
|
||||
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
|
||||
if(NOT GRPC_CPP_PLUGIN)
|
||||
message(FATAL_ERROR "System grpc_cpp_plugin not found")
|
||||
endif()
|
||||
|
||||
else()
|
||||
find_package(PkgConfig)
|
||||
if(NOT PKG_CONFIG_FOUND)
|
||||
message(FATAL_ERROR "pkg-config binary not found")
|
||||
endif()
|
||||
message(STATUS "Found pkg-config executable: ${PKG_CONFIG_EXECUTABLE}")
|
||||
set(GRPC_SRC "${PROJECT_BINARY_DIR}/grpc-prefix/src/grpc")
|
||||
set(GRPC_INCLUDE "${GRPC_SRC}/include")
|
||||
set(GRPC_LIBS_ABSOLUTE "${GRPC_SRC}/libs/opt")
|
||||
set(GRPC_LIB "${GRPC_LIBS_ABSOLUTE}/libgrpc.a")
|
||||
set(GRPCPP_LIB "${GRPC_LIBS_ABSOLUTE}/libgrpc++.a")
|
||||
set(GRPC_CPP_PLUGIN "${GRPC_SRC}/bins/opt/grpc_cpp_plugin")
|
||||
|
||||
# we tell gRPC to compile protobuf for us because when a gRPC package is not available, like on CentOS, it's very
|
||||
# likely that protobuf will be very outdated
|
||||
set(PROTOBUF_INCLUDE "${GRPC_SRC}/third_party/protobuf/src")
|
||||
set(PROTOC "${PROTOBUF_INCLUDE}/protoc")
|
||||
set(PROTOBUF_LIB "${GRPC_LIBS_ABSOLUTE}/protobuf/libprotobuf.a")
|
||||
# we tell gRPC to compile zlib for us because when a gRPC package is not available, like on CentOS, it's very likely
|
||||
# that zlib will be very outdated
|
||||
set(ZLIB_INCLUDE "${GRPC_SRC}/third_party/zlib")
|
||||
set(ZLIB_LIB "${GRPC_LIBS_ABSOLUTE}/libz.a")
|
||||
# we tell gRPC to compile c-ares for us because when a gRPC package is not available, like on CentOS, it's very likely
|
||||
# that c-ares will be very outdated
|
||||
set(CARES_INCLUDE "${GRPC_SRC}/third_party/cares" "${GRPC_SRC}/third_party/cares/cares")
|
||||
set(CARES_LIB "${GRPC_LIBS_ABSOLUTE}/libares.a")
|
||||
|
||||
message(STATUS "Using bundled gRPC in '${GRPC_SRC}'")
|
||||
message(
|
||||
STATUS
|
||||
"Bundled gRPC comes with protobuf: compiler: ${PROTOC}, include: ${PROTOBUF_INCLUDE}, lib: ${PROTOBUF_LIB}")
|
||||
message(STATUS "Bundled gRPC comes with zlib: include: ${ZLIB_INCLUDE}, lib: ${ZLIB_LIB}}")
|
||||
message(STATUS "Bundled gRPC comes with cares: include: ${CARES_INCLUDE}, lib: ${CARES_LIB}}")
|
||||
message(STATUS "Bundled gRPC comes with gRPC C++ plugin: include: ${GRPC_CPP_PLUGIN}")
|
||||
|
||||
get_filename_component(PROTOC_DIR ${PROTOC} PATH)
|
||||
|
||||
ExternalProject_Add(
|
||||
grpc
|
||||
DEPENDS openssl
|
||||
GIT_REPOSITORY https://github.com/grpc/grpc.git
|
||||
GIT_TAG v1.32.0
|
||||
GIT_SUBMODULES "third_party/protobuf third_party/zlib third_party/cares/cares third_party/abseil-cpp third_party/re2"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND
|
||||
CFLAGS=-Wno-implicit-fallthrough
|
||||
HAS_SYSTEM_ZLIB=false
|
||||
HAS_SYSTEM_PROTOBUF=false
|
||||
HAS_SYSTEM_CARES=false
|
||||
HAS_EMBEDDED_OPENSSL_ALPN=false
|
||||
HAS_SYSTEM_OPENSSL_ALPN=true
|
||||
PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}
|
||||
PKG_CONFIG=${PKG_CONFIG_EXECUTABLE}
|
||||
PATH=${PROTOC_DIR}:$ENV{PATH}
|
||||
make
|
||||
static_cxx
|
||||
static_c
|
||||
grpc_cpp_plugin)
|
||||
endif()
|
||||
@@ -1,54 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco 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.
|
||||
#
|
||||
mark_as_advanced(JQ_INCLUDE JQ_LIB)
|
||||
if (NOT USE_BUNDLED_DEPS)
|
||||
find_path(JQ_INCLUDE jq.h PATH_SUFFIXES jq)
|
||||
find_library(JQ_LIB NAMES jq)
|
||||
if (JQ_INCLUDE AND JQ_LIB)
|
||||
message(STATUS "Found jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
else ()
|
||||
message(FATAL_ERROR "Couldn't find system jq")
|
||||
endif ()
|
||||
else ()
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}/target/include")
|
||||
set(JQ_INSTALL_DIR "${JQ_SRC}/target")
|
||||
set(JQ_LIB "${JQ_INSTALL_DIR}/lib/libjq.a")
|
||||
set(ONIGURUMA_LIB "${JQ_INSTALL_DIR}/lib/libonig.a")
|
||||
message(STATUS "Bundled jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
|
||||
# Why we mirror jq here?
|
||||
#
|
||||
# In their readme, jq claims that you don't have
|
||||
# to do autoreconf -fi when downloading a released tarball.
|
||||
#
|
||||
# However, they forgot to push the released makefiles
|
||||
# into their release tarbal.
|
||||
#
|
||||
# For this reason, we have to mirror their release after
|
||||
# doing the configuration ourselves.
|
||||
#
|
||||
# This is needed because many distros do not ship the right
|
||||
# version of autoreconf, making virtually impossible to build Falco on them.
|
||||
# Read more about it here:
|
||||
# https://github.com/stedolan/jq/issues/2061#issuecomment-593445920
|
||||
ExternalProject_Add(
|
||||
jq
|
||||
URL "https://download.falco.org/dependencies/jq-1.6.tar.gz"
|
||||
URL_HASH "SHA256=787518068c35e244334cc79b8e56b60dbab352dff175b7f04a94f662b540bfd9"
|
||||
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking --with-oniguruma=builtin --prefix=${JQ_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
endif ()
|
||||
@@ -11,9 +11,10 @@
|
||||
# specific language governing permissions and limitations under the License.
|
||||
#
|
||||
|
||||
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'")
|
||||
set(LYAML_ROOT "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml")
|
||||
set(LYAML_LIB "${LYAML_ROOT}/ext/yaml/.libs/yaml.a")
|
||||
set(LYAML_LUA_DIR "${LYAML_ROOT}/lib")
|
||||
message(STATUS "Using bundled lyaml in '${LYAML_ROOT}'")
|
||||
externalproject_add(
|
||||
lyaml
|
||||
DEPENDS luajit libyaml
|
||||
@@ -22,7 +23,6 @@ externalproject_add(
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${LYAML_LIB}
|
||||
INSTALL_COMMAND ""
|
||||
CONFIGURE_COMMAND ./configure --enable-static CFLAGS=-I${LIBYAML_INSTALL_DIR}/include CPPFLAGS=-I${LIBYAML_INSTALL_DIR}/include LDFLAGS=-L${LIBYAML_INSTALL_DIR}/lib LIBS=-lyaml LUA=${LUAJIT_SRC}/luajit LUA_INCLUDE=-I${LUAJIT_INCLUDE}
|
||||
INSTALL_COMMAND sh -c
|
||||
"cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua"
|
||||
)
|
||||
|
||||
36
cmake/modules/plugins.cmake
Normal file
36
cmake/modules/plugins.cmake
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
set(PLUGINS_VERSION "0.1.0-rc1-28-g019437e")
|
||||
|
||||
ExternalProject_Add(
|
||||
cloudtrail-plugin
|
||||
URL "https://download.falco.org/plugins/dev/cloudtrail-${PLUGINS_VERSION}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
|
||||
URL_HASH "SHA256=ad9692957c5435238e07d1625e1b247eabe98b85f54de9218367fdd73a6f3f0b"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/cloudtrail-plugin-prefix/src/cloudtrail-plugin/libcloudtrail.so" DESTINATION "${FALCO_PLUGINS_DIR}")
|
||||
|
||||
ExternalProject_Add(
|
||||
json-plugin
|
||||
URL "https://download.falco.org/plugins/dev/json-${PLUGINS_VERSION}-${CMAKE_HOST_SYSTEM_PROCESSOR}.tar.gz"
|
||||
URL_HASH "SHA256=721ea5226b0f623915d0d5c34870589ad33a8ff795b0daa1af72f21a67430077"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
install(FILES "${PROJECT_BINARY_DIR}/json-plugin-prefix/src/json-plugin/libjson.so" DESTINATION "${FALCO_PLUGINS_DIR}")
|
||||
@@ -1,49 +0,0 @@
|
||||
diff --git a/userspace/libscap/scap.c b/userspace/libscap/scap.c
|
||||
index 6f51588e..5f9ea84e 100644
|
||||
--- a/userspace/libscap/scap.c
|
||||
+++ b/userspace/libscap/scap.c
|
||||
@@ -55,7 +55,7 @@ limitations under the License.
|
||||
//#define NDEBUG
|
||||
#include <assert.h>
|
||||
|
||||
-static const char *SYSDIG_BPF_PROBE_ENV = "SYSDIG_BPF_PROBE";
|
||||
+static const char *SYSDIG_BPF_PROBE_ENV = "FALCO_BPF_PROBE";
|
||||
|
||||
//
|
||||
// Probe version string size
|
||||
@@ -114,7 +114,7 @@ scap_t* scap_open_udig_int(char *error, int32_t *rc,
|
||||
static uint32_t get_max_consumers()
|
||||
{
|
||||
uint32_t max;
|
||||
- FILE *pfile = fopen("/sys/module/" PROBE_DEVICE_NAME "_probe/parameters/max_consumers", "r");
|
||||
+ FILE *pfile = fopen("/sys/module/" PROBE_DEVICE_NAME "/parameters/max_consumers", "r");
|
||||
if(pfile != NULL)
|
||||
{
|
||||
int w = fscanf(pfile, "%"PRIu32, &max);
|
||||
@@ -186,7 +186,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- snprintf(buf, sizeof(buf), "%s/.sysdig/%s-bpf.o", home, PROBE_NAME);
|
||||
+ snprintf(buf, sizeof(buf), "%s/.falco/%s-bpf.o", home, PROBE_NAME);
|
||||
bpf_probe = buf;
|
||||
}
|
||||
}
|
||||
@@ -344,7 +344,7 @@ scap_t* scap_open_live_int(char *error, int32_t *rc,
|
||||
else if(errno == EBUSY)
|
||||
{
|
||||
uint32_t curr_max_consumers = get_max_consumers();
|
||||
- snprintf(error, SCAP_LASTERR_SIZE, "Too many sysdig instances attached to device %s. Current value for /sys/module/" PROBE_DEVICE_NAME "_probe/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
|
||||
+ snprintf(error, SCAP_LASTERR_SIZE, "Too many Falco instances attached to device %s. Current value for /sys/module/" PROBE_DEVICE_NAME "/parameters/max_consumers is '%"PRIu32"'.", filename, curr_max_consumers);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2175,7 +2175,7 @@ int32_t scap_disable_dynamic_snaplen(scap_t* handle)
|
||||
|
||||
const char* scap_get_host_root()
|
||||
{
|
||||
- char* p = getenv("SYSDIG_HOST_ROOT");
|
||||
+ char* p = getenv("HOST_ROOT");
|
||||
static char env_str[SCAP_MAX_PATH_SIZE + 1];
|
||||
static bool inited = false;
|
||||
if (! inited) {
|
||||
@@ -1,57 +0,0 @@
|
||||
diff --git a/userspace/libsinsp/chisel.cpp b/userspace/libsinsp/chisel.cpp
|
||||
index 0a6e3cf8..0c2e255a 100644
|
||||
--- a/userspace/libsinsp/chisel.cpp
|
||||
+++ b/userspace/libsinsp/chisel.cpp
|
||||
@@ -98,7 +98,7 @@ void lua_stackdump(lua_State *L)
|
||||
// Lua callbacks
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef HAS_LUA_CHISELS
|
||||
-const static struct luaL_reg ll_sysdig [] =
|
||||
+const static struct luaL_Reg ll_sysdig [] =
|
||||
{
|
||||
{"set_filter", &lua_cbacks::set_global_filter},
|
||||
{"set_snaplen", &lua_cbacks::set_snaplen},
|
||||
@@ -134,7 +134,7 @@ const static struct luaL_reg ll_sysdig [] =
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
-const static struct luaL_reg ll_chisel [] =
|
||||
+const static struct luaL_Reg ll_chisel [] =
|
||||
{
|
||||
{"request_field", &lua_cbacks::request_field},
|
||||
{"set_filter", &lua_cbacks::set_filter},
|
||||
@@ -146,7 +146,7 @@ const static struct luaL_reg ll_chisel [] =
|
||||
{NULL,NULL}
|
||||
};
|
||||
|
||||
-const static struct luaL_reg ll_evt [] =
|
||||
+const static struct luaL_Reg ll_evt [] =
|
||||
{
|
||||
{"field", &lua_cbacks::field},
|
||||
{"get_num", &lua_cbacks::get_num},
|
||||
diff --git a/userspace/libsinsp/lua_parser.cpp b/userspace/libsinsp/lua_parser.cpp
|
||||
index 0e26617d..78810d96 100644
|
||||
--- a/userspace/libsinsp/lua_parser.cpp
|
||||
+++ b/userspace/libsinsp/lua_parser.cpp
|
||||
@@ -32,7 +32,7 @@ extern "C" {
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
-const static struct luaL_reg ll_filter [] =
|
||||
+const static struct luaL_Reg ll_filter [] =
|
||||
{
|
||||
{"rel_expr", &lua_parser_cbacks::rel_expr},
|
||||
{"bool_op", &lua_parser_cbacks::bool_op},
|
||||
diff --git a/userspace/libsinsp/lua_parser_api.cpp b/userspace/libsinsp/lua_parser_api.cpp
|
||||
index c89e9126..c3d8008a 100644
|
||||
--- a/userspace/libsinsp/lua_parser_api.cpp
|
||||
+++ b/userspace/libsinsp/lua_parser_api.cpp
|
||||
@@ -266,7 +266,7 @@ int lua_parser_cbacks::rel_expr(lua_State *ls)
|
||||
string err = "Got non-table as in-expression operand\n";
|
||||
throw sinsp_exception("parser API error");
|
||||
}
|
||||
- int n = luaL_getn(ls, 4); /* get size of table */
|
||||
+ int n = lua_objlen (ls, 4); /* get size of table */
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
lua_rawgeti(ls, 4, i);
|
||||
@@ -1,78 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2020 The Falco 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.
|
||||
#
|
||||
|
||||
set(SYSDIG_CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/sysdig-repo")
|
||||
set(SYSDIG_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/sysdig-repo")
|
||||
|
||||
# this needs to be here at the top
|
||||
if(USE_BUNDLED_DEPS)
|
||||
# explicitly force this dependency to use the bundled OpenSSL
|
||||
if(NOT MINIMAL_BUILD)
|
||||
set(USE_BUNDLED_OPENSSL ON)
|
||||
endif()
|
||||
set(USE_BUNDLED_JQ ON)
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
# The sysdig git reference (branch name, commit hash, or tag) To update sysdig version for the next release, change the
|
||||
# default below In case you want to test against another sysdig version just pass the variable - ie., `cmake
|
||||
# -DSYSDIG_VERSION=dev ..`
|
||||
if(NOT SYSDIG_VERSION)
|
||||
set(SYSDIG_VERSION "5c0b863ddade7a45568c0ac97d037422c9efb750")
|
||||
set(SYSDIG_CHECKSUM "SHA256=9de717b3a4b611ea6df56afee05171860167112f74bb7717b394bcc88ac843cd")
|
||||
endif()
|
||||
set(PROBE_VERSION "${SYSDIG_VERSION}")
|
||||
|
||||
# cd /path/to/build && cmake /path/to/source
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" -DSYSDIG_VERSION=${SYSDIG_VERSION} -DSYSDIG_CHECKSUM=${SYSDIG_CHECKSUM}
|
||||
${SYSDIG_CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
|
||||
|
||||
# todo(leodido, fntlnz) > use the following one when CMake version will be >= 3.13
|
||||
|
||||
# execute_process(COMMAND "${CMAKE_COMMAND}" -B ${SYSDIG_CMAKE_WORKING_DIR} WORKING_DIRECTORY
|
||||
# "${SYSDIG_CMAKE_SOURCE_DIR}")
|
||||
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" --build . WORKING_DIRECTORY "${SYSDIG_CMAKE_WORKING_DIR}")
|
||||
set(SYSDIG_SOURCE_DIR "${SYSDIG_CMAKE_WORKING_DIR}/sysdig-prefix/src/sysdig")
|
||||
|
||||
# jsoncpp
|
||||
set(JSONCPP_SRC "${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp")
|
||||
set(JSONCPP_INCLUDE "${JSONCPP_SRC}")
|
||||
set(JSONCPP_LIB_SRC "${JSONCPP_SRC}/jsoncpp.cpp")
|
||||
|
||||
# Add driver directory
|
||||
add_subdirectory("${SYSDIG_SOURCE_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
|
||||
|
||||
# Add libscap directory
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
add_definitions(-DHAS_CAPTURE)
|
||||
add_definitions(-DNOCURSESUI)
|
||||
if(MUSL_OPTIMIZED_BUILD)
|
||||
add_definitions(-DMUSL_OPTIMIZED)
|
||||
endif()
|
||||
add_subdirectory("${SYSDIG_SOURCE_DIR}/userspace/libscap" "${PROJECT_BINARY_DIR}/userspace/libscap")
|
||||
|
||||
# Add libsinsp directory
|
||||
add_subdirectory("${SYSDIG_SOURCE_DIR}/userspace/libsinsp" "${PROJECT_BINARY_DIR}/userspace/libsinsp")
|
||||
add_dependencies(sinsp tbb b64 luajit)
|
||||
|
||||
# explicitly disable the tests of this dependency
|
||||
set(CREATE_TEST_TARGETS OFF)
|
||||
|
||||
if(USE_BUNDLED_DEPS)
|
||||
add_dependencies(scap jq)
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_dependencies(scap curl grpc)
|
||||
endif()
|
||||
endif()
|
||||
@@ -28,6 +28,7 @@ else()
|
||||
yamlcpp
|
||||
URL "https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.6.2.tar.gz"
|
||||
URL_HASH "SHA256=e4d8560e163c3d875fd5d9e5542b5fd5bec810febdcba61481fe5fc4e6b1fd05"
|
||||
BUILD_BYPRODUCTS ${YAMLCPP_LIB}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
@@ -20,11 +20,11 @@ ENV FALCO_VERSION=${FALCO_VERSION}
|
||||
|
||||
# build toolchain
|
||||
RUN yum -y install centos-release-scl && \
|
||||
INSTALL_PKGS="devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-toolchain devtoolset-7-libstdc++-devel devtoolset-7-elfutils-libelf-devel llvm-toolset-7 glibc-static autoconf automake libtool createrepo expect git which libcurl-devel zlib-devel ncurses-devel rpm-build libyaml-devel" && \
|
||||
INSTALL_PKGS="devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-toolchain devtoolset-7-libstdc++-devel devtoolset-7-elfutils-libelf-devel llvm-toolset-7 glibc-static autoconf automake libtool createrepo expect git which libcurl-devel zlib-devel rpm-build libyaml-devel" && \
|
||||
yum -y install --setopt=tsflags=nodocs $INSTALL_PKGS && \
|
||||
rpm -V $INSTALL_PKGS
|
||||
|
||||
ARG CMAKE_VERSION=3.5.1
|
||||
ARG CMAKE_VERSION=3.6.3
|
||||
RUN source scl_source enable devtoolset-7 llvm-toolset-7 && \
|
||||
cd /tmp && \
|
||||
curl -L https://github.com/kitware/cmake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz | tar xz; \
|
||||
|
||||
@@ -34,7 +34,6 @@ case "$CMD" in
|
||||
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DBUILD_DRIVER="$BUILD_DRIVER" \
|
||||
-DMINIMAL_BUILD="$MINIMAL_BUILD" \
|
||||
-DBUILD_BPF="$BUILD_BPF" \
|
||||
-DBUILD_WARNINGS_AS_ERRORS="$BUILD_WARNINGS_AS_ERRORS" \
|
||||
-DFALCO_VERSION="$FALCO_VERSION" \
|
||||
|
||||
@@ -18,7 +18,7 @@ How to use.
|
||||
* docker run -ti falcosecurity/falco-builder bash
|
||||
|
||||
To build Falco it needs:
|
||||
- a bind-mount on the source directory (ie., the directory containing Falco and sysdig source as siblings)
|
||||
- a bind-mount on the source directory (ie., the directory containing the Falco source as sibling)
|
||||
|
||||
Optionally, you can also bind-mount the build directory.
|
||||
So, you can execute it from the Falco root directory as follows.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:stable
|
||||
FROM debian:buster
|
||||
|
||||
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
|
||||
|
||||
@@ -30,6 +30,7 @@ RUN apt-get update \
|
||||
libc6-dev \
|
||||
libelf-dev \
|
||||
libmpx2 \
|
||||
libssl-dev \
|
||||
llvm-7 \
|
||||
netcat \
|
||||
xz-utils \
|
||||
|
||||
56
falco.yaml
56
falco.yaml
@@ -33,6 +33,32 @@ rules_file:
|
||||
- /etc/falco/k8s_audit_rules.yaml
|
||||
- /etc/falco/rules.d
|
||||
|
||||
|
||||
#
|
||||
# Plugins that are available for use. These plugins are not loaded by
|
||||
# default, as they require explicit configuration to point to
|
||||
# cloudtrail log files.
|
||||
#
|
||||
|
||||
# To learn more about the supported formats for
|
||||
# init_config/open_params for the cloudtrail plugin, see the README at
|
||||
# https://github.com/falcosecurity/plugins/blob/master/plugins/cloudtrail/README.md.
|
||||
plugins:
|
||||
- name: cloudtrail
|
||||
library_path: libcloudtrail.so
|
||||
init_config: ""
|
||||
open_params: ""
|
||||
- name: json
|
||||
library_path: libjson.so
|
||||
init_config: ""
|
||||
|
||||
# Setting this list to empty ensures that the above plugins are *not*
|
||||
# loaded and enabled by default. If you want to use the above plugins,
|
||||
# set a meaningful init_config/open_params for the cloudtrail plugin
|
||||
# and then change this to:
|
||||
# load_plugins: [cloudtrail, json]
|
||||
load_plugins: []
|
||||
|
||||
# If true, the times displayed in log messages and output messages
|
||||
# will be in ISO 8601. By default, times are displayed in the local
|
||||
# time zone, as governed by /etc/localtime.
|
||||
@@ -46,6 +72,12 @@ json_output: false
|
||||
# (user=root ....") in the json output.
|
||||
json_include_output_property: true
|
||||
|
||||
# When using json output, whether or not to include the "tags" property
|
||||
# itself in the json output. If set to true, outputs caused by rules
|
||||
# with no tags will have a "tags" field set to an empty array. If set to
|
||||
# false, the "tags" field will not be included in the json output at all.
|
||||
json_include_tags_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
|
||||
@@ -97,6 +129,24 @@ syscall_event_drops:
|
||||
rate: .03333
|
||||
max_burst: 1
|
||||
|
||||
# Falco uses a shared buffer between the kernel and userspace to receive
|
||||
# the events (eg., system call information) in userspace.
|
||||
#
|
||||
# Anyways, the underlying libraries can also timeout for various reasons.
|
||||
# For example, there could have been issues while reading an event.
|
||||
# Or the particular event needs to be skipped.
|
||||
# Normally, it's very unlikely that Falco does not receive events consecutively.
|
||||
#
|
||||
# Falco is able to detect such uncommon situation.
|
||||
#
|
||||
# Here you can configure the maximum number of consecutive timeouts without an event
|
||||
# after which you want Falco to alert.
|
||||
# By default this value is set to 1000 consecutive timeouts without an event at all.
|
||||
# How this value maps to a time interval depends on the CPU frequency.
|
||||
|
||||
syscall_event_timeouts:
|
||||
max_consecutives: 1000
|
||||
|
||||
# Falco continuously monitors outputs performance. When an output channel does not allow
|
||||
# to deliver an alert within a given deadline, an error is reported indicating
|
||||
# which output is blocking notifications.
|
||||
@@ -231,3 +281,9 @@ grpc:
|
||||
# Make sure to have a consumer for them or leave this disabled.
|
||||
grpc_output:
|
||||
enabled: false
|
||||
|
||||
# Container orchestrator metadata fetching params
|
||||
metadata_download:
|
||||
max_mb: 100
|
||||
chunk_wait_us: 1000
|
||||
watch_freq_sec: 1
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
This document reflects when and how we clean up the Falco artifacts from their storage location.
|
||||
|
||||
**Superseeded by**: [drivers-storage-s3 proposal](https://github.com/falcosecurity/falco/blob/master/proposals/20201025-drivers-storage-s3.md).
|
||||
|
||||
## Motivation
|
||||
|
||||
The [bintray](https://bintray.com/falcosecurity) open-source plan offers 10GB free space for storing artifacts.
|
||||
@@ -94,9 +96,19 @@ Since the process of building drivers is time and resource consuming, this docum
|
||||
|
||||
The candidate is an AWS S3 bucket responsible for holding the deleted driver version files.
|
||||
|
||||
#### Notice
|
||||
|
||||
The current mechanism the Falco community uses to store the Falco drivers is explained by the [drivers-storage-s3](https://github.com/falcosecurity/falco/blob/master/proposals/20201025-drivers-storage-s3.md) proposal.
|
||||
|
||||
### Implementation
|
||||
|
||||
The [test-infra](https://github.com/falcosecurity/test-infra) CI, specifically its part dedicated to run the **Drivers Build Grid** that runs every time it detects changes into the `driverkit` directory of the [test-infra](https://github.com/falcosecurity/test-infra) repository,
|
||||
will have a new job - called `drivers/cleanup` - responsible for removing all the Falco driver versions except the last two.
|
||||
|
||||
This job will be triggered after the `drivers/publish` completed successfully on the master branch.
|
||||
This job will be triggered after the `drivers/publish` completed successfully on the master branch.
|
||||
|
||||
#### Notice
|
||||
|
||||
At the moment of writing (2021 09 28) the `drivers/cleanup` job is no more in place.
|
||||
|
||||
Pragmatically, this means that the older Falco drivers will remain available in their [S3 bucket](https://download.falco.org/?prefix=driver/).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# OSS Libraries Donation Plan
|
||||
# OSS Libraries Contribution Plan
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -6,7 +6,7 @@ Sysdig Inc. intends to donate **libsinsp**, **libscap**, the **kernel module dri
|
||||
|
||||
This means that some parts of the [draios/sysdig](https://github.com/draios/sysdig) repository will be moved to a new GitHub repository called [falcosecurity/libs](https://github.com/falcosecurity/libs).
|
||||
|
||||
This plan aims to describe and clarify the terms and goals to get the donation done.
|
||||
This plan aims to describe and clarify the terms and goals to get the contribution done.
|
||||
|
||||
## Motivation
|
||||
|
||||
@@ -22,7 +22,7 @@ Sysdig (the command line tool) will continue to use the libraries now provided b
|
||||
This change is win-win for both parties because of the following reasons:
|
||||
|
||||
- The Falco community owns the source code of the three most important parts of the software it distributes.
|
||||
- Right now it is "only" an engine on top of the libraries. This **donation** helps in making the scope of the Falco project broader. Having the majority of the source code under an **open governance** in the same organization gives the Falco project more contribution opportunities, helps it in **evolving independently** and makes the whole Falco community a strong owner of the processes and decision making regarding those crucial parts.
|
||||
- Right now it is "only" an engine on top of the libraries. This **contribution** helps in making the scope of the Falco project broader. Having the majority of the source code under an **open governance** in the same organization gives the Falco project more contribution opportunities, helps it in **evolving independently** and makes the whole Falco community a strong owner of the processes and decision making regarding those crucial parts.
|
||||
|
||||
- Given the previous point, Sysdig (the command line tool) will benefit from the now **extended contributors base**
|
||||
|
||||
@@ -34,7 +34,7 @@ This change is win-win for both parties because of the following reasons:
|
||||
|
||||
## Goals
|
||||
|
||||
There are many sub-projects and each of them interacts in a different way in this donation.
|
||||
There are many sub-projects and each of them interacts in a different way in this contribution.
|
||||
|
||||
Let's see the goals per sub-project.
|
||||
|
||||
@@ -68,7 +68,7 @@ Let's see the goals per sub-project.
|
||||
|
||||
13. Falco follows a [multi-stage model for adopting new projects](https://github.com/falcosecurity/evolution#falco-project-evolution), in this case we will do an exception since the library is foundational for Falco and it has a very good track record already
|
||||
|
||||
14. This project will go already "Official support" once the donation is completed
|
||||
14. This project will go already "Official support" once the contribution is completed
|
||||
|
||||
15. Contributing, Code of Conduct, Governance, Security, and Support will be the same as the rest of the organization, find them [here](https://github.com/falcosecurity/.github)
|
||||
|
||||
@@ -110,7 +110,7 @@ Let's see the goals per sub-project.
|
||||
|
||||
13. Falco follows a [multi-stage model for adopting new projects](https://github.com/falcosecurity/evolution#falco-project-evolution), in this case we will do an exception since the library is foundational for Falco and it has a very good track record already
|
||||
|
||||
14. This project will go already "Official support" once the donation is completed
|
||||
14. This project will go already "Official support" once the contribution is completed
|
||||
|
||||
15. Contributing, Code of Conduct, Governance, Security, and Support will be the same as the rest of the organization, find them [here](https://github.com/falcosecurity/.github)
|
||||
|
||||
613
proposals/20210501-plugin-system.md
Normal file
613
proposals/20210501-plugin-system.md
Normal file
@@ -0,0 +1,613 @@
|
||||
# Plugin System
|
||||
|
||||
## Summary
|
||||
|
||||
This is a proposal to create an infrastructure to extend the functionality of the Falco libraries via plugins.
|
||||
|
||||
Plugins will allow users to easily extend the functionality of the libraries and, as a consequence, of Falco and any other tool based on the libraries.
|
||||
|
||||
This proposal, in particular, focuses on two types of plugins: source plugins and extractor plugins.
|
||||
|
||||
## Motivation
|
||||
|
||||
[libscap](https://github.com/falcosecurity/libs/tree/master/userspace/libscap) and [libsinsp](https://github.com/falcosecurity/libs/tree/master/userspace/libsinsp) provide a powerful data capture framework, with a rich set of features that includes:
|
||||
|
||||
- data capture
|
||||
- trace files management
|
||||
- enrichment
|
||||
- filtering
|
||||
- formatting and screen rendering
|
||||
- Lua scripting (chisels)
|
||||
|
||||
These features have been designed with one specific input in mind: system calls. However, they are generically adaptable to a broad set of inputs, such as cloud logs.
|
||||
|
||||
With this proposal, we want to dramatically extend the scope of what the libraries, Falco and other tools can be applied to. We want to do it in a way that is easy, efficient and empowers anyone in the community to write a plugin.
|
||||
|
||||
## Goals
|
||||
|
||||
- To design and implement a plugin framework that makes the libraries more modular and extensible
|
||||
- To have a framework that is easy to use
|
||||
- To support dynamic loading of plugins, so that the libraries can be extended without having to be recompiled and relinked
|
||||
- To enable users to write plugins in any language, with a particular focus on Go, C and C++
|
||||
- To have an efficient plugin framework so that, performance-wise, writing a plugin is as close as possible as extending the libraries internal source code
|
||||
- To make it possible to write plugins for Linux, MacOS and Windows
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- To implement plugins other than source and extractor: to be approached as separate task
|
||||
- To document the plugin framework and interface: to be approached as separate task
|
||||
|
||||
## Proposal
|
||||
|
||||
### Plugin Common Information
|
||||
|
||||
Both source and extractor plugins have the following:
|
||||
|
||||
- A required api version, to ensure compatibility with the plugin framework.
|
||||
- A name
|
||||
- A description
|
||||
- A version
|
||||
- A contact field for the plugin authors (website, github repo, twitter, etc).
|
||||
- Functions to initialize and destroy the plugin internal state.
|
||||
|
||||
### Plugin types
|
||||
|
||||
Initially, we will implement support for two types of plugins: source plugins and extractor plugins.
|
||||
|
||||
#### Source Plugin
|
||||
|
||||
A source plugin implements a new sinsp/scap event source. It has the ability to "open" and "close" a session that provides events. It also has the ability to return an event to the plugin framework via a next() method. Events returned by source plugins have an "event source", which describes the information in the event. This is distinct from the plugin name to allow for multiple kinds of plugins to generate the same kind of events. For example, there might be plugins gke-audit-bridge, eks-audit-bridge, ibmcloud-audit-bridge, etc. that all fetch [K8s Audit](https://kubernetes.io/docs/tasks/debug-application-cluster/audit/) information. The plugins would have different names but would have the same event source "k8s_audit".
|
||||
|
||||
Source plugins also have the ability to extract information from events based on fields. For example, a field proc.name extracts a process name from a syscall event. The plugin returns a set of supported fields, and there are functions to extract a value given an event and field. The plugin framework can then build filtering expressions/Falco rule conditions based on these fields combined with relational and/or logical operators. For example, given an expression "ct.name=root and ct.region=us-east-1", the plugin framework handles parsing the expression, calling the plugin to extract values for a given event, and determining the result of the expression. In a Falco output string like "An EC2 Node was created (name=%ec2.name region=%ct.region)", the plugin framework handles parsing the output string, calling the plugin to extract values for a given event, and building the resolved string.
|
||||
|
||||
Source plugins also provide an "id", which is globally unique and is used in capture files (see below).
|
||||
|
||||
#### Extractor Plugin
|
||||
|
||||
An extractor plugin focuses only on field extraction from events generated by other plugins, or by the core libraries. It does *not* provide an event source, but can extract fields from other event sources. An example is json field extraction, where a plugin might be able to extract fields from arbitrary json payloads.
|
||||
|
||||
An extractor plugin provides an optional set of event sources. When the framework receives an event with an event source in the plugin's set of event sources, fields in expressions/Falco outputs will be extracted from events using the plugin. An extractor plugin can also *not* name a set of event sources. In this case, fields will be extracted from *all* events, regardless of source. In this case, the exctractor plugin must detect the format of arbitrary payloads and be able to return NULL/no value when the payload is not supported.
|
||||
|
||||
### Support for Plugin Events in Capture Files.
|
||||
|
||||
libscap will define a new event type called "pluginevent" that contains two fields:
|
||||
|
||||
* "plugin ID": This uniquely identifies the plugin that generated this event.
|
||||
* "event_data": This is a variable-length data buffer containing the event data, as returned by the plugin.
|
||||
|
||||
Defining an event for plugins allows creating capture files from plugins. These capture files can be saved, read, filtered, etc, like any other capture file, allowing for later analysis/display/etc.
|
||||
|
||||
### Plugins format
|
||||
|
||||
Plugins are dynamic libraries (.so files in Unix, .dll files in windows) that export a minimum set of functions that the libraries will recognize.
|
||||
|
||||
Plugins are versioned using semantic versioning to minimize regressions and compatibility issues.
|
||||
|
||||
Plugins can be written in any language, as long as they export the required functions. Go, however, is the preferred language to write plugins, followed by C/C++.
|
||||
|
||||
### Protecting from plugin issues
|
||||
|
||||
The libraries will do everything possible to validate the data coming from the plugins and protect Falco and the other consumers from corrupted data. However, for performance reasons, plugins will be "trusted": they will run in the same thread and address space as Falco and they could crash the program. We assume that the user will be in control of plugin loading and will make sure only trusted plugins are loaded/packaged with Falco.
|
||||
|
||||
### Plugin/Event Source registries
|
||||
|
||||
Every source plugin requires its own, unique plugin ID to interoperate with Falco and the other plugins. The plugin ID will be used by the libs to properly process incoming events (for example, when saving events to file and loading them back), and by plugins to unuambiguosly recognize their dependencies.
|
||||
|
||||
To facilitate the allocation and distribution of plugin IDs, we will require that plugin developers request IDs for their plugins to the Falco organization. The mechanism used for plugin allocation is not determined yet and will be discussed in the future.
|
||||
|
||||
Similarly, plugin developers must register event sources with the Falco organization. This allows coordination between plugins that wish to provide compatible payloads, and to allow extractor plugins to know what data format is associated with a given event source.
|
||||
|
||||
### golang plugin SDK
|
||||
|
||||
To facilitate the development of plugins written in go, an SDK has been developed. We intend this SDK (and future SDKs for other languages) to be part of the Falco organization. For this reason, we submitted the following incubation request: https://github.com/falcosecurity/evolution/issues/62
|
||||
|
||||
### Proposed API (subject to change)
|
||||
|
||||
```c
|
||||
// This struct represents an event returned by the plugin, and is used
|
||||
// below in next()/next_batch().
|
||||
// - data: pointer to a memory buffer pointer. The plugin will set it
|
||||
// to point to the memory containing the next event. Once returned,
|
||||
// the memory is owned by the plugin framework and will be freed via
|
||||
// a call to free().
|
||||
// - datalen: pointer to a 32bit integer. The plugin will set it the size of the
|
||||
// buffer pointed by data.
|
||||
// - ts: the event timestamp. Can be (uint64_t)-1, in which case the engine will
|
||||
// automatically fill the event time with the current time.
|
||||
typedef struct ss_plugin_event
|
||||
{
|
||||
uint8_t *data;
|
||||
uint32_t datalen;
|
||||
uint64_t ts;
|
||||
} ss_plugin_event;
|
||||
|
||||
//
|
||||
// This is the opaque pointer to the state of a plugin.
|
||||
// It points to any data that might be needed plugin-wise. It is
|
||||
// allocated by init() and must be destroyed by destroy().
|
||||
// It is defined as void because the engine doesn't care what it is
|
||||
// and it treats is as opaque.
|
||||
//
|
||||
typedef void ss_plugin_t;
|
||||
|
||||
//
|
||||
// This is the opaque pointer to the state of an open instance of the source
|
||||
// plugin.
|
||||
// It points to any data that is needed while a capture is running. It is
|
||||
// allocated by open() and must be destroyed by close().
|
||||
// It is defined as void because the engine doesn't care what it is
|
||||
// and it treats is as opaque.
|
||||
//
|
||||
typedef void ss_instance_t;
|
||||
|
||||
//
|
||||
// Interface for a sinsp/scap source plugin
|
||||
//
|
||||
//
|
||||
// NOTE: For all functions below that return a char *, the memory
|
||||
// pointed to by the char * must be allocated by the plugin using
|
||||
// malloc() and should be freed by the caller using free().
|
||||
//
|
||||
// For each function below, the exported symbol from the dynamic
|
||||
// library should have a prefix of "plugin_"
|
||||
// (e.g. plugin_get_required_api_version, plugin_init, etc.)
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
//
|
||||
// Return the version of the plugin API used by this plugin.
|
||||
// Required: yes
|
||||
// Return value: the API version string, in the following format:
|
||||
// "<major>.<minor>.<patch>", e.g. "1.2.3".
|
||||
// NOTE: to ensure correct interoperability between the engine and the plugins,
|
||||
// we use a semver approach. Plugins are required to specify the version
|
||||
// of the API they run against, and the engine will take care of checking
|
||||
// and enforcing compatibility.
|
||||
//
|
||||
char* (*get_required_api_version)();
|
||||
//
|
||||
// Return the plugin type.
|
||||
// Required: yes
|
||||
// Should return TYPE_SOURCE_PLUGIN. It still makes sense to
|
||||
// have a function get_type() as the plugin interface will
|
||||
// often dlsym() functions from shared libraries, and can't
|
||||
// inspect any C struct type.
|
||||
//
|
||||
uint32_t (*get_type)();
|
||||
//
|
||||
// Initialize the plugin and, if needed, allocate its state.
|
||||
// Required: yes
|
||||
// Arguments:
|
||||
// - config: a string with the plugin configuration. The format of the
|
||||
// string is chosen by the plugin itself.
|
||||
// - rc: pointer to an integer that will contain the initialization result,
|
||||
// as a SCAP_* value (e.g. SCAP_SUCCESS=0, SCAP_FAILURE=1)
|
||||
// Return value: pointer to the plugin state that will be treated as opaque
|
||||
// by the engine and passed to the other plugin functions.
|
||||
// If rc is SCAP_FAILURE, this function should return NULL.
|
||||
//
|
||||
ss_plugin_t* (*init)(char* config, int32_t* rc);
|
||||
//
|
||||
// Destroy the plugin and, if plugin state was allocated, free it.
|
||||
// Required: yes
|
||||
//
|
||||
void (*destroy)(ss_plugin_t* s);
|
||||
//
|
||||
// Return a string with the error that was last generated by
|
||||
// the plugin.
|
||||
// Required: yes
|
||||
//
|
||||
// In cases where any other api function returns an error, the
|
||||
// plugin should be prepared to return a human-readable error
|
||||
// string with more context for the error. The plugin manager
|
||||
// calls get_last_error() to access that string.
|
||||
//
|
||||
char* (*get_last_error)(ss_plugin_t* s);
|
||||
//
|
||||
// Return the unique ID of the plugin.
|
||||
// Required: yes
|
||||
// EVERY SOURCE PLUGIN (see get_type()) MUST OBTAIN AN OFFICIAL ID FROM THE
|
||||
// FALCOSECURITY ORGANIZATION, OTHERWISE IT WON'T PROPERLY COEXIST WITH OTHER PLUGINS.
|
||||
//
|
||||
uint32_t (*get_id)();
|
||||
//
|
||||
// Return the name of the plugin, which will be printed when displaying
|
||||
// information about the plugin.
|
||||
// Required: yes
|
||||
//
|
||||
char* (*get_name)();
|
||||
//
|
||||
// Return the descriptions of the plugin, which will be printed when displaying
|
||||
// information about the plugin or its events.
|
||||
// Required: yes
|
||||
//
|
||||
char* (*get_description)();
|
||||
//
|
||||
// Return a string containing contact info (url, email, twitter, etc) for
|
||||
// the plugin authors.
|
||||
// Required: yes
|
||||
//
|
||||
char* (*get_contact)();
|
||||
//
|
||||
// Return the version of this plugin itself
|
||||
// Required: yes
|
||||
// Return value: a string with a version identifier, in the following format:
|
||||
// "<major>.<minor>.<patch>", e.g. "1.2.3".
|
||||
// This differs from the api version in that this versions the
|
||||
// plugin itself, as compared to the plugin interface. When
|
||||
// reading capture files, the major version of the plugin that
|
||||
// generated events must match the major version of the plugin
|
||||
// used to read events.
|
||||
//
|
||||
char* (*get_version)();
|
||||
//
|
||||
// Return a string describing the events generated by this source plugin.
|
||||
// Required: yes
|
||||
// Example event sources would be strings like "syscall",
|
||||
// "k8s_audit", etc. The source can be used by extractor
|
||||
// plugins to filter the events they receive.
|
||||
//
|
||||
char* (*get_event_source)();
|
||||
//
|
||||
// Return the list of extractor fields exported by this plugin. Extractor
|
||||
// fields can be used in Falco rule conditions and sysdig filters.
|
||||
// Required: no
|
||||
// Return value: a string with the list of fields encoded as a json
|
||||
// array.
|
||||
// Each field entry is a json object with the following properties:
|
||||
// "type": one of "string", "uint64"
|
||||
// "name": a string with a name for the field
|
||||
// "desc": a string with a description of the field
|
||||
// Example return value:
|
||||
// [
|
||||
// {"type": "string", "name": "field1", "desc": "Describing field 1"},
|
||||
// {"type": "uint64", "name": "field2", "desc": "Describing field 2"}
|
||||
// ]
|
||||
char* (*get_fields)();
|
||||
//
|
||||
// Open the source and start a capture.
|
||||
// Required: yes
|
||||
// Arguments:
|
||||
// - s: the plugin state returned by init()
|
||||
// - params: the open parameters, as a string. The format is defined by the plugin
|
||||
// itsef
|
||||
// - rc: pointer to an integer that will contain the open result, as a SCAP_* value
|
||||
// (e.g. SCAP_SUCCESS=0, SCAP_FAILURE=1)
|
||||
// Return value: a pointer to the open context that will be passed to next(),
|
||||
// close(), event_to_string() and extract_*.
|
||||
//
|
||||
ss_instance_t* (*open)(ss_plugin_t* s, char* params, int32_t* rc);
|
||||
//
|
||||
// Close a capture.
|
||||
// Required: yes
|
||||
// Arguments:
|
||||
// - s: the plugin context, returned by init(). Can be NULL.
|
||||
// - h: the capture context, returned by open(). Can be NULL.
|
||||
//
|
||||
void (*close)(ss_plugin_t* s, ss_instance_t* h);
|
||||
//
|
||||
// Return the next event.
|
||||
// Required: yes
|
||||
// Arguments:
|
||||
// - s: the plugin context, returned by init(). Can be NULL.
|
||||
// - h: the capture context, returned by open(). Can be NULL.
|
||||
//
|
||||
// - evt: pointer to a ss_plugin_event pointer. The plugin should
|
||||
// allocate a ss_plugin_event struct using malloc(), as well as
|
||||
// allocate the data buffer within the ss_plugin_event struct.
|
||||
// Both the struct and data buffer are owned by the plugin framework
|
||||
// and will free them using free().
|
||||
//
|
||||
// Return value: the status of the operation (e.g. SCAP_SUCCESS=0, SCAP_FAILURE=1,
|
||||
// SCAP_TIMEOUT=-1)
|
||||
//
|
||||
int32_t (*next)(ss_plugin_t* s, ss_instance_t* h, ss_plugin_event **evt);
|
||||
//
|
||||
// Return the read progress.
|
||||
// Required: no
|
||||
// Arguments:
|
||||
// - progress_pct: the read progress, as a number between 0 (no data has been read)
|
||||
// and 10000 (100% of the data has been read). This encoding allows the engine to
|
||||
// print progress decimals without requiring to deal with floating point numbers
|
||||
// (which could cause incompatibility problems with some languages).
|
||||
// Return value: a string representation of the read
|
||||
// progress. This might include the progress percentage
|
||||
// combined with additional context added by the plugin. If
|
||||
// NULL, progress_pct should be used.
|
||||
// NOTE: reporting progress is optional and in some case could be impossible. However,
|
||||
// when possible, it's recommended as it provides valuable information to the
|
||||
// user.
|
||||
//
|
||||
char* (*get_progress)(ss_plugin_t* s, ss_instance_t* h, uint32_t* progress_pct);
|
||||
//
|
||||
// Return a text representation of an event generated by this source plugin.
|
||||
// Required: yes
|
||||
// Arguments:
|
||||
// - data: the buffer from an event produced by next().
|
||||
// - datalen: the length of the buffer from an event produced by next().
|
||||
// Return value: the text representation of the event. This is used, for example,
|
||||
// by sysdig to print a line for the given event.
|
||||
//
|
||||
char *(*event_to_string)(ss_plugin_t *s, const uint8_t *data, uint32_t datalen);
|
||||
//
|
||||
// Extract a filter field value from an event.
|
||||
// We offer multiple versions of extract(), differing from each other only in
|
||||
// the type of the value they return (string, integer...).
|
||||
// Required: no
|
||||
// Arguments:
|
||||
// - evtnum: the number of the event that is bein processed
|
||||
// - id: the numeric identifier of the field to extract. It corresponds to the
|
||||
// position of the field in the array returned by get_fields().
|
||||
// - arg: the field argument, if an argument has been specified for the field,
|
||||
// otherwise it's NULL. For example:
|
||||
// * if the field specified by the user is foo.bar[pippo], arg will be the
|
||||
// string "pippo"
|
||||
// * if the field specified by the user is foo.bar, arg will be NULL
|
||||
// - data: the buffer produced by next().
|
||||
// - datalen: the length of the buffer produced by next().
|
||||
// - field_present: nonzero if the field is present for the given event.
|
||||
// Return value: the produced value of the filter field. For extract_str(), a
|
||||
// NULL return value means that the field is missing for the given event.
|
||||
//
|
||||
char *(*extract_str)(ss_plugin_t *s, uint64_t evtnum, const char * field, const char *arg, uint8_t *data, uint32_t datalen);
|
||||
uint64_t (*extract_u64)(ss_plugin_t *s, uint64_t evtnum, const char *field, const char *arg, uint8_t *data, uint32_t datalen, uint32_t *field_present);
|
||||
//
|
||||
// This is an optional, internal, function used to speed up event capture by
|
||||
// batching the calls to next().
|
||||
// On success:
|
||||
// - nevts will be filled in with the number of events.
|
||||
// - evts: pointer to an ss_plugin_event pointer. The plugin should
|
||||
// allocate an array of contiguous ss_plugin_event structs using malloc(),
|
||||
// as well as allocate each data buffer within each ss_plugin_event
|
||||
// struct using malloc(). Both the array of structs and each data buffer are
|
||||
// owned by the plugin framework and will free them using free().
|
||||
// Required: no
|
||||
//
|
||||
int32_t (*next_batch)(ss_plugin_t* s, ss_instance_t* h, uint32_t *nevts, ss_plugin_event **evts);
|
||||
//
|
||||
// This is an optional, internal, function used to speed up value extraction
|
||||
// Required: no
|
||||
//
|
||||
int32_t (*register_async_extractor)(ss_plugin_t *s, async_extractor_info *info);
|
||||
|
||||
//
|
||||
// The following members are PRIVATE for the engine and should not be touched.
|
||||
//
|
||||
ss_plugin_t* state;
|
||||
ss_instance_t* handle;
|
||||
uint32_t id;
|
||||
char *name;
|
||||
} source_plugin_info;
|
||||
|
||||
//
|
||||
// Interface for a sinsp/scap extractor plugin
|
||||
//
|
||||
//
|
||||
// NOTE: For all functions below that return a char *, the memory
|
||||
// pointed to by the char * must be allocated by the plugin using
|
||||
// malloc() and should be freed by the caller using free().
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
//
|
||||
// Return the version of the plugin API used by this plugin.
|
||||
// Required: yes
|
||||
// Return value: the API version string, in the following format:
|
||||
// "<major>.<minor>.<patch>", e.g. "1.2.3".
|
||||
// NOTE: to ensure correct interoperability between the engine and the plugins,
|
||||
// we use a semver approach. Plugins are required to specify the version
|
||||
// of the API they run against, and the engine will take care of checking
|
||||
// and enforcing compatibility.
|
||||
//
|
||||
char* (*get_required_api_version)();
|
||||
//
|
||||
// Return the plugin type.
|
||||
// Required: yes
|
||||
// Should return TYPE_EXTRACTOR_PLUGIN. It still makes sense to
|
||||
// have a function get_type() as the plugin interface will
|
||||
// often dlsym() functions from shared libraries, and can't
|
||||
// inspect any C struct type.
|
||||
//
|
||||
uint32_t (*get_type)();
|
||||
//
|
||||
// Initialize the plugin and, if needed, allocate its state.
|
||||
// Required: yes
|
||||
// Arguments:
|
||||
// - config: a string with the plugin configuration. The format of the
|
||||
// string is chosen by the plugin itself.
|
||||
// - rc: pointer to an integer that will contain the initialization result,
|
||||
// as a SCAP_* value (e.g. SCAP_SUCCESS=0, SCAP_FAILURE=1)
|
||||
// Return value: pointer to the plugin state that will be treated as opaque
|
||||
// by the engine and passed to the other plugin functions.
|
||||
//
|
||||
ss_plugin_t* (*init)(char* config, int32_t* rc);
|
||||
//
|
||||
// Destroy the plugin and, if plugin state was allocated, free it.
|
||||
// Required: yes
|
||||
//
|
||||
void (*destroy)(ss_plugin_t* s);
|
||||
//
|
||||
// Return a string with the error that was last generated by
|
||||
// the plugin.
|
||||
// Required: yes
|
||||
//
|
||||
// In cases where any other api function returns an error, the
|
||||
// plugin should be prepared to return a human-readable error
|
||||
// string with more context for the error. The plugin manager
|
||||
// calls get_last_error() to access that string.
|
||||
//
|
||||
char* (*get_last_error)(ss_plugin_t* s);
|
||||
//
|
||||
// Return the name of the plugin, which will be printed when displaying
|
||||
// information about the plugin.
|
||||
// Required: yes
|
||||
//
|
||||
char* (*get_name)();
|
||||
//
|
||||
// Return the descriptions of the plugin, which will be printed when displaying
|
||||
// information about the plugin or its events.
|
||||
// Required: yes
|
||||
//
|
||||
char* (*get_description)();
|
||||
//
|
||||
// Return a string containing contact info (url, email, twitter, etc) for
|
||||
// the plugin author.
|
||||
// Required: yes
|
||||
//
|
||||
char* (*get_contact)();
|
||||
//
|
||||
// Return the version of this plugin itself
|
||||
// Required: yes
|
||||
// Return value: a string with a version identifier, in the following format:
|
||||
// "<major>.<minor>.<patch>", e.g. "1.2.3".
|
||||
// This differs from the api version in that this versions the
|
||||
// plugin itself, as compared to the plugin interface. When
|
||||
// reading capture files, the major version of the plugin that
|
||||
// generated events must match the major version of the plugin
|
||||
// used to read events.
|
||||
//
|
||||
char* (*get_version)();
|
||||
//
|
||||
// Return a string describing the event sources that this
|
||||
// extractor plugin can consume.
|
||||
// Required: no
|
||||
// Return value: a json array of strings containing event
|
||||
// sources returned by a source plugin's get_event_source()
|
||||
// function.
|
||||
// This function is optional--if NULL then the exctractor
|
||||
// plugin will receive every event.
|
||||
//
|
||||
char* (*get_extract_event_sources)();
|
||||
//
|
||||
// Return the list of extractor fields exported by this plugin. Extractor
|
||||
// fields can be used in Falco rules and sysdig filters.
|
||||
// Required: yes
|
||||
// Return value: a string with the list of fields encoded as a json
|
||||
// array.
|
||||
//
|
||||
char* (*get_fields)();
|
||||
//
|
||||
// Extract a filter field value from an event.
|
||||
// We offer multiple versions of extract(), differing from each other only in
|
||||
// the type of the value they return (string, integer...).
|
||||
// Required: for plugins of type TYPE_EXTRACTOR_PLUGIN only
|
||||
// Arguments:
|
||||
// - evtnum: the number of the event that is being processed
|
||||
// - id: the numeric identifier of the field to extract. It corresponds to the
|
||||
// position of the field in the array returned by get_fields().
|
||||
// - arg: the field argument, if an argument has been specified for the field,
|
||||
// otherwise it's NULL. For example:
|
||||
// * if the field specified by the user is foo.bar[pippo], arg will be the
|
||||
// string "pippo"
|
||||
// * if the field specified by the user is foo.bar, arg will be NULL
|
||||
// - data: the buffer produced by next().
|
||||
// - datalen: the length of the buffer produced by next().
|
||||
// - field_present: nonzero if the field is present for the given event.
|
||||
// Return value: the produced value of the filter field. For extract_str(), a
|
||||
// NULL return value means that the field is missing for the given event.
|
||||
//
|
||||
char *(*extract_str)(ss_plugin_t *s, uint64_t evtnum, const char *field, const char *arg, uint8_t *data, uint32_t datalen);
|
||||
uint64_t (*extract_u64)(ss_plugin_t *s, uint64_t evtnum, const char *field, const char *arg, uint8_t *data, uint32_t datalen, uint32_t *field_present);
|
||||
} extractor_plugin_info;
|
||||
|
||||
```
|
||||
|
||||
### Event Sources and Falco Rules
|
||||
|
||||
Falco rules already have the notion of a "source", using the source property in rules objects, and there are currently two kinds of event sources: "syscall" and "k8s_audit". We will use the source property in Falco rules to map a given rule to the event source on which the rule runs.
|
||||
|
||||
For example, given a plugin with source "aws_cloudtrail", and a Falco rule with source "aws_cloudtrail", the rule will be evaluated for any events generated by the plugin.
|
||||
|
||||
Similarly, an extractor plugin that includes "aws_cloudtrail" in its set of event sources will have the opportunity to extract information from aws_cloudtrail events if a matching field is found in the rule's condition, exception, or output properties.
|
||||
|
||||
This, combined with the restrictions below, allows a set of loaded rules files to contain a mix of rules for plugins as well as "core" syscall/k8s_audit events.
|
||||
|
||||
We will also make a change to compile rules/macros/lists selectively based on the set of loaded plugins (specifically, their event sources), instead of unconditionally as Falco is started. This is especially important for macros, which do not contain a source property, but might contain fields that are only implemented by a given plugin.
|
||||
|
||||
### Handling Duplicate/Overlapping Fields in Plugins/Libraries Core
|
||||
|
||||
At an initial glance, adding plugins introduces the possibility of tens/hundreds of new filtercheck fields that could potentially overlap/conflict. For example, what happens if a plugin defines a "proc.name" field? However, the notion of "event source" makes these potential conflicts managable.
|
||||
|
||||
Remember that field extraction is always done in the context of an event, and each event can be mapped back to an event source. So we only need to ensure that filtercheck fields are distinct for a given event source. For example, it's perfectly valid for an AWS Cloudtrail plugin to define a proc.name field, as the events generated by that plugin are wholly separate from syscall events. For syscall events, the AWS Cloudtrail plugin is not involved and the core libraries extract the process name for the tid performing a syscall. For AWS Cloudtrail events, the core libraries are not involved in field extraction and is performed by the AWS Cloudtrail plugin instead.
|
||||
|
||||
We only need to ensure the following:
|
||||
|
||||
* That only one plugin is loaded at a time that exports a given event source. For example, the libraries can load either a gke-audit-bridge plugin with event source k8s_audit, or eks-audit-bridge with event source k8s_audit, but not both.
|
||||
* That for a mix of source and extractor plugins having the same event source, that the fields are distinct. For example, a source plugin with source k8s_audit can export ka.* fields, and an extractor plugin with event source k8s_audit can export a jevt.value[/...] field, and the appropriate plugin will be used to extract fields from k8s_audit events as fields are parsed from condition expressions/output format strings.
|
||||
|
||||
### Plugin Versions and Falco Rules
|
||||
|
||||
To allow rules files to document the plugin versions they are compatible with, we will add a new top-level field `required_plugin_versions` to the Falco rules file format. The field is optional, and if not provided no plugin compatibility checks will be performed. The syntax of `required_plugin_versions` will be the following:
|
||||
|
||||
```yaml
|
||||
- required_plugin_versions:
|
||||
- name: <plugin_name>
|
||||
version: x.y.z
|
||||
...
|
||||
```
|
||||
|
||||
Below required_plugin_versions is a list of objects, where each object has `name` and `version` properties. If a plugin is loaded, and if an entry in `required_plugin_versions` has a matching name, then the loaded plugin version must be semver compatible with the version property.
|
||||
|
||||
Falco can load multiple rules files, and each file may contain its own `required_plugin_versions` property. In this case, name+version pairs across all files will be merged, and in the case of duplicate names all provided versions must be compatible.
|
||||
|
||||
### Loading the plugins
|
||||
|
||||
The mechanics of loading a plugin are implemented in the libraries and leverage the dynamic library functionality of the operating system (dlopen/dlsym in unix, LoadLibrary/GetProcAddress in Windows). The plugin loading code also ensures that:
|
||||
|
||||
- the plugin is valid, i.e. that it exports the set of expected symbols
|
||||
- the plugin has an api version number that is compatible with the libraries instance
|
||||
- that only one source plugin is loaded at a time for a given event source
|
||||
- if a mix of source and extractor plugins are loaded for a given event source, that the exported fields have unique names that don't overlap across plugins
|
||||
|
||||
#### Loading plugins in falcosecurity/libs
|
||||
|
||||
At the libraries level, loading plugins is handled via the static method:
|
||||
|
||||
```c++
|
||||
void sinsp_plugin::register_plugin(sinsp* inspector, string filepath, char* config, ...)
|
||||
```
|
||||
|
||||
filepath points to a dynamic library containing code that exports plugin API functions. config contains arbitrary config content which is passed to init().
|
||||
|
||||
Note that the code using the libraries is responsible for determining the location of plugin libraries and their configuration.
|
||||
|
||||
#### Loading plugins in falcosecurity/falco
|
||||
|
||||
Falco will control/configure loading plugins via the new "plugins" property in falco.yaml. Here's an example:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
- name: aws_cloudtrail
|
||||
library_path: aws_cloudtrail/plugin.so
|
||||
init_config: "..."
|
||||
open_params: "..."
|
||||
- name: http_json
|
||||
library_path: http_json/plugin.so
|
||||
init_config_file: http_json/config.txt
|
||||
open_params_file: http_json/params.txt
|
||||
|
||||
# Optional
|
||||
load_plugins: [aws_cloudtrail]
|
||||
```
|
||||
|
||||
A new "plugins" property in falco.yaml will define the set of plugins that can be loaded by Falco. The property contains a list of objects, with the following properties:
|
||||
|
||||
* name: Only used for load_plugins, but by convention should be the same as the value returned by the name() api function.
|
||||
* library_path: a path to the shared library. The path can be relative, in which case it is relative to Falco's "share" directory under a "plugins" subdirectory e.g. /usr/share/falco/plugins.
|
||||
* init_config: If present, the exact configuration text that will be provided as an argument to the init() function.
|
||||
* init_config_file: If present, the provided file will be read and the contents will be provided as an argument to the init() function.
|
||||
* open_params: If present, the exact params text that will be provided as an argument to the open() function.
|
||||
* open_params_file: If present, the provided file will be read and the contents will be provided as an argument to the open() function.
|
||||
|
||||
For a given yaml object in the plugins list, only one of init_config/init_config_file and one of open_params/open_params_file can be provided at a time.
|
||||
|
||||
A new "load_plugins" property in falco.yaml will allow for loading a subset of the plugins defined in plugins. If present, only the plugins with the provided names will be loaded.
|
||||
|
||||
### Examples
|
||||
|
||||
We have an initial version working, consisting of:
|
||||
|
||||
* A version of falcosecurity/libs that supports the [plugin framework](https://github.com/falcosecurity/libs/tree/new/plugin-system-api-additions)
|
||||
* Support code and examples for [writing plugins in go](https://github.com/mstemm/libsinsp-plugin-sdk-go/tree/new/plugin-system-api-additions)
|
||||
* A [cloudtrail](https://github.com/mstemm/plugins/tree/new/plugin-system-api-additions) plugin that can generate events from cloudtrail logs and extract fields from those events.
|
||||
* A version of Falco that uses all of the above to [load and evaluate rules with plugins](https://github.com/leogr/falco/tree/new/plugin-system-api-additions)
|
||||
@@ -23,6 +23,7 @@ if(NOT DEFINED FALCO_RULES_DEST_FILENAME)
|
||||
set(FALCO_LOCAL_RULES_DEST_FILENAME "falco_rules.local.yaml")
|
||||
set(FALCO_APP_RULES_DEST_FILENAME "application_rules.yaml")
|
||||
set(FALCO_K8S_AUDIT_RULES_DEST_FILENAME "k8s_audit_rules.yaml")
|
||||
set(FALCO_AWS_CLOUDTRAIL_RULES_DEST_FILENAME "aws_cloudtrail_rules.yaml")
|
||||
endif()
|
||||
|
||||
if(DEFINED FALCO_COMPONENT)
|
||||
@@ -59,5 +60,10 @@ else()
|
||||
DESTINATION "${FALCO_ETC_DIR}/rules.available"
|
||||
RENAME "${FALCO_APP_RULES_DEST_FILENAME}")
|
||||
|
||||
install(
|
||||
FILES aws_cloudtrail_rules.yaml
|
||||
DESTINATION "${FALCO_ETC_DIR}"
|
||||
RENAME "${FALCO_AWS_CLOUDTRAIL_RULES_DEST_FILENAME}")
|
||||
|
||||
install(DIRECTORY DESTINATION "${FALCO_ETC_DIR}/rules.d")
|
||||
endif()
|
||||
|
||||
440
rules/aws_cloudtrail_rules.yaml
Normal file
440
rules/aws_cloudtrail_rules.yaml
Normal file
@@ -0,0 +1,440 @@
|
||||
#
|
||||
# Copyright (C) 2019 The Falco 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.
|
||||
#
|
||||
|
||||
# All rules files related to plugins should require engine version 10
|
||||
- required_engine_version: 10
|
||||
|
||||
# These rules can be read by cloudtrail plugin version 0.1.0, or
|
||||
# anything semver-compatible.
|
||||
- required_plugin_versions:
|
||||
- name: cloudtrail
|
||||
version: 0.1.0
|
||||
|
||||
# Note that this rule is disabled by default. It's useful only to
|
||||
# verify that the cloudtrail plugin is sending events properly. The
|
||||
# very broad condition evt.num > 0 only works because the rule source
|
||||
# is limited to aws_cloudtrail. This ensures that the only events that
|
||||
# are matched against the rule are from the cloudtrail plugin (or
|
||||
# a different plugin with the same source).
|
||||
- rule: All Cloudtrail Events
|
||||
desc: Match all cloudtrail events.
|
||||
condition:
|
||||
evt.num > 0
|
||||
output: Some Cloudtrail Event (evtnum=%evt.num info=%evt.plugininfo ts=%evt.time.iso8601 id=%ct.id error=%ct.error)
|
||||
priority: DEBUG
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
source: aws_cloudtrail
|
||||
enabled: false
|
||||
|
||||
- rule: Console Login Through Assume Role
|
||||
desc: Detect a console login through Assume Role.
|
||||
condition:
|
||||
ct.name="ConsoleLogin" and not ct.error exists
|
||||
and ct.user.identitytype="AssumedRole"
|
||||
and json.value[/responseElements/ConsoleLogin]="Success"
|
||||
output:
|
||||
Detected a console login through Assume Role
|
||||
(principal=%ct.user.principalid,
|
||||
assumedRole=%ct.user.arn,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_console
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Console Login Without MFA
|
||||
desc: Detect a console login without MFA.
|
||||
condition:
|
||||
ct.name="ConsoleLogin" and not ct.error exists
|
||||
and ct.user.identitytype!="AssumedRole"
|
||||
and json.value[/responseElements/ConsoleLogin]="Success"
|
||||
and json.value[/additionalEventData/MFAUsed]="No"
|
||||
output:
|
||||
Detected a console login without MFA
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region)
|
||||
priority: CRITICAL
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_console
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Console Root Login Without MFA
|
||||
desc: Detect root console login without MFA.
|
||||
condition:
|
||||
ct.name="ConsoleLogin" and not ct.error exists
|
||||
and json.value[/additionalEventData/MFAUsed]="No"
|
||||
and ct.user.identitytype!="AssumedRole"
|
||||
and json.value[/responseElements/ConsoleLogin]="Success"
|
||||
and ct.user.identitytype="Root"
|
||||
output:
|
||||
Detected a root console login without MFA.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region)
|
||||
priority: CRITICAL
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_console
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Deactivate MFA for Root User
|
||||
desc: Detect deactivating MFA configuration for root.
|
||||
condition:
|
||||
ct.name="DeactivateMFADevice" and not ct.error exists
|
||||
and ct.user.identitytype="Root"
|
||||
and ct.request.username="AWS ROOT USER"
|
||||
output:
|
||||
Multi Factor Authentication configuration has been disabled for root
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
MFA serial number=%ct.request.serialnumber)
|
||||
priority: CRITICAL
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Create AWS user
|
||||
desc: Detect creation of a new AWS user.
|
||||
condition:
|
||||
ct.name="CreateUser" and not ct.error exists
|
||||
output:
|
||||
A new AWS user has been created
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
new user created=%ct.request.username)
|
||||
priority: INFO
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Create Group
|
||||
desc: Detect creation of a new user group.
|
||||
condition:
|
||||
ct.name="CreateGroup" and not ct.error exists
|
||||
output:
|
||||
A new user group has been created.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
group name=%ct.request.groupname)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Delete Group
|
||||
desc: Detect deletion of a user group.
|
||||
condition:
|
||||
ct.name="DeleteGroup" and not ct.error exists
|
||||
output:
|
||||
A user group has been deleted.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
group name=%ct.request.groupname)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_iam
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: ECS Service Created
|
||||
desc: Detect a new service is created in ECS.
|
||||
condition:
|
||||
ct.src="ecs.amazonaws.com" and
|
||||
ct.name="CreateService" and
|
||||
not ct.error exists
|
||||
output:
|
||||
A new service has been created in ECS
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
cluster=%ct.request.cluster,
|
||||
service name=%ct.request.servicename,
|
||||
task definition=%ct.request.taskdefinition)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_ecs
|
||||
- aws_fargate
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: ECS Task Run or Started
|
||||
desc: Detect a new task is started in ECS.
|
||||
condition:
|
||||
ct.src="ecs.amazonaws.com" and
|
||||
(ct.name="RunTask" or ct.name="StartTask") and
|
||||
not ct.error exists
|
||||
output:
|
||||
A new task has been started in ECS
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
cluster=%ct.request.cluster,
|
||||
task definition=%ct.request.taskdefinition)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_ecs
|
||||
- aws_fargate
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Create Lambda Function
|
||||
desc: Detect creation of a Lambda function.
|
||||
condition:
|
||||
ct.name="CreateFunction20150331" and not ct.error exists
|
||||
output:
|
||||
Lambda function has been created.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
lambda function=%ct.request.functionname)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_lambda
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Update Lambda Function Code
|
||||
desc: Detect updates to a Lambda function code.
|
||||
condition:
|
||||
ct.name="UpdateFunctionCode20150331v2" and not ct.error exists
|
||||
output:
|
||||
The code of a Lambda function has been updated.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
lambda function=%ct.request.functionname)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_lambda
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Update Lambda Function Configuration
|
||||
desc: Detect updates to a Lambda function configuration.
|
||||
condition:
|
||||
ct.name="UpdateFunctionConfiguration20150331v2" and not ct.error exists
|
||||
output:
|
||||
The configuration of a Lambda function has been updated.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
lambda function=%ct.request.functionname)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_lambda
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Run Instances
|
||||
desc: Detect launching of a specified number of instances.
|
||||
condition:
|
||||
ct.name="RunInstances" and not ct.error exists
|
||||
output:
|
||||
A number of instances have been launched.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
availability zone=%ct.request.availabilityzone,
|
||||
subnet id=%ct.response.subnetid,
|
||||
reservation id=%ct.response.reservationid)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_ec2
|
||||
source: aws_cloudtrail
|
||||
|
||||
# Only instances launched on regions in this list are approved.
|
||||
- list: approved_regions
|
||||
items:
|
||||
- us-east-0
|
||||
|
||||
- rule: Run Instances in Non-approved Region
|
||||
desc: Detect launching of a specified number of instances in a non-approved region.
|
||||
condition:
|
||||
ct.name="RunInstances" and not ct.error exists and
|
||||
not ct.region in (approved_regions)
|
||||
output:
|
||||
A number of instances have been launched in a non-approved region.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
availability zone=%ct.request.availabilityzone,
|
||||
subnet id=%ct.response.subnetid,
|
||||
reservation id=%ct.response.reservationid,
|
||||
image id=%json.value[/responseElements/instancesSet/items/0/instanceId])
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_ec2
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Delete Bucket Encryption
|
||||
desc: Detect deleting configuration to use encryption for bucket storage.
|
||||
condition:
|
||||
ct.name="DeleteBucketEncryption" and not ct.error exists
|
||||
output:
|
||||
A encryption configuration for a bucket has been deleted
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
bucket=%s3.bucket)
|
||||
priority: CRITICAL
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_s3
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Delete Bucket Public Access Block
|
||||
desc: Detect deleting blocking public access to bucket.
|
||||
condition:
|
||||
ct.name="PutBucketPublicAccessBlock" and not ct.error exists and
|
||||
json.value[/requestParameters/publicAccessBlock]="" and
|
||||
(json.value[/requestParameters/PublicAccessBlockConfiguration/RestrictPublicBuckets]=false or
|
||||
json.value[/requestParameters/PublicAccessBlockConfiguration/BlockPublicPolicy]=false or
|
||||
json.value[/requestParameters/PublicAccessBlockConfiguration/BlockPublicAcls]=false or
|
||||
json.value[/requestParameters/PublicAccessBlockConfiguration/IgnorePublicAcls]=false)
|
||||
output:
|
||||
A pulic access block for a bucket has been deleted
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
bucket=%s3.bucket)
|
||||
priority: CRITICAL
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_s3
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: List Buckets
|
||||
desc: Detect listing of all S3 buckets.
|
||||
condition:
|
||||
ct.name="ListBuckets" and not ct.error exists
|
||||
output:
|
||||
A list of all S3 buckets has been requested.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
host=%ct.request.host)
|
||||
priority: WARNING
|
||||
enabled: false
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_s3
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Put Bucket ACL
|
||||
desc: Detect setting the permissions on an existing bucket using access control lists.
|
||||
condition:
|
||||
ct.name="PutBucketAcl" and not ct.error exists
|
||||
output:
|
||||
The permissions on an existing bucket have been set using access control lists.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
bucket name=%s3.bucket)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_s3
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: Put Bucket Policy
|
||||
desc: Detect applying an Amazon S3 bucket policy to an Amazon S3 bucket.
|
||||
condition:
|
||||
ct.name="PutBucketPolicy" and not ct.error exists
|
||||
output:
|
||||
An Amazon S3 bucket policy has been applied to an Amazon S3 bucket.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
bucket name=%s3.bucket,
|
||||
policy=%ct.request.policy)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_s3
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: CloudTrail Trail Created
|
||||
desc: Detect creation of a new trail.
|
||||
condition:
|
||||
ct.name="CreateTrail" and not ct.error exists
|
||||
output:
|
||||
A new trail has been created.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
trail name=%ct.request.name)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_cloudtrail
|
||||
source: aws_cloudtrail
|
||||
|
||||
- rule: CloudTrail Logging Disabled
|
||||
desc: The CloudTrail logging has been disabled, this could be potentially malicious.
|
||||
condition:
|
||||
ct.name="StopLogging" and not ct.error exists
|
||||
output:
|
||||
The CloudTrail logging has been disabled.
|
||||
(requesting user=%ct.user,
|
||||
requesting IP=%ct.srcip,
|
||||
AWS region=%ct.region,
|
||||
resource name=%ct.request.name)
|
||||
priority: WARNING
|
||||
tags:
|
||||
- cloud
|
||||
- aws
|
||||
- aws_cloudtrail
|
||||
source: aws_cloudtrail
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# The latest Falco Engine version is 8 if you want to
|
||||
# use exceptions. However the default rules file does not
|
||||
# use them so we stick with 7 for compatibility.
|
||||
- required_engine_version: 7
|
||||
# The latest Falco Engine version is 9.
|
||||
# Starting with version 8, the Falco engine supports exceptions.
|
||||
# However the Falco rules file does not use them by default.
|
||||
- required_engine_version: 9
|
||||
|
||||
# Currently disabled as read/write are ignored syscalls. The nearly
|
||||
# similar open_write/open_read check for files being opened for
|
||||
@@ -29,13 +29,13 @@
|
||||
# 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
|
||||
condition: evt.type in (open,openat,openat2) 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
|
||||
condition: evt.type in (open,openat,openat2) and evt.is_open_read=true and fd.typechar='f' and fd.num>=0
|
||||
|
||||
- macro: open_directory
|
||||
condition: (evt.type=open or evt.type=openat) and evt.is_open_read=true and fd.typechar='d' and fd.num>=0
|
||||
condition: evt.type in (open,openat,openat2) and evt.is_open_read=true and fd.typechar='d' and fd.num>=0
|
||||
|
||||
- macro: never_true
|
||||
condition: (evt.num=0)
|
||||
@@ -220,7 +220,7 @@
|
||||
]
|
||||
|
||||
# The truncated dpkg-preconfigu is intentional, process names are
|
||||
# truncated at the sysdig level.
|
||||
# truncated at the falcosecurity-libs level.
|
||||
- list: package_mgmt_binaries
|
||||
items: [rpm_binaries, deb_binaries, update-alternat, gem, pip, pip3, sane-utils.post, alternatives, chef-client, apk, snapd]
|
||||
|
||||
@@ -333,7 +333,7 @@
|
||||
# for efficiency.
|
||||
- macro: inbound_outbound
|
||||
condition: >
|
||||
((((evt.type in (accept,listen,connect) and evt.dir=<)) or
|
||||
((((evt.type in (accept,listen,connect) and evt.dir=<)) and
|
||||
(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))
|
||||
@@ -538,11 +538,6 @@
|
||||
- macro: system_users
|
||||
condition: user.name in (bin, daemon, games, lp, mail, nobody, sshd, sync, uucp, www-data)
|
||||
|
||||
- macro: python_running_sdchecks
|
||||
condition: >
|
||||
(proc.name in (python, python2.7) and
|
||||
(proc.cmdline contains /opt/draios/bin/sdchecks))
|
||||
|
||||
- macro: httpd_writing_ssl_conf
|
||||
condition: >
|
||||
(proc.pname=run-httpd and
|
||||
@@ -1397,6 +1392,15 @@
|
||||
- macro: user_read_sensitive_file_containers
|
||||
condition: (container and container.image.repository in (read_sensitive_file_images))
|
||||
|
||||
# This macro detects man-db postinst, see https://salsa.debian.org/debian/man-db/-/blob/master/debian/postinst
|
||||
# The rule "Read sensitive file untrusted" use this macro to avoid FPs.
|
||||
- macro: mandb_postinst
|
||||
condition: >
|
||||
(proc.name=perl and proc.args startswith "-e" and
|
||||
proc.args contains "@pwd = getpwnam(" and
|
||||
proc.args contains "exec " and
|
||||
proc.args contains "/usr/bin/mandb")
|
||||
|
||||
- rule: Read sensitive file untrusted
|
||||
desc: >
|
||||
an attempt to read any sensitive file (e.g. files containing user/password/authentication
|
||||
@@ -1412,11 +1416,11 @@
|
||||
)
|
||||
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 run_by_google_accounts_daemon
|
||||
and not user_read_sensitive_file_conditions
|
||||
and not mandb_postinst
|
||||
and not perl_running_plesk
|
||||
and not perl_running_updmap
|
||||
and not veritas_driver_script
|
||||
@@ -1554,7 +1558,6 @@
|
||||
and not proc.name startswith "runc"
|
||||
and not proc.cmdline startswith "containerd"
|
||||
and not proc.pname in (sysdigcloud_binaries, hyperkube, kubelet, protokube, dockerd, tini, aws)
|
||||
and not python_running_sdchecks
|
||||
and not java_running_sdjagent
|
||||
and not kubelet_running_loopback
|
||||
and not rancher_agent
|
||||
@@ -1562,6 +1565,7 @@
|
||||
and not calico_node
|
||||
and not weaveworks_scope
|
||||
and not user_known_change_thread_namespace_activities
|
||||
enabled: false
|
||||
output: >
|
||||
Namespace change (setns) by unexpected program (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline
|
||||
parent=%proc.pname %container.info container_id=%container.id image=%container.image.repository:%container.image.tag)
|
||||
@@ -1744,6 +1748,32 @@
|
||||
container.image.repository endswith /prometheus-node-exporter or
|
||||
container.image.repository endswith /image-inspector))
|
||||
|
||||
# https://docs.aws.amazon.com/eks/latest/userguide/add-ons-images.html
|
||||
# official AWS EKS registry list. AWS has different ECR repo per region
|
||||
- macro: allowed_aws_ecr_registry_root_for_eks
|
||||
condition: >
|
||||
(container.image.repository startswith "602401143452.dkr.ecr" or
|
||||
container.image.repository startswith "877085696533.dkr.ecr" or
|
||||
container.image.repository startswith "800184023465.dkr.ecr" or
|
||||
container.image.repository startswith "918309763551.dkr.ecr" or
|
||||
container.image.repository startswith "961992271922.dkr.ecr" or
|
||||
container.image.repository startswith "590381155156.dkr.ecr" or
|
||||
container.image.repository startswith "558608220178.dkr.ecr" or
|
||||
container.image.repository startswith "151742754352.dkr.ecr" or
|
||||
container.image.repository startswith "013241004608.dkr.ecr")
|
||||
|
||||
|
||||
- macro: aws_eks_core_images
|
||||
condition: >
|
||||
(allowed_aws_ecr_registry_root_for_eks and
|
||||
(container.image.repository endswith ".amazonaws.com/amazon-k8s-cni" or
|
||||
container.image.repository endswith ".amazonaws.com/eks/kube-proxy"))
|
||||
|
||||
|
||||
- macro: aws_eks_image_sensitive_mount
|
||||
condition: >
|
||||
(allowed_aws_ecr_registry_root_for_eks and container.image.repository endswith ".amazonaws.com/amazon-k8s-cni")
|
||||
|
||||
# These images are allowed both to run with --privileged and to mount
|
||||
# sensitive paths from the host filesystem.
|
||||
#
|
||||
@@ -1784,7 +1814,6 @@
|
||||
docker.io/falcosecurity/falco,
|
||||
docker.io/mesosphere/mesos-slave,
|
||||
docker.io/rook/toolbox,
|
||||
docker.io/sysdig/falco,
|
||||
docker.io/sysdig/sysdig,
|
||||
falcosecurity/falco,
|
||||
gcr.io/google_containers/kube-proxy,
|
||||
@@ -1797,8 +1826,8 @@
|
||||
k8s.gcr.io/ip-masq-agent-amd64,
|
||||
k8s.gcr.io/kube-proxy,
|
||||
k8s.gcr.io/prometheus-to-sd,
|
||||
public.ecr.aws/falcosecurity/falco,
|
||||
quay.io/calico/node,
|
||||
sysdig/falco,
|
||||
sysdig/sysdig,
|
||||
sematext_images
|
||||
]
|
||||
@@ -1806,6 +1835,7 @@
|
||||
- macro: falco_privileged_containers
|
||||
condition: (openshift_image or
|
||||
user_trusted_containers or
|
||||
aws_eks_core_images or
|
||||
container.image.repository in (trusted_images) or
|
||||
container.image.repository in (falco_privileged_images) or
|
||||
container.image.repository startswith istio/proxy_ or
|
||||
@@ -1824,8 +1854,8 @@
|
||||
# host filesystem.
|
||||
- list: falco_sensitive_mount_images
|
||||
items: [
|
||||
docker.io/sysdig/falco, docker.io/sysdig/sysdig, sysdig/falco, sysdig/sysdig,
|
||||
docker.io/falcosecurity/falco, falcosecurity/falco,
|
||||
docker.io/sysdig/sysdig, sysdig/sysdig,
|
||||
docker.io/falcosecurity/falco, falcosecurity/falco, public.ecr.aws/falcosecurity/falco,
|
||||
gcr.io/google_containers/hyperkube,
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/consul,
|
||||
@@ -1836,6 +1866,7 @@
|
||||
|
||||
- macro: falco_sensitive_mount_containers
|
||||
condition: (user_trusted_containers or
|
||||
aws_eks_image_sensitive_mount or
|
||||
container.image.repository in (trusted_images) or
|
||||
container.image.repository in (falco_sensitive_mount_images) or
|
||||
container.image.repository startswith quay.io/sysdig/)
|
||||
@@ -1875,12 +1906,13 @@
|
||||
|
||||
# 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
|
||||
# below /etc as well, but the globbing mechanism
|
||||
# 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[/var/run/crio/crio.sock] != "N/A" or
|
||||
container.mount.dest[/run/containerd/containerd.sock] != "N/A" or
|
||||
container.mount.dest[/var/lib/kubelet] != "N/A" or
|
||||
container.mount.dest[/var/lib/kubelet/pki] != "N/A" or
|
||||
container.mount.dest[/] != "N/A" or
|
||||
@@ -2204,7 +2236,7 @@
|
||||
condition: >
|
||||
evt.type=setuid and evt.dir=>
|
||||
and (known_user_in_container or not container)
|
||||
and not user.name=root
|
||||
and not (user.name=root or user.uid=0)
|
||||
and not somebody_becoming_themself
|
||||
and not proc.name in (known_setuid_binaries, userexec_binaries, mail_binaries, docker_binaries,
|
||||
nomachine_binaries)
|
||||
@@ -2265,7 +2297,7 @@
|
||||
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 or evt.type = openat) and evt.arg.flags contains O_CREAT))
|
||||
(evt.type = creat or (evt.type in (open,openat,openat2) 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
|
||||
@@ -2329,11 +2361,12 @@
|
||||
- macro: k8s_containers
|
||||
condition: >
|
||||
(container.image.repository in (gcr.io/google_containers/hyperkube-amd64,
|
||||
gcr.io/google_containers/kube2sky, docker.io/sysdig/falco,
|
||||
gcr.io/google_containers/kube2sky,
|
||||
docker.io/sysdig/sysdig, docker.io/falcosecurity/falco,
|
||||
sysdig/falco, sysdig/sysdig, falcosecurity/falco,
|
||||
sysdig/sysdig, falcosecurity/falco,
|
||||
fluent/fluentd-kubernetes-daemonset, prom/prometheus,
|
||||
ibm_cloud_containers)
|
||||
ibm_cloud_containers,
|
||||
public.ecr.aws/falcosecurity/falco)
|
||||
or (k8s.ns.name = "kube-system"))
|
||||
|
||||
- macro: k8s_api_server
|
||||
@@ -2611,6 +2644,7 @@
|
||||
and not proc.name in (user_known_chmod_applications)
|
||||
and not exe_running_docker_save
|
||||
and not user_known_set_setuid_or_setgid_bit_conditions
|
||||
enabled: false
|
||||
output: >
|
||||
Setuid or setgid bit is set via chmod (fd=%evt.arg.fd filename=%evt.arg.filename mode=%evt.arg.mode user=%user.name user_loginuid=%user.loginuid process=%proc.name
|
||||
command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
@@ -2674,7 +2708,7 @@
|
||||
create_symlink and
|
||||
(evt.arg.target in (sensitive_file_names) or evt.arg.target in (sensitive_directory_names))
|
||||
output: >
|
||||
Symlinks created over senstivie files (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline target=%evt.arg.target linkpath=%evt.arg.linkpath parent_process=%proc.pname)
|
||||
Symlinks created over sensitive files (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline target=%evt.arg.target linkpath=%evt.arg.linkpath parent_process=%proc.pname)
|
||||
priority: NOTICE
|
||||
tags: [file, mitre_exfiltration]
|
||||
|
||||
@@ -2715,7 +2749,12 @@
|
||||
"xmr-eu1.nanopool.org","xmr-eu2.nanopool.org",
|
||||
"xmr-jp1.nanopool.org","xmr-us-east1.nanopool.org",
|
||||
"xmr-us-west1.nanopool.org","xmr.crypto-pool.fr",
|
||||
"xmr.pool.minergate.com"
|
||||
"xmr.pool.minergate.com", "rx.unmineable.com",
|
||||
"ss.antpool.com","dash.antpool.com",
|
||||
"eth.antpool.com","zec.antpool.com",
|
||||
"xmc.antpool.com","btm.antpool.com",
|
||||
"stratum-dash.antpool.com","stratum-xmc.antpool.com",
|
||||
"stratum-btm.antpool.com"
|
||||
]
|
||||
|
||||
- list: https_miner_domains
|
||||
@@ -2732,7 +2771,12 @@
|
||||
"stratum-ltc.antpool.com",
|
||||
"stratum-zec.antpool.com",
|
||||
"stratum.antpool.com",
|
||||
"xmr.crypto-pool.fr"
|
||||
"xmr.crypto-pool.fr",
|
||||
"ss.antpool.com",
|
||||
"stratum-dash.antpool.com",
|
||||
"stratum-xmc.antpool.com",
|
||||
"stratum-btm.antpool.com",
|
||||
"btm.antpool.com"
|
||||
]
|
||||
|
||||
- list: http_miner_domains
|
||||
@@ -2761,7 +2805,7 @@
|
||||
condition: (evt.type in (sendto, sendmsg) and evt.dir=< and (fd.net != "127.0.0.0/8" and not fd.snet in (rfc_1918_addresses)) and ((minerpool_http) or (minerpool_https) or (minerpool_other)))
|
||||
|
||||
- macro: trusted_images_query_miner_domain_dns
|
||||
condition: (container.image.repository in (docker.io/falcosecurity/falco, falcosecurity/falco))
|
||||
condition: (container.image.repository in (docker.io/falcosecurity/falco, falcosecurity/falco, public.ecr.aws/falcosecurity/falco))
|
||||
append: false
|
||||
|
||||
# The rule is disabled by default.
|
||||
@@ -2912,7 +2956,7 @@
|
||||
|
||||
# The two Container Drift rules below will fire when a new executable is created in a container.
|
||||
# There are two ways to create executables - file is created with execution permissions or permissions change of existing file.
|
||||
# We will use a new sysdig filter, is_open_exec, to find all files creations with execution permission, and will trace all chmods in a container.
|
||||
# We will use a new filter, is_open_exec, to find all files creations with execution permission, and will trace all chmods in a container.
|
||||
# The use case we are targeting here is an attempt to execute code that was not shipped as part of a container (drift) -
|
||||
# an activity that might be malicious or non-compliant.
|
||||
# Two things to pay attention to:
|
||||
@@ -2945,7 +2989,7 @@
|
||||
- rule: Container Drift Detected (open+create)
|
||||
desc: New executable created in a container due to open+create
|
||||
condition: >
|
||||
evt.type in (open,openat,creat) and
|
||||
evt.type in (open,openat,openat2,creat) and
|
||||
evt.is_open_exec=true and
|
||||
container and
|
||||
not runc_writing_exec_fifo and
|
||||
@@ -2971,7 +3015,7 @@
|
||||
- rule: Linux Kernel Module Injection Detected
|
||||
desc: Detect kernel module was injected (from container).
|
||||
condition: spawned_process and container and proc.name=insmod and not proc.args in (white_listed_modules)
|
||||
output: Linux Kernel Module injection using insmod detected (user=%user.name user_loginuid=%user.loginuid parent_process=%proc.pname module=%proc.args)
|
||||
output: Linux Kernel Module injection using insmod detected (user=%user.name user_loginuid=%user.loginuid parent_process=%proc.pname module=%proc.args %container.info image=%container.image.repository:%container.image.tag)
|
||||
priority: WARNING
|
||||
tags: [process]
|
||||
|
||||
@@ -2995,13 +3039,13 @@
|
||||
# A privilege escalation to root through heap-based buffer overflow
|
||||
- rule: Sudo Potential Privilege Escalation
|
||||
desc: Privilege escalation vulnerability affecting sudo (<= 1.9.5p2). Executing sudo using sudoedit -s or sudoedit -i command with command-line argument that ends with a single backslash character from an unprivileged user it's possible to elevate the user privileges to root.
|
||||
condition: spawned_process and user.uid!= 0 and proc.name=sudoedit and (proc.args contains -s or proc.args contains -i) and (proc.args contains "\ " or proc.args endswith \)
|
||||
condition: spawned_process and user.uid != 0 and proc.name=sudoedit and (proc.args contains -s or proc.args contains -i) and (proc.args contains "\ " or proc.args endswith \)
|
||||
output: "Detect Sudo Privilege Escalation Exploit (CVE-2021-3156) (user=%user.name parent=%proc.pname cmdline=%proc.cmdline %container.info)"
|
||||
priority: CRITICAL
|
||||
tags: [filesystem, mitre_privilege_escalation]
|
||||
|
||||
- rule: Debugfs Launched in Privileged Container
|
||||
desc: Detect file system debugger debugfs launched inside a privilegd container which might lead to container escape.
|
||||
desc: Detect file system debugger debugfs launched inside a privileged container which might lead to container escape.
|
||||
condition: >
|
||||
spawned_process and container
|
||||
and container.privileged=true
|
||||
@@ -3024,6 +3068,58 @@
|
||||
priority: WARNING
|
||||
tags: [container, cis, mitre_lateral_movement]
|
||||
|
||||
- macro: consider_userfaultfd_activities
|
||||
condition: (always_true)
|
||||
|
||||
- list: user_known_userfaultfd_processes
|
||||
items: []
|
||||
|
||||
- rule: Unprivileged Delegation of Page Faults Handling to a Userspace Process
|
||||
desc: Detect a successful unprivileged userfaultfd syscall which might act as an attack primitive to exploit other bugs
|
||||
condition: >
|
||||
consider_userfaultfd_activities and
|
||||
evt.type = userfaultfd and
|
||||
user.uid != 0 and
|
||||
(evt.rawres >= 0 or evt.res != -1) and
|
||||
not proc.name in (user_known_userfaultfd_processes)
|
||||
output: An userfaultfd syscall was successfully executed by an unprivileged user (user=%user.name user_loginuid=%user.loginuid process=%proc.name command=%proc.cmdline %container.info image=%container.image.repository:%container.image.tag)
|
||||
priority: CRITICAL
|
||||
tags: [syscall, mitre_defense_evasion]
|
||||
|
||||
- list: ingress_remote_file_copy_binaries
|
||||
items: [wget]
|
||||
|
||||
- macro: ingress_remote_file_copy_procs
|
||||
condition: (proc.name in (ingress_remote_file_copy_binaries))
|
||||
|
||||
# Users should overwrite this macro to specify conditions under which a
|
||||
# Custom condition for use of ingress remote file copy tool in container
|
||||
- macro: user_known_ingress_remote_file_copy_activities
|
||||
condition: (never_true)
|
||||
|
||||
- macro: curl_download
|
||||
condition: proc.name = curl and
|
||||
(proc.cmdline contains " > " or
|
||||
proc.cmdline contains " >> " or
|
||||
proc.cmdline contains " | " or
|
||||
proc.cmdline contains " -o " or
|
||||
proc.cmdline contains " --output " or
|
||||
proc.cmdline contains " -O " or
|
||||
proc.cmdline contains " --remote-name ")
|
||||
|
||||
- rule: Launch Ingress Remote File Copy Tools in Container
|
||||
desc: Detect ingress remote file copy tools launched in container
|
||||
condition: >
|
||||
spawned_process and
|
||||
container and
|
||||
(ingress_remote_file_copy_procs or curl_download) and
|
||||
not user_known_ingress_remote_file_copy_activities
|
||||
output: >
|
||||
Ingress remote file copy tool launched in container (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline parent_process=%proc.pname
|
||||
container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
priority: NOTICE
|
||||
tags: [network, process, mitre_command_and_control]
|
||||
|
||||
# Application rules have moved to application_rules.yaml. Please look
|
||||
# there if you want to enable them by adding to
|
||||
# falco_rules.local.yaml.
|
||||
|
||||
@@ -302,9 +302,31 @@
|
||||
items: []
|
||||
|
||||
- list: known_sa_list
|
||||
items: ["pod-garbage-collector","resourcequota-controller","cronjob-controller","generic-garbage-collector",
|
||||
"daemon-set-controller","endpointslice-controller","deployment-controller", "replicaset-controller",
|
||||
"endpoint-controller"]
|
||||
items: [
|
||||
coredns,
|
||||
coredns-autoscaler,
|
||||
cronjob-controller,
|
||||
daemon-set-controller,
|
||||
deployment-controller,
|
||||
disruption-controller,
|
||||
endpoint-controller,
|
||||
endpointslice-controller,
|
||||
endpointslicemirroring-controller,
|
||||
generic-garbage-collector,
|
||||
horizontal-pod-autoscaler,
|
||||
job-controller,
|
||||
namespace-controller,
|
||||
node-controller,
|
||||
persistent-volume-binder,
|
||||
pod-garbage-collector,
|
||||
pv-protection-controller,
|
||||
pvc-protection-controller,
|
||||
replicaset-controller,
|
||||
resourcequota-controller,
|
||||
root-ca-cert-publisher,
|
||||
service-account-controller,
|
||||
statefulset-controller
|
||||
]
|
||||
|
||||
- macro: trusted_sa
|
||||
condition: (ka.target.name in (known_sa_list, user_known_sa_list))
|
||||
|
||||
@@ -154,13 +154,15 @@ load_kernel_module_compile() {
|
||||
fi
|
||||
|
||||
# Try to compile using all the available gcc versions
|
||||
for CURRENT_GCC in $(which gcc) $(ls "$(dirname "$(which gcc)")"/gcc-* | grep 'gcc-[0-9]\+' | sort -r); do
|
||||
for CURRENT_GCC in $(which gcc) $(ls "$(dirname "$(which gcc)")"/gcc-* | grep 'gcc-[0-9]\+' | sort -n -r -k 2 -t -); do
|
||||
echo "* Trying to dkms install ${DRIVER_NAME} module with GCC ${CURRENT_GCC}"
|
||||
echo "#!/usr/bin/env bash" > /tmp/falco-dkms-make
|
||||
echo "make CC=${CURRENT_GCC} \$@" >> /tmp/falco-dkms-make
|
||||
chmod +x /tmp/falco-dkms-make
|
||||
if dkms install --directive="MAKE='/tmp/falco-dkms-make'" -m "${DRIVER_NAME}" -v "${DRIVER_VERSION}" -k "${KERNEL_RELEASE}" 2>/dev/null; then
|
||||
echo "* ${DRIVER_NAME} module installed in dkms, trying to insmod"
|
||||
chcon -t modules_object_t "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko" > /dev/null 2>&1 || true
|
||||
chcon -t modules_object_t "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko.xz" > /dev/null 2>&1 || true
|
||||
if insmod "/var/lib/dkms/${DRIVER_NAME}/${DRIVER_VERSION}/${KERNEL_RELEASE}/${ARCH}/module/${DRIVER_NAME}.ko" > /dev/null 2>&1; then
|
||||
echo "* Success: ${DRIVER_NAME} module found and loaded in dkms"
|
||||
exit 0
|
||||
@@ -193,6 +195,7 @@ load_kernel_module_download() {
|
||||
echo "* Trying to download a prebuilt ${DRIVER_NAME} module from ${URL}"
|
||||
if curl -L --create-dirs "${FALCO_DRIVER_CURL_OPTIONS}" -o "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" "${URL}"; then
|
||||
echo "* Download succeeded"
|
||||
chcon -t modules_object_t "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true
|
||||
insmod "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted"
|
||||
exit $?
|
||||
else
|
||||
@@ -252,6 +255,7 @@ load_kernel_module() {
|
||||
|
||||
if [ -f "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" ]; then
|
||||
echo "* Found a prebuilt ${DRIVER_NAME} module at ${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}, loading it"
|
||||
chcon -t modules_object_t "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" > /dev/null 2>&1 || true
|
||||
insmod "${HOME}/.falco/${FALCO_KERNEL_MODULE_FILENAME}" && echo "* Success: ${DRIVER_NAME} module found and inserted"
|
||||
exit $?
|
||||
fi
|
||||
@@ -296,16 +300,16 @@ clean_kernel_module() {
|
||||
return
|
||||
fi
|
||||
|
||||
DRIVER_VERSIONS=$(dkms status -m "${DRIVER_NAME}" | cut -d',' -f2 | sed -e 's/^[[:space:]]*//')
|
||||
DRIVER_VERSIONS=$(dkms status -m "${DRIVER_NAME}" | cut -d',' -f1 | sed -e 's/^[[:space:]]*//')
|
||||
if [ -z "${DRIVER_VERSIONS}" ]; then
|
||||
echo "* There is no ${DRIVER_NAME} module in dkms"
|
||||
return
|
||||
fi
|
||||
for CURRENT_VER in ${DRIVER_VERSIONS}; do
|
||||
if dkms remove -m "${DRIVER_NAME}" -v "${CURRENT_VER}" --all 2>/dev/null; then
|
||||
echo "* Removing ${DRIVER_NAME}/${CURRENT_VER} succeeded"
|
||||
if dkms remove "${CURRENT_VER}" --all 2>/dev/null; then
|
||||
echo "* Removing ${CURRENT_VER} succeeded"
|
||||
else
|
||||
echo "* Removing ${DRIVER_NAME}/${CURRENT_VER} failed"
|
||||
echo "* Removing ${CURRENT_VER} failed"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
@@ -634,4 +638,4 @@ if [ -z "$source_only" ]; then
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
#
|
||||
scriptdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
parentdir="$(dirname "$scriptdir")"
|
||||
sysdigdir="${parentdir}/build/sysdig-repo/sysdig-prefix/src/sysdig"
|
||||
cat "${sysdigdir}/userspace/libscap/syscall_info_table.c" | grep EF_DROP_SIMPLE_CONS | sed -e 's/.*\"\(.*\)\".*/\1/' | sort > /tmp/ignored_syscall_info_table.txt
|
||||
cat "${sysdigdir}/driver/event_table.c" | grep EF_DROP_SIMPLE_CONS | sed -e 's/[^\"]*\"\([^\"]*\)\".*/\1/' | sort | uniq > /tmp/ignored_driver_event_table.txt
|
||||
libsdir="${parentdir}/build/falcosecurity-libs-repo/falcosecurity-libs-prefix/src/falcosecurity-libs"
|
||||
cat "${libsdir}/userspace/libscap/syscall_info_table.c" | grep EF_DROP_SIMPLE_CONS | sed -e 's/.*\"\(.*\)\".*/\1/' | sort > /tmp/ignored_syscall_info_table.txt
|
||||
cat "${libsdir}/driver/event_table.c" | grep EF_DROP_SIMPLE_CONS | sed -e 's/[^\"]*\"\([^\"]*\)\".*/\1/' | sort | uniq > /tmp/ignored_driver_event_table.txt
|
||||
|
||||
cat /tmp/ignored_driver_event_table.txt /tmp/ignored_syscall_info_table.txt | sort | uniq | tr '\n' ', '
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ add_deb() {
|
||||
cp -f $3 $1/$2
|
||||
pushd $1/$2 > /dev/null
|
||||
rm -f $(basename -- $3).asc
|
||||
gpg --detach-sign --armor $(basename -- $3)
|
||||
gpg --detach-sign --digest-algo SHA256 --armor $(basename -- $3)
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ update_repo() {
|
||||
${release_dir} > ${release_dir}/Release
|
||||
|
||||
# release signature
|
||||
gpg --detach-sign --armor ${release_dir}/Release
|
||||
gpg --detach-sign --digest-algo SHA256 --armor ${release_dir}/Release
|
||||
rm -f ${release_dir}/Release.gpg
|
||||
mv ${release_dir}/Release.asc ${release_dir}/Release.gpg
|
||||
|
||||
@@ -129,4 +129,4 @@ aws s3 sync ${tmp_repo_path}/dists ${s3_bucket_repo}/dists --delete --acl public
|
||||
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${debSuite}/${package}
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${debSuite}/${package}.asc
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/dists/*
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/dists/*
|
||||
|
||||
@@ -22,7 +22,7 @@ add_rpm() {
|
||||
cp -f $2 $1
|
||||
pushd $1 > /dev/null
|
||||
rm -f $(basename -- $2).asc
|
||||
gpg --detach-sign --armor $(basename -- $2)
|
||||
gpg --detach-sign --digest-algo SHA256 --armor $(basename -- $2)
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ update_repo() {
|
||||
pushd $1 > /dev/null
|
||||
createrepo --update --no-database .
|
||||
rm -f repodata/repomd.xml.asc
|
||||
gpg --detach-sign --armor repodata/repomd.xml
|
||||
gpg --detach-sign --digest-algo SHA256 --armor repodata/repomd.xml
|
||||
popd > /dev/null
|
||||
}
|
||||
|
||||
@@ -93,4 +93,4 @@ aws s3 sync ${tmp_repo_path}/repodata ${s3_bucket_repo}/repodata --delete --acl
|
||||
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/${package}.asc
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/repodata/*
|
||||
aws cloudfront create-invalidation --distribution-id ${AWS_CLOUDFRONT_DIST_ID} --paths ${cloudfront_path}/repodata/*
|
||||
|
||||
@@ -19,6 +19,7 @@ ProtectSystem=full
|
||||
ProtectKernelTunables=true
|
||||
RestrictRealtime=true
|
||||
RestrictAddressFamilies=~AF_PACKET
|
||||
StandardOutput=null
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
add_subdirectory(trace_files)
|
||||
|
||||
add_custom_target(test-trace-files ALL)
|
||||
add_dependencies(test-trace-files trace-files-base-scap trace-files-psp trace-files-k8s-audit)
|
||||
add_dependencies(test-trace-files trace-files-base-scap trace-files-psp trace-files-k8s-audit trace-files-plugins)
|
||||
|
||||
add_subdirectory(plugins)
|
||||
add_subdirectory(confs/plugins)
|
||||
|
||||
16
test/confs/plugins/CMakeLists.txt
Normal file
16
test/confs/plugins/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
# This list is populated at cmake time, not build time
|
||||
file(GLOB test_conf_files
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.yaml")
|
||||
|
||||
foreach(conf_file_path ${test_conf_files})
|
||||
get_filename_component(conf_file ${conf_file_path} NAME)
|
||||
add_custom_target(test-conf-${conf_file} ALL
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${conf_file})
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${conf_file}
|
||||
COMMAND sed -e s!BUILD_DIR!${CMAKE_BINARY_DIR}! < ${CMAKE_CURRENT_SOURCE_DIR}/${conf_file} > ${CMAKE_CURRENT_BINARY_DIR}/${conf_file}
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${conf_file})
|
||||
list(APPEND PLUGINS_CONF_FILES_TARGETS test-conf-${conf_file})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(conf-files-plugins ALL)
|
||||
add_dependencies(conf-files-plugins ${PLUGINS_CONF_FILES_TARGETS})
|
||||
14
test/confs/plugins/cloudtrail_json_create_instances.yaml
Normal file
14
test/confs/plugins/cloudtrail_json_create_instances.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: cloudtrail
|
||||
library_path: BUILD_DIR/cloudtrail-plugin-prefix/src/cloudtrail-plugin/libcloudtrail.so
|
||||
init_config: ""
|
||||
open_params: "BUILD_DIR/test/trace_files/plugins/alice_start_instances.json"
|
||||
- name: json
|
||||
library_path: BUILD_DIR/json-plugin-prefix/src/json-plugin/libjson.so
|
||||
init_config: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [cloudtrail, json]
|
||||
@@ -0,0 +1,14 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: cloudtrail
|
||||
library_path: BUILD_DIR/cloudtrail-plugin-prefix/src/cloudtrail-plugin/libcloudtrail.so
|
||||
init_config: ""
|
||||
open_params: "BUILD_DIR/test/trace_files/plugins/alice_start_instances_bigevent.json"
|
||||
- name: json
|
||||
library_path: BUILD_DIR/json-plugin-prefix/src/json-plugin/libjson.so
|
||||
init_config: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [cloudtrail, json]
|
||||
14
test/confs/plugins/incompatible_extract_sources.yaml
Normal file
14
test/confs/plugins/incompatible_extract_sources.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: cloudtrail
|
||||
library_path: BUILD_DIR/cloudtrail-plugin-prefix/src/cloudtrail-plugin/libcloudtrail.so
|
||||
init_config: ""
|
||||
open_params: ""
|
||||
- name: test_extract_p1
|
||||
library_path: BUILD_DIR/test/plugins/libtest_extract_p1.so
|
||||
init_config: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [cloudtrail, test_extract_p1]
|
||||
10
test/confs/plugins/incompatible_plugin_api.yaml
Normal file
10
test/confs/plugins/incompatible_plugin_api.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: incompatible_plugin_api
|
||||
library_path: BUILD_DIR/test/plugins/libtest_incompat_api.so
|
||||
init_config: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [incompatible_plugin_api]
|
||||
15
test/confs/plugins/multiple_source_plugins.yaml
Normal file
15
test/confs/plugins/multiple_source_plugins.yaml
Normal file
@@ -0,0 +1,15 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: cloudtrail
|
||||
library_path: BUILD_DIR/cloudtrail-plugin-prefix/src/cloudtrail-plugin/libcloudtrail.so
|
||||
init_config: ""
|
||||
open_params: "BUILD_DIR/test/trace_files/plugins/alice_start_instances.json"
|
||||
- name: test_source
|
||||
library_path: BUILD_DIR/test/plugins/libtest_source.so
|
||||
init_config: ""
|
||||
open_params: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [cloudtrail, test_source]
|
||||
17
test/confs/plugins/overlap_extract_sources.yaml
Normal file
17
test/confs/plugins/overlap_extract_sources.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: test_source
|
||||
library_path: BUILD_DIR/test/plugins/libtest_source.so
|
||||
init_config: ""
|
||||
open_params: ""
|
||||
- name: test_extract_p1
|
||||
library_path: BUILD_DIR/test/plugins/libtest_extract_p1.so
|
||||
init_config: ""
|
||||
- name: test_extract_p2
|
||||
library_path: BUILD_DIR/test/plugins/libtest_extract_p2.so
|
||||
init_config: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [test_source, test_extract_p1, test_extract_p2]
|
||||
10
test/confs/plugins/wrong_plugin_path.yaml
Normal file
10
test/confs/plugins/wrong_plugin_path.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
plugins:
|
||||
- name: wrong_plugin_path
|
||||
library_path: BUILD_DIR/test/plugins/wrong_plugin_path.so
|
||||
init_config: ""
|
||||
|
||||
# Optional
|
||||
load_plugins: [wrong_plugin_path]
|
||||
@@ -43,6 +43,12 @@ json_output: false
|
||||
# (user=root ....") in the json output.
|
||||
json_include_output_property: true
|
||||
|
||||
# When using json output, whether or not to include the "tags" property
|
||||
# itself in the json output. If set to true, outputs caused by rules
|
||||
# with no tags will have a "tags" field set to an empty array. If set to
|
||||
# false, the "tags" field will not be included in the json output at all.
|
||||
json_include_tags_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
|
||||
|
||||
@@ -622,4 +622,22 @@ trace_files: !mux
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Secret Deleted: 1
|
||||
trace_file: trace_files/k8s_audit/delete_secret.json
|
||||
trace_file: trace_files/k8s_audit/delete_secret.json
|
||||
|
||||
fal_01_003:
|
||||
detect: False
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
trace_file: trace_files/k8s_audit/fal_01_003.json
|
||||
stderr_contains: 'Could not read k8s audit event line #1, "{"kind": 0}": Data not recognized as a k8s audit event, stopping'
|
||||
|
||||
json_pointer_correct_parse:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ./rules/k8s_audit/single_rule_with_json_pointer.yaml
|
||||
detect_counts:
|
||||
- json_pointer_example: 1
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_unprivileged.json
|
||||
@@ -82,6 +82,7 @@ class FalcoTest(Test):
|
||||
|
||||
self.exit_status = self.params.get('exit_status', '*', default=0)
|
||||
self.should_detect = self.params.get('detect', '*', default=False)
|
||||
self.check_detection_counts = self.params.get('check_detection_counts', '*', default=True)
|
||||
self.trace_file = self.params.get('trace_file', '*', default='')
|
||||
|
||||
if self.trace_file and not os.path.isabs(self.trace_file):
|
||||
@@ -90,8 +91,11 @@ class FalcoTest(Test):
|
||||
self.json_output = self.params.get('json_output', '*', default=False)
|
||||
self.json_include_output_property = self.params.get(
|
||||
'json_include_output_property', '*', default=True)
|
||||
self.json_include_tags_property = self.params.get(
|
||||
'json_include_tags_property', '*', default=True)
|
||||
self.all_events = self.params.get('all_events', '*', default=False)
|
||||
self.priority = self.params.get('priority', '*', default='debug')
|
||||
self.addl_cmdline_opts = self.params.get('addl_cmdline_opts', '*', default='')
|
||||
self.rules_file = self.params.get(
|
||||
'rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))
|
||||
|
||||
@@ -128,6 +132,7 @@ class FalcoTest(Test):
|
||||
|
||||
self.conf_file = self.params.get(
|
||||
'conf_file', '*', default=os.path.join(self.basedir, '../falco.yaml'))
|
||||
self.conf_file = self.conf_file.replace("BUILD_DIR", build_dir)
|
||||
if not os.path.isabs(self.conf_file):
|
||||
self.conf_file = os.path.join(self.basedir, self.conf_file)
|
||||
|
||||
@@ -388,10 +393,11 @@ class FalcoTest(Test):
|
||||
for line in res.stdout.decode("utf-8").splitlines():
|
||||
if line.startswith('{'):
|
||||
obj = json.loads(line)
|
||||
attrs = ['time', 'rule', 'priority']
|
||||
if self.json_include_output_property:
|
||||
attrs = ['time', 'rule', 'priority', 'output']
|
||||
else:
|
||||
attrs = ['time', 'rule', 'priority']
|
||||
attrs.append('output')
|
||||
if self.json_include_tags_property:
|
||||
attrs.append('tags')
|
||||
for attr in attrs:
|
||||
if not attr in obj:
|
||||
self.fail(
|
||||
@@ -409,10 +415,15 @@ class FalcoTest(Test):
|
||||
else:
|
||||
actual = open(output['actual']).read()
|
||||
|
||||
if expected not in actual:
|
||||
self.fail("Output '{}' does not strictly contains the expected content '{}'".format(
|
||||
output['actual'], output['expected']))
|
||||
return False
|
||||
actual_cursor = actual
|
||||
expected_lines = expected.splitlines()
|
||||
for line in expected_lines:
|
||||
pos = actual_cursor.find(line)
|
||||
if pos < 0:
|
||||
self.fail("Output '{}' does not strictly contains the expected content '{}'".format(
|
||||
output['actual'], output['expected']))
|
||||
return False
|
||||
actual_cursor = actual_cursor[pos + len(line):]
|
||||
|
||||
return True
|
||||
|
||||
@@ -609,8 +620,9 @@ class FalcoTest(Test):
|
||||
self.log.debug("Converted Rules: {}".format(psp_rules))
|
||||
|
||||
# Run falco
|
||||
cmd = '{} {} {} -c {} {} -o json_output={} -o json_include_output_property={} -o priority={} -v'.format(
|
||||
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output, self.json_include_output_property, self.priority)
|
||||
cmd = '{} {} {} -c {} {} -o json_output={} -o json_include_output_property={} -o json_include_tags_property={} -o priority={} -v {}'.format(
|
||||
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output,
|
||||
self.json_include_output_property, self.json_include_tags_property, self.priority, self.addl_cmdline_opts)
|
||||
|
||||
for tag in self.disable_tags:
|
||||
cmd += ' -T {}'.format(tag)
|
||||
@@ -641,13 +653,13 @@ class FalcoTest(Test):
|
||||
self.fail("Stdout was not exactly {}".format(self.stderr_is))
|
||||
|
||||
for pattern in self.stderr_contains:
|
||||
match = re.search(pattern, res.stderr.decode("utf-8"))
|
||||
match = re.search(pattern, res.stderr.decode("utf-8"), re.DOTALL)
|
||||
if match is None:
|
||||
self.fail(
|
||||
"Stderr of falco process did not contain content matching {}".format(pattern))
|
||||
|
||||
for pattern in self.stdout_contains:
|
||||
match = re.search(pattern, res.stdout.decode("utf-8"))
|
||||
match = re.search(pattern, res.stdout.decode("utf-8"), re.DOTALL)
|
||||
if match is None:
|
||||
self.fail("Stdout of falco process '{}' did not contain content matching {}".format(
|
||||
res.stdout.decode("utf-8"), pattern))
|
||||
@@ -675,7 +687,7 @@ class FalcoTest(Test):
|
||||
self.check_rules_warnings(res)
|
||||
if len(self.rules_events) > 0:
|
||||
self.check_rules_events(res)
|
||||
if len(self.validate_rules_file) == 0:
|
||||
if len(self.validate_rules_file) == 0 and self.check_detection_counts:
|
||||
self.check_detections(res)
|
||||
if len(self.detect_counts) > 0:
|
||||
self.check_detections_by_rule(res)
|
||||
|
||||
@@ -32,20 +32,10 @@ trace_files: !mux
|
||||
- leading_not
|
||||
- not_equals_at_end
|
||||
- not_at_end
|
||||
- not_before_trailing_evttype
|
||||
- not_equals_before_trailing_evttype
|
||||
- not_equals_and_not
|
||||
- not_equals_before_in
|
||||
- not_before_in
|
||||
- not_in_before_in
|
||||
- leading_in_not_equals_before_evttype
|
||||
- leading_in_not_equals_at_evttype
|
||||
- not_with_evttypes
|
||||
- not_with_evttypes_addl
|
||||
- not_equals_before_evttype
|
||||
- not_equals_before_in_evttype
|
||||
- not_before_evttype
|
||||
- not_before_evttype_using_in
|
||||
rules_events:
|
||||
- no_warnings: [execve]
|
||||
- no_evttype: [all]
|
||||
@@ -364,7 +354,7 @@ trace_files: !mux
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule must have exceptions or condition property
|
||||
Appended rule must have exceptions or condition property
|
||||
---
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
@@ -644,6 +634,20 @@ trace_files: !mux
|
||||
rules_file:
|
||||
- rules/single_rule_enabled_flag.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
disabled_rule_using_false_enabled_flag_only:
|
||||
detect: False
|
||||
rules_file:
|
||||
- rules/disabled_rule_using_enabled_flag_only.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
enabled_rule_using_false_enabled_flag_only:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/enabled_rule_using_enabled_flag_only.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "Warning An open was seen"
|
||||
|
||||
disabled_and_enabled_rules_1:
|
||||
exit_status: 1
|
||||
@@ -688,7 +692,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
- rules/single_rule_with_tags.yaml
|
||||
conf_file: confs/stdout_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
time_iso_8601: true
|
||||
@@ -721,7 +725,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/single_rule.yaml
|
||||
- rules/single_rule_with_tags.yaml
|
||||
conf_file: confs/grpc_unix_socket.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
run_duration: 5
|
||||
@@ -745,6 +749,10 @@ trace_files: !mux
|
||||
# For the hostname, since we don't know that beforehand,
|
||||
# only check the field presence
|
||||
- "hostname: "
|
||||
#tags
|
||||
- "tags: \"filesystem\""
|
||||
- "tags: \"process\""
|
||||
- "tags: \"testing\""
|
||||
|
||||
detect_counts:
|
||||
detect: True
|
||||
@@ -763,7 +771,7 @@ trace_files: !mux
|
||||
- "Non sudo setuid": 1
|
||||
- "Create files below dev": 1
|
||||
- "Modify binary dirs": 2
|
||||
- "Change thread namespace": 1
|
||||
- "Change thread namespace": 0
|
||||
|
||||
disabled_tags_a:
|
||||
detect: True
|
||||
@@ -1107,6 +1115,25 @@ trace_files: !mux
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "^(?!.*Warning An open of /dev/null was seen.*)"
|
||||
|
||||
json_output_no_tags_property:
|
||||
json_output: True
|
||||
json_include_tags_property: False
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/rule_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "^(?!.*\"tags\":[ ]*\\[.*\\],.*)"
|
||||
|
||||
json_output_empty_tags_property:
|
||||
json_output: True
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/rule_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "^(.*\"tags\":[ ]*\\[\\],.*)"
|
||||
|
||||
in_operator_netmasks:
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
@@ -1119,6 +1146,8 @@ trace_files: !mux
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- rules/syscalls.yaml
|
||||
rules_warning:
|
||||
- detect_madvise
|
||||
detect_counts:
|
||||
- detect_madvise: 2
|
||||
- detect_open: 2
|
||||
@@ -1137,7 +1166,8 @@ trace_files: !mux
|
||||
|
||||
skip_unknown_noevt:
|
||||
detect: False
|
||||
stdout_contains: Skipping rule "Contains Unknown Event And Skipping". contains unknown filter proc.nobody
|
||||
rules_warning:
|
||||
- Contains Unknown Event And Skipping
|
||||
rules_file:
|
||||
- rules/skip_unknown_evt.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -1152,7 +1182,7 @@ trace_files: !mux
|
||||
exit_status: 1
|
||||
stderr_contains: |+
|
||||
Could not load rules file.*skip_unknown_error.yaml: 1 errors:
|
||||
rule "Contains Unknown Event And Not Skipping". contains unknown filter proc.nobody
|
||||
Rule Contains Unknown Event And Not Skipping: error filter_check called with nonexistent field proc.nobody
|
||||
---
|
||||
- rule: Contains Unknown Event And Not Skipping
|
||||
desc: Contains an unknown event
|
||||
@@ -1169,7 +1199,7 @@ trace_files: !mux
|
||||
exit_status: 1
|
||||
stderr_contains: |+
|
||||
Could not load rules file .*skip_unknown_unspec.yaml: 1 errors:
|
||||
rule "Contains Unknown Event And Unspecified". contains unknown filter proc.nobody
|
||||
Rule Contains Unknown Event And Unspecified: error filter_check called with nonexistent field proc.nobody
|
||||
---
|
||||
- rule: Contains Unknown Event And Unspecified
|
||||
desc: Contains an unknown event
|
||||
|
||||
@@ -177,10 +177,18 @@ trace_files: !mux
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_append_item_not_in_rule:
|
||||
exit_status: 0
|
||||
stderr_contains: |+
|
||||
1 warnings:
|
||||
Rule My Rule with append=true: no set of fields matching name ex2
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception new item ex2: must have fields property with a list of fields
|
||||
---
|
||||
- rule: My Rule
|
||||
exceptions:
|
||||
- name: ex2
|
||||
values:
|
||||
- [apache, /tmp]
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/append_item_not_in_rule.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -311,4 +319,35 @@ trace_files: !mux
|
||||
- rules/exceptions/rule_exception_single_field_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_new_single_field_append:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_new_single_field_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_new_second_field_append:
|
||||
detect: False
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/exceptions/rule_exception_new_second_field_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
rule_exception_new_append_no_field:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
1 errors:
|
||||
Rule exception new item proc_cmdline: must have fields property with a list of fields
|
||||
---
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
comps: in
|
||||
values:
|
||||
- "cat /dev/null"
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/exceptions/rule_exception_new_no_field_append.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
|
||||
106
test/falco_tests_plugins.yaml
Normal file
106
test/falco_tests_plugins.yaml
Normal file
@@ -0,0 +1,106 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco Authors.
|
||||
#
|
||||
# This file is part of Falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
trace_files: !mux
|
||||
|
||||
list_plugins:
|
||||
check_detection_counts: False
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml
|
||||
addl_cmdline_opts: --list-plugins
|
||||
stdout_contains: "2 Plugins Loaded.*Name: cloudtrail.*Type: source plugin.*Name: json.*Type: extractor plugin"
|
||||
|
||||
list_plugin_fields:
|
||||
check_detection_counts: False
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml
|
||||
addl_cmdline_opts: --list
|
||||
stdout_contains: "ct.id"
|
||||
|
||||
detect_create_instance:
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
detect_counts:
|
||||
- 'Cloudtrail Create Instance': 1
|
||||
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml
|
||||
|
||||
detect_create_instance_bigevent:
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
detect_counts:
|
||||
- 'Cloudtrail Create Instance': 1
|
||||
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances_bigevent.yaml
|
||||
|
||||
multiple_source_plugins:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Can not load multiple source plugins. cloudtrail already loaded. Exiting."
|
||||
conf_file: BUILD_DIR/test/confs/plugins/multiple_source_plugins.yaml
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
|
||||
incompatible_extract_sources:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Extractor plugin not compatible with event source aws_cloudtrail. Exiting."
|
||||
conf_file: BUILD_DIR/test/confs/plugins/incompatible_extract_sources.yaml
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
|
||||
overlap_extract_sources:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Extractor plugins have overlapping compatible event source test_source. Exiting."
|
||||
conf_file: BUILD_DIR/test/confs/plugins/overlap_extract_sources.yaml
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
|
||||
incompat_plugin_api:
|
||||
exit_status: 1
|
||||
stderr_contains: "Unsupported plugin required api version 10000000.0.0"
|
||||
conf_file: BUILD_DIR/test/confs/plugins/incompatible_plugin_api.yaml
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
|
||||
incompat_plugin_rules_version:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Plugin cloudtrail version 0.1.0 not compatible with required plugin version 100000.0.0. Exiting."
|
||||
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_incompat_plugin_version.yaml
|
||||
|
||||
wrong_plugin_path:
|
||||
exit_status: 1
|
||||
stderr_contains: "error loading plugin.*No such file or directory. Exiting"
|
||||
conf_file: BUILD_DIR/test/confs/plugins/wrong_plugin_path.yaml
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_incompat_plugin_version.yaml
|
||||
|
||||
no_plugins_unknown_source:
|
||||
detect: False
|
||||
rules_file:
|
||||
- rules/plugins/cloudtrail_create_instances.yaml
|
||||
trace_file: trace_files/empty.scap
|
||||
rules_warning:
|
||||
- Cloudtrail Create Instance
|
||||
stderr_contains: "Rule Cloudtrail Create Instance: warning .unknown-source.: unknown source aws_cloudtrail, skipping"
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ has_json_output: !mux
|
||||
traces: !mux
|
||||
change-thread-namespace:
|
||||
trace_file: traces-positive/change-thread-namespace.scap
|
||||
detect: True
|
||||
detect: False
|
||||
detect_level: NOTICE
|
||||
detect_counts:
|
||||
- "Change thread namespace": 1
|
||||
- "Change thread namespace": 0
|
||||
|
||||
container-privileged:
|
||||
trace_file: traces-positive/container-privileged.scap
|
||||
@@ -73,7 +73,7 @@ traces: !mux
|
||||
- "Non sudo setuid": 1
|
||||
- "Create files below dev": 1
|
||||
- "Modify binary dirs": 2
|
||||
- "Change thread namespace": 1
|
||||
- "Change thread namespace": 0
|
||||
|
||||
mkdir-binary-dirs:
|
||||
trace_file: traces-positive/mkdir-binary-dirs.scap
|
||||
@@ -111,12 +111,17 @@ traces: !mux
|
||||
detect_counts:
|
||||
- "Read sensitive file untrusted": 1
|
||||
|
||||
# This should *not* generate any falco alerts as of the changes in
|
||||
# https://github.com/falcosecurity/libs/pull/94--the execve event in
|
||||
# this trace file is PPME_SYSCALL_EXECVE_18, which was deprecated by
|
||||
# PPME_SYSCALL_EXECVE_19 in 2018.
|
||||
#
|
||||
# This activity in this trace file overlaps with the activity in
|
||||
# falco-event-generator.scap so the rule is still being tested.
|
||||
run-shell-untrusted:
|
||||
trace_file: traces-positive/run-shell-untrusted.scap
|
||||
detect: True
|
||||
detect: False
|
||||
detect_level: DEBUG
|
||||
detect_counts:
|
||||
- "Run shell untrusted": 1
|
||||
|
||||
system-binaries-network-activity:
|
||||
trace_file: traces-positive/system-binaries-network-activity.scap
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"output":"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881781397Z", "output_fields": {"evt.time.iso8601":1470327477881781397,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881785348Z", "output_fields": {"evt.time.iso8601":1470327477881785348,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881796705Z", "output_fields": {"evt.time.iso8601":1470327477881796705,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.881799840Z", "output_fields": {"evt.time.iso8601":1470327477881799840,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882003104Z", "output_fields": {"evt.time.iso8601":1470327477882003104,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882008208Z", "output_fields": {"evt.time.iso8601":1470327477882008208,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882045694Z", "output_fields": {"evt.time.iso8601":1470327477882045694,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","time":"2016-08-04T16:17:57.882054739Z", "output_fields": {"evt.time.iso8601":1470327477882054739,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881781397+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881781397Z", "output_fields": {"evt.time.iso8601":1470327477881781397,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881785348+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881785348Z", "output_fields": {"evt.time.iso8601":1470327477881785348,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881796705+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881796705Z", "output_fields": {"evt.time.iso8601":1470327477881796705,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.881799840+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.881799840Z", "output_fields": {"evt.time.iso8601":1470327477881799840,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882003104+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882003104Z", "output_fields": {"evt.time.iso8601":1470327477882003104,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882008208+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882008208Z", "output_fields": {"evt.time.iso8601":1470327477882008208,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882045694+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882045694Z", "output_fields": {"evt.time.iso8601":1470327477882045694,"proc.cmdline":"cat /dev/null"}}
|
||||
{"output":"2016-08-04T16:17:57.882054739+0000: Warning An open was seen (command=cat /dev/null)","priority":"Warning","rule":"open_from_cat","source":"syscall","tags":["filesystem","process","testing"],"time":"2016-08-04T16:17:57.882054739Z", "output_fields": {"evt.time.iso8601":1470327477882054739,"proc.cmdline":"cat /dev/null"}}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2019 The Falco 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.
|
||||
#
|
||||
|
||||
require(jsonlite)
|
||||
library(ggplot2)
|
||||
library(GetoptLong)
|
||||
|
||||
initial.options <- commandArgs(trailingOnly = FALSE)
|
||||
file.arg.name <- "--file="
|
||||
script.name <- sub(file.arg.name, "", initial.options[grep(file.arg.name, initial.options)])
|
||||
script.basename <- dirname(script.name)
|
||||
|
||||
if (substr(script.basename, 1, 1) != '/') {
|
||||
script.basename = paste(getwd(), script.basename, sep='/')
|
||||
}
|
||||
|
||||
results = paste(script.basename, "results.json", sep='/')
|
||||
output = "./output.png"
|
||||
metric = "cpu"
|
||||
|
||||
GetoptLong(
|
||||
"results=s", "Path to results file",
|
||||
"benchmark=s", "Benchmark from results file to graph",
|
||||
"variant=s@", "Variant(s) to include in graph. Can be specified multiple times",
|
||||
"output=s", "Output graph file",
|
||||
"metric=s", "Metric to graph. Can be one of (cpu|drops)"
|
||||
)
|
||||
|
||||
if (metric == "cpu") {
|
||||
data_metric="cpu_usage"
|
||||
yaxis_label="CPU Usage (%)"
|
||||
title="Falco/Sysdig/Multimatch CPU Usage: %s"
|
||||
} else if (metric == "drops") {
|
||||
data_metric="drop_pct"
|
||||
yaxis_label="Event Drops (%)"
|
||||
title="Falco/Sysdig/Multimatch Event Drops: %s"
|
||||
}
|
||||
|
||||
res <- fromJSON(results, flatten=TRUE)
|
||||
|
||||
res2 = res[res$benchmark == benchmark & res$variant %in% variant,]
|
||||
|
||||
plot <- ggplot(data=res2, aes(x=sample, y=get(data_metric), group=variant, colour=variant)) +
|
||||
geom_line() +
|
||||
ylab(yaxis_label) +
|
||||
xlab("Time") +
|
||||
ggtitle(sprintf(title, benchmark))
|
||||
theme(legend.position=c(.2, .88));
|
||||
|
||||
print(paste("Writing graph to", output, sep=" "))
|
||||
ggsave(file=output)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2019 The Falco 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.
|
||||
#
|
||||
|
||||
require(jsonlite)
|
||||
library(ggplot2)
|
||||
library(reshape)
|
||||
|
||||
res <- fromJSON("/home/mstemm/results.txt", flatten=TRUE)
|
||||
|
||||
plot <- ggplot(data=res, aes(x=config, y=elapsed.real)) +
|
||||
geom_bar(stat = "summary", fun.y = "mean") +
|
||||
coord_flip() +
|
||||
facet_grid(shortfile ~ .) +
|
||||
ylab("Wall Clock Time (sec)") +
|
||||
xlab("Trace File/Program")
|
||||
|
||||
|
||||
ggsave(file="/mnt/sf_mstemm/res-real.png")
|
||||
|
||||
plot <- ggplot(data=res, aes(x=config, y=elapsed.user)) +
|
||||
geom_bar(stat = "summary", fun.y = "mean") +
|
||||
coord_flip() +
|
||||
facet_grid(shortfile ~ .) +
|
||||
ylab("User Time (sec)") +
|
||||
xlab("Trace File/Program")
|
||||
|
||||
|
||||
ggsave(file="/mnt/sf_mstemm/res-user.png")
|
||||
|
||||
res2 <- melt(res, id.vars = c("config", "shortfile"), measure.vars = c("elapsed.sys", "elapsed.user"))
|
||||
plot <- ggplot(data=res2, aes(x=config, y=value, fill=variable, order=variable)) +
|
||||
geom_bar(stat = "summary", fun.y = "mean") +
|
||||
coord_flip() +
|
||||
facet_grid(shortfile ~ .) +
|
||||
ylab("User/System Time (sec)") +
|
||||
xlab("Trace File/Program")
|
||||
|
||||
ggsave(file="/mnt/sf_mstemm/res-sys-user.png")
|
||||
13
test/plugins/CMakeLists.txt
Normal file
13
test/plugins/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
add_library(test_extract_p1 SHARED test_extract.cpp)
|
||||
add_library(test_extract_p2 SHARED test_extract.cpp)
|
||||
add_library(test_source SHARED test_source.cpp)
|
||||
add_library(test_incompat_api SHARED incompat_api.cpp)
|
||||
|
||||
target_include_directories(
|
||||
test_extract_p1 PUBLIC "${LIBSCAP_INCLUDE_DIRS}")
|
||||
|
||||
target_include_directories(
|
||||
test_extract_p2 PUBLIC "${LIBSCAP_INCLUDE_DIRS}")
|
||||
|
||||
target_include_directories(
|
||||
test_source PUBLIC "${LIBSCAP_INCLUDE_DIRS}")
|
||||
28
test/plugins/incompat_api.cpp
Normal file
28
test/plugins/incompat_api.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
Copyright (C) 2021 The Falco 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Don't need any function other than plugin_get_required_api_version,
|
||||
// plugin load will fail after that.
|
||||
static const char *pl_required_api_version = "10000000.0.0";
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_required_api_version()
|
||||
{
|
||||
return pl_required_api_version;
|
||||
}
|
||||
116
test/plugins/test_extract.cpp
Normal file
116
test/plugins/test_extract.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (C) 2021 The Falco 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <plugin_info.h>
|
||||
|
||||
static const char *pl_required_api_version = "0.1.0";
|
||||
static uint32_t pl_type = TYPE_EXTRACTOR_PLUGIN;
|
||||
static const char *pl_name_base = "test_extract";
|
||||
static char pl_name[1024];
|
||||
static const char *pl_desc = "Test Plugin For Regression Tests";
|
||||
static const char *pl_contact = "github.com/falcosecurity/falco";
|
||||
static const char *pl_version = "0.1.0";
|
||||
static const char *pl_extract_sources = "[\"test_source\"]";
|
||||
static const char *pl_fields = "[]";
|
||||
|
||||
// This struct represents the state of a plugin. Just has a placeholder string value.
|
||||
typedef struct plugin_state
|
||||
{
|
||||
} plugin_state;
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_required_api_version()
|
||||
{
|
||||
return pl_required_api_version;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
uint32_t plugin_get_type()
|
||||
{
|
||||
return pl_type;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_name()
|
||||
{
|
||||
// Add a random-ish suffix to the end, as some tests load
|
||||
// multiple copies of this plugin
|
||||
snprintf(pl_name, sizeof(pl_name)-1, "%s%ld\n", pl_name_base, random());
|
||||
return pl_name;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_description()
|
||||
{
|
||||
return pl_desc;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_contact()
|
||||
{
|
||||
return pl_contact;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_version()
|
||||
{
|
||||
return pl_version;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_extract_event_sources()
|
||||
{
|
||||
return pl_extract_sources;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_fields()
|
||||
{
|
||||
return pl_fields;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_last_error(ss_plugin_t* s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
ss_plugin_t* plugin_init(const char* config, int32_t* rc)
|
||||
{
|
||||
// Note: Using new/delete is okay, as long as the plugin
|
||||
// framework is not deleting the memory.
|
||||
plugin_state *ret = new plugin_state();
|
||||
*rc = SS_PLUGIN_SUCCESS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void plugin_destroy(ss_plugin_t* s)
|
||||
{
|
||||
plugin_state *ps = (plugin_state *) s;
|
||||
|
||||
delete(ps);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int32_t plugin_extract_fields(ss_plugin_t *s, const ss_plugin_event *evt, uint32_t num_fields, ss_plugin_extract_field *fields)
|
||||
{
|
||||
return SS_PLUGIN_SUCCESS;
|
||||
}
|
||||
161
test/plugins/test_source.cpp
Normal file
161
test/plugins/test_source.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright (C) 2021 The Falco 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.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <plugin_info.h>
|
||||
|
||||
static const char *pl_required_api_version = "0.1.0";
|
||||
static uint32_t pl_type = TYPE_SOURCE_PLUGIN;
|
||||
static uint32_t pl_id = 999;
|
||||
static const char *pl_name = "test_source";
|
||||
static const char *pl_desc = "Test Plugin For Regression Tests";
|
||||
static const char *pl_contact = "github.com/falcosecurity/falco";
|
||||
static const char *pl_version = "0.1.0";
|
||||
static const char *pl_event_source = "test_source";
|
||||
static const char *pl_fields = "[]";
|
||||
|
||||
// This struct represents the state of a plugin. Just has a placeholder string value.
|
||||
typedef struct plugin_state
|
||||
{
|
||||
} plugin_state;
|
||||
|
||||
typedef struct instance_state
|
||||
{
|
||||
} instance_state;
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_required_api_version()
|
||||
{
|
||||
return pl_required_api_version;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
uint32_t plugin_get_type()
|
||||
{
|
||||
return pl_type;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
uint32_t plugin_get_id()
|
||||
{
|
||||
return pl_id;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_name()
|
||||
{
|
||||
return pl_name;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_description()
|
||||
{
|
||||
return pl_desc;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_contact()
|
||||
{
|
||||
return pl_contact;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_version()
|
||||
{
|
||||
return pl_version;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_event_source()
|
||||
{
|
||||
return pl_event_source;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_fields()
|
||||
{
|
||||
return pl_fields;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* plugin_get_last_error(ss_plugin_t* s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
ss_plugin_t* plugin_init(const char* config, int32_t* rc)
|
||||
{
|
||||
// Note: Using new/delete is okay, as long as the plugin
|
||||
// framework is not deleting the memory.
|
||||
plugin_state *ret = new plugin_state();
|
||||
|
||||
*rc = SS_PLUGIN_SUCCESS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void plugin_destroy(ss_plugin_t* s)
|
||||
{
|
||||
plugin_state *ps = (plugin_state *) s;
|
||||
|
||||
delete(ps);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
ss_instance_t* plugin_open(ss_plugin_t* s, const char* params, int32_t* rc)
|
||||
{
|
||||
// Note: Using new/delete is okay, as long as the plugin
|
||||
// framework is not deleting the memory.
|
||||
instance_state *ret = new instance_state();
|
||||
*rc = SS_PLUGIN_SUCCESS;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void plugin_close(ss_plugin_t* s, ss_instance_t* i)
|
||||
{
|
||||
instance_state *istate = (instance_state *) i;
|
||||
|
||||
delete(istate);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int32_t plugin_next_batch(ss_plugin_t* s, ss_instance_t* i, uint32_t *nevts, ss_plugin_event **evts)
|
||||
{
|
||||
return SS_PLUGIN_EOF;
|
||||
}
|
||||
|
||||
// This plugin does not implement plugin_next_batch, due to the lower
|
||||
// overhead of calling C functions from the plugin framework compared
|
||||
// to calling Go functions.
|
||||
|
||||
extern "C"
|
||||
const char *plugin_event_to_string(ss_plugin_t *s, const uint8_t *data, uint32_t datalen)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int32_t plugin_extract_fields(ss_plugin_t *s, const ss_plugin_event *evt, uint32_t num_fields, ss_plugin_extract_field *fields)
|
||||
{
|
||||
return SS_PLUGIN_SUCCESS;
|
||||
}
|
||||
@@ -9,5 +9,5 @@ PyYAML==5.4
|
||||
requests==2.23.0
|
||||
six==1.14.0
|
||||
stevedore==1.32.0
|
||||
urllib3==1.25.9
|
||||
urllib3==1.26.5
|
||||
watchdog==0.10.2
|
||||
|
||||
24
test/rules/disabled_rule_using_enabled_flag_only.yaml
Normal file
24
test/rules/disabled_rule_using_enabled_flag_only.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen"
|
||||
priority: WARNING
|
||||
|
||||
- rule: open_from_cat
|
||||
enabled: false
|
||||
25
test/rules/enabled_rule_using_enabled_flag_only.yaml
Normal file
25
test/rules/enabled_rule_using_enabled_flag_only.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen"
|
||||
priority: WARNING
|
||||
enabled: false
|
||||
|
||||
- rule: open_from_cat
|
||||
enabled: true
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2019 The Falco Authors.
|
||||
# Copyright (C) 2021 The Falco Authors.
|
||||
#
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -16,10 +15,17 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
SUBJ_PID=$1
|
||||
BENCHMARK=$2
|
||||
VARIANT=$3
|
||||
RESULTS_FILE=$4
|
||||
CPU_INTERVAL=$5
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
comps: in
|
||||
values:
|
||||
- "cat /dev/null"
|
||||
append: true
|
||||
|
||||
top -d $CPU_INTERVAL -b -p $SUBJ_PID | grep -E '(falco|sysdig|dragent|test_mm)' --line-buffered | awk -v benchmark=$BENCHMARK -v variant=$VARIANT '{printf("{\"time\": \"%s\", \"sample\": %d, \"benchmark\": \"%s\", \"variant\": \"%s\", \"cpu_usage\": %s},\n", strftime("%Y-%m-%d %H:%M:%S", systime(), 1), NR, benchmark, variant, $9); fflush();}' >> $RESULTS_FILE
|
||||
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
fields: proc.cmdline
|
||||
comps: in
|
||||
values:
|
||||
- cat /dev/zero
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_cmdline_2
|
||||
fields: proc.cmdline
|
||||
comps: in
|
||||
values:
|
||||
- "cat /dev/null"
|
||||
append: true
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
- rule: Open From Cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
|
||||
- rule: Open From Cat
|
||||
exceptions:
|
||||
- name: proc_cmdline
|
||||
fields: proc.cmdline
|
||||
comps: in
|
||||
values:
|
||||
- "cat /dev/null"
|
||||
append: true
|
||||
|
||||
|
||||
@@ -1,2 +1,24 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
- rule: no condition rule
|
||||
desc: simpe rule
|
||||
condition: evt.type=open
|
||||
output: simple output
|
||||
priority: WARNING
|
||||
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
23
test/rules/k8s_audit/single_rule_with_json_pointer.yaml
Normal file
23
test/rules/k8s_audit/single_rule_with_json_pointer.yaml
Normal file
@@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
- rule: json_pointer_example
|
||||
desc: A rule example using JSON Pointer (RFC 6901)
|
||||
condition: jevt.value[/annotations/authorization.k8s.io~1decision] exists and not (jevt.value[/a~1~0b] exists)
|
||||
output: "JSON Pointer Test Alert"
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
6
test/rules/plugins/cloudtrail_create_instances.yaml
Normal file
6
test/rules/plugins/cloudtrail_create_instances.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- rule: Cloudtrail Create Instance
|
||||
desc: Detect Creating an EC2 Instance
|
||||
condition: evt.num > 0 and ct.name="StartInstances"
|
||||
output: EC2 Instance Created (evtnum=%evt.num info=%evt.plugininfo id=%ct.id user name=%json.value[/userIdentity/userName])
|
||||
priority: INFO
|
||||
source: aws_cloudtrail
|
||||
10
test/rules/plugins/cloudtrail_incompat_plugin_version.yaml
Normal file
10
test/rules/plugins/cloudtrail_incompat_plugin_version.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
- required_plugin_versions:
|
||||
- name: cloudtrail
|
||||
version: 100000.0.0
|
||||
|
||||
- rule: Cloudtrail Create Instance
|
||||
desc: Detect Creating an EC2 Instance
|
||||
condition: evt.num > 0 and ct.name="StartInstances"
|
||||
output: EC2 Instance Created (evtnum=%evt.num info=%evt.plugininfo id=%ct.id user name=%json.value[/userIdentity/userName])
|
||||
priority: INFO
|
||||
source: aws_cloudtrail
|
||||
@@ -16,10 +16,10 @@
|
||||
#
|
||||
- rule: my_rule
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and fd.name=not-a-real-file
|
||||
condition: (evt.type=open and fd.name=not-a-real-file)
|
||||
output: "An open of /dev/null was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
|
||||
- rule: my_rule
|
||||
append: true
|
||||
condition: or fd.name=/dev/null
|
||||
condition: or (evt.type=open and fd.name=/dev/null)
|
||||
|
||||
34
test/rules/single_rule_with_tags.yaml
Normal file
34
test/rules/single_rule_with_tags.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2021 The Falco 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.
|
||||
#
|
||||
|
||||
- required_engine_version: 2
|
||||
|
||||
- list: cat_binaries
|
||||
items: [cat]
|
||||
|
||||
- list: cat_capable_binaries
|
||||
items: [cat_binaries]
|
||||
|
||||
- macro: is_cat
|
||||
condition: proc.name in (cat_capable_binaries)
|
||||
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
tags: [filesystem, process, testing]
|
||||
@@ -15,7 +15,7 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
- macro: open_read
|
||||
condition: (evt.type=open or evt.type=openat) and evt.is_open_read=true and fd.typechar='f'
|
||||
condition: evt.type in (open,openat,openat2) and evt.is_open_read=true and fd.typechar='f'
|
||||
|
||||
- rule: open_1
|
||||
desc: open one
|
||||
|
||||
@@ -1,444 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Copyright (C) 2019 The Falco 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.
|
||||
#
|
||||
|
||||
#set -x
|
||||
|
||||
trap "cleanup; exit" SIGHUP SIGINT SIGTERM
|
||||
|
||||
TRACE_FILES_BASE_URL=${TRACE_FILES_BASE_URL:-"https://download.falco.org/fixtures/trace-files/"}
|
||||
|
||||
function download_trace_files() {
|
||||
|
||||
(mkdir -p $TRACEDIR && rm -rf $TRACEDIR/traces-perf && curl -fo $TRACEDIR/traces-perf.zip "${TRACE_FILES_BASE_URL}traces-perf.zip" && unzip -d $TRACEDIR $TRACEDIR/traces-perf.zip && rm -f $TRACEDIR/traces-perf.zip) || exit 1
|
||||
|
||||
}
|
||||
|
||||
function time_cmd() {
|
||||
cmd="$1"
|
||||
file="$2"
|
||||
|
||||
benchmark=`basename $file .scap`
|
||||
|
||||
echo -n "$benchmark: "
|
||||
for i in `seq 1 5`; do
|
||||
echo -n "$i "
|
||||
time=`date --iso-8601=sec`
|
||||
/usr/bin/time -a -o $RESULTS_FILE --format "{\"time\": \"$time\", \"benchmark\": \"$benchmark\", \"file\": \"$file\", \"variant\": \"$VARIANT\", \"elapsed\": {\"real\": %e, \"user\": %U, \"sys\": %S}}," $cmd >> $OUTPUT_FILE 2>&1
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
function run_falco_on() {
|
||||
file="$1"
|
||||
|
||||
if [ -z $RULES_FILE ]; then
|
||||
RULES_FILE=$SOURCE/rules/falco_rules.yaml
|
||||
fi
|
||||
|
||||
cmd="$ROOT/userspace/falco/falco -c $SOURCE/falco.yaml -r $SOURCE/rules/falco_rules.yaml --option=stdout_output.enabled=false -e $file -A"
|
||||
|
||||
time_cmd "$cmd" "$file"
|
||||
}
|
||||
|
||||
function run_sysdig_on() {
|
||||
file="$1"
|
||||
|
||||
cmd="$ROOT/userspace/sysdig/sysdig -N -z -r $file evt.type=none"
|
||||
|
||||
time_cmd "$cmd" "$file"
|
||||
}
|
||||
|
||||
function write_agent_config() {
|
||||
cat > $ROOT/userspace/dragent/dragent.yaml <<EOF
|
||||
customerid: XXX
|
||||
app_checks_enabled: false
|
||||
log:
|
||||
file_priority: info
|
||||
console_priority: info
|
||||
event_priority: info
|
||||
jmx:
|
||||
enabled: false
|
||||
statsd:
|
||||
enabled: false
|
||||
collector: collector-staging.sysdigcloud.com
|
||||
EOF
|
||||
|
||||
if [ $FALCO_AGENT == 1 ]; then
|
||||
cat >> $ROOT/userspace/dragent/dragent.yaml <<EOF
|
||||
falco_engine:
|
||||
enabled: true
|
||||
rules_filename: /etc/falco_rules.yaml
|
||||
sampling_multiplier: 0
|
||||
EOF
|
||||
else
|
||||
cat >> $ROOT/userspace/dragent/dragent.yaml <<EOF
|
||||
falco_engine:
|
||||
enabled: false
|
||||
EOF
|
||||
fi
|
||||
|
||||
if [ $AGENT_AUTODROP == 1 ]; then
|
||||
cat >> $ROOT/userspace/dragent/dragent.yaml <<EOF
|
||||
autodrop:
|
||||
enabled: true
|
||||
EOF
|
||||
else
|
||||
cat >> $ROOT/userspace/dragent/dragent.yaml <<EOF
|
||||
autodrop:
|
||||
enabled: false
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat $ROOT/userspace/dragent/dragent.yaml
|
||||
}
|
||||
|
||||
function run_agent_on() {
|
||||
|
||||
file="$1"
|
||||
|
||||
write_agent_config
|
||||
|
||||
cmd="$ROOT/userspace/dragent/dragent -r $file"
|
||||
|
||||
time_cmd "$cmd" "$file"
|
||||
}
|
||||
|
||||
function run_trace() {
|
||||
|
||||
if [ ! -e $TRACEDIR ]; then
|
||||
download_trace_files
|
||||
fi
|
||||
|
||||
trace_file="$1"
|
||||
|
||||
if [ $trace_file == "all" ]; then
|
||||
files=($TRACEDIR/traces-perf/*.scap)
|
||||
else
|
||||
files=($TRACEDIR/traces-perf/$trace_file.scap)
|
||||
fi
|
||||
|
||||
for file in "${files[@]}"; do
|
||||
if [[ $ROOT == *"falco"* ]]; then
|
||||
run_falco_on "$file"
|
||||
elif [[ $ROOT == *"sysdig"* ]]; then
|
||||
run_sysdig_on "$file"
|
||||
else
|
||||
run_agent_on "$file"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
function start_monitor_cpu_usage() {
|
||||
echo " monitoring cpu usage for falcosecurity/falco program"
|
||||
|
||||
setsid bash `dirname $0`/cpu_monitor.sh $SUBJ_PID $live_test $VARIANT $RESULTS_FILE $CPU_INTERVAL &
|
||||
CPU_PID=$!
|
||||
sleep 5
|
||||
}
|
||||
|
||||
function start_subject_prog() {
|
||||
|
||||
# Do a blocking sudo command now just to ensure we have a password
|
||||
sudo bash -c ""
|
||||
|
||||
if [[ $ROOT == *"multimatch"* ]]; then
|
||||
echo " starting test_mm..."
|
||||
if [ -z $RULES_FILE ]; then
|
||||
RULES_FILE=$SOURCE/../output/rules.yaml
|
||||
fi
|
||||
sudo FALCO_STATS_EXTRA_variant=$VARIANT FALCO_STATS_EXTRA_benchmark=$live_test $ROOT/test_mm -S $SOURCE/search_order.yaml -s $STATS_FILE -r $RULES_FILE > ./prog-output.txt 2>&1 &
|
||||
elif [[ $ROOT == *"falco"* ]]; then
|
||||
echo " starting falco..."
|
||||
if [ -z $RULES_FILE ]; then
|
||||
RULES_FILE=$SOURCE/rules/falco_rules.yaml
|
||||
fi
|
||||
sudo FALCO_STATS_EXTRA_variant=$VARIANT FALCO_STATS_EXTRA_benchmark=$live_test $ROOT/userspace/falco/falco -c $SOURCE/falco.yaml -s $STATS_FILE -r $RULES_FILE --option=stdout_output.enabled=false > ./prog-output.txt -A 2>&1 &
|
||||
elif [[ $ROOT == *"sysdig"* ]]; then
|
||||
echo " starting sysdig..."
|
||||
sudo $ROOT/userspace/sysdig/sysdig -N -z evt.type=none &
|
||||
else
|
||||
echo " starting agent..."
|
||||
write_agent_config
|
||||
pushd $ROOT/userspace/dragent
|
||||
sudo ./dragent > ./prog-output.txt 2>&1 &
|
||||
popd
|
||||
fi
|
||||
|
||||
SUDO_PID=$!
|
||||
sleep 5
|
||||
if [[ $ROOT == *"agent"* ]]; then
|
||||
# The agent spawns several processes all below a main monitor
|
||||
# process. We want the child with the lowest pid.
|
||||
MON_PID=`ps -h -o pid --ppid $SUDO_PID`
|
||||
SUBJ_PID=`ps -h -o pid --ppid $MON_PID | head -1`
|
||||
else
|
||||
SUBJ_PID=`ps -h -o pid --ppid $SUDO_PID`
|
||||
fi
|
||||
|
||||
if [ -z $SUBJ_PID ]; then
|
||||
echo "Could not find pid of subject program--did it start successfully? Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function run_htop() {
|
||||
screen -S htop-screen -d -m /usr/bin/htop -d2
|
||||
sleep 90
|
||||
screen -X -S htop-screen quit
|
||||
}
|
||||
|
||||
function run_juttle_examples() {
|
||||
pushd $SCRIPTDIR/../../juttle-engine/examples
|
||||
docker-compose -f dc-juttle-engine.yml -f aws-cloudwatch/dc-aws-cloudwatch.yml -f elastic-newstracker/dc-elastic.yml -f github-tutorial/dc-elastic.yml -f nginx_logs/dc-nginx-logs.yml -f postgres-diskstats/dc-postgres.yml -f cadvisor-influx/dc-cadvisor-influx.yml up -d
|
||||
sleep 120
|
||||
docker-compose -f dc-juttle-engine.yml -f aws-cloudwatch/dc-aws-cloudwatch.yml -f elastic-newstracker/dc-elastic.yml -f github-tutorial/dc-elastic.yml -f nginx_logs/dc-nginx-logs.yml -f postgres-diskstats/dc-postgres.yml -f cadvisor-influx/dc-cadvisor-influx.yml stop
|
||||
docker-compose -f dc-juttle-engine.yml -f aws-cloudwatch/dc-aws-cloudwatch.yml -f elastic-newstracker/dc-elastic.yml -f github-tutorial/dc-elastic.yml -f nginx_logs/dc-nginx-logs.yml -f postgres-diskstats/dc-postgres.yml -f cadvisor-influx/dc-cadvisor-influx.yml rm -fv
|
||||
popd
|
||||
}
|
||||
|
||||
function run_kubernetes_demo() {
|
||||
pushd $SCRIPTDIR/../../infrastructure/test-infrastructures/kubernetes-demo
|
||||
sudo bash run-local.sh
|
||||
sudo bash init.sh
|
||||
sleep 600
|
||||
docker stop $(docker ps -qa)
|
||||
docker rm -fv $(docker ps -qa)
|
||||
popd
|
||||
}
|
||||
|
||||
function run_live_test() {
|
||||
|
||||
live_test="$1"
|
||||
|
||||
echo "Running live test $live_test"
|
||||
|
||||
case "$live_test" in
|
||||
htop ) CPU_INTERVAL=2;;
|
||||
* ) CPU_INTERVAL=10;;
|
||||
esac
|
||||
|
||||
start_subject_prog
|
||||
start_monitor_cpu_usage
|
||||
|
||||
echo " starting live program and waiting for it to finish"
|
||||
case "$live_test" in
|
||||
htop ) run_htop ;;
|
||||
juttle-examples ) run_juttle_examples ;;
|
||||
kube-demo ) run_kubernetes_demo ;;
|
||||
* ) usage; cleanup; exit 1 ;;
|
||||
esac
|
||||
|
||||
cleanup
|
||||
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
|
||||
if [ -n "$SUBJ_PID" ] ; then
|
||||
echo " stopping falco/sysdig program $SUBJ_PID"
|
||||
sudo kill $SUBJ_PID
|
||||
fi
|
||||
|
||||
if [ -n "$CPU_PID" ] ; then
|
||||
echo " stopping cpu monitor program $CPU_PID"
|
||||
kill -- -$CPU_PID
|
||||
fi
|
||||
}
|
||||
|
||||
run_live_tests() {
|
||||
test="$1"
|
||||
|
||||
if [ $test == "all" ]; then
|
||||
tests="htop juttle-examples kube-demo"
|
||||
else
|
||||
tests=$test
|
||||
fi
|
||||
|
||||
for test in $tests; do
|
||||
run_live_test $test
|
||||
done
|
||||
}
|
||||
|
||||
function run_phoronix_test() {
|
||||
|
||||
live_test="$1"
|
||||
|
||||
case "$live_test" in
|
||||
pts/aio-stress | pts/fs-mark | pts/iozone | pts/network-loopback | pts/nginx | pts/pybench | pts/redis | pts/sqlite | pts/unpack-linux ) CPU_INTERVAL=2;;
|
||||
* ) CPU_INTERVAL=10;;
|
||||
esac
|
||||
|
||||
echo "Running phoronix test $live_test"
|
||||
|
||||
start_subject_prog
|
||||
start_monitor_cpu_usage
|
||||
|
||||
echo " starting phoronix test and waiting for it to finish"
|
||||
|
||||
TEST_RESULTS_NAME=$VARIANT FORCE_TIMES_TO_RUN=1 phoronix-test-suite default-run $live_test
|
||||
|
||||
cleanup
|
||||
|
||||
}
|
||||
|
||||
# To install and configure phoronix:
|
||||
# (redhat instructions, adapt as necessary for ubuntu or other distros)
|
||||
# - install phoronix: yum install phoronix-test-suite.noarch
|
||||
# - install dependencies not handled by phoronix: yum install libaio-devel pcre-devel popt-devel glibc-static zlib-devel nc bc
|
||||
# - fix trivial bugs in tests:
|
||||
# - edit ~/.phoronix-test-suite/installed-tests/pts/network-loopback-1.0.1/network-loopback line "nc -d -l 9999 > /dev/null &" to "nc -d -l 9999 > /dev/null &"
|
||||
# - edit ~/.phoronix-test-suite/test-profiles/pts/nginx-1.1.0/test-definition.xml line "<Arguments>-n 500000 -c 100 http://localhost:8088/test.html</Arguments>" to "<Arguments>-n 500000 -c 100 http://127.0.0.1:8088/test.html</Arguments>"
|
||||
# - phoronix batch-install <test list below>
|
||||
|
||||
function run_phoronix_tests() {
|
||||
|
||||
test="$1"
|
||||
|
||||
if [ $test == "all" ]; then
|
||||
tests="pts/aio-stress pts/apache pts/blogbench pts/compilebench pts/dbench pts/fio pts/fs-mark pts/iozone pts/network-loopback pts/nginx pts/pgbench pts/phpbench pts/postmark pts/pybench pts/redis pts/sqlite pts/unpack-linux"
|
||||
else
|
||||
tests=$test
|
||||
fi
|
||||
|
||||
for test in $tests; do
|
||||
run_phoronix_test $test
|
||||
done
|
||||
}
|
||||
|
||||
run_tests() {
|
||||
|
||||
IFS=':' read -ra PARTS <<< "$TEST"
|
||||
|
||||
case "${PARTS[0]}" in
|
||||
trace ) run_trace "${PARTS[1]}" ;;
|
||||
live ) run_live_tests "${PARTS[1]}" ;;
|
||||
phoronix ) run_phoronix_tests "${PARTS[1]}" ;;
|
||||
* ) usage; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [options]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h/--help: show this help"
|
||||
echo " -v/--variant: a variant name to attach to this set of test results"
|
||||
echo " -r/--root: root directory containing falco/sysdig binaries (i.e. where you ran 'cmake')"
|
||||
echo " -s/--source: root directory containing falco/sysdig source code"
|
||||
echo " -R/--results: append test results to this file"
|
||||
echo " -S/--stats: append capture statistics to this file (only works for falco/test_mm)"
|
||||
echo " -o/--output: append program output to this file"
|
||||
echo " -U/--rules: path to rules file (only applicable for falco/test_mm)"
|
||||
echo " -t/--test: test to run. Argument has the following format:"
|
||||
echo " trace:<trace>: read the specified trace file."
|
||||
echo " trace:all means run all traces"
|
||||
echo " live:<live test>: run the specified live test."
|
||||
echo " live:all means run all live tests."
|
||||
echo " possible live tests:"
|
||||
echo " live:htop: run htop -d2"
|
||||
echo " live:kube-demo: run kubernetes demo from infrastructure repo"
|
||||
echo " live:juttle-examples: run a juttle demo environment based on docker-compose"
|
||||
echo " phoronix:<test>: run the specified phoronix test."
|
||||
echo " if <test> is not 'all', it is passed directly to the command line of \"phoronix-test-suite run <test>\""
|
||||
echo " if <test> is 'all', a built-in set of phoronix tests will be chosen and run"
|
||||
echo " -T/--tracedir: Look for trace files in this directory. If doesn't exist, will download trace files from s3"
|
||||
echo " -A/--agent-autodrop: When running an agent, whether or not to enable autodrop"
|
||||
echo " -F/--falco-agent: When running an agent, whether or not to enable falco"
|
||||
}
|
||||
|
||||
OPTS=`getopt -o hv:r:s:R:S:o:U:t:T: --long help,variant:,root:,source:,results:,stats:,output:,rules:,test:,tracedir:,agent-autodrop:,falco-agent: -n $0 -- "$@"`
|
||||
|
||||
if [ $? != 0 ]; then
|
||||
echo "Exiting" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eval set -- "$OPTS"
|
||||
|
||||
VARIANT="falco"
|
||||
ROOT=`dirname $0`/../build
|
||||
SOURCE=$ROOT
|
||||
SCRIPTDIR=`dirname $0`
|
||||
RESULTS_FILE=`dirname $0`/results.json
|
||||
STATS_FILE=`dirname $0`/capture_stats.json
|
||||
OUTPUT_FILE=`dirname $0`/program-output.txt
|
||||
RULES_FILE=
|
||||
TEST=trace:all
|
||||
TRACEDIR=/tmp/falco-perf-traces.$USER
|
||||
CPU_INTERVAL=10
|
||||
AGENT_AUTODROP=1
|
||||
FALCO_AGENT=1
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
-h | --help ) usage; exit 1;;
|
||||
-v | --variant ) VARIANT="$2"; shift 2;;
|
||||
-r | --root ) ROOT="$2"; shift 2;;
|
||||
-s | --source ) SOURCE="$2"; shift 2;;
|
||||
-R | --results ) RESULTS_FILE="$2"; shift 2;;
|
||||
-S | --stats ) STATS_FILE="$2"; shift 2;;
|
||||
-o | --output ) OUTPUT_FILE="$2"; shift 2;;
|
||||
-U | --rules ) RULES_FILE="$2"; shift 2;;
|
||||
-t | --test ) TEST="$2"; shift 2;;
|
||||
-T | --tracedir ) TRACEDIR="$2"; shift 2;;
|
||||
-A | --agent-autodrop ) AGENT_AUTODROP="$2"; shift 2;;
|
||||
-F | --falco-agent ) FALCO_AGENT="$2"; shift 2;;
|
||||
* ) break;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z $VARIANT ]; then
|
||||
echo "A test variant name must be provided. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $ROOT ]; then
|
||||
echo "A root directory containing a falco/sysdig binary must be provided. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROOT=`realpath $ROOT`
|
||||
|
||||
if [ -z $SOURCE ]; then
|
||||
echo "A source directory containing falco/sysdig source code. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE=`realpath $SOURCE`
|
||||
|
||||
if [ -z $RESULTS_FILE ]; then
|
||||
echo "An output file for test results must be provided. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $STATS_FILE ]; then
|
||||
echo "An output file for capture statistics must be provided. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $OUTPUT_FILE ]; then
|
||||
echo "An file for program output must be provided. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z $TEST ]; then
|
||||
echo "A test must be provided. Not continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run_tests
|
||||
@@ -20,6 +20,7 @@ set -euo pipefail
|
||||
SCRIPT=$(readlink -f $0)
|
||||
SCRIPTDIR=$(dirname "$SCRIPT")
|
||||
SKIP_PACKAGES_TESTS=${SKIP_PACKAGES_TESTS:-false}
|
||||
SKIP_PLUGINS_TESTS=${SKIP_PLUGINS_TESTS:-false}
|
||||
TRACE_FILES_BASE_URL=${TRACE_FILES_BASE_URL:-"https://download.falco.org/fixtures/trace-files/"}
|
||||
|
||||
# Trace file tarballs are now versioned. Any time a substantial change
|
||||
@@ -104,6 +105,10 @@ function run_tests() {
|
||||
if [ "$SKIP_PACKAGES_TESTS" = false ] ; then
|
||||
suites+=($SCRIPTDIR/falco_tests_package.yaml)
|
||||
fi
|
||||
|
||||
if [ "$SKIP_PLUGINS_TESTS" = false ] ; then
|
||||
suites+=($SCRIPTDIR/falco_tests_plugins.yaml)
|
||||
fi
|
||||
|
||||
XUNIT_DIR="${OPT_BUILD_DIR}/integration-tests-xunit"
|
||||
mkdir -p "${XUNIT_DIR}"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
add_subdirectory(k8s_audit)
|
||||
add_subdirectory(psp)
|
||||
add_subdirectory(plugins)
|
||||
|
||||
# Note: list of traces is created at cmake time, not build time
|
||||
file(GLOB test_trace_files
|
||||
@@ -16,4 +17,4 @@ foreach(trace_file_path ${test_trace_files})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(trace-files-base-scap ALL)
|
||||
add_dependencies(trace-files-base-scap ${BASE_SCAP_TRACE_FILES_TARGETS})
|
||||
add_dependencies(trace-files-base-scap ${BASE_SCAP_TRACE_FILES_TARGETS})
|
||||
|
||||
1
test/trace_files/k8s_audit/fal_01_003.json
Normal file
1
test/trace_files/k8s_audit/fal_01_003.json
Normal file
@@ -0,0 +1 @@
|
||||
{"kind": 0}
|
||||
16
test/trace_files/plugins/CMakeLists.txt
Normal file
16
test/trace_files/plugins/CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
# Note: list of traces is created at cmake time, not build time
|
||||
file(GLOB test_trace_files
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.json")
|
||||
|
||||
foreach(trace_file_path ${test_trace_files})
|
||||
get_filename_component(trace_file ${trace_file_path} NAME)
|
||||
add_custom_target(test-trace-${trace_file} ALL
|
||||
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${trace_file})
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${trace_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${trace_file_path} ${CMAKE_CURRENT_BINARY_DIR}/${trace_file}
|
||||
DEPENDS ${trace_file_path})
|
||||
list(APPEND PLUGINS_TRACE_FILES_TARGETS test-trace-${trace_file})
|
||||
endforeach()
|
||||
|
||||
add_custom_target(trace-files-plugins ALL)
|
||||
add_dependencies(trace-files-plugins ${PLUGINS_TRACE_FILES_TARGETS})
|
||||
31
test/trace_files/plugins/alice_start_instances.json
Normal file
31
test/trace_files/plugins/alice_start_instances.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{"Records": [{
|
||||
"eventVersion": "1.0",
|
||||
"userIdentity": {
|
||||
"type": "IAMUser",
|
||||
"principalId": "EX_PRINCIPAL_ID",
|
||||
"arn": "arn:aws:iam::123456789012:user/Alice",
|
||||
"accessKeyId": "EXAMPLE_KEY_ID",
|
||||
"accountId": "123456789012",
|
||||
"userName": "Alice"
|
||||
},
|
||||
"eventTime": "2014-03-06T21:22:54Z",
|
||||
"eventSource": "ec2.amazonaws.com",
|
||||
"eventType": "AwsApiCall",
|
||||
"eventName": "StartInstances",
|
||||
"awsRegion": "us-east-2",
|
||||
"sourceIPAddress": "205.251.233.176",
|
||||
"userAgent": "ec2-api-tools 1.6.12.2",
|
||||
"requestParameters": {"instancesSet": {"items": [{"instanceId": "i-ebeaf9e2"}]}},
|
||||
"responseElements": {"instancesSet": {"items": [{
|
||||
"instanceId": "i-ebeaf9e2",
|
||||
"currentState": {
|
||||
"code": 0,
|
||||
"name": "pending"
|
||||
},
|
||||
"previousState": {
|
||||
"code": 80,
|
||||
"name": "stopped"
|
||||
}
|
||||
}]}}
|
||||
}]}
|
||||
|
||||
32
test/trace_files/plugins/alice_start_instances_bigevent.json
Normal file
32
test/trace_files/plugins/alice_start_instances_bigevent.json
Normal file
File diff suppressed because one or more lines are too long
@@ -15,12 +15,25 @@
|
||||
# the License.
|
||||
#
|
||||
if(MINIMAL_BUILD)
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp engine/test_falco_utils.cpp)
|
||||
set(
|
||||
FALCO_TESTS_SOURCES
|
||||
test_base.cpp
|
||||
engine/test_rulesets.cpp
|
||||
engine/test_falco_utils.cpp
|
||||
falco/test_configuration.cpp
|
||||
)
|
||||
else()
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp engine/test_falco_utils.cpp falco/test_webserver.cpp)
|
||||
set(
|
||||
FALCO_TESTS_SOURCES
|
||||
test_base.cpp
|
||||
engine/test_rulesets.cpp
|
||||
engine/test_falco_utils.cpp
|
||||
falco/test_configuration.cpp
|
||||
falco/test_webserver.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
set(FALCO_TESTED_LIBRARIES falco_engine)
|
||||
set(FALCO_TESTED_LIBRARIES falco_engine ${YAMLCPP_LIB})
|
||||
|
||||
SET(FALCO_TESTS_ARGUMENTS "" CACHE STRING "Test arguments to pass to the Falco test suite")
|
||||
|
||||
@@ -46,6 +59,7 @@ if(FALCO_BUILD_TESTS)
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||
else()
|
||||
@@ -54,6 +68,7 @@ if(FALCO_BUILD_TESTS)
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||
|
||||
@@ -25,15 +25,25 @@ static uint16_t default_ruleset = 0;
|
||||
static uint16_t non_default_ruleset = 3;
|
||||
static uint16_t other_non_default_ruleset = 2;
|
||||
static std::set<std::string> tags = {"some_tag", "some_other_tag"};
|
||||
static std::set<uint32_t> event_tags = {1};
|
||||
|
||||
static std::shared_ptr<gen_event_filter> create_filter()
|
||||
{
|
||||
// The actual contents of the filters don't matter here.
|
||||
sinsp_filter_compiler compiler(NULL, "evt.type=open");
|
||||
sinsp_filter *f = compiler.compile();
|
||||
|
||||
std::shared_ptr<gen_event_filter> ret(f);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TEST_CASE("Should enable/disable for exact match w/ default ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("one_rule", exact_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -45,10 +55,10 @@ TEST_CASE("Should enable/disable for exact match w/ default ruleset", "[rulesets
|
||||
TEST_CASE("Should enable/disable for exact match w/ specific ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("one_rule", exact_match, enabled, non_default_ruleset);
|
||||
REQUIRE(r.num_rules_for_ruleset(non_default_ruleset) == 1);
|
||||
@@ -64,10 +74,10 @@ TEST_CASE("Should enable/disable for exact match w/ specific ruleset", "[ruleset
|
||||
TEST_CASE("Should not enable for exact match different rule name", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("some_other_rule", exact_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 0);
|
||||
@@ -76,10 +86,10 @@ TEST_CASE("Should not enable for exact match different rule name", "[rulesets]")
|
||||
TEST_CASE("Should enable/disable for exact match w/ substring and default ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("one_rule", substring_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -91,10 +101,10 @@ TEST_CASE("Should enable/disable for exact match w/ substring and default rulese
|
||||
TEST_CASE("Should not enable for substring w/ exact_match", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("one_", exact_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 0);
|
||||
@@ -103,10 +113,10 @@ TEST_CASE("Should not enable for substring w/ exact_match", "[rulesets]")
|
||||
TEST_CASE("Should enable/disable for prefix match w/ default ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("one_", substring_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -118,10 +128,10 @@ TEST_CASE("Should enable/disable for prefix match w/ default ruleset", "[ruleset
|
||||
TEST_CASE("Should enable/disable for suffix match w/ default ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("_rule", substring_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -133,10 +143,10 @@ TEST_CASE("Should enable/disable for suffix match w/ default ruleset", "[ruleset
|
||||
TEST_CASE("Should enable/disable for substring match w/ default ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("ne_ru", substring_match, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -148,10 +158,10 @@ TEST_CASE("Should enable/disable for substring match w/ default ruleset", "[rule
|
||||
TEST_CASE("Should enable/disable for substring match w/ specific ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable("ne_ru", substring_match, enabled, non_default_ruleset);
|
||||
REQUIRE(r.num_rules_for_ruleset(non_default_ruleset) == 1);
|
||||
@@ -167,11 +177,11 @@ TEST_CASE("Should enable/disable for substring match w/ specific ruleset", "[rul
|
||||
TEST_CASE("Should enable/disable for tags w/ default ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
std::set<std::string> want_tags = {"some_tag"};
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable_tags(want_tags, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -183,11 +193,11 @@ TEST_CASE("Should enable/disable for tags w/ default ruleset", "[rulesets]")
|
||||
TEST_CASE("Should enable/disable for tags w/ specific ruleset", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
std::set<std::string> want_tags = {"some_tag"};
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable_tags(want_tags, enabled, non_default_ruleset);
|
||||
REQUIRE(r.num_rules_for_ruleset(non_default_ruleset) == 1);
|
||||
@@ -203,11 +213,11 @@ TEST_CASE("Should enable/disable for tags w/ specific ruleset", "[rulesets]")
|
||||
TEST_CASE("Should not enable for different tags", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
std::set<std::string> want_tags = {"some_different_tag"};
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable_tags(want_tags, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(non_default_ruleset) == 0);
|
||||
@@ -216,11 +226,11 @@ TEST_CASE("Should not enable for different tags", "[rulesets]")
|
||||
TEST_CASE("Should enable/disable for overlapping tags", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> filter = create_filter();
|
||||
string rule_name = "one_rule";
|
||||
std::set<std::string> want_tags = {"some_tag", "some_different_tag"};
|
||||
|
||||
r.add(rule_name, tags, event_tags, filter);
|
||||
r.add(rule_name, tags, filter);
|
||||
|
||||
r.enable_tags(want_tags, enabled);
|
||||
REQUIRE(r.num_rules_for_ruleset(default_ruleset) == 1);
|
||||
@@ -232,15 +242,15 @@ TEST_CASE("Should enable/disable for overlapping tags", "[rulesets]")
|
||||
TEST_CASE("Should enable/disable for incremental adding tags", "[rulesets]")
|
||||
{
|
||||
falco_ruleset r;
|
||||
gen_event_filter *rule1_filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> rule1_filter = create_filter();
|
||||
string rule1_name = "one_rule";
|
||||
std::set<std::string> rule1_tags = {"rule1_tag"};
|
||||
r.add(rule1_name, rule1_tags, event_tags, rule1_filter);
|
||||
r.add(rule1_name, rule1_tags, rule1_filter);
|
||||
|
||||
gen_event_filter *rule2_filter = new gen_event_filter();
|
||||
std::shared_ptr<gen_event_filter> rule2_filter = create_filter();
|
||||
string rule2_name = "two_rule";
|
||||
std::set<std::string> rule2_tags = {"rule2_tag"};
|
||||
r.add(rule2_name, rule2_tags, event_tags, rule2_filter);
|
||||
r.add(rule2_name, rule2_tags, rule2_filter);
|
||||
|
||||
std::set<std::string> want_tags;
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2019 The Falco 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.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "token_bucket.h"
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace Catch::literals;
|
||||
|
||||
TEST_CASE("token bucket default ctor", "[token_bucket]")
|
||||
{
|
||||
auto tb = std::make_shared<token_bucket>();
|
||||
|
||||
REQUIRE(tb->get_tokens() == 1);
|
||||
|
||||
SECTION("initialising with specific time, rate 2 tokens/sec")
|
||||
{
|
||||
auto max = 2.0;
|
||||
uint64_t now = 1;
|
||||
tb->init(1.0, max, now);
|
||||
REQUIRE(tb->get_last_seen() == now);
|
||||
REQUIRE(tb->get_tokens() == max);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket ctor with custom timer", "[token_bucket]")
|
||||
{
|
||||
auto t = []() -> uint64_t { return 22; };
|
||||
auto tb = std::make_shared<token_bucket>(t);
|
||||
|
||||
REQUIRE(tb->get_tokens() == 1);
|
||||
REQUIRE(tb->get_last_seen() == 22);
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket with 2 tokens/sec rate, max 10 tokens", "[token_bucket]")
|
||||
{
|
||||
auto tb = std::make_shared<token_bucket>();
|
||||
tb->init(2.0, 10, 1);
|
||||
|
||||
SECTION("claiming 5 tokens")
|
||||
{
|
||||
bool claimed = tb->claim(5, 1000000001);
|
||||
REQUIRE(tb->get_last_seen() == 1000000001);
|
||||
REQUIRE(tb->get_tokens() == 5.0_a);
|
||||
REQUIRE(claimed);
|
||||
|
||||
SECTION("claiming all the 7 remaining tokens")
|
||||
{
|
||||
bool claimed = tb->claim(7, 2000000001);
|
||||
REQUIRE(tb->get_last_seen() == 2000000001);
|
||||
REQUIRE(tb->get_tokens() == 0.0_a);
|
||||
REQUIRE(claimed);
|
||||
|
||||
SECTION("claiming 1 token more than the 2 available fails")
|
||||
{
|
||||
bool claimed = tb->claim(3, 3000000001);
|
||||
REQUIRE(tb->get_last_seen() == 3000000001);
|
||||
REQUIRE(tb->get_tokens() == 2.0_a);
|
||||
REQUIRE_FALSE(claimed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket default initialization", "[token_bucket]")
|
||||
{
|
||||
token_bucket tb;
|
||||
REQUIRE(tb.get_tokens() == 1);
|
||||
}
|
||||
106
tests/falco/test_configuration.cpp
Normal file
106
tests/falco/test_configuration.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright (C) 2021 The Falco 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.
|
||||
*/
|
||||
#include "configuration.h"
|
||||
#include <catch.hpp>
|
||||
|
||||
string sample_yaml =
|
||||
"base_value:\n"
|
||||
" id: 1\n"
|
||||
" name: 'sample_name'\n"
|
||||
" subvalue:\n"
|
||||
" subvalue2:\n"
|
||||
" boolean: true\n"
|
||||
"base_value_2:\n"
|
||||
" sample_list:\n"
|
||||
" - elem1\n"
|
||||
" - elem2\n"
|
||||
" - elem3\n"
|
||||
;
|
||||
|
||||
TEST_CASE("configuration must load YAML data", "[configuration]")
|
||||
{
|
||||
yaml_configuration conf;
|
||||
|
||||
SECTION("broken YAML")
|
||||
{
|
||||
string sample_broken_yaml = sample_yaml + " / bad_symbol";
|
||||
REQUIRE_THROWS(conf.load_from_string(sample_broken_yaml));
|
||||
}
|
||||
|
||||
SECTION("valid YAML")
|
||||
{
|
||||
REQUIRE_NOTHROW(conf.load_from_string(sample_yaml));
|
||||
}
|
||||
|
||||
SECTION("clearing and reloading")
|
||||
{
|
||||
conf.load_from_string(sample_yaml);
|
||||
REQUIRE(conf.is_defined("base_value") == true);
|
||||
conf.clear();
|
||||
REQUIRE(conf.is_defined("base_value") == false);
|
||||
conf.load_from_string(sample_yaml);
|
||||
REQUIRE(conf.is_defined("base_value") == true);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("configuration must read YAML fields", "[configuration]")
|
||||
{
|
||||
yaml_configuration conf;
|
||||
conf.load_from_string(sample_yaml);
|
||||
|
||||
SECTION("base level")
|
||||
{
|
||||
REQUIRE(conf.is_defined("base_value") == true);
|
||||
REQUIRE(conf.is_defined("base_value_2") == true);
|
||||
REQUIRE(conf.is_defined("unknown_base_value") == false);
|
||||
}
|
||||
|
||||
SECTION("arbitrary depth nesting")
|
||||
{
|
||||
REQUIRE(conf.get_scalar<int>("base_value.id", -1) == 1);
|
||||
REQUIRE(conf.get_scalar<string>("base_value.name", "none") == "sample_name");
|
||||
REQUIRE(conf.get_scalar<bool>("base_value.subvalue.subvalue2.boolean", false) == true);
|
||||
}
|
||||
|
||||
SECTION("list field elements")
|
||||
{
|
||||
REQUIRE(conf.get_scalar<string>("base_value_2.sample_list[0]", "none") == "elem1");
|
||||
REQUIRE(conf.get_scalar<string>("base_value_2.sample_list[1]", "none") == "elem2");
|
||||
REQUIRE(conf.get_scalar<string>("base_value_2.sample_list[2]", "none") == "elem3");
|
||||
}
|
||||
|
||||
SECTION("sequence")
|
||||
{
|
||||
vector<string> seq;
|
||||
conf.get_sequence(seq, "base_value_2.sample_list");
|
||||
REQUIRE(seq.size() == 3);
|
||||
REQUIRE(seq[0] == "elem1");
|
||||
REQUIRE(seq[1] == "elem2");
|
||||
REQUIRE(seq[2] == "elem3");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("configuration must modify YAML fields", "[configuration]")
|
||||
{
|
||||
string key = "base_value.subvalue.subvalue2.boolean";
|
||||
yaml_configuration conf;
|
||||
conf.load_from_string(sample_yaml);
|
||||
REQUIRE(conf.get_scalar<bool>(key, false) == true);
|
||||
conf.set_scalar<bool>(key, false);
|
||||
REQUIRE(conf.get_scalar<bool>(key, true) == false);
|
||||
conf.set_scalar<bool>(key, true);
|
||||
REQUIRE(conf.get_scalar<bool>(key, false) == true);
|
||||
}
|
||||
@@ -10,6 +10,8 @@
|
||||
# "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.
|
||||
|
||||
add_subdirectory(lua)
|
||||
|
||||
set(FALCO_ENGINE_SOURCE_FILES
|
||||
rules.cpp
|
||||
falco_common.cpp
|
||||
@@ -17,7 +19,6 @@ set(FALCO_ENGINE_SOURCE_FILES
|
||||
falco_utils.cpp
|
||||
json_evt.cpp
|
||||
ruleset.cpp
|
||||
token_bucket.cpp
|
||||
formats.cpp)
|
||||
|
||||
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
|
||||
@@ -35,10 +36,10 @@ if(MINIMAL_BUILD)
|
||||
"${NJSON_INCLUDE}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
"${LIBSCAP_INCLUDE_DIRS}"
|
||||
"${LIBSINSP_INCLUDE_DIRS}"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine/lua")
|
||||
else()
|
||||
target_include_directories(
|
||||
falco_engine
|
||||
@@ -48,27 +49,13 @@ else()
|
||||
"${CURL_INCLUDE_DIR}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${STRING_VIEW_LITE_INCLUDE}"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
|
||||
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
"${LIBSCAP_INCLUDE_DIRS}"
|
||||
"${LIBSINSP_INCLUDE_DIRS}"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine/lua")
|
||||
endif()
|
||||
|
||||
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}")
|
||||
target_link_libraries(falco_engine "${FALCO_SINSP_LIBRARY}" "${LPEG_LIB}" "${LYAML_LIB}" "${LIBYAML_LIB}" luafiles)
|
||||
|
||||
configure_file(config_falco_engine.h.in config_falco_engine.h)
|
||||
|
||||
if(DEFINED FALCO_COMPONENT)
|
||||
install(
|
||||
DIRECTORY lua
|
||||
DESTINATION "${FALCO_SHARE_DIR}"
|
||||
COMPONENT "${FALCO_COMPONENT}"
|
||||
FILES_MATCHING
|
||||
PATTERN *.lua)
|
||||
else()
|
||||
install(
|
||||
DIRECTORY lua
|
||||
DESTINATION "${FALCO_SHARE_DIR}"
|
||||
FILES_MATCHING
|
||||
PATTERN *.lua)
|
||||
endif()
|
||||
|
||||
@@ -19,6 +19,7 @@ limitations under the License.
|
||||
#include "config_falco_engine.h"
|
||||
#include "falco_common.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
#include "falco_engine_lua_files.hh"
|
||||
|
||||
std::vector<std::string> falco_common::priority_names = {
|
||||
"Emergency",
|
||||
@@ -48,73 +49,33 @@ falco_common::~falco_common()
|
||||
}
|
||||
}
|
||||
|
||||
void falco_common::set_inspector(sinsp *inspector)
|
||||
void falco_common::init()
|
||||
{
|
||||
m_inspector = inspector;
|
||||
}
|
||||
|
||||
void falco_common::init(const char *lua_main_filename, const char *alternate_lua_dir)
|
||||
{
|
||||
ifstream is;
|
||||
string lua_dir = FALCO_ENGINE_LUA_DIR;
|
||||
string lua_main_path = lua_dir + lua_main_filename;
|
||||
|
||||
is.open(lua_main_path);
|
||||
if (!is.is_open())
|
||||
// Strings in the list lua_module_strings need to be loaded as
|
||||
// lua modules, which also involves adding them to the
|
||||
// package.module table.
|
||||
for(const auto &pair : lua_module_strings)
|
||||
{
|
||||
lua_dir = alternate_lua_dir;
|
||||
lua_main_path = lua_dir + lua_main_filename;
|
||||
lua_getglobal(m_ls, "package");
|
||||
lua_getfield(m_ls, -1, "preload");
|
||||
|
||||
is.open(lua_main_path);
|
||||
if (!is.is_open())
|
||||
if(luaL_loadstring(m_ls, pair.first))
|
||||
{
|
||||
throw falco_exception("Could not find Falco Lua entrypoint (tried " +
|
||||
string(FALCO_ENGINE_LUA_DIR) + lua_main_filename + ", " +
|
||||
string(alternate_lua_dir) + lua_main_filename + ")");
|
||||
throw falco_exception("Failed to load embedded lua code " +
|
||||
string(pair.second) + ": " + lua_tostring(m_ls, -1));
|
||||
}
|
||||
|
||||
lua_setfield(m_ls, -2, pair.second);
|
||||
}
|
||||
|
||||
// Strings in the list lua_code_strings need to be loaded and
|
||||
// evaluated so any public functions can be directly called.
|
||||
for(const auto &str : lua_code_strings)
|
||||
{
|
||||
if(luaL_loadstring(m_ls, str) || lua_pcall(m_ls, 0, 0, 0))
|
||||
{
|
||||
throw falco_exception("Failed to load + evaluate embedded lua code " +
|
||||
string(str) + ": " + lua_tostring(m_ls, -1));
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize Lua interpreter
|
||||
add_lua_path(lua_dir);
|
||||
|
||||
// Load the main program, which defines all the available functions.
|
||||
string scriptstr((istreambuf_iterator<char>(is)),
|
||||
istreambuf_iterator<char>());
|
||||
|
||||
if(luaL_loadstring(m_ls, scriptstr.c_str()) || lua_pcall(m_ls, 0, 0, 0))
|
||||
{
|
||||
throw falco_exception("Failed to load script " +
|
||||
lua_main_path + ": " + lua_tostring(m_ls, -1));
|
||||
}
|
||||
}
|
||||
|
||||
void falco_common::add_lua_path(string &path)
|
||||
{
|
||||
string cpath = string(path);
|
||||
path += "?.lua";
|
||||
cpath += "?.so";
|
||||
|
||||
lua_getglobal(m_ls, "package");
|
||||
|
||||
lua_getfield(m_ls, -1, "path");
|
||||
string cur_path = lua_tostring(m_ls, -1 );
|
||||
cur_path += ';';
|
||||
lua_pop(m_ls, 1);
|
||||
|
||||
cur_path.append(path.c_str());
|
||||
|
||||
lua_pushstring(m_ls, cur_path.c_str());
|
||||
lua_setfield(m_ls, -2, "path");
|
||||
|
||||
lua_getfield(m_ls, -1, "cpath");
|
||||
string cur_cpath = lua_tostring(m_ls, -1 );
|
||||
cur_cpath += ';';
|
||||
lua_pop(m_ls, 1);
|
||||
|
||||
cur_cpath.append(cpath.c_str());
|
||||
|
||||
lua_pushstring(m_ls, cur_cpath.c_str());
|
||||
lua_setfield(m_ls, -2, "cpath");
|
||||
|
||||
lua_pop(m_ls, 1);
|
||||
}
|
||||
|
||||
@@ -69,9 +69,7 @@ public:
|
||||
falco_common();
|
||||
virtual ~falco_common();
|
||||
|
||||
void init(const char *lua_main_filename, const char *alternate_lua_dir);
|
||||
|
||||
void set_inspector(sinsp *inspector);
|
||||
void init();
|
||||
|
||||
// Priority levels, as a vector of strings
|
||||
static std::vector<std::string> priority_names;
|
||||
@@ -93,9 +91,4 @@ protected:
|
||||
lua_State *m_ls;
|
||||
|
||||
std::mutex m_ls_semaphore;
|
||||
|
||||
sinsp *m_inspector;
|
||||
|
||||
private:
|
||||
void add_lua_path(std::string &path);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -19,6 +19,9 @@ limitations under the License.
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include <sinsp.h>
|
||||
#include <plugin.h>
|
||||
|
||||
#include "falco_engine.h"
|
||||
#include "falco_utils.h"
|
||||
#include "falco_engine_version.h"
|
||||
@@ -37,13 +40,12 @@ extern "C" {
|
||||
|
||||
string lua_on_event = "on_event";
|
||||
string lua_print_stats = "print_stats";
|
||||
const std::string falco_engine::s_default_ruleset = "falco-default-ruleset";
|
||||
|
||||
using namespace std;
|
||||
|
||||
nlohmann::json::json_pointer falco_engine::k8s_audit_time = "/stageTimestamp"_json_pointer;
|
||||
|
||||
falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
|
||||
: m_rules(NULL), m_next_ruleset_id(0),
|
||||
: m_next_ruleset_id(0),
|
||||
m_min_priority(falco_common::PRIORITY_DEBUG),
|
||||
m_sampling_ratio(1), m_sampling_multiplier(0),
|
||||
m_replace_container_info(false)
|
||||
@@ -51,29 +53,21 @@ falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
|
||||
luaopen_lpeg(m_ls);
|
||||
luaopen_yaml(m_ls);
|
||||
|
||||
falco_common::init(m_lua_main_filename.c_str(), alternate_lua_dir.c_str());
|
||||
falco_common::init();
|
||||
falco_rules::init(m_ls);
|
||||
|
||||
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||
m_k8s_audit_rules.reset(new falco_ruleset());
|
||||
m_required_plugin_versions.clear();
|
||||
|
||||
if(seed_rng)
|
||||
{
|
||||
srandom((unsigned) getpid());
|
||||
}
|
||||
|
||||
m_default_ruleset_id = find_ruleset_id(m_default_ruleset);
|
||||
|
||||
// Create this now so we can potentially list filters and exit
|
||||
m_json_factory = make_shared<json_event_filter_factory>();
|
||||
m_default_ruleset_id = find_ruleset_id(s_default_ruleset);
|
||||
}
|
||||
|
||||
falco_engine::~falco_engine()
|
||||
{
|
||||
if (m_rules)
|
||||
{
|
||||
delete m_rules;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t falco_engine::engine_version()
|
||||
@@ -81,65 +75,70 @@ uint32_t falco_engine::engine_version()
|
||||
return (uint32_t) FALCO_ENGINE_VERSION;
|
||||
}
|
||||
|
||||
#define DESCRIPTION_TEXT_START 16
|
||||
|
||||
#define CONSOLE_LINE_LEN 79
|
||||
|
||||
void falco_engine::list_fields(bool names_only)
|
||||
// Return a key that uniquely represents a field class.
|
||||
// For now, we assume name + shortdesc is unique.
|
||||
static std::string fieldclass_key(const gen_event_filter_factory::filter_fieldclass_info &fld_info)
|
||||
{
|
||||
for(auto &chk_field : json_factory().get_fields())
|
||||
return fld_info.name + fld_info.shortdesc;
|
||||
}
|
||||
|
||||
void falco_engine::list_fields(std::string &source, bool verbose, bool names_only)
|
||||
{
|
||||
// Maps from field class name + short desc to list of event
|
||||
// sources for which this field class can be used.
|
||||
std::map<std::string,std::set<std::string>> fieldclass_event_sources;
|
||||
|
||||
// Do a first pass to group together classes that are
|
||||
// applicable to multiple event sources.
|
||||
for(auto &it : m_filter_factories)
|
||||
{
|
||||
if(!names_only)
|
||||
if(source != "" && source != it.first)
|
||||
{
|
||||
printf("\n----------------------\n");
|
||||
printf("Field Class: %s (%s)\n\n", chk_field.m_name.c_str(), chk_field.m_desc.c_str());
|
||||
if(chk_field.m_class_info != "")
|
||||
{
|
||||
std::string str = falco::utils::wrap_text(chk_field.m_class_info, 0, 0, CONSOLE_LINE_LEN);
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for(auto &field : chk_field.m_fields)
|
||||
for(auto &fld_class : it.second->get_fields())
|
||||
{
|
||||
printf("%s", field.m_name.c_str());
|
||||
fieldclass_event_sources[fieldclass_key(fld_class)].insert(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
if(names_only)
|
||||
// The set of field classes already printed. Used to avoid
|
||||
// printing field classes multiple times for different sources
|
||||
std::set<std::string> seen_fieldclasses;
|
||||
|
||||
// In the second pass, actually print info, skipping duplicate
|
||||
// field classes and also printing info on supported sources.
|
||||
for(auto &it : m_filter_factories)
|
||||
{
|
||||
if(source != "" && source != it.first)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for(auto &fld_class : it.second->get_fields())
|
||||
{
|
||||
std::string key = fieldclass_key(fld_class);
|
||||
|
||||
if(seen_fieldclasses.find(key) != seen_fieldclasses.end())
|
||||
{
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
uint32_t namelen = field.m_name.size();
|
||||
|
||||
if(namelen >= DESCRIPTION_TEXT_START)
|
||||
seen_fieldclasses.insert(key);
|
||||
|
||||
if(!names_only)
|
||||
{
|
||||
printf("\n");
|
||||
namelen = 0;
|
||||
printf("%s\n", fld_class.as_string(verbose,
|
||||
fieldclass_event_sources[fieldclass_key(fld_class)]).c_str());
|
||||
}
|
||||
|
||||
for(uint32_t l = 0; l < DESCRIPTION_TEXT_START - namelen; l++)
|
||||
else
|
||||
{
|
||||
printf(" ");
|
||||
for(auto &field : fld_class.fields)
|
||||
{
|
||||
printf("%s\n", field.name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string desc = field.m_desc;
|
||||
switch(field.m_idx_mode)
|
||||
{
|
||||
case json_event_filter_check::IDX_REQUIRED:
|
||||
case json_event_filter_check::IDX_ALLOWED:
|
||||
desc += " (";
|
||||
desc += json_event_filter_check::s_index_mode_strs[field.m_idx_mode];
|
||||
desc += ", ";
|
||||
desc += json_event_filter_check::s_index_type_strs[field.m_idx_type];
|
||||
desc += ")";
|
||||
break;
|
||||
case json_event_filter_check::IDX_NONE:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
std::string str = falco::utils::wrap_text(desc, namelen, DESCRIPTION_TEXT_START, CONSOLE_LINE_LEN);
|
||||
printf("%s\n", str.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,33 +152,18 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
||||
|
||||
void falco_engine::load_rules(const string &rules_content, bool verbose, bool all_events, uint64_t &required_engine_version)
|
||||
{
|
||||
// The engine must have been given an inspector by now.
|
||||
if(! m_inspector)
|
||||
{
|
||||
throw falco_exception("No inspector provided");
|
||||
}
|
||||
|
||||
if(!m_sinsp_factory)
|
||||
{
|
||||
m_sinsp_factory = make_shared<sinsp_filter_factory>(m_inspector);
|
||||
}
|
||||
|
||||
if(!m_rules)
|
||||
{
|
||||
m_rules = new falco_rules(m_inspector,
|
||||
this,
|
||||
m_ls);
|
||||
m_rules.reset(new falco_rules(this,
|
||||
m_ls));
|
||||
|
||||
for(auto const &it : m_filter_factories)
|
||||
{
|
||||
m_rules->add_filter_factory(it.first, it.second);
|
||||
}
|
||||
}
|
||||
|
||||
// Note that falco_formats is added to the lua state used
|
||||
// by the falco engine only. Within the engine, only
|
||||
// formats.formatter is used, so we can unconditionally set
|
||||
// json_output to false.
|
||||
bool json_output = false;
|
||||
bool json_include_output_property = false;
|
||||
falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property);
|
||||
|
||||
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version);
|
||||
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version, m_required_plugin_versions);
|
||||
}
|
||||
|
||||
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
|
||||
@@ -212,13 +196,10 @@ void falco_engine::enable_rule(const string &substring, bool enabled, const stri
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
bool match_exact = false;
|
||||
|
||||
m_sinsp_rules->enable(substring, match_exact, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable(substring, match_exact, enabled, ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule(const string &substring, bool enabled)
|
||||
{
|
||||
enable_rule(substring, enabled, m_default_ruleset);
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
it.second->enable(substring, match_exact, enabled, ruleset_id);
|
||||
}
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule_exact(const string &rule_name, bool enabled, const string &ruleset)
|
||||
@@ -226,26 +207,20 @@ void falco_engine::enable_rule_exact(const string &rule_name, bool enabled, cons
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
bool match_exact = true;
|
||||
|
||||
m_sinsp_rules->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule_exact(const string &rule_name, bool enabled)
|
||||
{
|
||||
enable_rule_exact(rule_name, enabled, m_default_ruleset);
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
it.second->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||
}
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled, const string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
m_sinsp_rules->enable_tags(tags, enabled, ruleset_id);
|
||||
m_k8s_audit_rules->enable_tags(tags, enabled, ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled)
|
||||
{
|
||||
enable_rule_by_tag(tags, enabled, m_default_ruleset);
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
it.second->enable_tags(tags, enabled, ruleset_id);
|
||||
}
|
||||
}
|
||||
|
||||
void falco_engine::set_min_priority(falco_common::priority_type priority)
|
||||
@@ -271,68 +246,85 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) +
|
||||
m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id);
|
||||
uint64_t ret = 0;
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
ret += it.second->num_rules_for_ruleset(ruleset_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset)
|
||||
void falco_engine::evttypes_for_ruleset(std::string &source, std::set<uint16_t> &evttypes, const std::string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
return m_sinsp_rules->evttypes_for_ruleset(evttypes, ruleset_id);
|
||||
auto it = m_rulesets.find(source);
|
||||
if(it == m_rulesets.end())
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
it->second->evttypes_for_ruleset(evttypes, ruleset_id);
|
||||
|
||||
}
|
||||
|
||||
void falco_engine::syscalls_for_ruleset(std::vector<bool> &syscalls, const std::string &ruleset)
|
||||
std::shared_ptr<gen_event_formatter> falco_engine::create_formatter(const std::string &source,
|
||||
const std::string &output)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
auto it = m_format_factories.find(source);
|
||||
|
||||
return m_sinsp_rules->syscalls_for_ruleset(syscalls, ruleset_id);
|
||||
if(it == m_format_factories.end())
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
return it->second->create_formatter(output);
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_sinsp_event(sinsp_evt *ev, uint16_t ruleset_id)
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::string &source, gen_event *ev, uint16_t ruleset_id)
|
||||
{
|
||||
if(should_drop_evt())
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
|
||||
if(!m_sinsp_rules->run(ev, ruleset_id))
|
||||
auto it = m_rulesets.find(source);
|
||||
if(it == m_rulesets.end())
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
if (!it->second->run(ev, ruleset_id))
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
|
||||
unique_ptr<struct rule_result> res(new rule_result());
|
||||
res->source = "syscall";
|
||||
res->source = source;
|
||||
|
||||
populate_rule_result(res, ev);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_sinsp_event(sinsp_evt *ev)
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::string &source, gen_event *ev)
|
||||
{
|
||||
return process_sinsp_event(ev, m_default_ruleset_id);
|
||||
return process_event(source, ev, m_default_ruleset_id);
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_k8s_audit_event(json_event *ev, uint16_t ruleset_id)
|
||||
void falco_engine::add_source(const std::string &source,
|
||||
std::shared_ptr<gen_event_filter_factory> filter_factory,
|
||||
std::shared_ptr<gen_event_formatter_factory> formatter_factory)
|
||||
{
|
||||
if(should_drop_evt())
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
m_filter_factories[source] = filter_factory;
|
||||
m_format_factories[source] = formatter_factory;
|
||||
|
||||
// All k8s audit events have the single tag "1".
|
||||
if(!m_k8s_audit_rules->run((gen_event *) ev, 1, ruleset_id))
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
|
||||
unique_ptr<struct rule_result> res(new rule_result());
|
||||
res->source = "k8s_audit";
|
||||
|
||||
populate_rule_result(res, ev);
|
||||
|
||||
return res;
|
||||
std::shared_ptr<falco_ruleset> ruleset(new falco_ruleset());
|
||||
m_rulesets[source] = ruleset;
|
||||
}
|
||||
|
||||
void falco_engine::populate_rule_result(unique_ptr<struct rule_result> &res, gen_event *ev)
|
||||
@@ -342,18 +334,29 @@ void falco_engine::populate_rule_result(unique_ptr<struct rule_result> &res, gen
|
||||
if(lua_isfunction(m_ls, -1))
|
||||
{
|
||||
lua_pushnumber(m_ls, ev->get_check_id());
|
||||
|
||||
if(lua_pcall(m_ls, 1, 4, 0) != 0)
|
||||
if(lua_pcall(m_ls, 1, 5, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
const char *p = lua_tostring(m_ls, -4);
|
||||
const char *p = lua_tostring(m_ls, -5);
|
||||
res->rule = p;
|
||||
res->evt = ev;
|
||||
res->priority_num = (falco_common::priority_type) lua_tonumber(m_ls, -3);
|
||||
res->format = lua_tostring(m_ls, -2);
|
||||
res->priority_num = (falco_common::priority_type) lua_tonumber(m_ls, -4);
|
||||
res->format = lua_tostring(m_ls, -3);
|
||||
|
||||
// Tags are passed back as a table, and is on the top of the stack
|
||||
lua_pushnil(m_ls); /* first key */
|
||||
while (lua_next(m_ls, -2) != 0) {
|
||||
// key is at index -2, value is at index
|
||||
// -1. We want the value.
|
||||
res->tags.insert(luaL_checkstring(m_ls, -1));
|
||||
|
||||
// Remove value, keep key for next iteration
|
||||
lua_pop(m_ls, 1);
|
||||
}
|
||||
lua_pop(m_ls, 1); // Clean table leftover
|
||||
|
||||
// Exception fields are passed back as a table
|
||||
lua_pushnil(m_ls); /* first key */
|
||||
@@ -374,84 +377,6 @@ void falco_engine::populate_rule_result(unique_ptr<struct rule_result> &res, gen
|
||||
}
|
||||
}
|
||||
|
||||
bool falco_engine::parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top)
|
||||
{
|
||||
// Note that nlohmann::basic_json::value can throw nlohmann::basic_json::type_error (302, 306)
|
||||
try
|
||||
{
|
||||
// If the object is an array, call parse_k8s_audit_json again for each item.
|
||||
if(j.is_array())
|
||||
{
|
||||
if(top)
|
||||
{
|
||||
for(auto &item : j)
|
||||
{
|
||||
// Note we only handle a single top level array, to
|
||||
// avoid excessive recursion.
|
||||
if(! parse_k8s_audit_json(item, evts, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the kind is EventList, split it into individual events
|
||||
if(j.value("kind", "<NA>") == "EventList")
|
||||
{
|
||||
for(auto &je : j["items"])
|
||||
{
|
||||
evts.emplace_back();
|
||||
je["kind"] = "Event";
|
||||
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(je.value(k8s_audit_time, "<NA>"), ns))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
sinsp_utils::ts_to_string(ns, &tmp, false, true);
|
||||
|
||||
evts.back().set_jevt(je, ns);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(j.value("kind", "<NA>") == "Event")
|
||||
{
|
||||
evts.emplace_back();
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(j.value(k8s_audit_time, "<NA>"), ns))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
evts.back().set_jevt(j, ns);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(exception &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_k8s_audit_event(json_event *ev)
|
||||
{
|
||||
return process_k8s_audit_event(ev, m_default_ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::describe_rule(string *rule)
|
||||
{
|
||||
return m_rules->describe_rule(rule);
|
||||
@@ -478,29 +403,68 @@ void falco_engine::print_stats()
|
||||
|
||||
}
|
||||
|
||||
void falco_engine::add_sinsp_filter(string &rule,
|
||||
set<uint32_t> &evttypes,
|
||||
set<uint32_t> &syscalls,
|
||||
set<string> &tags,
|
||||
sinsp_filter* filter)
|
||||
void falco_engine::add_filter(std::shared_ptr<gen_event_filter> filter,
|
||||
std::string &rule,
|
||||
std::string &source,
|
||||
std::set<std::string> &tags)
|
||||
{
|
||||
m_sinsp_rules->add(rule, evttypes, syscalls, tags, filter);
|
||||
auto it = m_rulesets.find(source);
|
||||
if(it == m_rulesets.end())
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
it->second->add(rule, tags, filter);
|
||||
}
|
||||
|
||||
void falco_engine::add_k8s_audit_filter(string &rule,
|
||||
set<string> &tags,
|
||||
json_event_filter* filter)
|
||||
bool falco_engine::is_source_valid(const std::string &source)
|
||||
{
|
||||
// All k8s audit events have a single tag "1".
|
||||
std::set<uint32_t> event_tags = {1};
|
||||
return (m_rulesets.find(source) != m_rulesets.end());
|
||||
}
|
||||
|
||||
m_k8s_audit_rules->add(rule, tags, event_tags, filter);
|
||||
bool falco_engine::is_plugin_compatible(const std::string &name,
|
||||
const std::string &version,
|
||||
std::string &required_version)
|
||||
{
|
||||
sinsp_plugin::version plugin_version(version.c_str());
|
||||
|
||||
if(!plugin_version.m_valid)
|
||||
{
|
||||
throw falco_exception(string("Plugin version string ") + version + " not valid");
|
||||
}
|
||||
|
||||
if(m_required_plugin_versions.find(name) == m_required_plugin_versions.end())
|
||||
{
|
||||
// No required engine versions, so no restrictions. Compatible.
|
||||
return true;
|
||||
}
|
||||
|
||||
for(auto &rversion : m_required_plugin_versions[name])
|
||||
{
|
||||
sinsp_plugin::version req_version(rversion.c_str());
|
||||
if(req_version.m_version_major > plugin_version.m_version_major)
|
||||
{
|
||||
required_version = rversion;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void falco_engine::clear_filters()
|
||||
{
|
||||
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||
m_k8s_audit_rules.reset(new falco_ruleset());
|
||||
m_rulesets.clear();
|
||||
|
||||
for(auto &it : m_filter_factories)
|
||||
{
|
||||
std::shared_ptr<falco_ruleset> ruleset(new falco_ruleset());
|
||||
m_rulesets[it.first] = ruleset;
|
||||
}
|
||||
|
||||
m_required_plugin_versions.clear();
|
||||
}
|
||||
|
||||
void falco_engine::set_sampling_ratio(uint32_t sampling_ratio)
|
||||
@@ -534,23 +498,3 @@ inline bool falco_engine::should_drop_evt()
|
||||
double coin = (random() * (1.0/RAND_MAX));
|
||||
return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio)));
|
||||
}
|
||||
|
||||
sinsp_filter_factory &falco_engine::sinsp_factory()
|
||||
{
|
||||
if(!m_sinsp_factory)
|
||||
{
|
||||
throw falco_exception("No sinsp factory created yet");
|
||||
}
|
||||
|
||||
return *(m_sinsp_factory.get());
|
||||
}
|
||||
|
||||
json_event_filter_factory &falco_engine::json_factory()
|
||||
{
|
||||
if(!m_json_factory)
|
||||
{
|
||||
throw falco_exception("No json factory created yet");
|
||||
}
|
||||
|
||||
return *(m_json_factory.get());
|
||||
}
|
||||
|
||||
@@ -28,10 +28,7 @@ limitations under the License.
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "sinsp.h"
|
||||
#include "filter.h"
|
||||
|
||||
#include "json_evt.h"
|
||||
#include "gen_filter.h"
|
||||
#include "rules.h"
|
||||
#include "ruleset.h"
|
||||
|
||||
@@ -57,7 +54,8 @@ public:
|
||||
static uint32_t engine_version();
|
||||
|
||||
// Print to stdout (using printf) a description of each field supported by this engine.
|
||||
void list_fields(bool names_only=false);
|
||||
// If source is non-empty, only fields for the provided source are printed.
|
||||
void list_fields(std::string &source, bool verbose, bool names_only);
|
||||
|
||||
//
|
||||
// Load rules either directly or from a filename.
|
||||
@@ -80,25 +78,16 @@ public:
|
||||
// be passed as an argument to process_event(). This allows
|
||||
// for different sets of rules being active at once.
|
||||
//
|
||||
void enable_rule(const std::string &substring, bool enabled, const std::string &ruleset);
|
||||
|
||||
// Wrapper that assumes the default ruleset
|
||||
void enable_rule(const std::string &substring, bool enabled);
|
||||
void enable_rule(const std::string &substring, bool enabled, const std::string &ruleset = s_default_ruleset);
|
||||
|
||||
|
||||
// Like enable_rule, but the rule name must be an exact match.
|
||||
void enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset);
|
||||
|
||||
// Wrapper that assumes the default ruleset
|
||||
void enable_rule_exact(const std::string &rule_name, bool enabled);
|
||||
void enable_rule_exact(const std::string &rule_name, bool enabled, const std::string &ruleset = s_default_ruleset);
|
||||
|
||||
//
|
||||
// Enable/Disable any rules with any of the provided tags (set, exact matches only)
|
||||
//
|
||||
void enable_rule_by_tag(const std::set<std::string> &tags, bool enabled, const std::string &ruleset);
|
||||
|
||||
// Wrapper that assumes the default ruleset
|
||||
void enable_rule_by_tag(const std::set<std::string> &tags, bool enabled);
|
||||
void enable_rule_by_tag(const std::set<std::string> &tags, bool enabled, const std::string &ruleset = s_default_ruleset);
|
||||
|
||||
// Only load rules having this priority or more severe.
|
||||
void set_min_priority(falco_common::priority_type priority);
|
||||
@@ -152,8 +141,8 @@ public:
|
||||
//
|
||||
void set_extra(string &extra, bool replace_container_info);
|
||||
|
||||
// **Methods Related to k8s audit log events, which are
|
||||
// **represented as json objects.
|
||||
// Represents the result of matching an event against a set of
|
||||
// rules.
|
||||
struct rule_result {
|
||||
gen_event *evt;
|
||||
std::string rule;
|
||||
@@ -161,18 +150,9 @@ public:
|
||||
falco_common::priority_type priority_num;
|
||||
std::string format;
|
||||
std::set<std::string> exception_fields;
|
||||
std::set<std::string> tags;
|
||||
};
|
||||
|
||||
//
|
||||
// Given a raw json object, return a list of k8s audit event
|
||||
// objects that represent the object. This method handles
|
||||
// things such as EventList splitting.
|
||||
//
|
||||
// Returns true if the json object was recognized as a k8s
|
||||
// audit event(s), false otherwise.
|
||||
//
|
||||
bool parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top=true);
|
||||
|
||||
//
|
||||
// Given an event, check it against the set of rules in the
|
||||
// engine and if a matching rule is found, return details on
|
||||
@@ -184,84 +164,81 @@ public:
|
||||
// with a ruleset string.
|
||||
//
|
||||
// the returned rule_result is allocated and must be delete()d.
|
||||
std::unique_ptr<rule_result> process_k8s_audit_event(json_event *ev, uint16_t ruleset_id);
|
||||
std::unique_ptr<rule_result> process_event(std::string &source, gen_event *ev, uint16_t ruleset_id);
|
||||
|
||||
//
|
||||
// Wrapper assuming the default ruleset
|
||||
//
|
||||
std::unique_ptr<rule_result> process_k8s_audit_event(json_event *ev);
|
||||
std::unique_ptr<rule_result> process_event(std::string &source, gen_event *ev);
|
||||
|
||||
//
|
||||
// Add a k8s_audit filter to the engine
|
||||
// Configure the engine to support events with the provided
|
||||
// source, with the provided filter factory and formatter factory.
|
||||
//
|
||||
void add_k8s_audit_filter(std::string &rule,
|
||||
std::set<std::string> &tags,
|
||||
json_event_filter* filter);
|
||||
void add_source(const std::string &source,
|
||||
std::shared_ptr<gen_event_filter_factory> filter_factory,
|
||||
std::shared_ptr<gen_event_formatter_factory> formatter_factory);
|
||||
|
||||
// **Methods Related to Sinsp Events e.g system calls
|
||||
//
|
||||
// Given a ruleset, fill in a bitset containing the event
|
||||
// types for which this ruleset can run.
|
||||
//
|
||||
void evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset);
|
||||
// Return whether or not there is a valid filter/formatter
|
||||
// factory for this source.
|
||||
bool is_source_valid(const std::string &source);
|
||||
|
||||
//
|
||||
// Given a ruleset, fill in a bitset containing the syscalls
|
||||
// for which this ruleset can run.
|
||||
// Add a filter for the provided event source to the engine
|
||||
//
|
||||
void syscalls_for_ruleset(std::vector<bool> &syscalls, const std::string &ruleset);
|
||||
void add_filter(std::shared_ptr<gen_event_filter> filter,
|
||||
std::string &rule,
|
||||
std::string &source,
|
||||
std::set<std::string> &tags);
|
||||
|
||||
//
|
||||
// Given an event, check it against the set of rules in the
|
||||
// engine and if a matching rule is found, return details on
|
||||
// the rule that matched. If no rule matched, returns NULL.
|
||||
// Given an event source and ruleset, fill in a bitset
|
||||
// containing the event types for which this ruleset can run.
|
||||
//
|
||||
// When ruleset_id is provided, use the enabled/disabled status
|
||||
// associated with the provided ruleset. This is only useful
|
||||
// when you have previously called enable_rule/enable_rule_by_tag
|
||||
// with a ruleset string.
|
||||
//
|
||||
// the returned rule_result is allocated and must be delete()d.
|
||||
std::unique_ptr<rule_result> process_sinsp_event(sinsp_evt *ev, uint16_t ruleset_id);
|
||||
void evttypes_for_ruleset(std::string &source,
|
||||
std::set<uint16_t> &evttypes,
|
||||
const std::string &ruleset = s_default_ruleset);
|
||||
|
||||
//
|
||||
// Wrapper assuming the default ruleset
|
||||
// Given a source and output string, return an
|
||||
// gen_event_formatter that can format output strings for an
|
||||
// event.
|
||||
//
|
||||
std::unique_ptr<rule_result> process_sinsp_event(sinsp_evt *ev);
|
||||
std::shared_ptr<gen_event_formatter> create_formatter(const std::string &source,
|
||||
const std::string &output);
|
||||
|
||||
//
|
||||
// Add a filter, which is related to the specified set of
|
||||
// event types/syscalls, to the engine.
|
||||
//
|
||||
void add_sinsp_filter(std::string &rule,
|
||||
std::set<uint32_t> &evttypes,
|
||||
std::set<uint32_t> &syscalls,
|
||||
std::set<std::string> &tags,
|
||||
sinsp_filter* filter);
|
||||
|
||||
sinsp_filter_factory &sinsp_factory();
|
||||
json_event_filter_factory &json_factory();
|
||||
// Return whether the provided plugin name + version is
|
||||
// compatible with the current set of loaded rules files.
|
||||
// required_version will be filled in with the required
|
||||
// version when the method returns false.
|
||||
bool is_plugin_compatible(const std::string &name, const std::string &version, std::string &required_version);
|
||||
|
||||
private:
|
||||
|
||||
static nlohmann::json::json_pointer k8s_audit_time;
|
||||
|
||||
//
|
||||
// Determine whether the given event should be matched at all
|
||||
// against the set of rules, given the current sampling
|
||||
// ratio/multiplier.
|
||||
//
|
||||
inline bool should_drop_evt();
|
||||
shared_ptr<sinsp_filter_factory> m_sinsp_factory;
|
||||
shared_ptr<json_event_filter_factory> m_json_factory;
|
||||
|
||||
falco_rules *m_rules;
|
||||
// Maps from event source to object that can generate filters from rules
|
||||
std::map<std::string, std::shared_ptr<gen_event_filter_factory>> m_filter_factories;
|
||||
|
||||
// Maps from event source to object that can format output strings in rules
|
||||
std::map<std::string, std::shared_ptr<gen_event_formatter_factory>> m_format_factories;
|
||||
|
||||
// Maps from event source to the set of rules for that event source
|
||||
std::map<std::string, std::shared_ptr<falco_ruleset>> m_rulesets;
|
||||
|
||||
std::unique_ptr<falco_rules> m_rules;
|
||||
uint16_t m_next_ruleset_id;
|
||||
std::map<string, uint16_t> m_known_rulesets;
|
||||
falco_common::priority_type m_min_priority;
|
||||
|
||||
std::unique_ptr<falco_sinsp_ruleset> m_sinsp_rules;
|
||||
std::unique_ptr<falco_ruleset> m_k8s_audit_rules;
|
||||
// Maps from plugin to a list of required plugin versions
|
||||
// found in any loaded rules files.
|
||||
std::map<std::string, std::list<std::string>> m_required_plugin_versions;
|
||||
|
||||
void populate_rule_result(unique_ptr<struct rule_result> &res, gen_event *ev);
|
||||
|
||||
@@ -288,8 +265,7 @@ private:
|
||||
uint32_t m_sampling_ratio;
|
||||
double m_sampling_multiplier;
|
||||
|
||||
std::string m_lua_main_filename = "rule_loader.lua";
|
||||
std::string m_default_ruleset = "falco-default-ruleset";
|
||||
static const std::string s_default_ruleset;
|
||||
uint32_t m_default_ruleset_id;
|
||||
|
||||
std::string m_extra;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2020 The Falco Authors.
|
||||
Copyright (C) 2021 The Falco Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,11 +14,12 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// The version of rules/filter fields/etc supported by this Falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (8)
|
||||
#define FALCO_ENGINE_VERSION (11)
|
||||
|
||||
// This is the result of running "falco --list -N | sha256sum" and
|
||||
// represents the fields supported by this version of falco. It's used
|
||||
// represents the fields supported by this version of Falco. It's used
|
||||
// at build time to detect a changed set of fields.
|
||||
#define FALCO_FIELDS_CHECKSUM "2f324e2e66d4b423f53600e7e0fcf2f0ff72e4a87755c490f2ae8f310aba9386"
|
||||
#define FALCO_FIELDS_CHECKSUM "4de812495f8529ac20bda2b9774462b15911a51df293d59fe9ccb6b922fdeb9d"
|
||||
|
||||
|
||||
@@ -27,31 +27,6 @@ namespace falco
|
||||
namespace utils
|
||||
{
|
||||
|
||||
std::string wrap_text(const std::string& str, uint32_t initial_pos, uint32_t indent, uint32_t line_len)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
size_t len = str.size();
|
||||
|
||||
for(uint32_t l = 0; l < len; l++)
|
||||
{
|
||||
if(l % (line_len - indent) == 0 && l != 0)
|
||||
{
|
||||
ret += "\n";
|
||||
|
||||
for(uint32_t m = 0; m < indent; m++)
|
||||
{
|
||||
ret += " ";
|
||||
}
|
||||
}
|
||||
ret += str.at(l);
|
||||
}
|
||||
|
||||
ret += "\n";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t hardware_concurrency()
|
||||
{
|
||||
auto hc = std::thread::hardware_concurrency();
|
||||
|
||||
@@ -17,6 +17,8 @@ limitations under the License.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -24,7 +26,13 @@ limitations under the License.
|
||||
#include <thread>
|
||||
#include <nonstd/string_view.hpp>
|
||||
|
||||
#pragma once
|
||||
#ifdef __GNUC__
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
namespace falco
|
||||
{
|
||||
|
||||
@@ -20,169 +20,54 @@ limitations under the License.
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
sinsp *falco_formats::s_inspector = NULL;
|
||||
falco_engine *falco_formats::s_engine = NULL;
|
||||
bool falco_formats::s_json_output = false;
|
||||
bool falco_formats::s_json_include_output_property = true;
|
||||
std::unique_ptr<sinsp_evt_formatter_cache> falco_formats::s_formatters = NULL;
|
||||
|
||||
const static struct luaL_Reg ll_falco[] =
|
||||
{
|
||||
{"formatter", &falco_formats::lua_formatter},
|
||||
{"free_formatter", &falco_formats::lua_free_formatter},
|
||||
{NULL, NULL}};
|
||||
|
||||
void falco_formats::init(sinsp *inspector,
|
||||
falco_engine *engine,
|
||||
lua_State *ls,
|
||||
bool json_output,
|
||||
bool json_include_output_property)
|
||||
falco_formats::falco_formats(falco_engine *engine,
|
||||
bool json_include_output_property,
|
||||
bool json_include_tags_property)
|
||||
: m_falco_engine(engine),
|
||||
m_json_include_output_property(json_include_output_property),
|
||||
m_json_include_tags_property(json_include_tags_property)
|
||||
{
|
||||
s_inspector = inspector;
|
||||
s_engine = engine;
|
||||
s_json_output = json_output;
|
||||
s_json_include_output_property = json_include_output_property;
|
||||
|
||||
// todo(leogr): we should have used std::make_unique, but we cannot since it's not C++14
|
||||
s_formatters = std::unique_ptr<sinsp_evt_formatter_cache>(new sinsp_evt_formatter_cache(s_inspector));
|
||||
|
||||
luaL_openlib(ls, "formats", ll_falco, 0);
|
||||
}
|
||||
|
||||
int falco_formats::lua_formatter(lua_State *ls)
|
||||
falco_formats::~falco_formats()
|
||||
{
|
||||
string source = luaL_checkstring(ls, -2);
|
||||
string format = luaL_checkstring(ls, -1);
|
||||
|
||||
try
|
||||
{
|
||||
if(source == "syscall")
|
||||
{
|
||||
sinsp_evt_formatter *formatter;
|
||||
formatter = new sinsp_evt_formatter(s_inspector, format);
|
||||
lua_pushnil(ls);
|
||||
lua_pushlightuserdata(ls, formatter);
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter *formatter;
|
||||
formatter = new json_event_formatter(s_engine->json_factory(), format);
|
||||
lua_pushnil(ls);
|
||||
lua_pushlightuserdata(ls, formatter);
|
||||
}
|
||||
}
|
||||
catch(exception &e)
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Invalid output format '"
|
||||
<< format
|
||||
<< "': '"
|
||||
<< e.what()
|
||||
<< "'";
|
||||
|
||||
lua_pushstring(ls, os.str().c_str());
|
||||
lua_pushnil(ls);
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
int falco_formats::lua_free_formatter(lua_State *ls)
|
||||
string falco_formats::format_event(gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format, std::set<std::string> &tags)
|
||||
{
|
||||
if(!lua_islightuserdata(ls, -1) ||
|
||||
!lua_isstring(ls, -2))
|
||||
|
||||
{
|
||||
luaL_error(ls, "Invalid argument passed to free_formatter");
|
||||
}
|
||||
|
||||
string source = luaL_checkstring(ls, -2);
|
||||
|
||||
if(source == "syscall")
|
||||
{
|
||||
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *)lua_topointer(ls, -1);
|
||||
delete(formatter);
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter *formatter = (json_event_formatter *)lua_topointer(ls, -1);
|
||||
delete(formatter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string falco_formats::format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format)
|
||||
{
|
||||
|
||||
string line;
|
||||
string json_line;
|
||||
string sformat = format;
|
||||
|
||||
if(strcmp(source.c_str(), "syscall") == 0)
|
||||
std::shared_ptr<gen_event_formatter> formatter;
|
||||
|
||||
formatter = m_falco_engine->create_formatter(source, format);
|
||||
|
||||
// Format the original output string, regardless of output format
|
||||
formatter->tostring_withformat(evt, line, gen_event_formatter::OF_NORMAL);
|
||||
|
||||
if(formatter->get_output_format() == gen_event_formatter::OF_JSON)
|
||||
{
|
||||
// This is "output"
|
||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &line);
|
||||
string json_line;
|
||||
|
||||
if(s_json_output)
|
||||
// Format the event into a json object with all fields resolved
|
||||
formatter->tostring(evt, json_line);
|
||||
|
||||
// The formatted string might have a leading newline. If it does, remove it.
|
||||
if(json_line[0] == '\n')
|
||||
{
|
||||
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
||||
switch(cur_fmt)
|
||||
{
|
||||
case sinsp_evt::PF_NORMAL:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
||||
break;
|
||||
case sinsp_evt::PF_EOLS:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
||||
break;
|
||||
case sinsp_evt::PF_HEX:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
||||
break;
|
||||
case sinsp_evt::PF_HEXASCII:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
||||
break;
|
||||
case sinsp_evt::PF_BASE64:
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
// This is output fields
|
||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &json_line);
|
||||
|
||||
// The formatted string might have a leading newline. If it does, remove it.
|
||||
if(json_line[0] == '\n')
|
||||
{
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
s_inspector->set_buffer_format(cur_fmt);
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
||||
|
||||
line = formatter.tostring((json_event *)evt);
|
||||
|
||||
if(s_json_output)
|
||||
{
|
||||
json_line = formatter.tojson((json_event *)evt);
|
||||
}
|
||||
}
|
||||
|
||||
// For JSON output, the formatter returned a json-as-text
|
||||
// object containing all the fields in the original format
|
||||
// message as well as the event time in ns. Use this to build
|
||||
// a more detailed object containing the event time, rule,
|
||||
// severity, full output, and fields.
|
||||
if(s_json_output)
|
||||
{
|
||||
// For JSON output, the formatter returned a json-as-text
|
||||
// object containing all the fields in the original format
|
||||
// message as well as the event time in ns. Use this to build
|
||||
// a more detailed object containing the event time, rule,
|
||||
// severity, full output, and fields.
|
||||
Json::Value event;
|
||||
Json::Value rule_tags;
|
||||
Json::FastWriter writer;
|
||||
string full_line;
|
||||
unsigned int rule_tags_idx = 0;
|
||||
|
||||
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||
time_t evttime = evt->get_ts() / 1000000000;
|
||||
@@ -197,13 +82,31 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
event["time"] = iso8601evttime;
|
||||
event["rule"] = rule;
|
||||
event["priority"] = level;
|
||||
event["source"] = source;
|
||||
|
||||
if(s_json_include_output_property)
|
||||
if(m_json_include_output_property)
|
||||
{
|
||||
// This is the filled-in output line.
|
||||
event["output"] = line;
|
||||
}
|
||||
|
||||
if(m_json_include_tags_property)
|
||||
{
|
||||
if (tags.size() == 0)
|
||||
{
|
||||
// This sets an empty array
|
||||
rule_tags = Json::arrayValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto &tag : tags)
|
||||
{
|
||||
rule_tags[rule_tags_idx++] = tag;
|
||||
}
|
||||
}
|
||||
event["tags"] = rule_tags;
|
||||
}
|
||||
|
||||
full_line = writer.write(event);
|
||||
|
||||
// Json::FastWriter may add a trailing newline. If it
|
||||
@@ -226,19 +129,19 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
||||
return line.c_str();
|
||||
}
|
||||
|
||||
map<string, string> falco_formats::resolve_tokens(const gen_event *evt, const std::string &source, const std::string &format)
|
||||
map<string, string> falco_formats::get_field_values(gen_event *evt, const std::string &source,
|
||||
const std::string &format)
|
||||
{
|
||||
string sformat = format;
|
||||
map<string, string> values;
|
||||
if(source == "syscall")
|
||||
std::shared_ptr<gen_event_formatter> formatter;
|
||||
|
||||
formatter = m_falco_engine->create_formatter(source, format);
|
||||
|
||||
map<string, string> ret;
|
||||
|
||||
if (! formatter->get_field_values(evt, ret))
|
||||
{
|
||||
s_formatters->resolve_tokens((sinsp_evt *)evt, sformat, values);
|
||||
throw falco_exception("Could not extract all field values from event");
|
||||
}
|
||||
// k8s_audit
|
||||
else
|
||||
{
|
||||
json_event_formatter json_formatter(s_engine->json_factory(), sformat);
|
||||
values = json_formatter.tomap((json_event *)evt);
|
||||
}
|
||||
return values;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sinsp.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -25,35 +26,26 @@ extern "C"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
#include "json_evt.h"
|
||||
#include "falco_engine.h"
|
||||
#include <gen_filter.h>
|
||||
|
||||
class sinsp_evt_formatter;
|
||||
#include "falco_engine.h"
|
||||
|
||||
class falco_formats
|
||||
{
|
||||
public:
|
||||
static void init(sinsp *inspector,
|
||||
falco_engine *engine,
|
||||
lua_State *ls,
|
||||
bool json_output,
|
||||
bool json_include_output_property);
|
||||
falco_formats(falco_engine *engine,
|
||||
bool json_include_output_property,
|
||||
bool json_include_tags_property);
|
||||
virtual ~falco_formats();
|
||||
|
||||
// formatter = falco.formatter(format_string)
|
||||
static int lua_formatter(lua_State *ls);
|
||||
std::string format_event(gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format, std::set<std::string> &tags);
|
||||
|
||||
// falco.free_formatter(formatter)
|
||||
static int lua_free_formatter(lua_State *ls);
|
||||
map<string, string> get_field_values(gen_event *evt, const std::string &source,
|
||||
const std::string &format);
|
||||
|
||||
static string format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||
const std::string &level, const std::string &format);
|
||||
|
||||
static map<string, string> resolve_tokens(const gen_event *evt, const std::string &source,
|
||||
const std::string &format);
|
||||
|
||||
static sinsp *s_inspector;
|
||||
static falco_engine *s_engine;
|
||||
static std::unique_ptr<sinsp_evt_formatter_cache> s_formatters;
|
||||
static bool s_json_output;
|
||||
static bool s_json_include_output_property;
|
||||
protected:
|
||||
falco_engine *m_falco_engine;
|
||||
bool m_json_include_output_property;
|
||||
bool m_json_include_tags_property;
|
||||
};
|
||||
|
||||
@@ -50,6 +50,81 @@ uint64_t json_event::get_ts() const
|
||||
return m_event_ts;
|
||||
}
|
||||
|
||||
static nlohmann::json::json_pointer k8s_audit_time = "/stageTimestamp"_json_pointer;
|
||||
|
||||
bool falco_k8s_audit::parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top)
|
||||
{
|
||||
// Note that nlohmann::basic_json::value can throw nlohmann::basic_json::type_error (302, 306)
|
||||
try
|
||||
{
|
||||
// If the object is an array, call parse_k8s_audit_json again for each item.
|
||||
if(j.is_array())
|
||||
{
|
||||
if(top)
|
||||
{
|
||||
for(auto &item : j)
|
||||
{
|
||||
// Note we only handle a single top level array, to
|
||||
// avoid excessive recursion.
|
||||
if(! parse_k8s_audit_json(item, evts, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the kind is EventList, split it into individual events
|
||||
if(j.value("kind", "<NA>") == "EventList")
|
||||
{
|
||||
for(auto &je : j["items"])
|
||||
{
|
||||
evts.emplace_back();
|
||||
je["kind"] = "Event";
|
||||
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(je.value(k8s_audit_time, "<NA>"), ns))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string tmp;
|
||||
sinsp_utils::ts_to_string(ns, &tmp, false, true);
|
||||
|
||||
evts.back().set_jevt(je, ns);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if(j.value("kind", "<NA>") == "Event")
|
||||
{
|
||||
evts.emplace_back();
|
||||
uint64_t ns = 0;
|
||||
if(!sinsp_utils::parse_iso_8601_utc_string(j.value(k8s_audit_time, "<NA>"), ns))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
evts.back().set_jevt(j, ns);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch(exception &e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
json_event_value::json_event_value()
|
||||
{
|
||||
}
|
||||
@@ -281,7 +356,11 @@ bool json_event_value::parse_as_int64(int64_t &intval, const std::string &val)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (std::invalid_argument &e)
|
||||
catch(std::out_of_range &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (std::invalid_argument &)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -611,7 +690,7 @@ size_t json_event_filter_check::parsed_size()
|
||||
}
|
||||
}
|
||||
|
||||
json_event_filter_check::check_info &json_event_filter_check::get_fields()
|
||||
json_event_filter_check::check_info &json_event_filter_check::get_info()
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
@@ -1353,7 +1432,7 @@ json_event_filter_factory::json_event_filter_factory()
|
||||
|
||||
for(auto &chk : m_defined_checks)
|
||||
{
|
||||
m_info.push_back(chk->get_fields());
|
||||
m_info.push_back(chk->get_info());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1385,36 +1464,99 @@ gen_event_filter_check *json_event_filter_factory::new_filtercheck(const char *f
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::list<json_event_filter_check::check_info> &json_event_filter_factory::get_fields()
|
||||
std::list<gen_event_filter_factory::filter_fieldclass_info> json_event_filter_factory::get_fields()
|
||||
{
|
||||
return m_info;
|
||||
std::list<gen_event_filter_factory::filter_fieldclass_info> ret;
|
||||
|
||||
// It's not quite copy to the public information, as m_info
|
||||
// has addl info about indexing. That info is added to the
|
||||
// description.
|
||||
|
||||
for(auto &chk: m_defined_checks)
|
||||
{
|
||||
json_event_filter_check::check_info &info = chk->get_info();
|
||||
gen_event_filter_factory::filter_fieldclass_info cinfo;
|
||||
|
||||
cinfo.name = info.m_name;
|
||||
cinfo.desc = info.m_desc;
|
||||
cinfo.shortdesc = info.m_shortdesc;
|
||||
|
||||
for(auto &field : info.m_fields)
|
||||
{
|
||||
gen_event_filter_factory::filter_field_info info;
|
||||
info.name = field.m_name;
|
||||
info.desc = field.m_desc;
|
||||
|
||||
// All json fields work on strings
|
||||
info.data_type = "CHARBUF";
|
||||
|
||||
switch(field.m_idx_mode)
|
||||
{
|
||||
case json_event_filter_check::IDX_REQUIRED:
|
||||
case json_event_filter_check::IDX_ALLOWED:
|
||||
info.tags.insert(json_event_filter_check::s_index_mode_strs[field.m_idx_mode]);
|
||||
break;
|
||||
case json_event_filter_check::IDX_NONE:
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
cinfo.fields.emplace_back(std::move(info));
|
||||
}
|
||||
|
||||
ret.emplace_back(std::move(cinfo));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format):
|
||||
m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
json_event_formatter::json_event_formatter(std::shared_ptr<gen_event_filter_factory> json_factory)
|
||||
: m_output_format(OF_NORMAL), m_json_factory(json_factory)
|
||||
{
|
||||
parse_format();
|
||||
}
|
||||
|
||||
json_event_formatter::~json_event_formatter()
|
||||
{
|
||||
}
|
||||
|
||||
std::string json_event_formatter::tostring(json_event *ev)
|
||||
void json_event_formatter::set_format(output_format of, const std::string &format)
|
||||
{
|
||||
m_output_format = of;
|
||||
m_format = format;
|
||||
parse_format();
|
||||
}
|
||||
|
||||
bool json_event_formatter::tostring_withformat(gen_event *gevt, std::string &output, gen_event_formatter::output_format of)
|
||||
{
|
||||
json_event *ev = static_cast<json_event *>(gevt);
|
||||
|
||||
std::string ret;
|
||||
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
for(auto &res : resolved)
|
||||
if(of == OF_JSON)
|
||||
{
|
||||
ret += res.second;
|
||||
ret = tojson(ev);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
return ret;
|
||||
resolve_format(ev, resolved);
|
||||
|
||||
output = "";
|
||||
|
||||
for(auto &res : resolved)
|
||||
{
|
||||
output += res.second;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool json_event_formatter::tostring(gen_event *gevt, std::string &output)
|
||||
{
|
||||
return tostring_withformat(gevt, output, m_output_format);
|
||||
}
|
||||
|
||||
std::string json_event_formatter::tojson(json_event *ev)
|
||||
@@ -1424,7 +1566,7 @@ std::string json_event_formatter::tojson(json_event *ev)
|
||||
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
resolve_format(ev, resolved);
|
||||
|
||||
for(auto &res : resolved)
|
||||
{
|
||||
@@ -1439,12 +1581,13 @@ std::string json_event_formatter::tojson(json_event *ev)
|
||||
return ret.dump();
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> json_event_formatter::tomap(json_event *ev)
|
||||
bool json_event_formatter::get_field_values(gen_event *gevt, std::map<std::string, std::string> &fields)
|
||||
{
|
||||
std::map<std::string, std::string> ret;
|
||||
json_event *ev = static_cast<json_event *>(gevt);
|
||||
|
||||
std::list<std::pair<std::string, std::string>> res;
|
||||
|
||||
resolve_tokens(ev, res);
|
||||
resolve_format(ev, res);
|
||||
|
||||
for(auto &r : res)
|
||||
{
|
||||
@@ -1455,11 +1598,11 @@ std::map<std::string, std::string> json_event_formatter::tomap(json_event *ev)
|
||||
{
|
||||
r.second = "<NA>";
|
||||
}
|
||||
ret.insert(r);
|
||||
fields.insert(r);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
void json_event_formatter::parse_format()
|
||||
@@ -1481,7 +1624,7 @@ void json_event_formatter::parse_format()
|
||||
{
|
||||
// Skip the %
|
||||
tformat.erase(0, 1);
|
||||
json_event_filter_check *chk = (json_event_filter_check *)m_json_factory.new_filtercheck(tformat.c_str());
|
||||
json_event_filter_check *chk = (json_event_filter_check *)m_json_factory->new_filtercheck(tformat.c_str());
|
||||
|
||||
if(!chk)
|
||||
{
|
||||
@@ -1517,7 +1660,7 @@ void json_event_formatter::parse_format()
|
||||
}
|
||||
}
|
||||
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
|
||||
void json_event_formatter::resolve_format(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
|
||||
{
|
||||
for(auto tok : m_tokens)
|
||||
{
|
||||
@@ -1557,3 +1700,43 @@ void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<st
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gen_event_formatter::output_format json_event_formatter::get_output_format()
|
||||
{
|
||||
return m_output_format;
|
||||
}
|
||||
|
||||
json_event_formatter_factory::json_event_formatter_factory(std::shared_ptr<gen_event_filter_factory> json_factory)
|
||||
: m_output_format(gen_event_formatter::OF_NORMAL), m_json_factory(json_factory)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_formatter_factory::~json_event_formatter_factory()
|
||||
{
|
||||
}
|
||||
|
||||
void json_event_formatter_factory::set_output_format(gen_event_formatter::output_format of)
|
||||
{
|
||||
m_formatters.clear();
|
||||
|
||||
m_output_format = of;
|
||||
}
|
||||
|
||||
std::shared_ptr<gen_event_formatter> json_event_formatter_factory::create_formatter(const std::string &format)
|
||||
{
|
||||
auto it = m_formatters.find(format);
|
||||
|
||||
if (it != m_formatters.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::shared_ptr<gen_event_formatter> ret;
|
||||
|
||||
ret.reset(new json_event_formatter(m_json_factory));
|
||||
|
||||
ret->set_format(m_output_format, format);
|
||||
m_formatters[format] = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -57,6 +57,19 @@ protected:
|
||||
uint64_t m_event_ts;
|
||||
};
|
||||
|
||||
namespace falco_k8s_audit {
|
||||
|
||||
//
|
||||
// Given a raw json object, return a list of k8s audit event
|
||||
// objects that represent the object. This method handles
|
||||
// things such as EventList splitting.
|
||||
//
|
||||
// Returns true if the json object was recognized as a k8s
|
||||
// audit event(s), false otherwise.
|
||||
//
|
||||
bool parse_k8s_audit_json(nlohmann::json &j, std::list<json_event> &evts, bool top=true);
|
||||
};
|
||||
|
||||
// A class representing an extracted value or a value on the rhs of a
|
||||
// filter_check. This intentionally doesn't use the same types as
|
||||
// ppm_events_public.h to take advantage of actual classes instead of
|
||||
@@ -153,8 +166,8 @@ public:
|
||||
struct check_info
|
||||
{
|
||||
std::string m_name;
|
||||
std::string m_shortdesc;
|
||||
std::string m_desc;
|
||||
std::string m_class_info;
|
||||
|
||||
std::list<field_info> m_fields;
|
||||
};
|
||||
@@ -176,7 +189,7 @@ public:
|
||||
// brackets (e.g. ka.image[foo])
|
||||
size_t parsed_size();
|
||||
|
||||
check_info &get_fields();
|
||||
check_info &get_info();
|
||||
|
||||
//
|
||||
// Allocate a new check of the same type. Must be overridden.
|
||||
@@ -386,29 +399,41 @@ public:
|
||||
gen_event_filter_check *new_filtercheck(const char *fldname);
|
||||
|
||||
// All defined field names
|
||||
std::list<json_event_filter_check::check_info> &get_fields();
|
||||
std::list<gen_event_filter_factory::filter_fieldclass_info> get_fields();
|
||||
|
||||
private:
|
||||
std::list<std::shared_ptr<json_event_filter_check>> m_defined_checks;
|
||||
std::list<json_event_filter_check::check_info> m_info;
|
||||
};
|
||||
|
||||
// Unlike the other classes, this does not inherit from a shared class
|
||||
// that's used both by json events and sinsp events. It might be
|
||||
// worthwhile, but it would require a lot of additional work to pull
|
||||
// up functionality into the generic filtercheck class.
|
||||
|
||||
class json_event_formatter
|
||||
class json_event_formatter : public gen_event_formatter
|
||||
{
|
||||
public:
|
||||
json_event_formatter(json_event_filter_factory &factory, std::string &format);
|
||||
json_event_formatter(std::shared_ptr<gen_event_filter_factory> factory);
|
||||
virtual ~json_event_formatter();
|
||||
|
||||
std::string tostring(json_event *ev);
|
||||
std::string tojson(json_event *ev);
|
||||
std::map<std::string, std::string> tomap(json_event *ev);
|
||||
void set_format(output_format of, const std::string &format) override;
|
||||
bool tostring(gen_event *evt, std::string &output) override;
|
||||
bool tostring_withformat(gen_event *evt, std::string &output, gen_event_formatter::output_format of) override;
|
||||
bool get_field_values(gen_event *evt, std::map<std::string, std::string> &fields) override;
|
||||
output_format get_output_format() override;
|
||||
|
||||
void resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved);
|
||||
std::string tojson(json_event *ev);
|
||||
|
||||
// Split the format string into a list of tuples, broken at
|
||||
// output fields, where each tuple is either a block of text
|
||||
// from the original format string, or a field value/pair from
|
||||
// the original format string.
|
||||
//
|
||||
// For example, given a format string "some output
|
||||
// (%proc.name)", this will fill in resolved with 3 tuples:
|
||||
// - ["", "some output ("]
|
||||
// - ["proc.name", "nginx"]
|
||||
// - ["", ")"]
|
||||
//
|
||||
// This can be used either to return a resolved output string
|
||||
// or a map of field name/value pairs.
|
||||
void resolve_format(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved);
|
||||
|
||||
private:
|
||||
void parse_format();
|
||||
@@ -428,6 +453,8 @@ private:
|
||||
std::shared_ptr<json_event_filter_check> check;
|
||||
};
|
||||
|
||||
gen_event_formatter::output_format m_output_format;
|
||||
|
||||
// The original format string
|
||||
std::string m_format;
|
||||
|
||||
@@ -436,5 +463,25 @@ private:
|
||||
std::list<fmt_token> m_tokens;
|
||||
|
||||
// All the filterchecks required to resolve tokens in the format string
|
||||
json_event_filter_factory &m_json_factory;
|
||||
std::shared_ptr<gen_event_filter_factory> m_json_factory;
|
||||
};
|
||||
|
||||
class json_event_formatter_factory : public gen_event_formatter_factory
|
||||
{
|
||||
public:
|
||||
json_event_formatter_factory(std::shared_ptr<gen_event_filter_factory> factory);
|
||||
virtual ~json_event_formatter_factory();
|
||||
|
||||
void set_output_format(gen_event_formatter::output_format of) override;
|
||||
|
||||
std::shared_ptr<gen_event_formatter> create_formatter(const std::string &format) override;
|
||||
|
||||
protected:
|
||||
// Maps from output string to formatter
|
||||
std::map<std::string, std::shared_ptr<gen_event_formatter>> m_formatters;
|
||||
|
||||
gen_event_formatter::output_format m_output_format;
|
||||
|
||||
// All the filterchecks required to resolve tokens in the format string
|
||||
std::shared_ptr<gen_event_filter_factory> m_json_factory;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user