mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-29 08:02:44 +00:00
Compare commits
18 Commits
embed-lua-
...
new/plugin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f7024189c | ||
|
|
8a9b7dfcfa | ||
|
|
635c413c5f | ||
|
|
797b861fbc | ||
|
|
f4182707e9 | ||
|
|
fce2b925f0 | ||
|
|
fc4cfa04b7 | ||
|
|
e580d042ac | ||
|
|
d3be537f7e | ||
|
|
849fb98bc2 | ||
|
|
c1d1fafade | ||
|
|
2aaee02d65 | ||
|
|
8ac6ea732e | ||
|
|
5d245f6569 | ||
|
|
b1d88c509f | ||
|
|
c7f18edd5a | ||
|
|
6adf79ea25 | ||
|
|
8b10a35a40 |
@@ -212,6 +212,7 @@ include(static-analysis)
|
|||||||
# Shared build variables
|
# Shared build variables
|
||||||
set(FALCO_SINSP_LIBRARY sinsp)
|
set(FALCO_SINSP_LIBRARY sinsp)
|
||||||
set(FALCO_SHARE_DIR share/falco)
|
set(FALCO_SHARE_DIR share/falco)
|
||||||
|
set(FALCO_PLUGINS_DIR ${FALCO_SHARE_DIR}/plugins)
|
||||||
set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}")
|
set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}")
|
||||||
set(FALCO_BIN_DIR bin)
|
set(FALCO_BIN_DIR bin)
|
||||||
|
|
||||||
@@ -220,5 +221,8 @@ add_subdirectory(userspace/engine)
|
|||||||
add_subdirectory(userspace/falco)
|
add_subdirectory(userspace/falco)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
||||||
|
# Reenable once test-infra is publishing plugins artifacts
|
||||||
|
#include(plugins)
|
||||||
|
|
||||||
# Packages configuration
|
# Packages configuration
|
||||||
include(CPackConfig)
|
include(CPackConfig)
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ file(MAKE_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR})
|
|||||||
# default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake
|
# default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake
|
||||||
# -DFALCOSECURITY_LIBS_VERSION=dev ..`
|
# -DFALCOSECURITY_LIBS_VERSION=dev ..`
|
||||||
if(NOT FALCOSECURITY_LIBS_VERSION)
|
if(NOT FALCOSECURITY_LIBS_VERSION)
|
||||||
set(FALCOSECURITY_LIBS_VERSION "13ec67ebd23417273275296813066e07cb85bc91")
|
set(FALCOSECURITY_LIBS_VERSION "new/plugin-system-api-additions")
|
||||||
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=c2cc1c17af98cef1fa958841da3cfc480774190b5cebc503faf4184cf2b2abfa")
|
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=d880d7437e7f943fb89dc31878eea2b56abbdf56db33e026b095af86a3900c22")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# cd /path/to/build && cmake /path/to/source
|
# cd /path/to/build && cmake /path/to/source
|
||||||
|
|||||||
31
cmake/modules/plugins.cmake
Normal file
31
cmake/modules/plugins.cmake
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2021 The Falco Authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
|
# the License. You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
|
||||||
|
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
# specific language governing permissions and limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
set(PLUGINS_PREFIX ${CMAKE_BINARY_DIR}/plugins-prefix)
|
||||||
|
set(PLUGINS_VERSION "0.1.0-rc1")
|
||||||
|
string(TOLOWER ${CMAKE_SYSTEM_NAME} PLUGIN_SYSTEM_NAME)
|
||||||
|
set(PLUGINS_FULL_VERSION "falcosecurity-plugins-${PLUGINS_VERSION}-${PLUGIN_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||||
|
message(STATUS "Using bundled plugins in ${PLUGINS_PREFIX}")
|
||||||
|
|
||||||
|
ExternalProject_Add(
|
||||||
|
plugins
|
||||||
|
PREFIX ${PLUGINS_PREFIX}
|
||||||
|
URL "https://download.falco.org/plugins/${PLUGINS_FULL_VERSION}.tar.gz"
|
||||||
|
URL_HASH "SHA256=3750b3e5120aba9c6d388f6bfdc3c150564edd21779876c3bcf7ec9d3afb66ad"
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND "")
|
||||||
|
|
||||||
|
install(FILES "${PLUGINS_PREFIX}/src/plugins/cloudtrail/libcloudtrail.so" "${PLUGINS_PREFIX}/src/plugins/json/libjson.so" DESTINATION "${FALCO_PLUGINS_DIR}")
|
||||||
27
falco.yaml
27
falco.yaml
@@ -33,6 +33,33 @@ rules_file:
|
|||||||
- /etc/falco/k8s_audit_rules.yaml
|
- /etc/falco/k8s_audit_rules.yaml
|
||||||
- /etc/falco/rules.d
|
- /etc/falco/rules.d
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Plugins that are available for use. These plugins are not loaded by
|
||||||
|
# default, as they require explicit configuration to point to
|
||||||
|
# cloudtrail log files.
|
||||||
|
#
|
||||||
|
|
||||||
|
# To learn more about the supported formats for
|
||||||
|
# init_config/open_params for the cloudtrail plugin, see the README at
|
||||||
|
# https://github.com/falcosecurity/plugins/blob/master/plugins/cloudtrail/README.md.
|
||||||
|
plugins:
|
||||||
|
- name: cloudtrail
|
||||||
|
library_path: libcloudtrail.so
|
||||||
|
init_config: ""
|
||||||
|
open_params: ""
|
||||||
|
- name: json
|
||||||
|
library_path: libjson.so
|
||||||
|
init_config: ""
|
||||||
|
open_params: ""
|
||||||
|
|
||||||
|
# Setting this list to empty ensures that the above plugins are *not*
|
||||||
|
# loaded and enabled by default. If you want to use the above plugins,
|
||||||
|
# set a meaningful init_config/open_params for the cloudtrail plugin
|
||||||
|
# and then change this to:
|
||||||
|
# load_plugins: [cloudtrail, json]
|
||||||
|
load_plugins: []
|
||||||
|
|
||||||
# If true, the times displayed in log messages and output messages
|
# If true, the times displayed in log messages and output messages
|
||||||
# will be in ISO 8601. By default, times are displayed in the local
|
# will be in ISO 8601. By default, times are displayed in the local
|
||||||
# time zone, as governed by /etc/localtime.
|
# time zone, as governed by /etc/localtime.
|
||||||
|
|||||||
440
rules/aws_cloudtrail_rules.yaml
Normal file
440
rules/aws_cloudtrail_rules.yaml
Normal file
@@ -0,0 +1,440 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2019 The Falco Authors.
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
# All rules files related to plugins should require engine version 10
|
||||||
|
- required_engine_version: 10
|
||||||
|
|
||||||
|
# These rules can be read by cloudtrail plugin version 0.1.0, or
|
||||||
|
# anything semver-compatible.
|
||||||
|
- required_plugin_versions:
|
||||||
|
- name: cloudtrail
|
||||||
|
version: 0.1.0
|
||||||
|
|
||||||
|
# Note that this rule is disabled by default. It's useful only to
|
||||||
|
# verify that the cloudtrail plugin is sending events properly. The
|
||||||
|
# very broad condition evt.num > 0 only works because the rule source
|
||||||
|
# is limited to aws_cloudtrail. This ensures that the only events that
|
||||||
|
# are matched against the rule are from the cloudtrail plugin (or
|
||||||
|
# a different plugin with the same source).
|
||||||
|
- rule: All Cloudtrail Events
|
||||||
|
desc: Match all cloudtrail events.
|
||||||
|
condition:
|
||||||
|
evt.num > 0
|
||||||
|
output: Some Cloudtrail Event (evtnum=%evt.num info=%evt.plugininfo ts=%evt.time.iso8601 id=%ct.id error=%ct.error)
|
||||||
|
priority: DEBUG
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
source: aws_cloudtrail
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
- rule: Console Login Through Assume Role
|
||||||
|
desc: Detect a console login through Assume Role.
|
||||||
|
condition:
|
||||||
|
ct.name="ConsoleLogin" and not ct.error exists
|
||||||
|
and ct.user.identitytype="AssumedRole"
|
||||||
|
and json.value[/responseElements/ConsoleLogin]="Success"
|
||||||
|
output:
|
||||||
|
Detected a console login through Assume Role
|
||||||
|
(principal=%ct.user.principalid,
|
||||||
|
assumedRole=%ct.user.arn,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_console
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Console Login Without MFA
|
||||||
|
desc: Detect a console login without MFA.
|
||||||
|
condition:
|
||||||
|
ct.name="ConsoleLogin" and not ct.error exists
|
||||||
|
and ct.user.identitytype!="AssumedRole"
|
||||||
|
and json.value[/responseElements/ConsoleLogin]="Success"
|
||||||
|
and json.value[/additionalEventData/MFAUsed]="No"
|
||||||
|
output:
|
||||||
|
Detected a console login without MFA
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region)
|
||||||
|
priority: CRITICAL
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_console
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Console Root Login Without MFA
|
||||||
|
desc: Detect root console login without MFA.
|
||||||
|
condition:
|
||||||
|
ct.name="ConsoleLogin" and not ct.error exists
|
||||||
|
and json.value[/additionalEventData/MFAUsed]="No"
|
||||||
|
and ct.user.identitytype!="AssumedRole"
|
||||||
|
and json.value[/responseElements/ConsoleLogin]="Success"
|
||||||
|
and ct.user.identitytype="Root"
|
||||||
|
output:
|
||||||
|
Detected a root console login without MFA.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region)
|
||||||
|
priority: CRITICAL
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_console
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Deactivate MFA for Root User
|
||||||
|
desc: Detect deactivating MFA configuration for root.
|
||||||
|
condition:
|
||||||
|
ct.name="DeactivateMFADevice" and not ct.error exists
|
||||||
|
and ct.user.identitytype="Root"
|
||||||
|
and ct.request.username="AWS ROOT USER"
|
||||||
|
output:
|
||||||
|
Multi Factor Authentication configuration has been disabled for root
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
MFA serial number=%ct.request.serialnumber)
|
||||||
|
priority: CRITICAL
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Create AWS user
|
||||||
|
desc: Detect creation of a new AWS user.
|
||||||
|
condition:
|
||||||
|
ct.name="CreateUser" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A new AWS user has been created
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
new user created=%ct.request.username)
|
||||||
|
priority: INFO
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Create Group
|
||||||
|
desc: Detect creation of a new user group.
|
||||||
|
condition:
|
||||||
|
ct.name="CreateGroup" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A new user group has been created.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
group name=%ct.request.groupname)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Delete Group
|
||||||
|
desc: Detect deletion of a user group.
|
||||||
|
condition:
|
||||||
|
ct.name="DeleteGroup" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A user group has been deleted.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
group name=%ct.request.groupname)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_iam
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: ECS Service Created
|
||||||
|
desc: Detect a new service is created in ECS.
|
||||||
|
condition:
|
||||||
|
ct.src="ecs.amazonaws.com" and
|
||||||
|
ct.name="CreateService" and
|
||||||
|
not ct.error exists
|
||||||
|
output:
|
||||||
|
A new service has been created in ECS
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
cluster=%ct.request.cluster,
|
||||||
|
service name=%ct.request.servicename,
|
||||||
|
task definition=%ct.request.taskdefinition)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_ecs
|
||||||
|
- aws_fargate
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: ECS Task Run or Started
|
||||||
|
desc: Detect a new task is started in ECS.
|
||||||
|
condition:
|
||||||
|
ct.src="ecs.amazonaws.com" and
|
||||||
|
(ct.name="RunTask" or ct.name="StartTask") and
|
||||||
|
not ct.error exists
|
||||||
|
output:
|
||||||
|
A new task has been started in ECS
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
cluster=%ct.request.cluster,
|
||||||
|
task definition=%ct.request.taskdefinition)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_ecs
|
||||||
|
- aws_fargate
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Create Lambda Function
|
||||||
|
desc: Detect creation of a Lambda function.
|
||||||
|
condition:
|
||||||
|
ct.name="CreateFunction20150331" and not ct.error exists
|
||||||
|
output:
|
||||||
|
Lambda function has been created.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
lambda function=%ct.request.functionname)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_lambda
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Update Lambda Function Code
|
||||||
|
desc: Detect updates to a Lambda function code.
|
||||||
|
condition:
|
||||||
|
ct.name="UpdateFunctionCode20150331v2" and not ct.error exists
|
||||||
|
output:
|
||||||
|
The code of a Lambda function has been updated.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
lambda function=%ct.request.functionname)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_lambda
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Update Lambda Function Configuration
|
||||||
|
desc: Detect updates to a Lambda function configuration.
|
||||||
|
condition:
|
||||||
|
ct.name="UpdateFunctionConfiguration20150331v2" and not ct.error exists
|
||||||
|
output:
|
||||||
|
The configuration of a Lambda function has been updated.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
lambda function=%ct.request.functionname)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_lambda
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Run Instances
|
||||||
|
desc: Detect launching of a specified number of instances.
|
||||||
|
condition:
|
||||||
|
ct.name="RunInstances" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A number of instances have been launched.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
availability zone=%ct.request.availabilityzone,
|
||||||
|
subnet id=%ct.response.subnetid,
|
||||||
|
reservation id=%ct.response.reservationid)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_ec2
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
# Only instances launched on regions in this list are approved.
|
||||||
|
- list: approved_regions
|
||||||
|
items:
|
||||||
|
- us-east-0
|
||||||
|
|
||||||
|
- rule: Run Instances in Non-approved Region
|
||||||
|
desc: Detect launching of a specified number of instances in a non-approved region.
|
||||||
|
condition:
|
||||||
|
ct.name="RunInstances" and not ct.error exists and
|
||||||
|
not ct.region in (approved_regions)
|
||||||
|
output:
|
||||||
|
A number of instances have been launched in a non-approved region.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
availability zone=%ct.request.availabilityzone,
|
||||||
|
subnet id=%ct.response.subnetid,
|
||||||
|
reservation id=%ct.response.reservationid,
|
||||||
|
image id=%json.value[/responseElements/instancesSet/items/0/instanceId])
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_ec2
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Delete Bucket Encryption
|
||||||
|
desc: Detect deleting configuration to use encryption for bucket storage.
|
||||||
|
condition:
|
||||||
|
ct.name="DeleteBucketEncryption" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A encryption configuration for a bucket has been deleted
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
bucket=%s3.bucket)
|
||||||
|
priority: CRITICAL
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_s3
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Delete Bucket Public Access Block
|
||||||
|
desc: Detect deleting blocking public access to bucket.
|
||||||
|
condition:
|
||||||
|
ct.name="PutBucketPublicAccessBlock" and not ct.error exists and
|
||||||
|
json.value[/requestParameters/publicAccessBlock]="" and
|
||||||
|
(json.value[/requestParameters/PublicAccessBlockConfiguration/RestrictPublicBuckets]=false or
|
||||||
|
json.value[/requestParameters/PublicAccessBlockConfiguration/BlockPublicPolicy]=false or
|
||||||
|
json.value[/requestParameters/PublicAccessBlockConfiguration/BlockPublicAcls]=false or
|
||||||
|
json.value[/requestParameters/PublicAccessBlockConfiguration/IgnorePublicAcls]=false)
|
||||||
|
output:
|
||||||
|
A pulic access block for a bucket has been deleted
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
bucket=%s3.bucket)
|
||||||
|
priority: CRITICAL
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_s3
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: List Buckets
|
||||||
|
desc: Detect listing of all S3 buckets.
|
||||||
|
condition:
|
||||||
|
ct.name="ListBuckets" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A list of all S3 buckets has been requested.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
host=%ct.request.host)
|
||||||
|
priority: WARNING
|
||||||
|
enabled: false
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_s3
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Put Bucket ACL
|
||||||
|
desc: Detect setting the permissions on an existing bucket using access control lists.
|
||||||
|
condition:
|
||||||
|
ct.name="PutBucketAcl" and not ct.error exists
|
||||||
|
output:
|
||||||
|
The permissions on an existing bucket have been set using access control lists.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
bucket name=%s3.bucket)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_s3
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: Put Bucket Policy
|
||||||
|
desc: Detect applying an Amazon S3 bucket policy to an Amazon S3 bucket.
|
||||||
|
condition:
|
||||||
|
ct.name="PutBucketPolicy" and not ct.error exists
|
||||||
|
output:
|
||||||
|
An Amazon S3 bucket policy has been applied to an Amazon S3 bucket.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
bucket name=%s3.bucket,
|
||||||
|
policy=%ct.request.policy)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_s3
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: CloudTrail Trail Created
|
||||||
|
desc: Detect creation of a new trail.
|
||||||
|
condition:
|
||||||
|
ct.name="CreateTrail" and not ct.error exists
|
||||||
|
output:
|
||||||
|
A new trail has been created.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
trail name=%ct.request.name)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_cloudtrail
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
|
- rule: CloudTrail Logging Disabled
|
||||||
|
desc: The CloudTrail logging has been disabled, this could be potentially malicious.
|
||||||
|
condition:
|
||||||
|
ct.name="StopLogging" and not ct.error exists
|
||||||
|
output:
|
||||||
|
The CloudTrail logging has been disabled.
|
||||||
|
(requesting user=%ct.user,
|
||||||
|
requesting IP=%ct.srcip,
|
||||||
|
AWS region=%ct.region,
|
||||||
|
resource name=%ct.request.name)
|
||||||
|
priority: WARNING
|
||||||
|
tags:
|
||||||
|
- cloud
|
||||||
|
- aws
|
||||||
|
- aws_cloudtrail
|
||||||
|
source: aws_cloudtrail
|
||||||
|
|
||||||
@@ -46,6 +46,7 @@ if(FALCO_BUILD_TESTS)
|
|||||||
PUBLIC "${CATCH2_INCLUDE}"
|
PUBLIC "${CATCH2_INCLUDE}"
|
||||||
"${FAKEIT_INCLUDE}"
|
"${FAKEIT_INCLUDE}"
|
||||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||||
|
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||||
"${YAMLCPP_INCLUDE_DIR}"
|
"${YAMLCPP_INCLUDE_DIR}"
|
||||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||||
else()
|
else()
|
||||||
@@ -54,6 +55,7 @@ if(FALCO_BUILD_TESTS)
|
|||||||
PUBLIC "${CATCH2_INCLUDE}"
|
PUBLIC "${CATCH2_INCLUDE}"
|
||||||
"${FAKEIT_INCLUDE}"
|
"${FAKEIT_INCLUDE}"
|
||||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||||
|
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||||
"${YAMLCPP_INCLUDE_DIR}"
|
"${YAMLCPP_INCLUDE_DIR}"
|
||||||
"${CIVETWEB_INCLUDE_DIR}"
|
"${CIVETWEB_INCLUDE_DIR}"
|
||||||
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
"${PROJECT_SOURCE_DIR}/userspace/falco")
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ limitations under the License.
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "falco_engine.h"
|
#include "falco_engine.h"
|
||||||
#include "falco_utils.h"
|
#include "falco_utils.h"
|
||||||
@@ -56,6 +57,8 @@ falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
|
|||||||
|
|
||||||
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||||
m_k8s_audit_rules.reset(new falco_ruleset());
|
m_k8s_audit_rules.reset(new falco_ruleset());
|
||||||
|
m_plugin_rules.clear();
|
||||||
|
m_required_plugin_versions.clear();
|
||||||
|
|
||||||
if(seed_rng)
|
if(seed_rng)
|
||||||
{
|
{
|
||||||
@@ -179,7 +182,7 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
|
|||||||
bool json_include_output_property = false;
|
bool json_include_output_property = false;
|
||||||
falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property);
|
falco_formats::init(m_inspector, this, m_ls, json_output, json_include_output_property);
|
||||||
|
|
||||||
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version);
|
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority, required_engine_version, m_required_plugin_versions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
|
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
|
||||||
@@ -214,6 +217,11 @@ void falco_engine::enable_rule(const string &substring, bool enabled, const stri
|
|||||||
|
|
||||||
m_sinsp_rules->enable(substring, match_exact, enabled, ruleset_id);
|
m_sinsp_rules->enable(substring, match_exact, enabled, ruleset_id);
|
||||||
m_k8s_audit_rules->enable(substring, match_exact, enabled, ruleset_id);
|
m_k8s_audit_rules->enable(substring, match_exact, enabled, ruleset_id);
|
||||||
|
|
||||||
|
for(auto &it : m_plugin_rules)
|
||||||
|
{
|
||||||
|
it.second->enable(substring, match_exact, enabled, ruleset_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::enable_rule(const string &substring, bool enabled)
|
void falco_engine::enable_rule(const string &substring, bool enabled)
|
||||||
@@ -228,6 +236,11 @@ void falco_engine::enable_rule_exact(const string &rule_name, bool enabled, cons
|
|||||||
|
|
||||||
m_sinsp_rules->enable(rule_name, match_exact, enabled, ruleset_id);
|
m_sinsp_rules->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||||
m_k8s_audit_rules->enable(rule_name, match_exact, enabled, ruleset_id);
|
m_k8s_audit_rules->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||||
|
|
||||||
|
for(auto &it : m_plugin_rules)
|
||||||
|
{
|
||||||
|
it.second->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::enable_rule_exact(const string &rule_name, bool enabled)
|
void falco_engine::enable_rule_exact(const string &rule_name, bool enabled)
|
||||||
@@ -241,6 +254,11 @@ void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled, con
|
|||||||
|
|
||||||
m_sinsp_rules->enable_tags(tags, enabled, ruleset_id);
|
m_sinsp_rules->enable_tags(tags, enabled, ruleset_id);
|
||||||
m_k8s_audit_rules->enable_tags(tags, enabled, ruleset_id);
|
m_k8s_audit_rules->enable_tags(tags, enabled, ruleset_id);
|
||||||
|
|
||||||
|
for(auto &it : m_plugin_rules)
|
||||||
|
{
|
||||||
|
it.second->enable_tags(tags, enabled, ruleset_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled)
|
void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled)
|
||||||
@@ -271,8 +289,16 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset)
|
|||||||
{
|
{
|
||||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||||
|
|
||||||
|
uint32_t num_plugin_rules = 0;
|
||||||
|
|
||||||
|
for(auto &it : m_plugin_rules)
|
||||||
|
{
|
||||||
|
num_plugin_rules += it.second->num_rules_for_ruleset(ruleset_id);
|
||||||
|
}
|
||||||
|
|
||||||
return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) +
|
return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) +
|
||||||
m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id);
|
m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id) +
|
||||||
|
num_plugin_rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset)
|
void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset)
|
||||||
@@ -296,13 +322,38 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_sinsp_event(sinsp_ev
|
|||||||
return unique_ptr<struct rule_result>();
|
return unique_ptr<struct rule_result>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_sinsp_rules->run(ev, ruleset_id))
|
unique_ptr<struct rule_result> res;
|
||||||
|
std::string source = "syscall";
|
||||||
|
|
||||||
|
if(ev->get_type() == PPME_PLUGINEVENT_E)
|
||||||
{
|
{
|
||||||
return unique_ptr<struct rule_result>();
|
sinsp_evt_param *parinfo = ev->get_param(0);
|
||||||
|
ASSERT(parinfo->m_len == sizeof(int32_t));
|
||||||
|
uint32_t plugin_id = *(int32_t *)parinfo->m_val;
|
||||||
|
|
||||||
|
// No rules for this plugin-->no rule match
|
||||||
|
auto it = m_plugin_rules.find(plugin_id);
|
||||||
|
if(it == m_plugin_rules.end())
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All plugin events have a single tag PPME_CONTAINER_X.
|
||||||
|
if (!it->second->run((gen_event *) ev, PPME_CONTAINER_X, ruleset_id))
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!m_sinsp_rules->run(ev, ruleset_id))
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<struct rule_result> res(new rule_result());
|
res.reset(new rule_result());
|
||||||
res->source = "syscall";
|
res->source = source;
|
||||||
|
|
||||||
populate_rule_result(res, ev);
|
populate_rule_result(res, ev);
|
||||||
|
|
||||||
@@ -478,11 +529,11 @@ void falco_engine::print_stats()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::add_sinsp_filter(string &rule,
|
void falco_engine::add_syscall_filter(string &rule,
|
||||||
set<uint32_t> &evttypes,
|
set<uint32_t> &evttypes,
|
||||||
set<uint32_t> &syscalls,
|
set<uint32_t> &syscalls,
|
||||||
set<string> &tags,
|
set<string> &tags,
|
||||||
sinsp_filter* filter)
|
sinsp_filter* filter)
|
||||||
{
|
{
|
||||||
m_sinsp_rules->add(rule, evttypes, syscalls, tags, filter);
|
m_sinsp_rules->add(rule, evttypes, syscalls, tags, filter);
|
||||||
}
|
}
|
||||||
@@ -497,10 +548,75 @@ void falco_engine::add_k8s_audit_filter(string &rule,
|
|||||||
m_k8s_audit_rules->add(rule, tags, event_tags, filter);
|
m_k8s_audit_rules->add(rule, tags, event_tags, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void falco_engine::add_plugin_filter(string &rule,
|
||||||
|
set<string> &tags,
|
||||||
|
sinsp_filter* filter,
|
||||||
|
string &source)
|
||||||
|
{
|
||||||
|
// Find the loaded source plugin with event source == source
|
||||||
|
// and add this filter to the map.
|
||||||
|
// XXX/mstemm what to do with extractor plugins?
|
||||||
|
std::shared_ptr<sinsp_plugin> plugin = m_inspector->get_source_plugin_by_source(source);
|
||||||
|
|
||||||
|
if(plugin)
|
||||||
|
{
|
||||||
|
// All plugin events have a single tag PPME_CONTAINER_X.
|
||||||
|
std::set<uint32_t> event_tags = {PPME_CONTAINER_X};
|
||||||
|
|
||||||
|
sinsp_source_plugin *splugin = static_cast<sinsp_source_plugin *>(plugin.get());
|
||||||
|
uint32_t id = splugin->id();
|
||||||
|
|
||||||
|
auto it = m_plugin_rules.find(id);
|
||||||
|
|
||||||
|
if(it == m_plugin_rules.end())
|
||||||
|
{
|
||||||
|
std::unique_ptr<falco_ruleset> add;
|
||||||
|
add.reset(new falco_ruleset());
|
||||||
|
m_plugin_rules[id] = std::move(add);
|
||||||
|
it = m_plugin_rules.find(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
it->second->add(rule, tags, event_tags, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool falco_engine::is_plugin_compatible(const std::string &name,
|
||||||
|
const std::string &version,
|
||||||
|
std::string &required_version)
|
||||||
|
{
|
||||||
|
sinsp_plugin::version plugin_version(version.c_str());
|
||||||
|
|
||||||
|
if(!plugin_version.m_valid)
|
||||||
|
{
|
||||||
|
throw falco_exception(string("Plugin version string ") + version + " not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_required_plugin_versions.find(name) == m_required_plugin_versions.end())
|
||||||
|
{
|
||||||
|
// No required engine versions, so no restrictions. Compatible.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &rversion : m_required_plugin_versions[name])
|
||||||
|
{
|
||||||
|
sinsp_plugin::version req_version(rversion.c_str());
|
||||||
|
if(req_version.m_version_major > plugin_version.m_version_major)
|
||||||
|
{
|
||||||
|
required_version = rversion;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void falco_engine::clear_filters()
|
void falco_engine::clear_filters()
|
||||||
{
|
{
|
||||||
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||||
m_k8s_audit_rules.reset(new falco_ruleset());
|
m_k8s_audit_rules.reset(new falco_ruleset());
|
||||||
|
m_plugin_rules.clear();
|
||||||
|
m_required_plugin_versions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_engine::set_sampling_ratio(uint32_t sampling_ratio)
|
void falco_engine::set_sampling_ratio(uint32_t sampling_ratio)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ limitations under the License.
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include "sinsp.h"
|
#include "sinsp.h"
|
||||||
|
#include "plugin.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
|
|
||||||
#include "json_evt.h"
|
#include "json_evt.h"
|
||||||
@@ -233,11 +234,22 @@ public:
|
|||||||
// Add a filter, which is related to the specified set of
|
// Add a filter, which is related to the specified set of
|
||||||
// event types/syscalls, to the engine.
|
// event types/syscalls, to the engine.
|
||||||
//
|
//
|
||||||
void add_sinsp_filter(std::string &rule,
|
void add_syscall_filter(std::string &rule,
|
||||||
std::set<uint32_t> &evttypes,
|
std::set<uint32_t> &evttypes,
|
||||||
std::set<uint32_t> &syscalls,
|
std::set<uint32_t> &syscalls,
|
||||||
|
std::set<std::string> &tags,
|
||||||
|
sinsp_filter* filter);
|
||||||
|
|
||||||
|
void add_plugin_filter(std::string &rule,
|
||||||
std::set<std::string> &tags,
|
std::set<std::string> &tags,
|
||||||
sinsp_filter* filter);
|
sinsp_filter* filter,
|
||||||
|
std::string &source);
|
||||||
|
|
||||||
|
// Return whether the provided plugin name + version is
|
||||||
|
// compatible with the current set of loaded rules files.
|
||||||
|
// required_version will be filled in with the required
|
||||||
|
// version when the method returns false.
|
||||||
|
bool is_plugin_compatible(const std::string &name, const std::string &version, std::string &required_version);
|
||||||
|
|
||||||
sinsp_filter_factory &sinsp_factory();
|
sinsp_filter_factory &sinsp_factory();
|
||||||
json_event_filter_factory &json_factory();
|
json_event_filter_factory &json_factory();
|
||||||
@@ -263,6 +275,14 @@ private:
|
|||||||
std::unique_ptr<falco_sinsp_ruleset> m_sinsp_rules;
|
std::unique_ptr<falco_sinsp_ruleset> m_sinsp_rules;
|
||||||
std::unique_ptr<falco_ruleset> m_k8s_audit_rules;
|
std::unique_ptr<falco_ruleset> m_k8s_audit_rules;
|
||||||
|
|
||||||
|
// Maps from plugin id to rules related to that plugin
|
||||||
|
// XXX/mstemm how to handle extractor-only plugins?
|
||||||
|
std::map<uint32_t, std::unique_ptr<falco_ruleset>> m_plugin_rules;
|
||||||
|
|
||||||
|
// Maps from plugin to a list of required plugin versions
|
||||||
|
// found in any loaded rules files.
|
||||||
|
std::map<std::string, std::list<std::string>> m_required_plugin_versions;
|
||||||
|
|
||||||
void populate_rule_result(unique_ptr<struct rule_result> &res, gen_event *ev);
|
void populate_rule_result(unique_ptr<struct rule_result> &res, gen_event *ev);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (C) 2020 The Falco Authors.
|
Copyright (C) 2021 The Falco Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -14,11 +14,11 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// The version of rules/filter fields/etc supported by this falco
|
// The version of rules/filter fields/etc supported by this Falco
|
||||||
// engine.
|
// engine.
|
||||||
#define FALCO_ENGINE_VERSION (8)
|
#define FALCO_ENGINE_VERSION (10)
|
||||||
|
|
||||||
// This is the result of running "falco --list -N | sha256sum" and
|
// This is the result of running "falco --list -N | sha256sum" and
|
||||||
// represents the fields supported by this version of falco. It's used
|
// represents the fields supported by this version of Falco. It's used
|
||||||
// at build time to detect a changed set of fields.
|
// at build time to detect a changed set of fields.
|
||||||
#define FALCO_FIELDS_CHECKSUM "2f324e2e66d4b423f53600e7e0fcf2f0ff72e4a87755c490f2ae8f310aba9386"
|
#define FALCO_FIELDS_CHECKSUM "8183621f52451d842036eee409e2ed920d9c91bab33e0c4a44e4a871378d103f"
|
||||||
|
|||||||
@@ -49,6 +49,14 @@ void falco_formats::init(sinsp *inspector,
|
|||||||
luaL_openlib(ls, "formats", ll_falco, 0);
|
luaL_openlib(ls, "formats", ll_falco, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void falco_formats::create_sinsp_formatter(lua_State *ls, const std::string &format)
|
||||||
|
{
|
||||||
|
sinsp_evt_formatter *formatter;
|
||||||
|
formatter = new sinsp_evt_formatter(s_inspector, format);
|
||||||
|
lua_pushnil(ls);
|
||||||
|
lua_pushlightuserdata(ls, formatter);
|
||||||
|
}
|
||||||
|
|
||||||
int falco_formats::lua_formatter(lua_State *ls)
|
int falco_formats::lua_formatter(lua_State *ls)
|
||||||
{
|
{
|
||||||
string source = luaL_checkstring(ls, -2);
|
string source = luaL_checkstring(ls, -2);
|
||||||
@@ -58,17 +66,18 @@ int falco_formats::lua_formatter(lua_State *ls)
|
|||||||
{
|
{
|
||||||
if(source == "syscall")
|
if(source == "syscall")
|
||||||
{
|
{
|
||||||
sinsp_evt_formatter *formatter;
|
create_sinsp_formatter(ls, format);
|
||||||
formatter = new sinsp_evt_formatter(s_inspector, format);
|
|
||||||
lua_pushnil(ls);
|
|
||||||
lua_pushlightuserdata(ls, formatter);
|
|
||||||
}
|
}
|
||||||
else
|
else if (source == "k8s_audit")
|
||||||
{
|
{
|
||||||
json_event_formatter *formatter;
|
json_event_formatter *formatter;
|
||||||
formatter = new json_event_formatter(s_engine->json_factory(), format);
|
formatter = new json_event_formatter(s_engine->json_factory(), format);
|
||||||
lua_pushnil(ls);
|
lua_pushnil(ls);
|
||||||
lua_pushlightuserdata(ls, formatter);
|
lua_pushlightuserdata(ls, formatter);
|
||||||
|
} else {
|
||||||
|
// Not one of the built-in sources, so assume it's a plugin.
|
||||||
|
// Plugins behave identically to syscall events for now.
|
||||||
|
create_sinsp_formatter(ls, format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(exception &e)
|
catch(exception &e)
|
||||||
@@ -88,6 +97,12 @@ int falco_formats::lua_formatter(lua_State *ls)
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void falco_formats::delete_sinsp_formatter(lua_State *ls)
|
||||||
|
{
|
||||||
|
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *)lua_topointer(ls, -1);
|
||||||
|
delete(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
int falco_formats::lua_free_formatter(lua_State *ls)
|
int falco_formats::lua_free_formatter(lua_State *ls)
|
||||||
{
|
{
|
||||||
if(!lua_islightuserdata(ls, -1) ||
|
if(!lua_islightuserdata(ls, -1) ||
|
||||||
@@ -101,18 +116,64 @@ int falco_formats::lua_free_formatter(lua_State *ls)
|
|||||||
|
|
||||||
if(source == "syscall")
|
if(source == "syscall")
|
||||||
{
|
{
|
||||||
sinsp_evt_formatter *formatter = (sinsp_evt_formatter *)lua_topointer(ls, -1);
|
delete_sinsp_formatter(ls);
|
||||||
delete(formatter);
|
|
||||||
}
|
}
|
||||||
else
|
else if (source == "k8s_audit")
|
||||||
{
|
{
|
||||||
json_event_formatter *formatter = (json_event_formatter *)lua_topointer(ls, -1);
|
json_event_formatter *formatter = (json_event_formatter *)lua_topointer(ls, -1);
|
||||||
delete(formatter);
|
delete(formatter);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not one of the built-in sources, so assume it's a plugin.
|
||||||
|
// Plugins behave identically to syscall events for now.
|
||||||
|
delete_sinsp_formatter(ls);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void falco_formats::format_sinsp_event(const gen_event *evt, const std::string &format,
|
||||||
|
std::string &line, std::string &json_line, std::string &sformat)
|
||||||
|
{
|
||||||
|
// This is "output"
|
||||||
|
s_formatters->tostring((sinsp_evt *)evt, sformat, &line);
|
||||||
|
|
||||||
|
if(s_json_output)
|
||||||
|
{
|
||||||
|
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
||||||
|
switch(cur_fmt)
|
||||||
|
{
|
||||||
|
case sinsp_evt::PF_NORMAL:
|
||||||
|
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
||||||
|
break;
|
||||||
|
case sinsp_evt::PF_EOLS:
|
||||||
|
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
||||||
|
break;
|
||||||
|
case sinsp_evt::PF_HEX:
|
||||||
|
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
||||||
|
break;
|
||||||
|
case sinsp_evt::PF_HEXASCII:
|
||||||
|
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
||||||
|
break;
|
||||||
|
case sinsp_evt::PF_BASE64:
|
||||||
|
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// do nothing
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// This is output fields
|
||||||
|
s_formatters->tostring((sinsp_evt *)evt, sformat, &json_line);
|
||||||
|
|
||||||
|
// The formatted string might have a leading newline. If it does, remove it.
|
||||||
|
if(json_line[0] == '\n')
|
||||||
|
{
|
||||||
|
json_line.erase(0, 1);
|
||||||
|
}
|
||||||
|
s_inspector->set_buffer_format(cur_fmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string falco_formats::format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
string falco_formats::format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||||
const std::string &level, const std::string &format)
|
const std::string &level, const std::string &format)
|
||||||
{
|
{
|
||||||
@@ -121,47 +182,11 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
|||||||
string json_line;
|
string json_line;
|
||||||
string sformat = format;
|
string sformat = format;
|
||||||
|
|
||||||
if(strcmp(source.c_str(), "syscall") == 0)
|
if(source == "syscall")
|
||||||
{
|
{
|
||||||
// This is "output"
|
format_sinsp_event(evt, format, line, json_line, sformat);
|
||||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &line);
|
|
||||||
|
|
||||||
if(s_json_output)
|
|
||||||
{
|
|
||||||
sinsp_evt::param_fmt cur_fmt = s_inspector->get_buffer_format();
|
|
||||||
switch(cur_fmt)
|
|
||||||
{
|
|
||||||
case sinsp_evt::PF_NORMAL:
|
|
||||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
|
|
||||||
break;
|
|
||||||
case sinsp_evt::PF_EOLS:
|
|
||||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONEOLS);
|
|
||||||
break;
|
|
||||||
case sinsp_evt::PF_HEX:
|
|
||||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEX);
|
|
||||||
break;
|
|
||||||
case sinsp_evt::PF_HEXASCII:
|
|
||||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONHEXASCII);
|
|
||||||
break;
|
|
||||||
case sinsp_evt::PF_BASE64:
|
|
||||||
s_inspector->set_buffer_format(sinsp_evt::PF_JSONBASE64);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// do nothing
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// This is output fields
|
|
||||||
s_formatters->tostring((sinsp_evt *)evt, sformat, &json_line);
|
|
||||||
|
|
||||||
// The formatted string might have a leading newline. If it does, remove it.
|
|
||||||
if(json_line[0] == '\n')
|
|
||||||
{
|
|
||||||
json_line.erase(0, 1);
|
|
||||||
}
|
|
||||||
s_inspector->set_buffer_format(cur_fmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else if (source == "k8s_audit")
|
||||||
{
|
{
|
||||||
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
json_event_formatter formatter(s_engine->json_factory(), sformat);
|
||||||
|
|
||||||
@@ -171,6 +196,10 @@ string falco_formats::format_event(const gen_event *evt, const std::string &rule
|
|||||||
{
|
{
|
||||||
json_line = formatter.tojson((json_event *)evt);
|
json_line = formatter.tojson((json_event *)evt);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Not one of the built-in sources, so assume it's a plugin.
|
||||||
|
// Plugins behave identically to syscall events for now.
|
||||||
|
format_sinsp_event(evt, format, line, json_line, sformat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For JSON output, the formatter returned a json-as-text
|
// For JSON output, the formatter returned a json-as-text
|
||||||
@@ -234,11 +263,16 @@ map<string, string> falco_formats::resolve_tokens(const gen_event *evt, const st
|
|||||||
{
|
{
|
||||||
s_formatters->resolve_tokens((sinsp_evt *)evt, sformat, values);
|
s_formatters->resolve_tokens((sinsp_evt *)evt, sformat, values);
|
||||||
}
|
}
|
||||||
// k8s_audit
|
else if (source == "k8s_audit")
|
||||||
else
|
|
||||||
{
|
{
|
||||||
json_event_formatter json_formatter(s_engine->json_factory(), sformat);
|
json_event_formatter json_formatter(s_engine->json_factory(), sformat);
|
||||||
values = json_formatter.tomap((json_event *)evt);
|
values = json_formatter.tomap((json_event *)evt);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not one of the built-in sources, so assume it's a plugin.
|
||||||
|
// Plugins behave identically to syscall events for now.
|
||||||
|
s_formatters->resolve_tokens((sinsp_evt *)evt, sformat, values);
|
||||||
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ limitations under the License.
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "sinsp.h"
|
#include "sinsp.h"
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@@ -39,12 +43,18 @@ public:
|
|||||||
bool json_output,
|
bool json_output,
|
||||||
bool json_include_output_property);
|
bool json_include_output_property);
|
||||||
|
|
||||||
|
static void create_sinsp_formatter(lua_State *ls, const std::string &format);
|
||||||
|
static void delete_sinsp_formatter(lua_State *ls);
|
||||||
|
|
||||||
// formatter = falco.formatter(format_string)
|
// formatter = falco.formatter(format_string)
|
||||||
static int lua_formatter(lua_State *ls);
|
static int lua_formatter(lua_State *ls);
|
||||||
|
|
||||||
// falco.free_formatter(formatter)
|
// falco.free_formatter(formatter)
|
||||||
static int lua_free_formatter(lua_State *ls);
|
static int lua_free_formatter(lua_State *ls);
|
||||||
|
|
||||||
|
static void format_sinsp_event(const gen_event *evt, const std::string &format,
|
||||||
|
std::string &line, std::string &json_line, std::string &sformat);
|
||||||
|
|
||||||
static string format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
static string format_event(const gen_event *evt, const std::string &rule, const std::string &source,
|
||||||
const std::string &level, const std::string &format);
|
const std::string &level, const std::string &format);
|
||||||
|
|
||||||
|
|||||||
@@ -426,6 +426,29 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
|||||||
return false, build_error_with_context(v['context'], "Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr)), warnings
|
return false, build_error_with_context(v['context'], "Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr)), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
|
elseif (v['required_plugin_versions']) then
|
||||||
|
|
||||||
|
for _, vobj in ipairs(v['required_plugin_versions']) do
|
||||||
|
if vobj['name'] == nil then
|
||||||
|
return false, build_error_with_context(v['context'], "required_plugin_versions item must have name property"), warnings
|
||||||
|
end
|
||||||
|
|
||||||
|
if vobj['version'] == nil then
|
||||||
|
return false, build_error_with_context(v['context'], "required_plugin_versions item must have version property"), warnings
|
||||||
|
end
|
||||||
|
|
||||||
|
-- In the rules yaml, it's a name + version. But it's
|
||||||
|
-- possible, although unlikely, that a single yaml blob
|
||||||
|
-- contains multiple docs, withe each doc having its own
|
||||||
|
-- required_engine_version entry. So populate a map plugin
|
||||||
|
-- name -> list of required plugin versions.
|
||||||
|
if load_state.required_plugin_versions[vobj['name']] == nil then
|
||||||
|
load_state.required_plugin_versions[vobj['name']] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(load_state.required_plugin_versions[vobj['name']], vobj['version'])
|
||||||
|
end
|
||||||
|
|
||||||
elseif (v['macro']) then
|
elseif (v['macro']) then
|
||||||
|
|
||||||
if (v['macro'] == nil or type(v['macro']) == "table") then
|
if (v['macro'] == nil or type(v['macro']) == "table") then
|
||||||
@@ -769,6 +792,7 @@ end
|
|||||||
-- Returns:
|
-- Returns:
|
||||||
-- - Load Result: bool
|
-- - Load Result: bool
|
||||||
-- - required engine version. will be nil when load result is false
|
-- - required engine version. will be nil when load result is false
|
||||||
|
-- - required_plugin_versions. will be nil when load_result is false
|
||||||
-- - List of Errors
|
-- - List of Errors
|
||||||
-- - List of Warnings
|
-- - List of Warnings
|
||||||
function load_rules(sinsp_lua_parser,
|
function load_rules(sinsp_lua_parser,
|
||||||
@@ -783,7 +807,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
|
|
||||||
local warnings = {}
|
local warnings = {}
|
||||||
|
|
||||||
local load_state = {lines={}, indices={}, cur_item_idx=0, min_priority=min_priority, required_engine_version=0}
|
local load_state = {lines={}, indices={}, cur_item_idx=0, min_priority=min_priority, required_engine_version=0, required_plugin_versions={}}
|
||||||
|
|
||||||
load_state.lines, load_state.indices = split_lines(rules_content)
|
load_state.lines, load_state.indices = split_lines(rules_content)
|
||||||
|
|
||||||
@@ -804,29 +828,29 @@ function load_rules(sinsp_lua_parser,
|
|||||||
row = tonumber(row)
|
row = tonumber(row)
|
||||||
col = tonumber(col)
|
col = tonumber(col)
|
||||||
|
|
||||||
return false, nil, build_error(load_state.lines, row, 3, docs), warnings
|
return false, nil, nil, build_error(load_state.lines, row, 3, docs), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
if docs == nil then
|
if docs == nil then
|
||||||
-- An empty rules file is acceptable
|
-- An empty rules file is acceptable
|
||||||
return true, load_state.required_engine_version, {}, warnings
|
return true, load_state.required_engine_version, {}, {}, warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(docs) ~= "table" then
|
if type(docs) ~= "table" then
|
||||||
return false, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml"), warnings
|
return false, nil, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml"), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
for docidx, doc in ipairs(docs) do
|
for docidx, doc in ipairs(docs) do
|
||||||
|
|
||||||
if type(doc) ~= "table" then
|
if type(doc) ~= "table" then
|
||||||
return false, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml"), warnings
|
return false, nil, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml"), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Look for non-numeric indices--implies that document is not array
|
-- Look for non-numeric indices--implies that document is not array
|
||||||
-- of objects.
|
-- of objects.
|
||||||
for key, val in pairs(doc) do
|
for key, val in pairs(doc) do
|
||||||
if type(key) ~= "number" then
|
if type(key) ~= "number" then
|
||||||
return false, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml array of objects"), warnings
|
return false, nil, nil, build_error(load_state.lines, 1, 1, "Rules content is not yaml array of objects"), warnings
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -839,7 +863,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not res then
|
if not res then
|
||||||
return res, nil, errors, warnings
|
return res, nil, nil, errors, warnings
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -880,7 +904,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
local status, ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
local status, ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||||
|
|
||||||
if status == false then
|
if status == false then
|
||||||
return false, nil, build_error_with_context(v['context'], ast), warnings
|
return false, nil, nil, build_error_with_context(v['context'], ast), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
if v['source'] == "syscall" then
|
if v['source'] == "syscall" then
|
||||||
@@ -912,7 +936,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
end
|
end
|
||||||
|
|
||||||
if err ~= nil then
|
if err ~= nil then
|
||||||
return false, nil, build_error_with_context(v['context'], err), warnings
|
return false, nil, nil, build_error_with_context(v['context'], err), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
if icond ~= "" then
|
if icond ~= "" then
|
||||||
@@ -937,7 +961,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
state.macros, state.lists)
|
state.macros, state.lists)
|
||||||
|
|
||||||
if status == false then
|
if status == false then
|
||||||
return false, nil, build_error_with_context(v['context'], filter_ast), warnings
|
return false, nil, nil, build_error_with_context(v['context'], filter_ast), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
local evtttypes = {}
|
local evtttypes = {}
|
||||||
@@ -960,7 +984,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
warnings[#warnings + 1] = msg
|
warnings[#warnings + 1] = msg
|
||||||
|
|
||||||
if not v['skip-if-unknown-filter'] then
|
if not v['skip-if-unknown-filter'] then
|
||||||
return false, nil, build_error_with_context(v['context'], msg), warnings
|
return false, nil, nil, build_error_with_context(v['context'], msg), warnings
|
||||||
else
|
else
|
||||||
print("Skipping "..msg)
|
print("Skipping "..msg)
|
||||||
goto next_rule
|
goto next_rule
|
||||||
@@ -992,6 +1016,10 @@ function load_rules(sinsp_lua_parser,
|
|||||||
install_filter(filter_ast.filter.value, k8s_audit_filter, json_lua_parser)
|
install_filter(filter_ast.filter.value, k8s_audit_filter, json_lua_parser)
|
||||||
|
|
||||||
falco_rules.add_k8s_audit_filter(rules_mgr, v['rule'], v['tags'])
|
falco_rules.add_k8s_audit_filter(rules_mgr, v['rule'], v['tags'])
|
||||||
|
else
|
||||||
|
install_filter(filter_ast.filter.value, filter, sinsp_lua_parser)
|
||||||
|
|
||||||
|
falco_rules.add_plugin_filter(rules_mgr, v['rule'], v['tags'], v['source'])
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Rule ASTs are merged together into one big AST, with "OR" between each
|
-- Rule ASTs are merged together into one big AST, with "OR" between each
|
||||||
@@ -1046,10 +1074,10 @@ function load_rules(sinsp_lua_parser,
|
|||||||
if err == nil then
|
if err == nil then
|
||||||
formats.free_formatter(v['source'], formatter)
|
formats.free_formatter(v['source'], formatter)
|
||||||
else
|
else
|
||||||
return false, nil, build_error_with_context(v['context'], err), warnings
|
return false, nil, nil, build_error_with_context(v['context'], err), warnings
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return false, nil, build_error_with_context(v['context'], "Unexpected type in load_rule: "..filter_ast.type), warnings
|
return false, nil, nil, build_error_with_context(v['context'], "Unexpected type in load_rule: "..filter_ast.type), warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
::next_rule::
|
::next_rule::
|
||||||
@@ -1072,7 +1100,7 @@ function load_rules(sinsp_lua_parser,
|
|||||||
|
|
||||||
io.flush()
|
io.flush()
|
||||||
|
|
||||||
return true, load_state.required_engine_version, {}, warnings
|
return true, load_state.required_engine_version, load_state.required_plugin_versions, {}, warnings
|
||||||
end
|
end
|
||||||
|
|
||||||
local rule_fmt = "%-50s %s"
|
local rule_fmt = "%-50s %s"
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const static struct luaL_Reg ll_falco_rules[] =
|
|||||||
{"clear_filters", &falco_rules::clear_filters},
|
{"clear_filters", &falco_rules::clear_filters},
|
||||||
{"add_filter", &falco_rules::add_filter},
|
{"add_filter", &falco_rules::add_filter},
|
||||||
{"add_k8s_audit_filter", &falco_rules::add_k8s_audit_filter},
|
{"add_k8s_audit_filter", &falco_rules::add_k8s_audit_filter},
|
||||||
|
{"add_plugin_filter", &falco_rules::add_plugin_filter},
|
||||||
{"enable_rule", &falco_rules::enable_rule},
|
{"enable_rule", &falco_rules::enable_rule},
|
||||||
{"engine_version", &falco_rules::engine_version},
|
{"engine_version", &falco_rules::engine_version},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
||||||
@@ -159,6 +160,41 @@ int falco_rules::add_k8s_audit_filter(lua_State *ls)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int falco_rules::add_plugin_filter(lua_State *ls)
|
||||||
|
{
|
||||||
|
if (! lua_islightuserdata(ls, -4) ||
|
||||||
|
! lua_isstring(ls, -3) ||
|
||||||
|
! lua_istable(ls, -2) ||
|
||||||
|
! lua_isstring(ls, -1))
|
||||||
|
{
|
||||||
|
lua_pushstring(ls, "Invalid arguments passed to add_plugin_filter()");
|
||||||
|
lua_error(ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
falco_rules *rules = (falco_rules *) lua_topointer(ls, -4);
|
||||||
|
const char *rulec = lua_tostring(ls, -3);
|
||||||
|
|
||||||
|
set<string> tags;
|
||||||
|
|
||||||
|
lua_pushnil(ls); /* first key */
|
||||||
|
while (lua_next(ls, -3) != 0) {
|
||||||
|
// key is at index -2, value is at index
|
||||||
|
// -1. We want the values.
|
||||||
|
tags.insert(lua_tostring(ls, -1));
|
||||||
|
|
||||||
|
// Remove value, keep key for next iteration
|
||||||
|
lua_pop(ls, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sourcec = lua_tostring(ls, -1);
|
||||||
|
|
||||||
|
std::string rule = rulec;
|
||||||
|
std::string source = sourcec;
|
||||||
|
rules->add_plugin_filter(rule, tags, source);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void falco_rules::add_filter(string &rule, set<uint32_t> &evttypes, set<uint32_t> &syscalls, set<string> &tags)
|
void falco_rules::add_filter(string &rule, set<uint32_t> &evttypes, set<uint32_t> &syscalls, set<string> &tags)
|
||||||
{
|
{
|
||||||
// While the current rule was being parsed, a sinsp_filter
|
// While the current rule was being parsed, a sinsp_filter
|
||||||
@@ -166,7 +202,7 @@ void falco_rules::add_filter(string &rule, set<uint32_t> &evttypes, set<uint32_t
|
|||||||
// and pass it to the engine.
|
// and pass it to the engine.
|
||||||
sinsp_filter *filter = (sinsp_filter *) m_sinsp_lua_parser->get_filter(true);
|
sinsp_filter *filter = (sinsp_filter *) m_sinsp_lua_parser->get_filter(true);
|
||||||
|
|
||||||
m_engine->add_sinsp_filter(rule, evttypes, syscalls, tags, filter);
|
m_engine->add_syscall_filter(rule, evttypes, syscalls, tags, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_rules::add_k8s_audit_filter(string &rule, set<string> &tags)
|
void falco_rules::add_k8s_audit_filter(string &rule, set<string> &tags)
|
||||||
@@ -179,6 +215,16 @@ void falco_rules::add_k8s_audit_filter(string &rule, set<string> &tags)
|
|||||||
m_engine->add_k8s_audit_filter(rule, tags, filter);
|
m_engine->add_k8s_audit_filter(rule, tags, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void falco_rules::add_plugin_filter(string &rule, set<string> &tags, string &source)
|
||||||
|
{
|
||||||
|
// While the current rule was being parsed, a sinsp_filter
|
||||||
|
// object was being populated by lua_parser. Grab that filter
|
||||||
|
// and pass it to the engine.
|
||||||
|
sinsp_filter *filter = (sinsp_filter *) m_sinsp_lua_parser->get_filter(true);
|
||||||
|
|
||||||
|
m_engine->add_plugin_filter(rule, tags, filter, source);
|
||||||
|
}
|
||||||
|
|
||||||
int falco_rules::enable_rule(lua_State *ls)
|
int falco_rules::enable_rule(lua_State *ls)
|
||||||
{
|
{
|
||||||
if (! lua_islightuserdata(ls, -3) ||
|
if (! lua_islightuserdata(ls, -3) ||
|
||||||
@@ -244,11 +290,48 @@ static std::list<std::string> get_lua_table_values(lua_State *ls, int idx)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_lua_table_list_values(lua_State *ls,
|
||||||
|
int idx,
|
||||||
|
std::map<std::string, std::list<std::string>> &required_plugin_versions)
|
||||||
|
{
|
||||||
|
if (lua_isnil(ls, idx)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushnil(ls); /* first key */
|
||||||
|
while (lua_next(ls, idx-1) != 0) {
|
||||||
|
// key is at index -2, table of values is at index -1.
|
||||||
|
if (! lua_isstring(ls, -2)) {
|
||||||
|
std::string err = "Non-string key in table of strings";
|
||||||
|
throw falco_exception(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key = string(lua_tostring(ls, -2));
|
||||||
|
std::list<std::string> vals = get_lua_table_values(ls, -1);
|
||||||
|
|
||||||
|
if (required_plugin_versions.find(key) == required_plugin_versions.end())
|
||||||
|
{
|
||||||
|
required_plugin_versions[key] = vals;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
required_plugin_versions[key].insert(required_plugin_versions[key].end(),
|
||||||
|
vals.begin(),
|
||||||
|
vals.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove value, keep key for next iteration
|
||||||
|
lua_pop(ls, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void falco_rules::load_rules(const string &rules_content,
|
void falco_rules::load_rules(const string &rules_content,
|
||||||
bool verbose, bool all_events,
|
bool verbose, bool all_events,
|
||||||
string &extra, bool replace_container_info,
|
string &extra, bool replace_container_info,
|
||||||
falco_common::priority_type min_priority,
|
falco_common::priority_type min_priority,
|
||||||
uint64_t &required_engine_version)
|
uint64_t &required_engine_version,
|
||||||
|
std::map<std::string, std::list<std::string>> &required_plugin_versions)
|
||||||
{
|
{
|
||||||
lua_getglobal(m_ls, m_lua_load_rules.c_str());
|
lua_getglobal(m_ls, m_lua_load_rules.c_str());
|
||||||
if(lua_isfunction(m_ls, -1))
|
if(lua_isfunction(m_ls, -1))
|
||||||
@@ -449,7 +532,7 @@ void falco_rules::load_rules(const string &rules_content,
|
|||||||
lua_pushstring(m_ls, extra.c_str());
|
lua_pushstring(m_ls, extra.c_str());
|
||||||
lua_pushboolean(m_ls, (replace_container_info ? 1 : 0));
|
lua_pushboolean(m_ls, (replace_container_info ? 1 : 0));
|
||||||
lua_pushnumber(m_ls, min_priority);
|
lua_pushnumber(m_ls, min_priority);
|
||||||
if(lua_pcall(m_ls, 9, 4, 0) != 0)
|
if(lua_pcall(m_ls, 9, 5, 0) != 0)
|
||||||
{
|
{
|
||||||
const char* lerr = lua_tostring(m_ls, -1);
|
const char* lerr = lua_tostring(m_ls, -1);
|
||||||
|
|
||||||
@@ -461,10 +544,12 @@ void falco_rules::load_rules(const string &rules_content,
|
|||||||
// Returns:
|
// Returns:
|
||||||
// Load result: bool
|
// Load result: bool
|
||||||
// required engine version: will be nil when load result is false
|
// required engine version: will be nil when load result is false
|
||||||
|
// required_engine_versions: will be nil when load result is false
|
||||||
// array of errors
|
// array of errors
|
||||||
// array of warnings
|
// array of warnings
|
||||||
bool successful = lua_toboolean(m_ls, -4);
|
bool successful = lua_toboolean(m_ls, -5);
|
||||||
required_engine_version = lua_tonumber(m_ls, -3);
|
required_engine_version = lua_tonumber(m_ls, -4);
|
||||||
|
get_lua_table_list_values(m_ls, -3, required_plugin_versions);
|
||||||
std::list<std::string> errors = get_lua_table_values(m_ls, -2);
|
std::list<std::string> errors = get_lua_table_values(m_ls, -2);
|
||||||
std::list<std::string> warnings = get_lua_table_values(m_ls, -1);
|
std::list<std::string> warnings = get_lua_table_values(m_ls, -1);
|
||||||
|
|
||||||
|
|||||||
@@ -39,13 +39,15 @@ class falco_rules
|
|||||||
void load_rules(const string &rules_content, bool verbose, bool all_events,
|
void load_rules(const string &rules_content, bool verbose, bool all_events,
|
||||||
std::string &extra, bool replace_container_info,
|
std::string &extra, bool replace_container_info,
|
||||||
falco_common::priority_type min_priority,
|
falco_common::priority_type min_priority,
|
||||||
uint64_t &required_engine_version);
|
uint64_t &required_engine_version,
|
||||||
|
std::map<std::string, std::list<std::string>> &required_plugin_versions);
|
||||||
void describe_rule(string *rule);
|
void describe_rule(string *rule);
|
||||||
|
|
||||||
static void init(lua_State *ls);
|
static void init(lua_State *ls);
|
||||||
static int clear_filters(lua_State *ls);
|
static int clear_filters(lua_State *ls);
|
||||||
static int add_filter(lua_State *ls);
|
static int add_filter(lua_State *ls);
|
||||||
static int add_k8s_audit_filter(lua_State *ls);
|
static int add_k8s_audit_filter(lua_State *ls);
|
||||||
|
static int add_plugin_filter(lua_State *ls);
|
||||||
static int enable_rule(lua_State *ls);
|
static int enable_rule(lua_State *ls);
|
||||||
static int engine_version(lua_State *ls);
|
static int engine_version(lua_State *ls);
|
||||||
|
|
||||||
@@ -53,6 +55,7 @@ class falco_rules
|
|||||||
void clear_filters();
|
void clear_filters();
|
||||||
void add_filter(string &rule, std::set<uint32_t> &evttypes, std::set<uint32_t> &syscalls, std::set<string> &tags);
|
void add_filter(string &rule, std::set<uint32_t> &evttypes, std::set<uint32_t> &syscalls, std::set<string> &tags);
|
||||||
void add_k8s_audit_filter(string &rule, std::set<string> &tags);
|
void add_k8s_audit_filter(string &rule, std::set<string> &tags);
|
||||||
|
void add_plugin_filter(string &rule, std::set<string> &tags, string &source);
|
||||||
void enable_rule(string &rule, bool enabled);
|
void enable_rule(string &rule, bool enabled);
|
||||||
|
|
||||||
lua_parser* m_sinsp_lua_parser;
|
lua_parser* m_sinsp_lua_parser;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ limitations under the License.
|
|||||||
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
|
||||||
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
|
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
|
||||||
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
|
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
|
||||||
|
#define FALCO_ENGINE_PLUGINS_DIR "${FALCO_ABSOLUTE_SHARE_DIR}/plugins/"
|
||||||
|
|
||||||
#define PROBE_NAME "@PROBE_NAME@"
|
#define PROBE_NAME "@PROBE_NAME@"
|
||||||
#define DRIVER_VERSION "@PROBE_VERSION@"
|
#define DRIVER_VERSION "@PROBE_VERSION@"
|
||||||
@@ -16,6 +16,9 @@ limitations under the License.
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -252,6 +255,36 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
|||||||
{
|
{
|
||||||
throw logic_error("Error reading config file(" + m_config_file + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
|
throw logic_error("Error reading config file(" + m_config_file + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::set<std::string> load_plugins;
|
||||||
|
|
||||||
|
YAML::Node load_plugins_node;
|
||||||
|
m_config->get_node(load_plugins_node, "load_plugins");
|
||||||
|
|
||||||
|
m_config->get_sequence<set<string>>(load_plugins, "load_plugins");
|
||||||
|
|
||||||
|
std::list<falco_configuration::plugin_config> plugins;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_config->get_sequence<std::list<falco_configuration::plugin_config>>(plugins, string("plugins"));
|
||||||
|
}
|
||||||
|
catch (exception &e)
|
||||||
|
{
|
||||||
|
// Might be thrown due to not being able to open files
|
||||||
|
throw logic_error("Error reading config file(" + m_config_file + "): could not load plugins config: " + e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If load_plugins was specified, only save plugins matching those in values
|
||||||
|
for (auto &p : plugins)
|
||||||
|
{
|
||||||
|
// If load_plugins was not specified at all, every
|
||||||
|
// plugin is added. Otherwise, the plugin must be in
|
||||||
|
// the load_plugins list.
|
||||||
|
if(!load_plugins_node.IsDefined() || load_plugins.find(p.m_name) != load_plugins.end())
|
||||||
|
{
|
||||||
|
m_plugins.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void falco_configuration::read_rules_file_directory(const string &path, list<string> &rules_filenames)
|
void falco_configuration::read_rules_file_directory(const string &path, list<string> &rules_filenames)
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ limitations under the License.
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "config_falco.h"
|
||||||
|
|
||||||
#include "event_drops.h"
|
#include "event_drops.h"
|
||||||
#include "falco_outputs.h"
|
#include "falco_outputs.h"
|
||||||
@@ -177,6 +180,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_node(YAML::Node &ret, const std::string &key)
|
||||||
|
{
|
||||||
|
ret = m_root[key];
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
YAML::Node m_root;
|
YAML::Node m_root;
|
||||||
};
|
};
|
||||||
@@ -184,6 +192,15 @@ private:
|
|||||||
class falco_configuration
|
class falco_configuration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
public:
|
||||||
|
std::string m_name;
|
||||||
|
std::string m_library_path;
|
||||||
|
std::string m_init_config;
|
||||||
|
std::string m_open_params;
|
||||||
|
} plugin_config;
|
||||||
|
|
||||||
falco_configuration();
|
falco_configuration();
|
||||||
virtual ~falco_configuration();
|
virtual ~falco_configuration();
|
||||||
|
|
||||||
@@ -229,6 +246,8 @@ public:
|
|||||||
|
|
||||||
uint32_t m_syscall_evt_timeout_max_consecutives;
|
uint32_t m_syscall_evt_timeout_max_consecutives;
|
||||||
|
|
||||||
|
std::vector<plugin_config> m_plugins;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init_cmdline_options(std::list<std::string>& cmdline_options);
|
void init_cmdline_options(std::list<std::string>& cmdline_options);
|
||||||
|
|
||||||
@@ -242,3 +261,102 @@ private:
|
|||||||
|
|
||||||
yaml_configuration* m_config;
|
yaml_configuration* m_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace YAML {
|
||||||
|
template<>
|
||||||
|
struct convert<falco_configuration::plugin_config> {
|
||||||
|
|
||||||
|
static bool read_file_from_key(const Node &node, const std::string &prefix, std::string &value)
|
||||||
|
{
|
||||||
|
std::string key = prefix;
|
||||||
|
|
||||||
|
if(node[key])
|
||||||
|
{
|
||||||
|
value = node[key].as<std::string>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
key += "_file";
|
||||||
|
|
||||||
|
if(node[key])
|
||||||
|
{
|
||||||
|
std::string path = node[key].as<std::string>();
|
||||||
|
|
||||||
|
// prepend share dir if path is not absolute
|
||||||
|
if(path.at(0) != '/')
|
||||||
|
{
|
||||||
|
path = string(FALCO_ENGINE_PLUGINS_DIR) + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intentionally letting potential
|
||||||
|
// exception be thrown, will get
|
||||||
|
// caught when reading config.
|
||||||
|
std::ifstream f(path);
|
||||||
|
std::string str((std::istreambuf_iterator<char>(f)),
|
||||||
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
value = str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that the distinction between
|
||||||
|
// init_config/init_config_file and
|
||||||
|
// open_params/open_params_file is lost. But also,
|
||||||
|
// this class doesn't write yaml config anyway.
|
||||||
|
static Node encode(const falco_configuration::plugin_config & rhs) {
|
||||||
|
Node node;
|
||||||
|
node["name"] = rhs.m_name;
|
||||||
|
node["library_path"] = rhs.m_library_path;
|
||||||
|
node["init_config"] = rhs.m_init_config;
|
||||||
|
node["open_params"] = rhs.m_open_params;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decode(const Node& node, falco_configuration::plugin_config & rhs) {
|
||||||
|
if(!node.IsMap())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!node["name"])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rhs.m_name = node["name"].as<std::string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!node["library_path"])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rhs.m_library_path = node["library_path"].as<std::string>();
|
||||||
|
|
||||||
|
// prepend share dir if path is not absolute
|
||||||
|
if(rhs.m_library_path.at(0) != '/')
|
||||||
|
{
|
||||||
|
rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!read_file_from_key(node, string("init_config"), rhs.m_init_config))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!read_file_from_key(node, string("open_params"), rhs.m_open_params))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ limitations under the License.
|
|||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
#include "grpc_server.h"
|
#include "grpc_server.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "plugin.h"
|
||||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||||
|
|
||||||
typedef function<void(sinsp* inspector)> open_t;
|
typedef function<void(sinsp* inspector)> open_t;
|
||||||
@@ -128,6 +129,7 @@ static void usage()
|
|||||||
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
||||||
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
|
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
|
||||||
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
|
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
|
||||||
|
" --list-plugins Print info on all loaded plugins and exit.\n"
|
||||||
#ifndef MINIMAL_BUILD
|
#ifndef MINIMAL_BUILD
|
||||||
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
|
||||||
" Enable Mesos support by connecting to the API server\n"
|
" Enable Mesos support by connecting to the API server\n"
|
||||||
@@ -478,6 +480,7 @@ int falco_init(int argc, char **argv)
|
|||||||
bool print_ignored_events = false;
|
bool print_ignored_events = false;
|
||||||
bool list_flds = false;
|
bool list_flds = false;
|
||||||
string list_flds_source = "";
|
string list_flds_source = "";
|
||||||
|
bool list_plugins = false;
|
||||||
bool print_support = false;
|
bool print_support = false;
|
||||||
string cri_socket_path;
|
string cri_socket_path;
|
||||||
bool cri_async = true;
|
bool cri_async = true;
|
||||||
@@ -518,6 +521,7 @@ int falco_init(int argc, char **argv)
|
|||||||
{"k8s-api-cert", required_argument, 0, 'K'},
|
{"k8s-api-cert", required_argument, 0, 'K'},
|
||||||
{"k8s-api", required_argument, 0, 'k'},
|
{"k8s-api", required_argument, 0, 'k'},
|
||||||
{"list", optional_argument, 0},
|
{"list", optional_argument, 0},
|
||||||
|
{"list-plugins", no_argument, 0},
|
||||||
{"mesos-api", required_argument, 0, 'm'},
|
{"mesos-api", required_argument, 0, 'm'},
|
||||||
{"option", required_argument, 0, 'o'},
|
{"option", required_argument, 0, 'o'},
|
||||||
{"pidfile", required_argument, 0, 'P'},
|
{"pidfile", required_argument, 0, 'P'},
|
||||||
@@ -701,6 +705,10 @@ int falco_init(int argc, char **argv)
|
|||||||
list_flds_source = optarg;
|
list_flds_source = optarg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (string(long_options[long_index].name) == "list-plugins")
|
||||||
|
{
|
||||||
|
list_plugins = true;
|
||||||
|
}
|
||||||
else if (string(long_options[long_index].name) == "stats-interval")
|
else if (string(long_options[long_index].name) == "stats-interval")
|
||||||
{
|
{
|
||||||
stats_interval = atoi(optarg);
|
stats_interval = atoi(optarg);
|
||||||
@@ -765,12 +773,6 @@ int falco_init(int argc, char **argv)
|
|||||||
engine->set_inspector(inspector);
|
engine->set_inspector(inspector);
|
||||||
engine->set_extra(output_format, replace_container_info);
|
engine->set_extra(output_format, replace_container_info);
|
||||||
|
|
||||||
if(list_flds)
|
|
||||||
{
|
|
||||||
list_source_fields(engine, verbose, names_only, list_flds_source);
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(disable_sources.size() > 0)
|
if(disable_sources.size() > 0)
|
||||||
{
|
{
|
||||||
auto it = disable_sources.begin();
|
auto it = disable_sources.begin();
|
||||||
@@ -865,6 +867,67 @@ int falco_init(int argc, char **argv)
|
|||||||
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<sinsp_plugin> input_plugin;
|
||||||
|
for(auto &p : config.m_plugins)
|
||||||
|
{
|
||||||
|
bool avoid_async = true;
|
||||||
|
|
||||||
|
falco_logger::log(LOG_INFO, "Loading plugin (" + p.m_name + ") from file " + p.m_library_path + "\n");
|
||||||
|
|
||||||
|
std::shared_ptr<sinsp_plugin> plugin = sinsp_plugin::register_plugin(inspector,
|
||||||
|
p.m_library_path,
|
||||||
|
(p.m_init_config.empty() ? NULL : (char *)p.m_init_config.c_str()),
|
||||||
|
avoid_async);
|
||||||
|
|
||||||
|
if(plugin->type() == TYPE_SOURCE_PLUGIN)
|
||||||
|
{
|
||||||
|
if(input_plugin)
|
||||||
|
{
|
||||||
|
throw std::invalid_argument(string("Can not load multiple source plugins. ") + input_plugin->name() + " already loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
inspector->set_input_plugin(p.m_name);
|
||||||
|
if(!p.m_open_params.empty())
|
||||||
|
{
|
||||||
|
inspector->set_input_plugin_open_params(p.m_open_params.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<sinsp_plugin::info> infos = sinsp_plugin::plugin_infos(inspector);
|
||||||
|
|
||||||
|
if(list_plugins)
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
|
||||||
|
for(auto &info : infos)
|
||||||
|
{
|
||||||
|
os << "Name: " << info.name << std::endl;
|
||||||
|
os << "Description: " << info.description << std::endl;
|
||||||
|
os << "Contact: " << info.contact << std::endl;
|
||||||
|
os << "Version: " << info.plugin_version.as_string() << std::endl;
|
||||||
|
|
||||||
|
if(info.type == TYPE_SOURCE_PLUGIN)
|
||||||
|
{
|
||||||
|
os << "Type: source plugin" << std::endl;
|
||||||
|
os << "ID: " << info.id << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << "Type: extractor plugin" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%lu Plugins Loaded:\n\n%s\n", infos.size(), os.str().c_str());
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(list_flds)
|
||||||
|
{
|
||||||
|
list_source_fields(engine, verbose, names_only, list_flds_source);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (rules_filenames.size())
|
if (rules_filenames.size())
|
||||||
{
|
{
|
||||||
config.m_rules_filenames = rules_filenames;
|
config.m_rules_filenames = rules_filenames;
|
||||||
@@ -905,6 +968,17 @@ int falco_init(int argc, char **argv)
|
|||||||
required_engine_versions[filename] = required_engine_version;
|
required_engine_versions[filename] = required_engine_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that all plugins are compatible with the loaded set of rules
|
||||||
|
for(auto &info : infos)
|
||||||
|
{
|
||||||
|
std::string required_version;
|
||||||
|
|
||||||
|
if(!engine->is_plugin_compatible(info.name, info.plugin_version.as_string(), required_version))
|
||||||
|
{
|
||||||
|
throw std::invalid_argument(std::string("Plugin ") + info.name + " version " + info.plugin_version.as_string() + " not compatible with required plugin version " + required_version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// You can't both disable and enable rules
|
// You can't both disable and enable rules
|
||||||
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
|
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
|
||||||
enabled_rule_tags.size() > 0) {
|
enabled_rule_tags.size() > 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user