mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-25 06:02:18 +00:00
Compare commits
66 Commits
0.19.0
...
feature/in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
beafd2b868 | ||
|
|
31bb5c5070 | ||
|
|
195b475204 | ||
|
|
4da9cd3764 | ||
|
|
b7e4913de1 | ||
|
|
356188542c | ||
|
|
fd7731cf09 | ||
|
|
b1d33ddf08 | ||
|
|
f7c66cbbdc | ||
|
|
d30df38e4b | ||
|
|
74d1a1f18f | ||
|
|
cc847f53bb | ||
|
|
051a1a6f74 | ||
|
|
9c112890d4 | ||
|
|
8ecf208901 | ||
|
|
bd3c2ce8e8 | ||
|
|
f49014bbe4 | ||
|
|
e4fe9104f3 | ||
|
|
03df81af23 | ||
|
|
fcb33d32cf | ||
|
|
cb1cb5b12c | ||
|
|
467f33c5ff | ||
|
|
4e916a7a58 | ||
|
|
325357c465 | ||
|
|
0f81e9b95a | ||
|
|
8b167bb1d9 | ||
|
|
8dba2485e2 | ||
|
|
85cd219682 | ||
|
|
488e667f46 | ||
|
|
253ff64d64 | ||
|
|
b3171dbae1 | ||
|
|
738d757b08 | ||
|
|
5663d4d02b | ||
|
|
2a9c9bdc53 | ||
|
|
ae2eb8de8e | ||
|
|
c7aff2d4cb | ||
|
|
bc297bdc8f | ||
|
|
2a91289ee4 | ||
|
|
c224633454 | ||
|
|
714a6619ad | ||
|
|
550ee0d8fc | ||
|
|
8d49e45d44 | ||
|
|
5e8f98ea92 | ||
|
|
e560056b92 | ||
|
|
84261d2071 | ||
|
|
c374264384 | ||
|
|
af3d89b706 | ||
|
|
5b9001d1d5 | ||
|
|
240f7e2057 | ||
|
|
22a95796c1 | ||
|
|
f98da284d0 | ||
|
|
3693b16c91 | ||
|
|
48a0f512fb | ||
|
|
01c9d8ba31 | ||
|
|
7794e468ba | ||
|
|
0d74f3938d | ||
|
|
e5f06e399f | ||
|
|
fa3e48ca1a | ||
|
|
bf0cdb7c38 | ||
|
|
be67c4adaf | ||
|
|
b088a57dd0 | ||
|
|
40fbc96736 | ||
|
|
c350876456 | ||
|
|
bf8367b280 | ||
|
|
c510808299 | ||
|
|
a1d6a4762e |
@@ -4,6 +4,8 @@ This is a list of production adopters of Falco (in alphabetical order):
|
||||
|
||||
* [Booz Allen Hamilton](https://www.boozallen.com/) - BAH leverages Falco as part of their Kubernetes environment to verify that work loads behave as they did in their CD DevSecOps pipelines. BAH offers a solution to internal developers to easily build DevSecOps pipelines for projects. This makes it easy for developers to incorporate Security principles early on in the development cycle. In production, Falco is used to verify that the code the developer ships does not violate any of the production security requirements. BAH [are speaking at Kubecon NA 2019](https://kccncna19.sched.com/event/UaWr/building-reusable-devsecops-pipelines-on-a-secure-kubernetes-platform-steven-terrana-booz-allen-hamilton-michael-ducy-sysdig) on their use of Falco.
|
||||
|
||||
* [Coveo](https://www.coveo.com/) - Coveo stitches together content and data, learning from every interaction, to tailor every experience using AI to drive growth, satisfy customers and develop employee proficiency. All Falco events are centralized in our SIEM for analysis. 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 with containers and orchestration systems. Falco is giving us a good visibility inside containers and complement other Host and Network Intrusion Detection Systems. In a near future, we expect to deploy serverless functions to take action when Falco identifies patterns worth taking action for.
|
||||
|
||||
* [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.
|
||||
|
||||
* [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 containerswhich 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.
|
||||
|
||||
@@ -18,7 +18,8 @@ option(USE_BUNDLED_DEPS "Bundle hard to find dependencies into the Falco binary"
|
||||
option(BUILD_WARNINGS_AS_ERRORS "Enable building with -Wextra -Werror flags" OFF)
|
||||
|
||||
# Elapsed time
|
||||
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time") # TODO(fntlnz, leodido): add a flag to enable this
|
||||
# TODO(fntlnz, leodido): add a flag to enable this
|
||||
# set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CMAKE_COMMAND} -E time")
|
||||
|
||||
# Make flag for parallel processing
|
||||
include(ProcessorCount)
|
||||
@@ -48,6 +49,7 @@ else()
|
||||
set(CMAKE_BUILD_TYPE "release")
|
||||
set(KBUILD_FLAGS "${DRAIOS_FEATURE_FLAGS}")
|
||||
endif()
|
||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
set(CMAKE_COMMON_FLAGS "-Wall -ggdb ${DRAIOS_FEATURE_FLAGS}")
|
||||
|
||||
@@ -67,24 +69,7 @@ set(CMAKE_CXX_FLAGS_DEBUG "${DRAIOS_DEBUG_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fno-strict-aliasing -DNDEBUG")
|
||||
|
||||
# Create the falco version variable according to git index
|
||||
if(NOT FALCO_VERSION)
|
||||
include(GetGitRevisionDescription)
|
||||
git_get_exact_tag(FALCO_TAG)
|
||||
if(NOT FALCO_TAG)
|
||||
git_describe(FALCO_VERSION "--always")
|
||||
git_local_changes(FALCO_CHANGES)
|
||||
if(FALCO_CHANGES STREQUAL "DIRTY")
|
||||
string(TOLOWER "${FALCO_CHANGES}" FALCO_CHANGES)
|
||||
set(FALCO_VERSION "${FALCO_VERSION}.${FALCO_CHANGES}")
|
||||
endif()
|
||||
set(FALCO_VERSION "0.${FALCO_VERSION}")
|
||||
else()
|
||||
set(FALCO_VERSION "${FALCO_TAG}")
|
||||
string(REGEX REPLACE "^v([0-9]+)(\\.[0-9]+)(\\.[0-9]+)?" "\\1\\2\\3" FALCO_VERSION ${FALCO_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Falco version: ${FALCO_VERSION}")
|
||||
include(GetFalcoVersion)
|
||||
|
||||
set(PACKAGE_NAME "falco")
|
||||
set(PROBE_VERSION "${FALCO_VERSION}")
|
||||
@@ -240,6 +225,7 @@ include(sysdig)
|
||||
# Installation
|
||||
install(FILES falco.yaml DESTINATION "${FALCO_ETC_DIR}")
|
||||
|
||||
# Coverage
|
||||
include(Coverage)
|
||||
|
||||
# Tests
|
||||
|
||||
36
README.md
36
README.md
@@ -1,16 +1,16 @@
|
||||
<p><img align="right" src="https://github.com/falcosecurity/falco-website/raw/master/themes/falco-fresh/static/images/favicon.png" width="64px"/></p>
|
||||
<p></p>
|
||||
<p align="center"><img src="https://raw.githubusercontent.com/falcosecurity/community/master/logo/primary-logo.png" width="360"></p>
|
||||
<p align="center"><b>Cloud Native Runtime Security.</b></p>
|
||||
|
||||
# Falco
|
||||
<hr>
|
||||
|
||||
# The Falco Project
|
||||
|
||||
#### Latest release
|
||||
|
||||
**v0.19.0**
|
||||
Read the [change log](https://github.com/falcosecurity/falco/blob/dev/CHANGELOG.md)
|
||||
Read the [change log](CHANGELOG.md)
|
||||
|
||||
Dev Branch: [](https://travis-ci.com/falcosecurity/falco)<br />
|
||||
Master Branch: [](https://travis-ci.com/falcosecurity/falco)<br />
|
||||
CII Best Practices: [](https://bestpractices.coreinfrastructure.org/projects/2317)
|
||||
[](https://circleci.com/gh/falcosecurity/falco) [](https://bestpractices.coreinfrastructure.org/projects/2317) [](COPYING)
|
||||
|
||||
---
|
||||
|
||||
@@ -47,27 +47,7 @@ See [Falco Documentation](https://falco.org/docs/) to quickly get started using
|
||||
Join the Community
|
||||
---
|
||||
|
||||
* [Join the mailing list](https://lists.cncf.io/g/cncf-falco-dev/) for news and a Google calendar invite for our Falco open source meetings. Note: this is the only way to get a calendar invite for our open meetings.
|
||||
* [Website](https://falco.org) for Falco.
|
||||
* Join our [Public Slack](https://slack.sysdig.com) channel for Falco announcements and discussions.
|
||||
|
||||
Community call
|
||||
---
|
||||
|
||||
> Are you using Falco? Do you have have ideas for things to do with Falco? How can Falco be better?
|
||||
|
||||
Falco has bi-weekly [community](https://github.com/falcosecurity/community) call which is an open call to discuss Falco from a user perspective. These happen on opposite weeks of Repo planning calls.
|
||||
|
||||
[Wednesdays at 8am Pacific](https://lists.cncf.io/g/cncf-falco-dev/calendar) on [Zoom](https://sysdig.zoom.us/j/213235330).
|
||||
|
||||
Repo planning
|
||||
---
|
||||
|
||||
> Do you want to contribute to Falco? Are you interested in working on Falco? Do you want to fix something or make something better?
|
||||
|
||||
Falco has bi-weekly planning meetings which is an open call to discuss upcoming Falco releases, and assign open GitHub issues to engineers. These happen on opposite weeks of office hours calls.
|
||||
|
||||
[Wednesdays at 8am Pacific](https://lists.cncf.io/g/cncf-falco-dev/calendar) on [Zoom](https://sysdig.zoom.us/j/213235330).
|
||||
To get involved with The Falco Project please visit [the community repository](https://github.com/falcosecurity/community) to find more.
|
||||
|
||||
License Terms
|
||||
---
|
||||
|
||||
142
brand/README.md
Normal file
142
brand/README.md
Normal file
@@ -0,0 +1,142 @@
|
||||
<p align="center"><img src="primary-logo.png" width="360"></p>
|
||||
<p align="center"><b>Cloud Native Runtime Security.</b></p>
|
||||
|
||||
# Falco Branding Guidelines
|
||||
|
||||
This document describes The Falco Project's branding guidelines, language, and message.
|
||||
|
||||
Content in this document can be used to publically share about Falco.
|
||||
|
||||
|
||||
|
||||
### Logo
|
||||
|
||||
There are 3 logos available for use in this directory. Use the primary logo unless required otherwise due to background issues, or printing.
|
||||
|
||||
The Falco logo is Apache 2 licensed and free to use in media and publication for the CNCF Falco project.
|
||||
|
||||
### Slogan
|
||||
|
||||
> Cloud Native Runtime Security
|
||||
|
||||
### What is Falco?
|
||||
|
||||
Falco is a runtime security project originally created by Sysdig, Inc.
|
||||
Falco was contributed to the CNCF in October 2018.
|
||||
The CNCF now owns The Falco Project.
|
||||
|
||||
### What is Runtime Security?
|
||||
|
||||
Runtime security refers to an approach to preventing unwanted activity on a computer system.
|
||||
With runtime security an operator deploys **both** prevention tooling (access control, policy enforcement, etc) along side detection tooling (systems observability, anomaly detection, etc).
|
||||
Runtime security is the practice of using detection tooling to detect unwanted behavior, such that it can then be prevented using prevention techniques.
|
||||
Runtime security is a holistic approach to defense, and useful in scenarios where prevention tooling either was unaware of an exploit or attack vector, or when defective applications are ran in even the most secure environment.
|
||||
|
||||
### What does Falco do?
|
||||
|
||||
Falco consumes signals from the Linux kernel, and container management tools such as Docker and Kubernetes.
|
||||
Falco parses the signals and asserts them against security rules.
|
||||
If a rule has been violated, Falco triggers an alert.
|
||||
|
||||
### How does Falco work?
|
||||
|
||||
Falco traces kernel events and reports information about the system calls being executed at runtime.
|
||||
Falco leverages the extended berkley packet filter (eBPF) which is a kernel feature implemented for dynamic crash-resilient and secure code execution in the kernel.
|
||||
Falco enriches these kernel events with information about containers running on the system.
|
||||
Falco also can consume signals from other input streams such as the containerd socket, the Kubernetes API server and the Kubernetes audit log.
|
||||
At runtime, Falco will reason about these events and assert them against configured security rules.
|
||||
Based on the severity of a violation an alert is triggered.
|
||||
These alerts are configurable and extensible, for instance sending a notification or [plumbing through to other projects like Prometheus](https://github.com/falcosecurity/falco-exporter).
|
||||
|
||||
### Benefits of using Falco
|
||||
|
||||
- **Strengthen Security** Create security rules driven by a context-rich and flexible engine to define unexpected application behavior.
|
||||
- **Reduce Risk** Immediately respond to policy violation alerts by plugging Falco into your current security response workflows and processes.
|
||||
- **Leverage up-to-date Rules** Alert using community-sourced detections of malicious activity and CVE exploits.
|
||||
|
||||
### Falco and securing Kubernetes
|
||||
|
||||
Securing Kubernetes requires putting controls in place to detect unexpected behavior that could be malicious or harmful to a cluster or application(s).
|
||||
|
||||
Examples of malicious behavior include:
|
||||
|
||||
- Exploits of unpatched and new vulnerabilities in applications or Kubernetes itself.
|
||||
- Insecure configurations in applications or Kubernetes itself.
|
||||
- Leaked or weak credentials or secret material.
|
||||
- Insider threats from adjacent applications running at the same layer.
|
||||
|
||||
Falco is capable of [consuming the Kubernetes audit logs](https://kubernetes.io/docs/tasks/debug-application-cluster/falco/#use-falco-to-collect-audit-events).
|
||||
By adding Kubernetes application context, and Kubernetes audit logs teams can understand who did what.
|
||||
|
||||
### Writing about Falco
|
||||
|
||||
##### Yes
|
||||
|
||||
Notice the capitalization of the following terms.
|
||||
|
||||
- The Falco Project
|
||||
- Falco
|
||||
|
||||
##### No
|
||||
|
||||
- falco
|
||||
- the falco project
|
||||
- the Falco project
|
||||
|
||||
### Encouraged Phrasing
|
||||
|
||||
Below are phrases that the project has reviewed, and found to be effective ways of messaging Falco's value add.
|
||||
Even when processes are in place for vulnerability scanning and implementing pod security and network policies, not every risk will be addressed. You still need mechanisms to confirm these security barriers are effective, help configure them, and provide with a last line of defense when they fail.
|
||||
|
||||
##### Falco as a factory
|
||||
|
||||
This term refers to the concept that Falco is a stateless processing engine. A large amount of data comes into the engine, but meticulously crafted security alerts come out.
|
||||
|
||||
##### The engine that powers...
|
||||
|
||||
Falco ultimately is a security engine. It reasons about signals coming from a system at runtime, and can alert if an anomaly is detected.
|
||||
|
||||
##### Anomaly detection
|
||||
|
||||
This refers to an event that occurs with something unsual, concerning, or odd occurs.
|
||||
We can associate anomalies with unwanted behavior, and alert in their presence.
|
||||
|
||||
##### Detection tooling
|
||||
|
||||
Falco does not prevent unwanted behavior.
|
||||
Falco however alerts when unusual behavior occurs.
|
||||
This is commonly referred to as **detection** or **forensics**.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# Glossary
|
||||
|
||||
#### Probe
|
||||
|
||||
Used to describe the `.o` object that would be dynamically loaded into the kernel as a secure and stable (e)BPF probe.
|
||||
This is one option used to pass kernel events up to userspace for Falco to consume.
|
||||
Sometimes this word is incorrectly used to refer to a `module`.
|
||||
|
||||
#### Module
|
||||
|
||||
Used to describe the `.ko` object that would be loaded into the kernel as a potentially risky kernel module.
|
||||
This is one option used to pass kernel events up to userspace for Falco to consume.
|
||||
Sometimes this word is incorrectly used to refer to a `probe`.
|
||||
|
||||
#### Driver (deprecated)
|
||||
|
||||
An older, more generalized term for a `module` or `probe`. We discourage the use of this word as a project.
|
||||
|
||||
#### Falco
|
||||
|
||||
The name of the project, and also the name of [the main engine](https://github.com/falcosecurity/falco) that the rest of the project is built on.
|
||||
|
||||
#### Sysdig, Inc
|
||||
|
||||
The name of the company that originally created The Falco Project, and later donated to the CNCF.
|
||||
|
||||
#### sysdig
|
||||
|
||||
A [CLI tool](https://github.com/draios/sysdig) used to evaluate kernel system events at runtime.
|
||||
|
||||
BIN
brand/primary-logo.png
Normal file
BIN
brand/primary-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
1
brand/teal-logo.png
Normal file
1
brand/teal-logo.png
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 708.41 374.92"><defs><style>.cls-1{fill:#00b4c8;}</style></defs><title>Falco horizontal logo_teal2</title><g id="fqqZXT"><path class="cls-1" d="M204.69,154.4Q151.5,208,98,261.25a48.42,48.42,0,0,1-5.27,4.87c-2.55,1.89-5.34,2-7.65-.45s-1.51-5,.41-7.06c4.6-4.94,9.35-9.74,14.13-14.5q52.56-52.31,105.14-104.59c3.35-3.34,18.05,7.52,21.58,11.1"/><path class="cls-1" d="M215.06,171.36c-.15,2.14-1.54,3.55-2.93,4.94l-87.82,87.79c-2.75,2.74-6,5.42-9.46,1.68-3.15-3.39-.5-6.44,2.06-9q43.44-43.44,86.89-86.87c2.21-2.22,4.58-4.23,8-3A4.61,4.61,0,0,1,215.06,171.36Z"/><path class="cls-1" d="M70.93,71c2.42-.09,4.09,1.31,5.64,2.87q41.82,41.79,83.61,83.59c2.6,2.61,5,5.74,1.69,9s-6.41,1-9-1.66Q111,123,69.25,81.2c-2.09-2.1-3.72-4.39-2.45-7.53A4.34,4.34,0,0,1,70.93,71Z"/><path class="cls-1" d="M203.42,268c-5,1-8.9-1.34-12.45-5-6.35-6.61-12.87-13-19.41-19.46-3.85-3.8-4-7.41-.14-11.28,11.14-11.07,22.21-22.21,33.35-33.29,2.45-2.44,5.43-4.49,8.55-1.55,3.48,3.29,1.19,6.41-1.39,9-8.74,8.84-17.44,17.73-26.4,26.35-3.4,3.27-3.93,5.72-.19,9.06,4.22,3.78,8.13,7.91,12,12,2.54,2.68,5.35,4.25,9.18,4.11s8.28-.12,8.16,5.09c-.12,5-4.74,4.8-8.4,5.14A21,21,0,0,1,203.42,268Z"/><path class="cls-1" d="M148.7,178.36c-.75,3.49-2.68,5.6-6.43,4.36a13,13,0,0,1-4.74-3.31q-30.11-30-60.1-60a23.14,23.14,0,0,1-2.56-3c-1.72-2.42-1.88-5,.3-7.11s4.84-1.76,7,.26c3.65,3.42,7.17,7,10.71,10.53q25.65,25.64,51.28,51.3C146.12,173.37,148.49,175.13,148.7,178.36Z"/><path class="cls-1" d="M133.74,192.93a4.9,4.9,0,0,1-2.53,4.29,5.37,5.37,0,0,1-6.63-.95c-3.35-3.1-6.57-6.34-9.8-9.57q-14.34-14.3-28.61-28.63a34.27,34.27,0,0,1-4.17-5,4.57,4.57,0,0,1,.36-6,5,5,0,0,1,6-1.12,11.65,11.65,0,0,1,3.7,2.58q19.44,19.33,38.79,38.76C132.4,188.85,133.77,190.54,133.74,192.93Z"/></g><path class="cls-1" d="M413.15,190.86a25.57,25.57,0,0,0-10.35-6.63,46.78,46.78,0,0,0-16-2.37A83.35,83.35,0,0,0,372,183.12a75.16,75.16,0,0,0-10.58,2.53l2.37,15.48a53.47,53.47,0,0,1,9-2.21A72.44,72.44,0,0,1,385,198a22.61,22.61,0,0,1,8.13,1.26,13,13,0,0,1,5.22,3.56,13.23,13.23,0,0,1,2.76,5.29,24.6,24.6,0,0,1,.79,6.32v3.16a61.65,61.65,0,0,0-7.42-1.34,57.43,57.43,0,0,0-6.64-.4,61.45,61.45,0,0,0-13,1.35,32.26,32.26,0,0,0-11,4.42,22.7,22.7,0,0,0-7.51,8,24.09,24.09,0,0,0-2.76,12A28.39,28.39,0,0,0,356,254.05a21.6,21.6,0,0,0,6.79,8.22,28.56,28.56,0,0,0,10.51,4.58,60.24,60.24,0,0,0,13.58,1.42A137.25,137.25,0,0,0,407,266.93c5.94-.9,10.4-1.66,13.35-2.29V214.56a50.84,50.84,0,0,0-1.66-13.35A24.93,24.93,0,0,0,413.15,190.86Zm-11.3,61.3a71.4,71.4,0,0,1-13.43.94q-7.26,0-11.53-2.6t-4.26-9.4a10,10,0,0,1,1.57-5.77,10.67,10.67,0,0,1,4.19-3.55,20.18,20.18,0,0,1,5.85-1.74,43.43,43.43,0,0,1,6.39-.47,42.23,42.23,0,0,1,6.64.47,37,37,0,0,1,4.58,1Z"/><path class="cls-1" d="M461.38,248.44a9.27,9.27,0,0,1-2-4,26.17,26.17,0,0,1-.55-5.85V143.94l-19.12,3.16v95.1a40.74,40.74,0,0,0,1.35,11,17.57,17.57,0,0,0,4.66,8.06,21.71,21.71,0,0,0,8.92,5,52,52,0,0,0,14.14,1.89l2.69-15.8a29.78,29.78,0,0,1-6.24-1.34A8.76,8.76,0,0,1,461.38,248.44Z"/><path class="cls-1" d="M532.2,251.05a49.24,49.24,0,0,1-9.64.95q-13.11,0-18.64-7.19t-5.53-19.51q0-12.8,5.85-19.83t17.06-7a40.4,40.4,0,0,1,8.92.95,43.38,43.38,0,0,1,7.51,2.37l4.1-15.64a57.88,57.88,0,0,0-22.11-4.26,42.15,42.15,0,0,0-17.06,3.31,37.35,37.35,0,0,0-12.88,9.17,40.64,40.64,0,0,0-8.14,13.82,50.82,50.82,0,0,0-2.84,17.14,56.83,56.83,0,0,0,2.53,17.3A37.22,37.22,0,0,0,489,256.34a34.82,34.82,0,0,0,13,9,47.83,47.83,0,0,0,18.4,3.24,68.05,68.05,0,0,0,13.19-1.27,39.84,39.84,0,0,0,9.56-2.84l-2.69-15.8A45,45,0,0,1,532.2,251.05Z"/><path class="cls-1" d="M625.77,207.37a40.7,40.7,0,0,0-8.14-13.67,35.23,35.23,0,0,0-12.56-8.76,40.93,40.93,0,0,0-16-3.08,40.34,40.34,0,0,0-16,3.08,36.32,36.32,0,0,0-12.56,8.76,39.88,39.88,0,0,0-8.21,13.67,51.31,51.31,0,0,0-2.93,17.77A52,52,0,0,0,552.31,243a40.47,40.47,0,0,0,8.13,13.75,36.57,36.57,0,0,0,12.48,8.85A40.14,40.14,0,0,0,589,268.74a40.69,40.69,0,0,0,16.19-3.15,36.32,36.32,0,0,0,12.56-8.85A39.7,39.7,0,0,0,625.85,243a53.47,53.47,0,0,0,2.84-17.85A51.55,51.55,0,0,0,625.77,207.37Zm-22,37.52q-5.29,7.28-14.77,7.27t-14.77-7.27q-5.29-7.26-5.3-19.75,0-12.31,5.3-19.51T589,198.44q9.48,0,14.77,7.19t5.29,19.51Q609.1,237.62,603.81,244.89Z"/><path class="cls-1" d="M347.24,218h-47.8v50.57H279.65V150h75.89v15.88h-56.1v36.23h47.8Z"/></svg>
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
BIN
brand/white-logo.png
Normal file
BIN
brand/white-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
59
cmake/modules/GetFalcoVersion.cmake
Normal file
59
cmake/modules/GetFalcoVersion.cmake
Normal file
@@ -0,0 +1,59 @@
|
||||
# Retrieve git ref and commit hash
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(FALCO_REF FALCO_HASH)
|
||||
|
||||
# Create the falco version variable according to git index
|
||||
if(NOT FALCO_VERSION)
|
||||
string(STRIP "${FALCO_HASH}" FALCO_HASH)
|
||||
# Try to obtain the exact git tag
|
||||
git_get_exact_tag(FALCO_TAG)
|
||||
if(NOT FALCO_TAG)
|
||||
# Obtain the closest tag
|
||||
git_describe(FALCO_VERSION "--abbrev=0" "--tags") # suppress the long format
|
||||
# Fallback version
|
||||
if(FALCO_VERSION MATCHES "NOTFOUND$")
|
||||
set(FALCO_VERSION "0.0.0")
|
||||
endif()
|
||||
# TODO(leodido) > Construct the prerelease part (semver 2) Construct the Build metadata part (semver 2)
|
||||
if(NOT FALCO_HASH MATCHES "NOTFOUND$")
|
||||
string(SUBSTRING "${FALCO_HASH}" 0 7 FALCO_VERSION_BUILD)
|
||||
# Check whether there are uncommitted changes or not
|
||||
git_local_changes(FALCO_CHANGES)
|
||||
if(FALCO_CHANGES STREQUAL "DIRTY")
|
||||
string(TOLOWER "${FALCO_CHANGES}" FALCO_CHANGES)
|
||||
set(FALCO_VERSION_BUILD "${FALCO_VERSION_BUILD}.${FALCO_CHANGES}")
|
||||
endif()
|
||||
endif()
|
||||
# Append the build metadata part (semver 2)
|
||||
if(FALCO_VERSION_BUILD)
|
||||
set(FALCO_VERSION "${FALCO_VERSION}+${FALCO_VERSION_BUILD}")
|
||||
endif()
|
||||
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-]*)*).*"
|
||||
"\\4"
|
||||
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()
|
||||
message(STATUS "Falco version: ${FALCO_VERSION}")
|
||||
@@ -104,18 +104,19 @@ function(git_describe _var)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize if((${ARGN}" MATCHES "&&") OR (ARGN MATCHES "||") OR (ARGN MATCHES "\\;")) message("Please report the
|
||||
# following error to the project!") message(FATAL_ERROR "Looks like someone's doing something nefarious with
|
||||
# git_describe! Passed arguments ${ARGN}") endif()
|
||||
|
||||
# message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" describe ${hash} ${ARGN}
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE res
|
||||
OUTPUT_VARIABLE out
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
@@ -16,7 +16,7 @@ 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 system OpenSSL
|
||||
# explicitly force this dependency to use the bundled OpenSSL
|
||||
set(USE_BUNDLED_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ ADD https://s3.amazonaws.com/download.draios.com/stable/tgz/x86_64/falco-${FALCO
|
||||
|
||||
# ADD will download from URL and unntar
|
||||
RUN apt-get update && \
|
||||
apt-get install -y binutils && \
|
||||
apt-get install -y libyaml-0-2 binutils && \
|
||||
# curl -O https://s3.amazonaws.com/download.draios.com/stable/tgz/x86_64/falco-${FALCO_VERSION}-x86_64.tar.gz && \
|
||||
tar xfzv falco-${FALCO_VERSION}-x86_64.tar.gz && \
|
||||
rm -f falco-${FALCO_VERSION}-x86_64.tar.gz && \
|
||||
@@ -24,17 +24,25 @@ RUN apt-get update && \
|
||||
FROM scratch
|
||||
|
||||
COPY --from=ubuntu /lib/x86_64-linux-gnu/libanl.so.1 \
|
||||
/lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libdl.so.2 \
|
||||
/lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/x86_64-linux-gnu/libm.so.6 \
|
||||
/lib/x86_64-linux-gnu/libnsl.so.1 /lib/x86_64-linux-gnu/libnss_compat.so.2 \
|
||||
/lib/x86_64-linux-gnu/libnss_files.so.2 /lib/x86_64-linux-gnu/libnss_nis.so.2 \
|
||||
/lib/x86_64-linux-gnu/libpthread.so.0 /lib/x86_64-linux-gnu/librt.so.1 \
|
||||
/lib/x86_64-linux-gnu/libc.so.6 \
|
||||
/lib/x86_64-linux-gnu/libdl.so.2 \
|
||||
/lib/x86_64-linux-gnu/libgcc_s.so.1 \
|
||||
/lib/x86_64-linux-gnu/libm.so.6 \
|
||||
/lib/x86_64-linux-gnu/libnsl.so.1 \
|
||||
/lib/x86_64-linux-gnu/libnss_compat.so.2 \
|
||||
/lib/x86_64-linux-gnu/libnss_files.so.2 \
|
||||
/lib/x86_64-linux-gnu/libnss_nis.so.2 \
|
||||
/lib/x86_64-linux-gnu/libpthread.so.0 \
|
||||
/lib/x86_64-linux-gnu/librt.so.1 \
|
||||
/lib/x86_64-linux-gnu/libz.so.1 \
|
||||
/lib/x86_64-linux-gnu/
|
||||
|
||||
COPY --from=ubuntu /usr/lib/x86_64-linux-gnu/libstdc++.so.6 \
|
||||
/usr/lib/x86_64-linux-gnu/libstdc++.so.6
|
||||
|
||||
COPY --from=ubuntu /usr/lib/x86_64-linux-gnu/libyaml-0.so.2.0.5 \
|
||||
/usr/lib/x86_64-linux-gnu/libyaml-0.so.2
|
||||
|
||||
COPY --from=ubuntu /etc/ld.so.cache \
|
||||
/etc/nsswitch.conf \
|
||||
/etc/ld.so.cache \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# gRPC Falco Output
|
||||
# gRPC Falco Outputs
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
@@ -77,18 +77,18 @@ syntax = "proto3";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "schema.proto";
|
||||
|
||||
package falco.output;
|
||||
package falco.outputs;
|
||||
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
|
||||
|
||||
// The `subscribe` service defines the RPC call
|
||||
// The `outputs` service defines a server-streaming RPC call
|
||||
// to perform an output `request` which will lead to obtain an output `response`.
|
||||
service service {
|
||||
rpc subscribe(request) returns (stream response);
|
||||
rpc outputs(request) returns (stream response);
|
||||
}
|
||||
|
||||
// The `request` message is the logical representation of the request model.
|
||||
// It is the input of the `subscribe` service.
|
||||
// It is the input of the `outputs` service.
|
||||
// It is used to configure the kind of subscription to the gRPC streaming server.
|
||||
message request {
|
||||
bool keepalive = 1;
|
||||
|
||||
@@ -744,7 +744,7 @@
|
||||
|
||||
- macro: ms_oms_writing_conf
|
||||
condition: >
|
||||
((proc.name in (omiagent,omsagent,in_heartbeat_r*,omsadmin.sh,PerformInventor)
|
||||
((proc.name in (omiagent,omsagent,in_heartbeat_r*,omsadmin.sh,PerformInventor,dsc_host)
|
||||
or proc.pname in (ms_oms_binaries)
|
||||
or proc.aname[2] in (ms_oms_binaries))
|
||||
and (fd.name startswith /etc/opt/omi or fd.name startswith /etc/opt/microsoft/omsagent))
|
||||
@@ -1156,6 +1156,16 @@
|
||||
- macro: automount_using_mtab
|
||||
condition: (proc.pname = automount and fd.name startswith /etc/mtab)
|
||||
|
||||
- macro: mcafee_writing_cma_d
|
||||
condition: (proc.name=macompatsvc and fd.directory=/etc/cma.d)
|
||||
|
||||
- macro: avinetworks_supervisor_writing_ssh
|
||||
condition: >
|
||||
(proc.cmdline="se_supervisor.p /opt/avi/scripts/se_supervisor.py -d" and
|
||||
(fd.name startswith /etc/ssh/known_host_ or
|
||||
fd.name startswith /etc/ssh/ssh_monitor_config_ or
|
||||
fd.name startswith /etc/ssh/ssh_config_))
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to allow for specific combinations of
|
||||
# programs writing below specific directories below
|
||||
@@ -1190,6 +1200,7 @@
|
||||
qualys-cloud-ag, locales.postins, nomachine_binaries,
|
||||
adclient, certutil, crlutil, pam-auth-update, parallels_insta,
|
||||
openshift-launc, update-rc.d, puppet)
|
||||
and not (container and proc.cmdline in ("cp /run/secrets/kubernetes.io/serviceaccount/ca.crt /etc/pki/ca-trust/source/anchors/openshift-ca.crt"))
|
||||
and not proc.pname in (sysdigcloud_binaries, mail_config_binaries, hddtemp.postins, sshkit_script_binaries, locales.postins, deb_binaries, dhcp_binaries)
|
||||
and not fd.name pmatch (safe_etc_dirs)
|
||||
and not fd.name in (/etc/container_environment.sh, /etc/container_environment.json, /etc/motd, /etc/motd.svc)
|
||||
@@ -1273,6 +1284,8 @@
|
||||
and not etcd_manager_updating_dns
|
||||
and not user_known_write_below_etc_activities
|
||||
and not automount_using_mtab
|
||||
and not mcafee_writing_cma_d
|
||||
and not avinetworks_supervisor_writing_ssh
|
||||
|
||||
- rule: Write below etc
|
||||
desc: an attempt to write to any file below /etc
|
||||
@@ -1340,6 +1353,9 @@
|
||||
- macro: user_known_write_below_root_activities
|
||||
condition: (never_true)
|
||||
|
||||
- macro: runc_writing_exec_fifo
|
||||
condition: (proc.cmdline="runc:[1:CHILD] init" and fd.name=/exec.fifo)
|
||||
|
||||
- rule: Write below root
|
||||
desc: an attempt to write to any file directly below / or /root
|
||||
condition: >
|
||||
@@ -1359,6 +1375,7 @@
|
||||
and not galley_writing_state
|
||||
and not calico_writing_state
|
||||
and not rancher_writing_root
|
||||
and not runc_writing_exec_fifo
|
||||
and not known_root_conditions
|
||||
and not user_known_write_root_conditions
|
||||
and not user_known_write_below_root_activities
|
||||
@@ -1529,7 +1546,7 @@
|
||||
condition: >
|
||||
evt.type = setns
|
||||
and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries,
|
||||
sysdig, nsenter, calico, oci-umount, network_plugin_binaries)
|
||||
sysdig, nsenter, calico, oci-umount, cilium-cni, network_plugin_binaries)
|
||||
and not proc.name in (user_known_change_thread_namespace_binaries)
|
||||
and not proc.name startswith "runc"
|
||||
and not proc.cmdline startswith "containerd"
|
||||
@@ -1668,7 +1685,8 @@
|
||||
mesos_shell_binaries,
|
||||
erl_child_setup, exechealthz,
|
||||
PM2, PassengerWatchd, c_rehash, svlogd, logrotate, hhvm, serf,
|
||||
lb-controller, nvidia-installe, runsv, statsite, erlexec)
|
||||
lb-controller, nvidia-installe, runsv, statsite, erlexec, calico-node,
|
||||
"puma reactor")
|
||||
and not proc.cmdline in (known_shell_spawn_cmdlines)
|
||||
and not proc.aname in (unicorn_launche)
|
||||
and not consul_running_net_scripts
|
||||
|
||||
@@ -13,7 +13,6 @@ 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 "webserver.h"
|
||||
#include <catch.hpp>
|
||||
|
||||
@@ -22,7 +21,7 @@ TEST_CASE("webserver must accept invalid data", "[!hide][webserver][k8s_audit_ha
|
||||
// falco_engine* engine = new falco_engine();
|
||||
// falco_outputs* outputs = new falco_outputs(engine);
|
||||
// std::string errstr;
|
||||
// std::string input("{\"kind\": 0}");
|
||||
// std::string input("{\"kind\": 0}");
|
||||
//k8s_audit_handler::accept_data(engine, outputs, input, errstr);
|
||||
|
||||
REQUIRE(1 == 1);
|
||||
|
||||
25
userspace/engine/banned.h
Normal file
25
userspace/engine/banned.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// BAN macro defines `function` as an invalid token that says using
|
||||
// the function is banned. This throws a compile time error when the
|
||||
// function is used.
|
||||
#define BAN(function) using_##function##_is_banned
|
||||
|
||||
#undef strcpy
|
||||
#define strcpy(a, b) BAN(strcpy)
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
|
||||
#include "config_falco_engine.h"
|
||||
#include "falco_common.h"
|
||||
#include "banned.h"
|
||||
|
||||
std::vector<std::string> falco_common::priority_names = {
|
||||
"Emergency",
|
||||
@@ -117,4 +118,3 @@ void falco_common::add_lua_path(string &path)
|
||||
|
||||
lua_pop(m_ls, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "utils.h"
|
||||
#include "banned.h"
|
||||
|
||||
|
||||
string lua_on_event = "on_event";
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "falco_utils.h"
|
||||
#include "banned.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
|
||||
#include "formats.h"
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h"
|
||||
|
||||
|
||||
sinsp* falco_formats::s_inspector = NULL;
|
||||
@@ -145,11 +146,13 @@ int falco_formats::format_event (lua_State *ls)
|
||||
if(strcmp(source, "syscall") == 0)
|
||||
{
|
||||
try {
|
||||
// This is "output"
|
||||
s_formatters->tostring((sinsp_evt *) evt, sformat, &line);
|
||||
|
||||
if(s_json_output)
|
||||
{
|
||||
switch(s_inspector->get_buffer_format())
|
||||
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);
|
||||
@@ -170,6 +173,7 @@ int falco_formats::format_event (lua_State *ls)
|
||||
// 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.
|
||||
@@ -177,8 +181,7 @@ int falco_formats::format_event (lua_State *ls)
|
||||
{
|
||||
json_line.erase(0, 1);
|
||||
}
|
||||
|
||||
s_inspector->set_buffer_format(sinsp_evt::PF_NORMAL);
|
||||
s_inspector->set_buffer_format(cur_fmt);
|
||||
}
|
||||
}
|
||||
catch (sinsp_exception& e)
|
||||
|
||||
@@ -21,6 +21,7 @@ limitations under the License.
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "json_evt.h"
|
||||
#include "banned.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace std;
|
||||
@@ -511,31 +512,27 @@ const json_event_filter_check::values_t &json_event_filter_check::extracted_valu
|
||||
|
||||
bool json_event_filter_check::compare(gen_event *evt)
|
||||
{
|
||||
json_event *jevt = (json_event *)evt;
|
||||
auto jevt = (json_event *)evt;
|
||||
|
||||
uint32_t len;
|
||||
|
||||
const extracted_values_t *evalues = (const extracted_values_t *) extract(jevt, &len);
|
||||
auto evalues = (const extracted_values_t *) extract(jevt, &len);
|
||||
values_set_t setvals;
|
||||
|
||||
switch(m_cmpop)
|
||||
{
|
||||
case CO_EQ:
|
||||
return evalues->second == m_values;
|
||||
break;
|
||||
case CO_NE:
|
||||
return evalues->second != m_values;
|
||||
break;
|
||||
case CO_STARTSWITH:
|
||||
return (evalues->first.size() == 1 &&
|
||||
m_values.size() == 1 &&
|
||||
evalues->first.at(0).startswith(*(m_values.begin())));
|
||||
break;
|
||||
case CO_CONTAINS:
|
||||
return (evalues->first.size() == 1 &&
|
||||
m_values.size() == 1 &&
|
||||
evalues->first.at(0).contains(*(m_values.begin())));
|
||||
break;
|
||||
case CO_IN:
|
||||
for(auto &item : evalues->second)
|
||||
{
|
||||
@@ -545,7 +542,6 @@ bool json_event_filter_check::compare(gen_event *evt)
|
||||
}
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
case CO_PMATCH:
|
||||
for(auto &item : evalues->second)
|
||||
{
|
||||
@@ -558,19 +554,16 @@ bool json_event_filter_check::compare(gen_event *evt)
|
||||
}
|
||||
}
|
||||
return true;
|
||||
break;
|
||||
case CO_INTERSECTS:
|
||||
std::set_intersection(evalues->second.begin(), evalues->second.end(),
|
||||
m_values.begin(), m_values.end(),
|
||||
std::inserter(setvals, setvals.begin()));
|
||||
return (setvals.size() > 0);
|
||||
break;
|
||||
return (!setvals.empty());
|
||||
case CO_LT:
|
||||
return (evalues->first.size() == 1 &&
|
||||
m_values.size() == 1 &&
|
||||
evalues->first.at(0).ptype() == m_values.begin()->ptype() &&
|
||||
evalues->first.at(0) < *(m_values.begin()));
|
||||
break;
|
||||
case CO_LE:
|
||||
return (evalues->first.size() == 1 &&
|
||||
m_values.size() == 1 &&
|
||||
@@ -588,11 +581,9 @@ bool json_event_filter_check::compare(gen_event *evt)
|
||||
evalues->first.at(0).ptype() == m_values.begin()->ptype() &&
|
||||
(evalues->first.at(0) > *(m_values.begin()) ||
|
||||
evalues->first.at(0) == *(m_values.begin())));
|
||||
break;
|
||||
case CO_EXISTS:
|
||||
return (evalues->first.size() == 1 &&
|
||||
(evalues->first.at(0) != json_event_filter_check::no_value));
|
||||
break;
|
||||
default:
|
||||
throw falco_exception("filter error: unsupported comparison operator");
|
||||
}
|
||||
|
||||
@@ -193,7 +193,6 @@ public:
|
||||
const values_t &extracted_values();
|
||||
|
||||
protected:
|
||||
|
||||
// Subclasses can override this method, calling
|
||||
// add_extracted_value to add extracted values.
|
||||
virtual bool extract_values(json_event *jevt);
|
||||
@@ -282,7 +281,8 @@ private:
|
||||
|
||||
// If true, this filtercheck works on paths, which enables
|
||||
// some extra bookkeeping to allow for path prefix searches.
|
||||
bool m_uses_paths;
|
||||
bool m_uses_paths = false;
|
||||
|
||||
path_prefix_search m_prefix_search;
|
||||
};
|
||||
|
||||
@@ -292,7 +292,7 @@ public:
|
||||
jevt_filter_check();
|
||||
virtual ~jevt_filter_check();
|
||||
|
||||
int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) final;
|
||||
int32_t parse_field_name(const char* str, bool alloc_state, bool needed_for_filtering) final;
|
||||
|
||||
json_event_filter_check *allocate_new();
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include "falco_engine.h"
|
||||
#include "banned.h"
|
||||
|
||||
const static struct luaL_reg ll_falco_rules [] =
|
||||
{
|
||||
{"clear_filters", &falco_rules::clear_filters},
|
||||
@@ -480,4 +482,3 @@ falco_rules::~falco_rules()
|
||||
delete m_sinsp_lua_parser;
|
||||
delete m_json_lua_parser;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ruleset.h"
|
||||
#include "banned.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ limitations under the License.
|
||||
|
||||
#include "token_bucket.h"
|
||||
#include "utils.h"
|
||||
#include "banned.h"
|
||||
|
||||
token_bucket::token_bucket():
|
||||
token_bucket(sinsp_utils::get_current_time_ns)
|
||||
|
||||
@@ -15,16 +15,47 @@ configure_file("${SYSDIG_SOURCE_DIR}/userspace/sysdig/config_sysdig.h.in" config
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/output.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
|
||||
COMMENT "Generate gRPC code"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/output.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/output.proto
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/inputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/inputs.grpc.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/inputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/inputs.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/event.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/event.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/grpc.pb.h
|
||||
COMMENT "Generate gRPC API"
|
||||
# version API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
|
||||
# outputs API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto ${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/output.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
# inputs API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/inputs.proto ${CMAKE_CURRENT_SOURCE_DIR}/event.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/inputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/event.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/inputs.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
# context API
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/grpc.proto
|
||||
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/grpc.proto)
|
||||
|
||||
add_executable(
|
||||
falco
|
||||
@@ -38,16 +69,23 @@ add_executable(
|
||||
webserver.cpp
|
||||
grpc_context.cpp
|
||||
grpc_server_impl.cpp
|
||||
grpc_request_context.cpp
|
||||
grpc_server.cpp
|
||||
utils.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/inputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/inputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/event.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/grpc.pb.cc)
|
||||
|
||||
add_dependencies(falco civetweb)
|
||||
|
||||
if(USE_BUNDLED_DEPS)
|
||||
add_dependencies(falco yamlcpp)
|
||||
add_dependencies(falco yamlcpp)
|
||||
endif()
|
||||
|
||||
target_include_directories(
|
||||
|
||||
@@ -16,7 +16,14 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FALCO_BRANCH "@FALCO_REF@"
|
||||
#define FALCO_HASH "@FALCO_HASH@"
|
||||
#define FALCO_VERSION "@FALCO_VERSION@"
|
||||
#define FALCO_VERSION_MAJOR @FALCO_VERSION_MAJOR@
|
||||
#define FALCO_VERSION_MINOR @FALCO_VERSION_MINOR@
|
||||
#define FALCO_VERSION_PATCH @FALCO_VERSION_PATCH@
|
||||
#define FALCO_VERSION_PRERELEASE "@FALCO_VERSION_PRERELEASE@"
|
||||
#define FALCO_VERSION_BUILD "@FALCO_VERSION_BUILD@"
|
||||
|
||||
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
|
||||
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
||||
|
||||
@@ -23,6 +23,7 @@ limitations under the License.
|
||||
|
||||
#include "configuration.h"
|
||||
#include "logger.h"
|
||||
#include "banned.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -87,7 +88,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
filename = m_config->get_scalar<string>("file_output", "filename", "");
|
||||
if(filename == string(""))
|
||||
{
|
||||
throw invalid_argument("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
|
||||
throw logic_error("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
|
||||
}
|
||||
file_output.options["filename"] = filename;
|
||||
|
||||
@@ -119,7 +120,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
program = m_config->get_scalar<string>("program_output", "program", "");
|
||||
if(program == string(""))
|
||||
{
|
||||
throw sinsp_exception("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
|
||||
throw logic_error("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
|
||||
}
|
||||
program_output.options["program"] = program;
|
||||
|
||||
@@ -138,7 +139,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
|
||||
if(url == string(""))
|
||||
{
|
||||
throw sinsp_exception("Error reading config file (" + m_config_file + "): http output enabled but no url in configuration block");
|
||||
throw logic_error("Error reading config file (" + m_config_file + "): http output enabled but no url in configuration block");
|
||||
}
|
||||
http_output.options["url"] = url;
|
||||
|
||||
@@ -148,6 +149,10 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_grpc_enabled = m_config->get_scalar<bool>("grpc", "enabled", false);
|
||||
m_grpc_bind_address = m_config->get_scalar<string>("grpc", "bind_address", "0.0.0.0:5060");
|
||||
m_grpc_threadiness = m_config->get_scalar<uint32_t>("grpc", "threadiness", 8); // todo > limit it to avoid overshubscription? std::thread::hardware_concurrency()
|
||||
if(m_grpc_threadiness == 0)
|
||||
{
|
||||
throw logic_error("error reading config file (" + m_config_file +"): gRPC threadiness must be greater than 0");
|
||||
}
|
||||
m_grpc_private_key = m_config->get_scalar<string>("grpc", "private_key", "/etc/falco/certs/server.key");
|
||||
m_grpc_cert_chain = m_config->get_scalar<string>("grpc", "cert_chain", "/etc/falco/certs/server.crt");
|
||||
m_grpc_root_certs = m_config->get_scalar<string>("grpc", "root_certs", "/etc/falco/certs/ca.crt");
|
||||
@@ -162,12 +167,12 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
|
||||
if(m_outputs.size() == 0)
|
||||
{
|
||||
throw invalid_argument("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
|
||||
throw logic_error("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
|
||||
}
|
||||
|
||||
string log_level = m_config->get_scalar<string>("log_level", "info");
|
||||
m_log_level = m_config->get_scalar<string>("log_level", "info");
|
||||
|
||||
falco_logger::set_level(log_level);
|
||||
falco_logger::set_level(m_log_level);
|
||||
|
||||
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
|
||||
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
|
||||
@@ -181,7 +186,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
|
||||
if((it = std::find_if(falco_common::priority_names.begin(), falco_common::priority_names.end(), comp)) == falco_common::priority_names.end())
|
||||
{
|
||||
throw invalid_argument("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
|
||||
throw logic_error("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
|
||||
}
|
||||
m_min_priority = (falco_common::priority_type)(it - falco_common::priority_names.begin());
|
||||
|
||||
@@ -220,7 +225,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
}
|
||||
else
|
||||
{
|
||||
throw invalid_argument("Error reading config file (" + m_config_file + "): syscall event drop action " + act + " must be one of \"ignore\", \"log\", \"alert\", or \"exit\"");
|
||||
throw logic_error("Error reading config file (" + m_config_file + "): syscall event drop action " + act + " must be one of \"ignore\", \"log\", \"alert\", or \"exit\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,7 +333,7 @@ void falco_configuration::set_cmdline_option(const string &opt)
|
||||
|
||||
if(!split(opt, '=', keyval))
|
||||
{
|
||||
throw invalid_argument("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val");
|
||||
throw logic_error("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val");
|
||||
}
|
||||
|
||||
if(split(keyval.first, '.', subkey))
|
||||
|
||||
@@ -195,6 +195,7 @@ public:
|
||||
std::list<std::string> m_rules_filenames;
|
||||
bool m_json_output;
|
||||
bool m_json_include_output_property;
|
||||
std::string m_log_level;
|
||||
std::vector<falco_outputs::output_config> m_outputs;
|
||||
uint32_t m_notifications_rate;
|
||||
uint32_t m_notifications_max_burst;
|
||||
|
||||
159
userspace/falco/event.proto
Normal file
159
userspace/falco/event.proto
Normal file
@@ -0,0 +1,159 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
package falco.event;
|
||||
|
||||
// note > from ppm_events_public.h
|
||||
// (ppm_param_type)
|
||||
enum param_type {
|
||||
PT_NONE = 0;
|
||||
PT_INT8 = 1;
|
||||
PT_INT16 = 2;
|
||||
PT_INT32 = 3;
|
||||
PT_INT64 = 4;
|
||||
PT_UINT8 = 5;
|
||||
PT_UINT16 = 6;
|
||||
PT_UINT32 = 7;
|
||||
PT_UINT64 = 8;
|
||||
PT_CHARBUF = 9; // A printable buffer of bytes, NULL terminated
|
||||
PT_BYTEBUF = 10; // A raw buffer of bytes not suitable for printing
|
||||
PT_ERRNO = 11; // This is an INT4; but will be interpreted as an error code
|
||||
PT_SOCKADDR = 12; // A sockaddr structure, 1byte family + data
|
||||
PT_SOCKTUPLE = 13; // A sockaddr tuple,1byte family + 12byte data + 12byte data
|
||||
PT_FD = 14; // An fd, 64bit
|
||||
PT_PID = 15; // A pid/tid, 64bit
|
||||
PT_FDLIST = 16; // A list of fds, 16bit count + count * (64bit fd + 16bit flags)
|
||||
PT_FSPATH = 17; // A string containing a relative or absolute file system path, null terminated
|
||||
PT_SYSCALLID = 18; // A 16bit system call ID that can be used as a key for the g_syscall_info_table table
|
||||
PT_SIGTYPE = 19; // An 8bit signal number
|
||||
PT_RELTIME = 20; // A relative time. Seconds * 10^9 + nanoseconds, 64bit
|
||||
PT_ABSTIME = 21; // An absolute time interval. Seconds from epoch * 10^9 + nanoseconds, 64bit
|
||||
PT_PORT = 22; // A TCP/UDP port, 2 bytes
|
||||
PT_L4PROTO = 23; // A 1 byte IP protocol type
|
||||
PT_SOCKFAMILY = 24; // A 1 byte socket family
|
||||
PT_BOOL = 25; // A boolean value, 4 bytes
|
||||
PT_IPV4ADDR = 26; // A 4 byte raw IPv4 address
|
||||
PT_DYN = 27; // Type can vary depending on the context (used for filter fields like evt.rawarg)
|
||||
PT_FLAGS8 = 28; // This is an UINT8; but will be interpreted as 8 bit flags
|
||||
PT_FLAGS16 = 29; // This is an UINT6; but will be interpreted as 16 bit flags
|
||||
PT_FLAGS32 = 30; // This is an UINT2; but will be interpreted as 32 bit flags
|
||||
PT_UID = 31; // This is an UINT2; MAX_UINT32 will be interpreted as no value
|
||||
PT_GID = 32; // This is an UINT2; MAX_UINT32 will be interpreted as no value
|
||||
PT_DOUBLE = 33; // This is a double precision floating point number
|
||||
PT_SIGSET = 34; // sigset_t (only the lower UINT32 of it)
|
||||
PT_CHARBUFARRAY = 35; // Pointer to an array of strings exported by the user events decoder, 64bit (internal use only)
|
||||
PT_CHARBUF_PAIR_ARRAY = 36; // Pointer to an array of string pairs, exported by the user events decoder, 64bit (internal use only)
|
||||
PT_IPV4NET = 37; // An IPv4 network
|
||||
PT_IPV6ADDR = 38; // A 16 byte raw IPv6 address
|
||||
PT_IPV6NET = 39; // An IPv6 network
|
||||
PT_IPADDR = 40; // Either an IPv4 or IPv6 address; the length indicateswhich one it is
|
||||
PT_IPNET = 41; // Either an IPv4 or IPv6 network; the length indicates which one it is
|
||||
PT_MODE = 42; // A 32 bit bitmask to represent file modes
|
||||
PT_MAX = 43; // Array size
|
||||
};
|
||||
|
||||
// note > ppm_events_public.h
|
||||
// (ppm_event_flags)
|
||||
enum event_flags {
|
||||
EF_NONE = 0;
|
||||
EF_CREATES_FD = 1; // this event creates an FD (e.g. open)
|
||||
EF_DESTROYS_FD = 2; // this event destroys an FD (e.g. close)
|
||||
EF_USES_FD = 4; // this event operates on an FD
|
||||
EF_READS_FROM_FD = 8; // this event reads data from an FD
|
||||
EF_WRITES_TO_FD = 16; // this event writes data to an FD
|
||||
EF_MODIFIES_STATE = 32; // this event causes the machine state to change and should not be dropped by the filtering engine
|
||||
EF_UNUSED = 64; // this event is not used
|
||||
EF_WAITS = 128; // this event reads data from an FD
|
||||
EF_SKIPPARSERESET = 256; // this event shouldn't pollute the parser lastevent state tracker
|
||||
EF_OLD_VERSION = 512; // this event is kept for backward compatibility
|
||||
EF_DROP_SIMPLE_CONS = 1024; // this event can be skipped by consumers that privilege low overhead to full event capture
|
||||
}
|
||||
|
||||
// todo(leodido) > complete
|
||||
// https://github.com/draios/sysdig/blob/master/driver/ppm_events_public.h
|
||||
// (ppm_event_type)
|
||||
enum event_type {
|
||||
PPME_GENERIC_E = 0;
|
||||
PPME_GENERIC_X = 1;
|
||||
}
|
||||
|
||||
// todo(leodido) > complete
|
||||
// https://github.com/draios/sysdig/blob/master/driver/ppm_events_public.h
|
||||
// (ppm_event_category)
|
||||
enum event_category {
|
||||
EC_UNKNOWN = 0;
|
||||
EC_OTHER = 1;
|
||||
EC_FILE = 2;
|
||||
}
|
||||
|
||||
message parameter {
|
||||
string name = 1;
|
||||
uint32 value = 2;
|
||||
}
|
||||
|
||||
message parameter_info {
|
||||
string name = 1; // parameter name, e.g. 'size'
|
||||
param_type type = 2; // parameter type, e.g. 'uint16', 'string'
|
||||
// print_format fmt = 3;
|
||||
// ? info = 4;
|
||||
}
|
||||
|
||||
message ppm_event {
|
||||
string name = 1;
|
||||
event_category category = 2; // event category, e.g. 'file, 'net'
|
||||
uint32 flags = 3;
|
||||
uint32 nparams = 4; // number of parameters in the parameters array
|
||||
repeated parameter_info params = 5;
|
||||
}
|
||||
|
||||
message scap_event {
|
||||
google.protobuf.Timestamp ts = 1;
|
||||
uint64 tid = 2;
|
||||
event_type type = 3;
|
||||
uint32 nparams = 4;
|
||||
}
|
||||
|
||||
enum command_category {
|
||||
CAT_NONE = 0;
|
||||
CAT_CONTAINER = 1;
|
||||
CAT_HEALTHCHECK = 2;
|
||||
CAT_LIVENESS_PROBE = 3;
|
||||
CAT_READINESS_PROBE = 4;
|
||||
}
|
||||
|
||||
// note > threadinfo.h
|
||||
message thread_info {
|
||||
uint64 tid = 1; // id of this thread
|
||||
uint64 pid = 2; // id of the process containing this thread
|
||||
uint64 ptid = 3; // id of the process that started this thread
|
||||
uint64 sid = 4; // session id of the process containing this thread
|
||||
string comm = 5; // name of the process containing this thread, e.g. "top"
|
||||
string exe = 6; // name of the process containing this thread from argv[0], e.g. "/bin/top"
|
||||
string exepath = 7; // full executable path of the process containing this thread, e.g. "/bin/top"
|
||||
string cwd = 8; // working directory of the process containing this thread
|
||||
repeated string env = 9; // values of all environment variables for the process containing this thread
|
||||
repeated string args = 10; // command line arguments, e.g., -d1
|
||||
// string container_id = 11;
|
||||
// ...
|
||||
command_category category = 12;
|
||||
}
|
||||
|
||||
// note > event.h
|
||||
message event {
|
||||
scap_event evt = 1;
|
||||
uint32 cpuid = 2;
|
||||
event_flags flags = 3; // fixme(leodido) > should this be a uint32?
|
||||
ppm_event info = 4;
|
||||
string params = 5;
|
||||
thread_info tinfo = 6;
|
||||
// fdinfo = 7
|
||||
uint32 iosize = 8;
|
||||
|
||||
|
||||
// bool fdinfo_name_changed = 9;
|
||||
// int64 fd_num = 10;
|
||||
// uint32 num_params = 11;
|
||||
// map<uint32, string> param_name = 12;
|
||||
// map<uint32, string> param_value = 13;
|
||||
}
|
||||
@@ -15,6 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "event_drops.h"
|
||||
#include "banned.h"
|
||||
|
||||
syscall_evt_drop_mgr::syscall_evt_drop_mgr():
|
||||
m_num_syscall_evt_drops(0),
|
||||
@@ -75,7 +76,7 @@ bool syscall_evt_drop_mgr::process_event(sinsp *inspector, sinsp_evt *evt)
|
||||
|
||||
if(m_simulate_drops)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Simulating syscall event drop");
|
||||
falco_logger::log(LOG_INFO, "Simulating syscall event drop\n");
|
||||
delta.n_drops++;
|
||||
}
|
||||
|
||||
@@ -93,7 +94,7 @@ bool syscall_evt_drop_mgr::process_event(sinsp *inspector, sinsp_evt *evt)
|
||||
}
|
||||
else
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, "Syscall event drop but token bucket depleted, skipping actions");
|
||||
falco_logger::log(LOG_DEBUG, "Syscall event drop but token bucket depleted, skipping actions\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,7 +156,7 @@ bool syscall_evt_drop_mgr::perform_actions(uint64_t now, scap_stats &delta, bool
|
||||
if(should_exit)
|
||||
{
|
||||
falco_logger::log(LOG_CRIT, msg);
|
||||
falco_logger::log(LOG_CRIT, "Exiting.");
|
||||
falco_logger::log(LOG_CRIT, "Exiting.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ limitations under the License.
|
||||
#include "statsfilewriter.h"
|
||||
#include "webserver.h"
|
||||
#include "grpc_server.h"
|
||||
#include "banned.h"
|
||||
|
||||
typedef function<void(sinsp* inspector)> open_t;
|
||||
|
||||
@@ -895,7 +896,7 @@ int falco_init(int argc, char **argv)
|
||||
printf("%s\n", support.dump().c_str());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
// read hostname
|
||||
string hostname;
|
||||
if(char* env_hostname = getenv("FALCO_GRPC_HOSTNAME"))
|
||||
@@ -1191,7 +1192,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per thread, or implement
|
||||
// different queuing mechanisms, round robin, fanout? What we want to achieve?
|
||||
grpc_server.init(config.m_grpc_bind_address, config.m_grpc_threadiness, config.m_grpc_private_key, config.m_grpc_cert_chain, config.m_grpc_root_certs);
|
||||
grpc_server.init(config.m_grpc_bind_address, config.m_grpc_private_key, config.m_grpc_cert_chain, config.m_grpc_root_certs, config.m_grpc_threadiness, config.m_log_level);
|
||||
grpc_server_thread = std::thread([&grpc_server] {
|
||||
grpc_server.run();
|
||||
});
|
||||
|
||||
@@ -16,12 +16,12 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "output.pb.h"
|
||||
#include "outputs.pb.h"
|
||||
#include "tbb/concurrent_queue.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace output
|
||||
namespace outputs
|
||||
{
|
||||
typedef tbb::concurrent_queue<response> response_cq;
|
||||
|
||||
|
||||
@@ -23,26 +23,25 @@ limitations under the License.
|
||||
#include "formats.h"
|
||||
#include "logger.h"
|
||||
#include "falco_output_queue.h"
|
||||
#include "banned.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace falco::output;
|
||||
|
||||
const static struct luaL_reg ll_falco_outputs [] =
|
||||
const static struct luaL_reg ll_falco_outputs[] =
|
||||
{
|
||||
{"handle_http", &falco_outputs::handle_http},
|
||||
{"handle_grpc", &falco_outputs::handle_grpc},
|
||||
{NULL,NULL}
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
falco_outputs::falco_outputs(falco_engine *engine)
|
||||
: m_falco_engine(engine),
|
||||
m_initialized(false),
|
||||
m_buffered(true),
|
||||
m_json_output(false),
|
||||
m_time_format_iso_8601(false),
|
||||
m_hostname("")
|
||||
falco_outputs::falco_outputs(falco_engine *engine):
|
||||
m_falco_engine(engine),
|
||||
m_initialized(false),
|
||||
m_buffered(true),
|
||||
m_json_output(false),
|
||||
m_time_format_iso_8601(false),
|
||||
m_hostname("")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
falco_outputs::~falco_outputs()
|
||||
@@ -57,13 +56,13 @@ falco_outputs::~falco_outputs()
|
||||
lua_getglobal(m_ls, m_lua_output_cleanup.c_str());
|
||||
if(!lua_isfunction(m_ls, -1))
|
||||
{
|
||||
falco_logger::log(LOG_ERR, std::string("No function ") + m_lua_output_cleanup + " found. ");
|
||||
falco_logger::log(LOG_ERR, std::string("No function ") + m_lua_output_cleanup + " found.\n");
|
||||
assert(nullptr == "Missing lua cleanup function in ~falco_outputs");
|
||||
}
|
||||
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
falco_logger::log(LOG_ERR, std::string("lua_pcall failed, err: ") + lerr);
|
||||
assert(nullptr == "lua_pcall failed in ~falco_outputs");
|
||||
}
|
||||
@@ -76,7 +75,7 @@ void falco_outputs::init(bool json_output,
|
||||
bool time_format_iso_8601, string hostname)
|
||||
{
|
||||
// The engine must have been given an inspector by now.
|
||||
if(! m_inspector)
|
||||
if(!m_inspector)
|
||||
{
|
||||
throw falco_exception("No inspector provided");
|
||||
}
|
||||
@@ -117,12 +116,12 @@ void falco_outputs::add_output(output_config oc)
|
||||
lua_pushnumber(m_ls, (m_time_format_iso_8601 ? 1 : 0));
|
||||
|
||||
// If we have options, build up a lua table containing them
|
||||
if (oc.options.size())
|
||||
if(oc.options.size())
|
||||
{
|
||||
nargs = 4;
|
||||
lua_createtable(m_ls, 0, oc.options.size());
|
||||
|
||||
for (auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
|
||||
for(auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
|
||||
{
|
||||
lua_pushstring(m_ls, (*it).second.c_str());
|
||||
lua_setfield(m_ls, -2, (*it).first.c_str());
|
||||
@@ -131,10 +130,9 @@ void falco_outputs::add_output(output_config oc)
|
||||
|
||||
if(lua_pcall(m_ls, nargs, 0, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(string(lerr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
|
||||
@@ -161,7 +159,7 @@ void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
|
||||
|
||||
if(lua_pcall(m_ls, 7, 0, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
@@ -176,7 +174,7 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
falco_common::priority_type priority,
|
||||
std::string &msg,
|
||||
std::string &rule,
|
||||
std::map<std::string,std::string> &output_fields)
|
||||
std::map<std::string, std::string> &output_fields)
|
||||
{
|
||||
std::string full_msg;
|
||||
|
||||
@@ -185,9 +183,9 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
nlohmann::json jmsg;
|
||||
|
||||
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||
time_t evttime = now/1000000000;
|
||||
time_t evttime = now / 1000000000;
|
||||
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||
string iso8601evttime;
|
||||
|
||||
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
|
||||
@@ -235,7 +233,7 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
|
||||
if(lua_pcall(m_ls, 3, 0, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
@@ -244,7 +242,6 @@ void falco_outputs::handle_msg(uint64_t now,
|
||||
{
|
||||
throw falco_exception("No function " + m_lua_output_msg + " found in lua compiler module");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void falco_outputs::reopen_outputs()
|
||||
@@ -257,7 +254,7 @@ void falco_outputs::reopen_outputs()
|
||||
|
||||
if(lua_pcall(m_ls, 0, 0, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
const char *lerr = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(string(lerr));
|
||||
}
|
||||
}
|
||||
@@ -276,8 +273,8 @@ int falco_outputs::handle_http(lua_State *ls)
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
string url = (char *) lua_tostring(ls, 1);
|
||||
string msg = (char *) lua_tostring(ls, 2);
|
||||
string url = (char *)lua_tostring(ls, 1);
|
||||
string msg = (char *)lua_tostring(ls, 2);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl)
|
||||
@@ -290,8 +287,9 @@ int falco_outputs::handle_http(lua_State *ls)
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
falco_logger::log(LOG_ERR,"libcurl error: " + string(curl_easy_strerror(res)));
|
||||
if(res != CURLE_OK)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "libcurl error: " + string(curl_easy_strerror(res)));
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
curl = NULL;
|
||||
@@ -317,15 +315,16 @@ int falco_outputs::handle_grpc(lua_State *ls)
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
response grpc_res = response();
|
||||
falco::outputs::response grpc_res = falco::outputs::response();
|
||||
|
||||
// time
|
||||
gen_event* evt = (gen_event*)lua_topointer(ls, 1);
|
||||
auto& timestamp = *grpc_res.mutable_time();
|
||||
timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
|
||||
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
|
||||
auto timestamp = grpc_res.mutable_time();
|
||||
*timestamp = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(evt->get_ts());
|
||||
|
||||
// rule
|
||||
grpc_res.set_rule((char *)lua_tostring(ls, 2));
|
||||
auto rule = grpc_res.mutable_rule();
|
||||
*rule = (char *)lua_tostring(ls, 2);
|
||||
|
||||
// source
|
||||
falco::schema::source s = falco::schema::source::SYSCALL;
|
||||
@@ -348,22 +347,25 @@ int falco_outputs::handle_grpc(lua_State *ls)
|
||||
grpc_res.set_priority(p);
|
||||
|
||||
// output
|
||||
grpc_res.set_output((char *)lua_tostring(ls, 5));
|
||||
auto output = grpc_res.mutable_output();
|
||||
*output = (char *)lua_tostring(ls, 5);
|
||||
|
||||
// output fields
|
||||
auto& fields = *grpc_res.mutable_output_fields();
|
||||
auto &fields = *grpc_res.mutable_output_fields();
|
||||
|
||||
lua_pushnil(ls); // so that lua_next removes it from stack and puts (k, v) on it
|
||||
while (lua_next(ls, 6) != 0) {
|
||||
while(lua_next(ls, 6) != 0)
|
||||
{
|
||||
fields[lua_tostring(ls, -2)] = lua_tostring(ls, -1);
|
||||
lua_pop(ls, 1); // remove value, keep key for lua_next
|
||||
}
|
||||
lua_pop(ls, 1); // pop table
|
||||
|
||||
// hostname
|
||||
grpc_res.set_hostname((char* )lua_tostring(ls, 7));
|
||||
auto host = grpc_res.mutable_hostname();
|
||||
*host = (char *)lua_tostring(ls, 7);
|
||||
|
||||
falco::output::queue::get().push(grpc_res);
|
||||
falco::outputs::queue::get().push(grpc_res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
16
userspace/falco/grpc.proto
Normal file
16
userspace/falco/grpc.proto
Normal file
@@ -0,0 +1,16 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package falco.grpc;
|
||||
|
||||
enum stream_status {
|
||||
STREAMING = 0;
|
||||
SUCCESS = 1;
|
||||
ERROR = 2;
|
||||
}
|
||||
|
||||
enum request_state {
|
||||
UNKNOWN = 0;
|
||||
REQUEST = 1;
|
||||
WRITE = 2;
|
||||
FINISH = 3;
|
||||
}
|
||||
@@ -17,36 +17,34 @@ limitations under the License.
|
||||
#include <sstream>
|
||||
|
||||
#include "grpc_context.h"
|
||||
#include "banned.h"
|
||||
|
||||
falco::grpc::context::context(::grpc::ServerContext* ctx):
|
||||
m_ctx(ctx)
|
||||
{
|
||||
std::string session_id;
|
||||
std::string request_id;
|
||||
get_metadata(meta_session, m_session_id);
|
||||
get_metadata(meta_request, m_request_id);
|
||||
|
||||
get_metadata(meta_session, session_id);
|
||||
get_metadata(meta_request, request_id);
|
||||
|
||||
bool has_meta = false;
|
||||
std::stringstream meta;
|
||||
if(!session_id.empty())
|
||||
if(!m_session_id.empty())
|
||||
{
|
||||
meta << "[sid=" << session_id << "]";
|
||||
has_meta = true;
|
||||
ctx->AddInitialMetadata(meta_session, m_session_id);
|
||||
meta << "sid=" << m_session_id << "";
|
||||
}
|
||||
if(!request_id.empty())
|
||||
if(!m_request_id.empty())
|
||||
{
|
||||
meta << "[rid=" << request_id << "]";
|
||||
has_meta = true;
|
||||
}
|
||||
if(has_meta)
|
||||
{
|
||||
meta << " ";
|
||||
ctx->AddInitialMetadata(meta_request, m_request_id);
|
||||
meta << ", rid=" << m_request_id << "";
|
||||
}
|
||||
m_prefix = meta.str();
|
||||
}
|
||||
|
||||
void falco::grpc::context::context::get_metadata(std::string key, std::string& val)
|
||||
std::string falco::grpc::context::peer() const
|
||||
{
|
||||
return m_ctx->peer();
|
||||
}
|
||||
|
||||
void falco::grpc::context::get_metadata(std::string key, std::string& val)
|
||||
{
|
||||
const std::multimap<::grpc::string_ref, ::grpc::string_ref>& client_metadata = m_ctx->client_metadata();
|
||||
auto it = client_metadata.find(key);
|
||||
@@ -54,4 +52,4 @@ void falco::grpc::context::context::get_metadata(std::string key, std::string& v
|
||||
{
|
||||
val.assign(it->second.data(), it->second.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ limitations under the License.
|
||||
#include <grpc++/grpc++.h>
|
||||
#endif
|
||||
|
||||
#include "grpc.pb.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
@@ -39,10 +41,14 @@ public:
|
||||
~context() = default;
|
||||
|
||||
void get_metadata(std::string key, std::string& val);
|
||||
std::string peer() const;
|
||||
|
||||
std::string m_prefix; // todo(leodido) > making this read only?
|
||||
|
||||
private:
|
||||
std::string m_session_id;
|
||||
std::string m_request_id;
|
||||
::grpc::ServerContext* m_ctx = nullptr;
|
||||
std::string m_prefix;
|
||||
};
|
||||
|
||||
class stream_context : public context
|
||||
@@ -52,15 +58,11 @@ public:
|
||||
context(ctx){};
|
||||
~stream_context() = default;
|
||||
|
||||
enum : char
|
||||
{
|
||||
STREAMING = 1,
|
||||
SUCCESS,
|
||||
ERROR
|
||||
} m_status = STREAMING;
|
||||
stream_status m_status = stream_status::STREAMING;
|
||||
|
||||
mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future
|
||||
mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future (request-specific stream data)
|
||||
mutable bool m_has_more = false;
|
||||
};
|
||||
|
||||
} // namespace grpc
|
||||
} // namespace falco
|
||||
|
||||
251
userspace/falco/grpc_request_context.cpp
Normal file
251
userspace/falco/grpc_request_context.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 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.
|
||||
*/
|
||||
|
||||
#include "grpc_request_context.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
{
|
||||
|
||||
template<>
|
||||
void request_stream_context<falco::outputs::service, falco::outputs::request, falco::outputs::response>::start(server* srv)
|
||||
{
|
||||
m_state = request_state::REQUEST;
|
||||
m_srv_ctx.reset(new ::grpc::ServerContext);
|
||||
auto srvctx = m_srv_ctx.get();
|
||||
m_res_writer.reset(new ::grpc::ServerAsyncWriter<outputs::response>(srvctx));
|
||||
m_stream_ctx.reset();
|
||||
m_req.Clear();
|
||||
auto cq = srv->m_completion_queue.get();
|
||||
// m_stream_ctx->m_stream = this; // todo(leodido) > save the tag - ie., this - into the stream?
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_stream_context<outputs>::%s -> m_request_func: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
(srv->m_outputs_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_stream_context<falco::outputs::service, falco::outputs::request, falco::outputs::response>::process(server* srv)
|
||||
{
|
||||
// When it is the 1st process call
|
||||
if(m_state == request_state::REQUEST)
|
||||
{
|
||||
m_state = request_state::WRITE;
|
||||
m_stream_ctx.reset(new stream_context(m_srv_ctx.get()));
|
||||
}
|
||||
|
||||
// Processing
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_stream_context<outputs>::%s -> m_process_func: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
|
||||
outputs::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // outputs_impl()
|
||||
|
||||
// When there are still more responses to stream
|
||||
if(m_stream_ctx->m_has_more)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_stream_context<outputs>::%s -> write: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
m_res_writer->Write(res, this);
|
||||
}
|
||||
// No more responses to stream
|
||||
else
|
||||
{
|
||||
// Communicate to the gRPC runtime that we have finished.
|
||||
// The memory address of "this" instance uniquely identifies the event.
|
||||
m_state = request_state::FINISH;
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_stream_context<outputs>::%s -> finish: tag=%p, state=finish",
|
||||
__func__,
|
||||
this);
|
||||
|
||||
m_res_writer->Finish(::grpc::Status::OK, this);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_stream_context<falco::outputs::service, falco::outputs::request, falco::outputs::response>::end(server* srv, bool errored)
|
||||
{
|
||||
if(m_stream_ctx)
|
||||
{
|
||||
if(errored)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"request_stream_context<outputs>::%s -> error streaming: tag=%p, state=%s, stream=%p",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str(),
|
||||
m_stream_ctx->m_stream);
|
||||
}
|
||||
m_stream_ctx->m_status = errored ? stream_status::ERROR : stream_status::SUCCESS;
|
||||
|
||||
// Complete the processing
|
||||
outputs::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // outputs()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flow enters here when the processing of "m_request_func" fails.
|
||||
// Since this happens into the `start()` function, the processing does not advance to the `process()` function.
|
||||
// So, `m_stream_ctx` is null because it is set into the `process()` function.
|
||||
// The stream haven't started.
|
||||
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"%s -> ending streaming: tag=%p, state=%s, stream=never started",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
}
|
||||
|
||||
// Ask to start processing requests
|
||||
start(srv);
|
||||
}
|
||||
|
||||
template<>
|
||||
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::start(server* srv)
|
||||
{
|
||||
m_state = request_state::REQUEST;
|
||||
m_srv_ctx.reset(new ::grpc::ServerContext);
|
||||
auto srvctx = m_srv_ctx.get();
|
||||
m_res_writer.reset(new ::grpc::ServerAsyncResponseWriter<version::response>(srvctx));
|
||||
m_req.Clear();
|
||||
auto cq = srv->m_completion_queue.get();
|
||||
// Request to start processing given requests.
|
||||
// Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request.
|
||||
// In this way, different contexts can serve different requests concurrently.
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_context<version>::%s -> m_request_func: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
(srv->m_version_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
|
||||
}
|
||||
|
||||
template<>
|
||||
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::process(server* srv)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_context<version>::%s -> m_process_func: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
|
||||
// Create empty response
|
||||
version::response res;
|
||||
// Call version service implementation
|
||||
(srv->*m_process_func)(m_srv_ctx.get(), m_req, res);
|
||||
|
||||
// Notify the gRPC runtime that this processing is done
|
||||
m_state = request_state::FINISH;
|
||||
// Using "this"- ie., the memory address of this context - to uniquely identify the event.
|
||||
m_res_writer->Finish(res, ::grpc::Status::OK, this);
|
||||
}
|
||||
|
||||
template<>
|
||||
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::end(server* srv, bool errored)
|
||||
{
|
||||
if(errored)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"request_context<version>::%s -> error replying: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
}
|
||||
|
||||
// Ask to start processing requests
|
||||
start(srv);
|
||||
}
|
||||
|
||||
template<>
|
||||
void falco::grpc::request_context<falco::inputs::service, falco::inputs::request, falco::inputs::response>::start(server* srv)
|
||||
{
|
||||
m_state = request_state::REQUEST;
|
||||
m_srv_ctx.reset(new ::grpc::ServerContext);
|
||||
auto srvctx = m_srv_ctx.get();
|
||||
m_res_writer.reset(new ::grpc::ServerAsyncResponseWriter<inputs::response>(srvctx));
|
||||
m_req.Clear();
|
||||
auto cq = srv->m_completion_queue.get();
|
||||
// Request to start processing given requests.
|
||||
// Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request.
|
||||
// In this way, different contexts can serve different requests concurrently.
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_context<inputs>::%s -> m_request_func: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
(srv->m_inputs_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
|
||||
}
|
||||
|
||||
template<>
|
||||
void falco::grpc::request_context<falco::inputs::service, falco::inputs::request, falco::inputs::response>::process(server* srv)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"request_context<inputs>::%s -> m_process_func: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
|
||||
inputs::response res;
|
||||
(srv->*m_process_func)(m_srv_ctx.get(), m_req, res);
|
||||
|
||||
// Notify the gRPC runtime that this processing is done
|
||||
m_state = request_state::FINISH;
|
||||
// Using "this"- ie., the memory address of this context - to uniquely identify the event.
|
||||
m_res_writer->Finish(res, ::grpc::Status::OK, this);
|
||||
}
|
||||
|
||||
template<>
|
||||
void falco::grpc::request_context<falco::inputs::service, falco::inputs::request, falco::inputs::response>::end(server* srv, bool errored)
|
||||
{
|
||||
if(errored)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"request_context<inputs>::%s -> error replying: tag=%p, state=%s",
|
||||
__func__,
|
||||
this,
|
||||
request_state_Name(m_state).c_str());
|
||||
}
|
||||
|
||||
// Ask to start processing requests
|
||||
start(srv);
|
||||
}
|
||||
|
||||
} // namespace grpc
|
||||
} // namespace falco
|
||||
95
userspace/falco/grpc_request_context.h
Normal file
95
userspace/falco/grpc_request_context.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "grpc_server.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
{
|
||||
|
||||
class request_context_base
|
||||
{
|
||||
public:
|
||||
request_context_base() = default;
|
||||
~request_context_base() = default;
|
||||
|
||||
std::unique_ptr<::grpc::ServerContext> m_srv_ctx;
|
||||
request_state m_state = request_state::UNKNOWN;
|
||||
|
||||
virtual void start(server* srv) = 0;
|
||||
virtual void process(server* srv) = 0;
|
||||
virtual void end(server* srv, bool isError) = 0;
|
||||
};
|
||||
|
||||
// The responsibility of `request_stream_context` template class
|
||||
// is to handle streaming responses.
|
||||
template<class Service, class Request, class Response>
|
||||
class request_stream_context : public request_context_base
|
||||
{
|
||||
public:
|
||||
request_stream_context():
|
||||
m_process_func(nullptr),
|
||||
m_request_func(nullptr){};
|
||||
~request_stream_context() = default;
|
||||
|
||||
// Pointer to function that does actual processing
|
||||
void (server::*m_process_func)(const stream_context&, const Request&, Response&);
|
||||
|
||||
// Pointer to function that requests the system to start processing given requests
|
||||
void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncWriter<Response>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
|
||||
|
||||
void start(server* srv);
|
||||
void process(server* srv);
|
||||
void end(server* srv, bool isError);
|
||||
|
||||
private:
|
||||
std::unique_ptr<::grpc::ServerAsyncWriter<Response>> m_res_writer;
|
||||
std::unique_ptr<stream_context> m_stream_ctx;
|
||||
Request m_req;
|
||||
};
|
||||
|
||||
// The responsibility of `request_context` template class
|
||||
// is to handle unary responses.
|
||||
template<class Service, class Request, class Response>
|
||||
class request_context : public request_context_base
|
||||
{
|
||||
public:
|
||||
request_context():
|
||||
m_process_func(nullptr),
|
||||
m_request_func(nullptr){};
|
||||
~request_context() = default;
|
||||
|
||||
// Pointer to function that does actual processing
|
||||
void (server::*m_process_func)(const context&, const Request&, Response&);
|
||||
|
||||
// Pointer to function that requests the system to start processing given requests
|
||||
void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncResponseWriter<Response>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
|
||||
|
||||
void start(server* srv);
|
||||
void process(server* srv);
|
||||
void end(server* srv, bool isError);
|
||||
|
||||
private:
|
||||
std::unique_ptr<::grpc::ServerAsyncResponseWriter<Response>> m_res_writer;
|
||||
Request m_req;
|
||||
};
|
||||
} // namespace grpc
|
||||
} // namespace falco
|
||||
@@ -14,90 +14,37 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef GRPC_INCLUDE_IS_GRPCPP
|
||||
#include <grpcpp/grpcpp.h>
|
||||
#else
|
||||
#include <grpc++/grpc++.h>
|
||||
#endif
|
||||
|
||||
#include "logger.h"
|
||||
#include "grpc_server.h"
|
||||
#include "grpc_context.h"
|
||||
#include "grpc_request_context.h"
|
||||
#include "utils.h"
|
||||
#include "banned.h"
|
||||
|
||||
#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \
|
||||
std::vector<request_stream_context<req, res>> rpc##_contexts(num); \
|
||||
for(request_stream_context<req, res> & ctx : rpc##_contexts) \
|
||||
{ \
|
||||
ctx.m_process_func = &server::impl; \
|
||||
ctx.m_request_func = &svc::AsyncService::Request##rpc; \
|
||||
ctx.start(this); \
|
||||
#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \
|
||||
std::vector<request_stream_context<svc, req, res>> rpc##_contexts(num); \
|
||||
for(request_stream_context<svc, req, res> & c : rpc##_contexts) \
|
||||
{ \
|
||||
c.m_process_func = &server::impl; \
|
||||
c.m_request_func = &svc::AsyncService::Request##rpc; \
|
||||
c.start(this); \
|
||||
}
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
{
|
||||
|
||||
template<>
|
||||
void request_stream_context<falco::output::request, falco::output::response>::start(server* srv)
|
||||
{
|
||||
m_state = request_context_base::REQUEST;
|
||||
m_srv_ctx.reset(new ::grpc::ServerContext);
|
||||
auto srvctx = m_srv_ctx.get();
|
||||
m_res_writer.reset(new ::grpc::ServerAsyncWriter<output::response>(srvctx));
|
||||
m_stream_ctx.reset();
|
||||
m_req.Clear();
|
||||
auto cq = srv->m_completion_queue.get();
|
||||
(srv->m_svc.*m_request_func)(srvctx, &m_req, m_res_writer.get(), cq, cq, this);
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_stream_context<falco::output::request, falco::output::response>::process(server* srv)
|
||||
{
|
||||
// When it is the 1st process call
|
||||
if(m_state == request_context_base::REQUEST)
|
||||
{
|
||||
m_state = request_context_base::WRITE;
|
||||
m_stream_ctx.reset(new stream_context(m_srv_ctx.get()));
|
||||
#define REGISTER_UNARY(req, res, svc, rpc, impl, num) \
|
||||
std::vector<request_context<svc, req, res>> rpc##_contexts(num); \
|
||||
for(request_context<svc, req, res> & c : rpc##_contexts) \
|
||||
{ \
|
||||
c.m_process_func = &server::impl; \
|
||||
c.m_request_func = &svc::AsyncService::Request##rpc; \
|
||||
c.start(this); \
|
||||
}
|
||||
|
||||
// Processing
|
||||
output::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
|
||||
|
||||
// When there still are more responses to stream
|
||||
if(m_stream_ctx->m_has_more)
|
||||
{
|
||||
m_res_writer->Write(res, this);
|
||||
}
|
||||
// No more responses to stream
|
||||
else
|
||||
{
|
||||
// Communicate to the gRPC runtime that we have finished.
|
||||
// The memory address of `this` instance uniquely identifies the event.
|
||||
m_state = request_context_base::FINISH;
|
||||
m_res_writer->Finish(::grpc::Status::OK, this);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_stream_context<falco::output::request, falco::output::response>::end(server* srv, bool errored)
|
||||
{
|
||||
if(m_stream_ctx)
|
||||
{
|
||||
m_stream_ctx->m_status = errored ? stream_context::ERROR : stream_context::SUCCESS;
|
||||
|
||||
// Complete the processing
|
||||
output::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
|
||||
}
|
||||
|
||||
start(srv);
|
||||
}
|
||||
} // namespace grpc
|
||||
} // namespace falco
|
||||
|
||||
void falco::grpc::server::thread_process(int thread_index)
|
||||
{
|
||||
void* tag = nullptr;
|
||||
@@ -106,17 +53,35 @@ void falco::grpc::server::thread_process(int thread_index)
|
||||
{
|
||||
if(tag == nullptr)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"server::%s -> server completion queue error: tag=(empty)",
|
||||
__func__);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Obtain the context for a given tag
|
||||
request_context_base* ctx = static_cast<request_context_base*>(tag);
|
||||
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"server::%s -> next event: tag=%p, read success=%s, state=%s",
|
||||
__func__,
|
||||
tag,
|
||||
event_read_success ? "true" : "false",
|
||||
request_state_Name(ctx->m_state).c_str());
|
||||
|
||||
// When event has not been read successfully
|
||||
if(!event_read_success)
|
||||
{
|
||||
if(ctx->m_state != request_context_base::REQUEST)
|
||||
if(ctx->m_state != request_state::REQUEST)
|
||||
{
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"server::%s -> server completion queue failing to read: tag=%p",
|
||||
__func__,
|
||||
tag);
|
||||
|
||||
// End the context with error
|
||||
ctx->end(this, true);
|
||||
}
|
||||
@@ -126,37 +91,71 @@ void falco::grpc::server::thread_process(int thread_index)
|
||||
// Process the event
|
||||
switch(ctx->m_state)
|
||||
{
|
||||
case request_context_base::REQUEST:
|
||||
case request_state::REQUEST:
|
||||
// Completion of m_request_func
|
||||
case request_context_base::WRITE:
|
||||
// Completion of ServerAsyncWriter::Write()
|
||||
case request_state::WRITE:
|
||||
// Completion of Write()
|
||||
ctx->process(this);
|
||||
break;
|
||||
case request_context_base::FINISH:
|
||||
// Completion of ServerAsyncWriter::Finish()
|
||||
case request_state::FINISH:
|
||||
// Completion of Finish()
|
||||
ctx->end(this, false);
|
||||
break;
|
||||
default:
|
||||
// todo > log "unkown completion queue event"
|
||||
gpr_log(
|
||||
GPR_ERROR,
|
||||
"server::%s -> unkown completion queue event: tag=%p, state=%s",
|
||||
__func__,
|
||||
tag,
|
||||
request_state_Name(ctx->m_state).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"server::%s -> thread completed: tag=%p, index=%d",
|
||||
__func__,
|
||||
tag,
|
||||
thread_index);
|
||||
}
|
||||
}
|
||||
|
||||
void falco::grpc::server::init(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs)
|
||||
void falco::grpc::server::init(std::string server_addr, std::string private_key, std::string cert_chain, std::string root_certs, int threadiness, std::string log_level)
|
||||
{
|
||||
m_server_addr = server_addr;
|
||||
m_threadiness = threadiness;
|
||||
m_private_key = private_key;
|
||||
m_cert_chain = cert_chain;
|
||||
m_root_certs = root_certs;
|
||||
|
||||
falco::schema::priority logging_level = falco::schema::INFORMATIONAL;
|
||||
falco::schema::priority_Parse(log_level, &logging_level);
|
||||
switch(logging_level)
|
||||
{
|
||||
case falco::schema::ERROR:
|
||||
gpr_set_log_verbosity(GPR_LOG_SEVERITY_ERROR);
|
||||
break;
|
||||
case falco::schema::DEBUG:
|
||||
gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
|
||||
break;
|
||||
case falco::schema::INFORMATIONAL:
|
||||
default:
|
||||
// note > info will always enter here since it is != from "informational"
|
||||
gpr_set_log_verbosity(GPR_LOG_SEVERITY_INFO);
|
||||
break;
|
||||
}
|
||||
|
||||
// gpr_set_log_function(custom_log);
|
||||
gpr_log_verbosity_init();
|
||||
}
|
||||
|
||||
// static void custom_log(gpr_log_func_args* args){};
|
||||
|
||||
void falco::grpc::server::run()
|
||||
{
|
||||
string private_key;
|
||||
string cert_chain;
|
||||
string root_certs;
|
||||
std::string private_key;
|
||||
std::string cert_chain;
|
||||
std::string root_certs;
|
||||
|
||||
falco::utils::read(m_cert_chain, cert_chain);
|
||||
falco::utils::read(m_private_key, private_key);
|
||||
@@ -170,19 +169,23 @@ void falco::grpc::server::run()
|
||||
|
||||
::grpc::ServerBuilder builder;
|
||||
builder.AddListeningPort(m_server_addr, ::grpc::SslServerCredentials(ssl_opts));
|
||||
builder.RegisterService(&m_svc);
|
||||
builder.RegisterService(&m_outputs_svc);
|
||||
builder.RegisterService(&m_version_svc);
|
||||
builder.RegisterService(&m_inputs_svc);
|
||||
|
||||
m_completion_queue = builder.AddCompletionQueue();
|
||||
m_server = builder.BuildAndStart();
|
||||
falco_logger::log(LOG_INFO, "Starting gRPC server at " + m_server_addr + "\n");
|
||||
gpr_log(GPR_INFO, "gRPC server starting: address=%s", m_server_addr.c_str());
|
||||
|
||||
// The number of contexts is multiple of the number of threads
|
||||
// This defines the number of simultaneous completion queue requests of the same type (service::AsyncService::Request##RPC)
|
||||
// For this approach to be sufficient server::IMPL have to be fast
|
||||
int context_num = m_threadiness * 10;
|
||||
REGISTER_STREAM(output::request, output::response, output::service, subscribe, subscribe, context_num)
|
||||
// todo(leodido) > take a look at thread_stress_test.cc into grpc repository
|
||||
|
||||
// register_stream<output::request, output::response>(subscribe, context_num)
|
||||
REGISTER_UNARY(version::request, version::response, version::service, version, version_impl, context_num)
|
||||
REGISTER_UNARY(inputs::request, inputs::response, inputs::service, input, input_impl, context_num)
|
||||
REGISTER_STREAM(outputs::request, outputs::response, outputs::service, outputs, outputs_impl, context_num)
|
||||
|
||||
m_threads.resize(m_threadiness);
|
||||
int thread_idx = 0;
|
||||
@@ -190,21 +193,23 @@ void falco::grpc::server::run()
|
||||
{
|
||||
thread = std::thread(&server::thread_process, this, thread_idx++);
|
||||
}
|
||||
gpr_log(GPR_INFO, "gRPC server running: threadiness=%zu", m_threads.size());
|
||||
|
||||
while(server_impl::is_running())
|
||||
{
|
||||
sleep(1);
|
||||
}
|
||||
gpr_log(GPR_INFO, "gRPC server stopping");
|
||||
stop();
|
||||
}
|
||||
|
||||
void falco::grpc::server::stop()
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Shutting down gRPC server. Waiting until external connections are closed by clients\n");
|
||||
gpr_log(GPR_INFO, "gRPC server shutting down");
|
||||
m_server->Shutdown();
|
||||
m_completion_queue->Shutdown();
|
||||
|
||||
falco_logger::log(LOG_INFO, "Waiting for the gRPC threads to complete\n");
|
||||
gpr_log(GPR_DEBUG, "gRPC server shutting down: waiting for the gRPC threads to complete");
|
||||
for(std::thread& t : m_threads)
|
||||
{
|
||||
if(t.joinable())
|
||||
@@ -214,7 +219,7 @@ void falco::grpc::server::stop()
|
||||
}
|
||||
m_threads.clear();
|
||||
|
||||
falco_logger::log(LOG_INFO, "Ignoring all the remaining gRPC events\n");
|
||||
gpr_log(GPR_DEBUG, "gRPC server shutting down: draining all the remaining gRPC events");
|
||||
// Ignore remaining events
|
||||
void* ignore_tag = nullptr;
|
||||
bool ignore_ok = false;
|
||||
@@ -222,5 +227,5 @@ void falco::grpc::server::stop()
|
||||
{
|
||||
}
|
||||
|
||||
falco_logger::log(LOG_INFO, "Shutting down gRPC server complete\n");
|
||||
gpr_log(GPR_INFO, "gRPC server shutting down: done");
|
||||
}
|
||||
|
||||
@@ -25,28 +25,22 @@ namespace falco
|
||||
{
|
||||
namespace grpc
|
||||
{
|
||||
|
||||
class server : public server_impl
|
||||
{
|
||||
public:
|
||||
server()
|
||||
{
|
||||
}
|
||||
server(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs):
|
||||
m_server_addr(server_addr),
|
||||
m_threadiness(threadiness),
|
||||
m_private_key(private_key),
|
||||
m_cert_chain(cert_chain),
|
||||
m_root_certs(root_certs)
|
||||
{
|
||||
}
|
||||
server() = default;
|
||||
virtual ~server() = default;
|
||||
|
||||
void init(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs);
|
||||
void init(std::string server_addr, std::string private_key, std::string cert_chain, std::string root_certs, int threadiness, std::string log_level);
|
||||
void thread_process(int thread_index);
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
output::service::AsyncService m_svc;
|
||||
outputs::service::AsyncService m_outputs_svc;
|
||||
version::service::AsyncService m_version_svc;
|
||||
inputs::service::AsyncService m_inputs_svc;
|
||||
|
||||
std::unique_ptr<::grpc::ServerCompletionQueue> m_completion_queue;
|
||||
|
||||
private:
|
||||
@@ -60,51 +54,5 @@ private:
|
||||
std::vector<std::thread> m_threads;
|
||||
};
|
||||
|
||||
class request_context_base
|
||||
{
|
||||
public:
|
||||
request_context_base() = default;
|
||||
~request_context_base() = default;
|
||||
|
||||
std::unique_ptr<::grpc::ServerContext> m_srv_ctx;
|
||||
enum : char
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
REQUEST,
|
||||
WRITE,
|
||||
FINISH
|
||||
} m_state = UNKNOWN;
|
||||
virtual void start(server* srv) = 0;
|
||||
virtual void process(server* srv) = 0;
|
||||
virtual void end(server* srv, bool isError) = 0;
|
||||
};
|
||||
|
||||
//
|
||||
// Template class to handle streaming responses
|
||||
//
|
||||
template<class Request, class Response>
|
||||
class request_stream_context : public request_context_base
|
||||
{
|
||||
public:
|
||||
request_stream_context():
|
||||
m_process_func(nullptr),
|
||||
m_request_func(nullptr){};
|
||||
~request_stream_context() = default;
|
||||
|
||||
// Pointer to function that does actual processing
|
||||
void (server::*m_process_func)(const stream_context&, const Request&, Response&);
|
||||
|
||||
// Pointer to function that requests the system to start processing given requests
|
||||
void (output::service::AsyncService::*m_request_func)(::grpc::ServerContext*, Request*, ::grpc::ServerAsyncWriter<Response>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
|
||||
|
||||
void start(server* srv);
|
||||
void process(server* srv);
|
||||
void end(server* srv, bool isError);
|
||||
|
||||
private:
|
||||
std::unique_ptr<::grpc::ServerAsyncWriter<Response>> m_res_writer;
|
||||
std::unique_ptr<stream_context> m_stream_ctx;
|
||||
Request m_req;
|
||||
};
|
||||
} // namespace grpc
|
||||
} // namespace falco
|
||||
} // namespace falco
|
||||
@@ -14,8 +14,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "config_falco.h"
|
||||
#include "grpc_server_impl.h"
|
||||
#include "falco_output_queue.h"
|
||||
#include "banned.h"
|
||||
|
||||
bool falco::grpc::server_impl::is_running()
|
||||
{
|
||||
@@ -26,21 +28,42 @@ bool falco::grpc::server_impl::is_running()
|
||||
return true;
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::subscribe(const stream_context& ctx, const output::request& req, output::response& res)
|
||||
void falco::grpc::server_impl::outputs_impl(const stream_context& ctx, const outputs::request& req, outputs::response& res)
|
||||
{
|
||||
if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR)
|
||||
std::string client = ctx.peer();
|
||||
if(ctx.m_status == stream_status::SUCCESS || ctx.m_status == stream_status::ERROR)
|
||||
{
|
||||
// Entering here when the streaming completed (request_context_base::FINISH)
|
||||
// context m_status == stream_context::SUCCESS when the gRPC server shutdown the context
|
||||
// context m_status == stream_context::ERROR when the gRPC client shutdown the context
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"server_impl::%s -> streaming done: %s, client=%s, status=%s, stream=%p",
|
||||
__func__,
|
||||
ctx.m_prefix.c_str(),
|
||||
client.c_str(),
|
||||
stream_status_Name(ctx.m_status).c_str(),
|
||||
ctx.m_stream);
|
||||
ctx.m_stream = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Streaming
|
||||
if(output::queue::get().try_pop(res) && !req.keepalive())
|
||||
// Start or continue streaming (m_status == stream_context::STREAMING)
|
||||
gpr_log(
|
||||
GPR_DEBUG,
|
||||
"server_impl::%s -> start or continue streaming: %s, client=%s, status=%s, stream=%p",
|
||||
__func__,
|
||||
ctx.m_prefix.c_str(),
|
||||
client.c_str(),
|
||||
stream_status_Name(ctx.m_status).c_str(),
|
||||
ctx.m_stream);
|
||||
// note(leodido) > set request-specific data on m_stream here, in case it is needed
|
||||
if(outputs::queue::get().try_pop(res) && !req.keepalive())
|
||||
{
|
||||
ctx.m_has_more = true;
|
||||
return;
|
||||
}
|
||||
while(is_running() && !output::queue::get().try_pop(res) && req.keepalive())
|
||||
while(is_running() && !outputs::queue::get().try_pop(res) && req.keepalive())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,6 +71,36 @@ void falco::grpc::server_impl::subscribe(const stream_context& ctx, const output
|
||||
}
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::version_impl(const context& ctx, const version::request& req, version::response& res)
|
||||
{
|
||||
gpr_log(GPR_DEBUG, "server_impl::%s -> replying: %s, client=%s", __func__, ctx.m_prefix.c_str(), ctx.peer().c_str());
|
||||
|
||||
auto& build = *res.mutable_build();
|
||||
build = FALCO_VERSION_BUILD;
|
||||
|
||||
auto& prerelease = *res.mutable_prerelease();
|
||||
prerelease = FALCO_VERSION_PRERELEASE;
|
||||
|
||||
auto& version = *res.mutable_version();
|
||||
version = FALCO_VERSION;
|
||||
|
||||
res.set_major(FALCO_VERSION_MAJOR);
|
||||
res.set_minor(FALCO_VERSION_MINOR);
|
||||
res.set_patch(FALCO_VERSION_PATCH);
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::input_impl(const context& ctx, const inputs::request& req, inputs::response& res)
|
||||
{
|
||||
std::string client = ctx.peer();
|
||||
gpr_log(GPR_DEBUG, "server_impl::%s -> replying: %s, client=%s", __func__, ctx.m_prefix.c_str(), client.c_str());
|
||||
// todo(leodido) > implement
|
||||
// retrieve metadata
|
||||
// if type = K8S_AUDIT
|
||||
// ...
|
||||
// if type = SYSCALL
|
||||
// ...
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::shutdown()
|
||||
{
|
||||
m_stop = true;
|
||||
|
||||
@@ -17,7 +17,9 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include "output.grpc.pb.h"
|
||||
#include "outputs.grpc.pb.h"
|
||||
#include "version.grpc.pb.h"
|
||||
#include "inputs.grpc.pb.h"
|
||||
#include "grpc_context.h"
|
||||
|
||||
namespace falco
|
||||
@@ -35,7 +37,11 @@ public:
|
||||
protected:
|
||||
bool is_running();
|
||||
|
||||
void subscribe(const stream_context& ctx, const output::request& req, output::response& res);
|
||||
void outputs_impl(const stream_context& ctx, const outputs::request& req, outputs::response& res);
|
||||
|
||||
void version_impl(const context& ctx, const version::request& req, version::response& res);
|
||||
|
||||
void input_impl(const context& ctx, const inputs::request& req, inputs::response& res);
|
||||
|
||||
private:
|
||||
std::atomic<bool> m_stop{false};
|
||||
|
||||
21
userspace/falco/inputs.proto
Normal file
21
userspace/falco/inputs.proto
Normal file
@@ -0,0 +1,21 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// import "event.proto";
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
package falco.inputs;
|
||||
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/inputs";
|
||||
|
||||
// service service { rpc input(request) returns (response); }
|
||||
|
||||
// message request { repeated falco.event.event data = 1; }
|
||||
|
||||
// message response {};
|
||||
|
||||
service service { rpc input(request) returns (response); }
|
||||
|
||||
message request { repeated google.protobuf.Any events = 1; }
|
||||
|
||||
message response {};
|
||||
@@ -19,6 +19,7 @@ limitations under the License.
|
||||
#include "chisel_api.h"
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "banned.h"
|
||||
|
||||
const static struct luaL_reg ll_falco [] =
|
||||
{
|
||||
@@ -158,5 +159,3 @@ void falco_logger::log(int priority, const string msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,18 +3,18 @@ syntax = "proto3";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "schema.proto";
|
||||
|
||||
package falco.output;
|
||||
package falco.outputs;
|
||||
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
|
||||
|
||||
// The `subscribe` service defines the RPC call
|
||||
// The `outputs` service defines a server-streaming RPC call
|
||||
// to perform an output `request` which will lead to obtain an output `response`.
|
||||
service service {
|
||||
rpc subscribe(request) returns (stream response);
|
||||
rpc outputs(request) returns (stream response);
|
||||
}
|
||||
|
||||
// The `request` message is the logical representation of the request model.
|
||||
// It is the input of the `subscribe` service.
|
||||
// It is the input of the `outputs` service.
|
||||
// It is used to configure the kind of subscription to the gRPC streaming server.
|
||||
//
|
||||
// By default the request asks to the server to only receive the accumulated events.
|
||||
@@ -18,6 +18,7 @@ limitations under the License.
|
||||
#include <signal.h>
|
||||
|
||||
#include "statsfilewriter.h"
|
||||
#include "banned.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "banned.h"
|
||||
|
||||
void falco::utils::read(const std::string& filename, std::string& data)
|
||||
{
|
||||
|
||||
29
userspace/falco/version.proto
Normal file
29
userspace/falco/version.proto
Normal file
@@ -0,0 +1,29 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package falco.version;
|
||||
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/version";
|
||||
|
||||
// This service defines a RPC call
|
||||
// to request the Falco version.
|
||||
service service {
|
||||
rpc version(request) returns (response);
|
||||
}
|
||||
|
||||
// The `request` message is an empty one.
|
||||
message request
|
||||
{
|
||||
}
|
||||
|
||||
// The `response` message contains the version of Falco.
|
||||
// It provides the whole version as a string and also
|
||||
// its parts as per semver 2.0 specification (https://semver.org).
|
||||
message response
|
||||
{
|
||||
string version = 1;
|
||||
uint32 major = 2;
|
||||
uint32 minor = 3;
|
||||
uint32 patch = 4;
|
||||
string prerelease = 5;
|
||||
string build = 6;
|
||||
}
|
||||
@@ -20,6 +20,7 @@ limitations under the License.
|
||||
#include "falco_common.h"
|
||||
#include "webserver.h"
|
||||
#include "json_evt.h"
|
||||
#include "banned.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace std;
|
||||
|
||||
Reference in New Issue
Block a user