Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add k8smeta plugin to the plugin repo #378

Merged
merged 6 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/k8smeta-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Build K8smeta plugin
on:
pull_request:
branches: [ master ]
paths:
- 'plugins/k8smeta/**'
push:
branches: [ master ]
paths:
- 'plugins/k8smeta/**'
workflow_dispatch:

# Checks if any concurrent jobs under the same pull request or branch are being executed
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
build-and-test:
name: build-and-test
runs-on: ubuntu-22.04
steps:
- name: Checkout ⤵️
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
fetch-depth: 0

- name: Setup Go
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
with:
go-version: '1.21'
check-latest: true

- name: Install deps ⛓️
run: |
sudo apt update -y
sudo apt install -y --no-install-recommends cmake build-essential autoconf libtool pkg-config

- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: cpp

- name: Build k8s meta plugin 🏗️
run: |
cd plugins/k8smeta
mkdir build
cd build && cmake -DCMAKE_BUILD_TYPE=Release ../
make k8smeta -j6

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2

- name: Build and run tests 🏎️
run: |
cd plugins/k8smeta/build
make build-server
make build-tests
make run-server &
make run-tests

formatting-check:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1

- name: Run clang-format style check
uses: jidicula/clang-format-action@f62da5e3d3a2d88ff364771d9d938773a618ab5e #v4.11.0
with:
clang-format-version: '14'
check-path: plugins/k8smeta
12 changes: 10 additions & 2 deletions .github/workflows/reusable_build_packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,16 @@ jobs:
- name: Install deps
run: |
apt update
apt install -y --no-install-recommends git awscli

apt install -y --no-install-recommends git awscli make build-essential autoconf libtool pkg-config

- name: Install updated cmake version ⛓️
run: |
curl -L -o /tmp/cmake.tar.gz https://github.com/Kitware/CMake/releases/download/v3.22.5/cmake-3.22.5-linux-$(uname -m).tar.gz
gzip -d /tmp/cmake.tar.gz
tar -xpf /tmp/cmake.tar --directory=/tmp
cp -R /tmp/cmake-3.22.5-linux-$(uname -m)/* /usr
rm -rf /tmp/cmake-3.22.5-linux-$(uname -m)

- name: Checkout Plugins ⤵️
uses: actions/checkout@v3
with:
Expand Down
6 changes: 6 additions & 0 deletions plugins/k8smeta/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.so
*.a
*.o
.vscode
build*
libk8smeta.so
72 changes: 72 additions & 0 deletions plugins/k8smeta/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
cmake_minimum_required(VERSION 3.22)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")

option(BUILD_TESTS "Enable test" ON)

# project metadata
project(
k8smeta
VERSION 0.1.0
DESCRIPTION "Falco Kubernetes enrichment Plugin"
LANGUAGES CXX)

# dependencies
include(FetchContent)
include(grpc)
include(spdlog)
include(plugin-sdk-cpp)
include(k8s-metacollector)

set(PROTO_PATH "${K8S_METACOLLECTOR_DIR}/metadata/metadata.proto")

get_filename_component(meta_proto "${PROTO_PATH}" ABSOLUTE)
get_filename_component(meta_proto_path "${meta_proto}" PATH)

# Generated sources
set(PROTO_GENERATED_INCLUDE "${CMAKE_BINARY_DIR}/generated")
if(NOT EXISTS "${PROTO_GENERATED_INCLUDE}")
file(MAKE_DIRECTORY "${PROTO_GENERATED_INCLUDE}")
endif()

set(meta_proto_srcs "${PROTO_GENERATED_INCLUDE}/metadata.pb.cc")
set(meta_proto_hdrs "${PROTO_GENERATED_INCLUDE}/metadata.pb.h")
set(meta_grpc_srcs "${PROTO_GENERATED_INCLUDE}/metadata.grpc.pb.cc")
set(meta_grpc_hdrs "${PROTO_GENERATED_INCLUDE}/metadata.grpc.pb.h")
add_custom_command(
OUTPUT "${meta_proto_srcs}" "${meta_proto_hdrs}" "${meta_grpc_srcs}"
"${meta_grpc_hdrs}"
COMMAND
${_PROTOBUF_PROTOC} ARGS --grpc_out "${PROTO_GENERATED_INCLUDE}" --cpp_out
"${PROTO_GENERATED_INCLUDE}" -I "${meta_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" "${meta_proto}"
DEPENDS "${meta_proto}")

# project target
file(GLOB_RECURSE K8S_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(k8smeta SHARED ${K8S_SOURCES} ${meta_grpc_srcs} ${meta_grpc_hdrs}
${meta_proto_srcs} ${meta_proto_hdrs})
set_target_properties(k8smeta PROPERTIES CXX_EXTENSIONS OFF)

# project compilation options
target_compile_options(k8smeta PRIVATE "-fPIC")
target_compile_options(k8smeta PRIVATE "-Wl,-z,relro,-z,now")
target_compile_options(k8smeta PRIVATE "-fstack-protector-strong")
# When compiling in Debug mode, this will define the DEBUG symbol for use in
# your code.
target_compile_options(k8smeta PUBLIC "$<$<CONFIG:DEBUG>:-DDEBUG>")
target_compile_features(k8smeta PUBLIC cxx_std_17)

# project includes
target_include_directories(
k8smeta PRIVATE "${PLUGIN_SDK_INLCUDE}" "${PROTO_GENERATED_INCLUDE}"
"${SPDLOG_INLCUDE}")

# project linked libraries
target_link_libraries(k8smeta ${_REFLECTION} ${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF} re2::re2)

# Testing
if(BUILD_TESTS)
add_subdirectory(test)
endif()
29 changes: 29 additions & 0 deletions plugins/k8smeta/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: Apache-2.0
#
# Copyright (C) 2023 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.
#


NAME := k8smeta
OUTPUT := lib$(NAME).so

all: $(OUTPUT)

clean:
rm -rf build $(OUTPUT)

# This Makefile requies CMake installed on the system
$(OUTPUT):
mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release ../ && make k8smeta -j6 && cp ./$(OUTPUT) ../$(OUTPUT)

readme:
@$(READMETOOL) -p ./$(OUTPUT) -f README.md
91 changes: 91 additions & 0 deletions plugins/k8smeta/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Kubernetes Audit Events Plugin

## Introduction

This plugin enriches Falco syscall flow with Kubernetes Metadata coming from the API server.
The plugin uses a GRPC channel to communicate with a remote [collector](https://github.com/falcosecurity/k8s-metacollector). The collector is indipendent from the plugin and should be deployed as a separate component. The main role of the plugin is to associate each syscall with information about the pod in which they are thrown.

### Functionality

TODO

## Capabilities

The `k8smeta` plugin implements these capabilities:
* `extraction`
* `parsing`
* `async`

### Supported Fields

<!-- README-PLUGIN-FIELDS -->
| NAME | TYPE | ARG | DESCRIPTION |
|-----------------------------|-----------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `k8smeta.pod.name` | `string` | None | Kubernetes pod name. |
| `k8smeta.pod.uid` | `string` | None | Kubernetes pod UID. |
| `k8smeta.pod.label` | `string` | Key, Required | Kubernetes pod label. E.g. 'k8smeta.pod.label[foo]'. |
| `k8smeta.pod.labels` | `string (list)` | None | Kubernetes pod comma-separated key/value labels. E.g. '(foo1:bar1,foo2:bar2)'. |
| `k8smeta.pod.ip` | `string` | None | Kubernetes pod ip |
| `k8smeta.ns.name` | `string` | None | Kubernetes namespace name. |
| `k8smeta.ns.uid` | `string` | None | Kubernetes namespace UID. |
| `k8smeta.ns.label` | `string` | Key, Required | Kubernetes namespace label. E.g. 'k8smeta.ns.label[foo]'. |
| `k8smeta.ns.labels` | `string (list)` | None | Kubernetes namespace comma-separated key/value labels. E.g. '(foo1:bar1,foo2:bar2)'. |
| `k8smeta.deployment.name` | `string` | None | Kubernetes deployment name. |
| `k8smeta.deployment.uid` | `string` | None | Kubernetes deployment UID. |
| `k8smeta.deployment.label` | `string` | Key, Required | Kubernetes deployment label. E.g. 'k8smeta.rs.label[foo]'. |
| `k8smeta.deployment.labels` | `string (list)` | None | Kubernetes deployment comma-separated key/value labels. E.g. '(foo1:bar1,foo2:bar2)'. |
| `k8smeta.svc.name` | `string (list)` | None | Kubernetes services name. Return a list with all the names of the services associated with the current pod. E.g. '(service1,service2)' |
| `k8smeta.svc.uid` | `string (list)` | None | Kubernetes services UID. Return a list with all the UIDs of the services associated with the current pod. E.g. '(88279776-941c-491e-8da1-95ef30f50fe8,149e72f4-a570-4282-bfa0-25307c5007e8)' |
| `k8smeta.svc.label` | `string (list)` | Key, Required | Kubernetes services label. If the services associated with the current pod have a label with this name, return the list of label's values. E.g. if the current pod has 2 services associated and both have the 'foo' label, 'k8smeta.svc.label[foo]' will return '(service1-label-value,service2-label-value) |
| `k8smeta.svc.labels` | `string (list)` | None | Kubernetes services labels. Return a list with all the comma-separated key/value labels of the services associated with the current pod. E.g. '(foo1:bar1,foo2:bar2)' |
| `k8smeta.rs.name` | `string` | None | Kubernetes replica set name. |
| `k8smeta.rs.uid` | `string` | None | Kubernetes replica set UID. |
| `k8smeta.rs.label` | `string` | Key, Required | Kubernetes replica set label. E.g. 'k8smeta.rs.label[foo]'. |
| `k8smeta.rs.labels` | `string (list)` | None | Kubernetes replica set comma-separated key/value labels. E.g. '(foo1:bar1,foo2:bar2)'. |
| `k8smeta.rc.name` | `string` | None | Kubernetes replication controller name. |
| `k8smeta.rc.uid` | `string` | None | Kubernetes replication controller UID. |
| `k8smeta.rc.label` | `string` | Key, Required | Kubernetes replication controller label. E.g. 'k8smeta.rc.label[foo]'. |
| `k8smeta.rc.labels` | `string (list)` | None | Kubernetes replication controller comma-separated key/value labels. E.g. '(foo1:bar1,foo2:bar2)'. |
<!-- /README-PLUGIN-FIELDS -->

## Usage

### Configuration

Here's an example of configuration of `falco.yaml`:

```yaml
load_plugins: [k8smeta]

plugins:
- name: k8smeta
library_path: libk8smeta.so
init_config:
collectorPort: 45000
collectorHostname: localhost
nodename: kind-control-plane
```

**Initialization Config**:

TODO

**Open Parameters**:

The plugin doesn't have open params

### Rule Example

To see how to use the plugin fields in a Falco rule check the example rule `/k8smeta/test/rules/example_rule.yaml`.

### Build the plugin on a fresh Ubuntu 22.04 machine

```bash
sudo apt update -y
sudo apt install -y cmake build-essential autoconf libtool pkg-config
git clone https://github.com/falcosecurity/plugins.git
cd plugins/k8smeta
mkdir build && cd build
cmake ..
make k8smeta -j10
```
35 changes: 35 additions & 0 deletions plugins/k8smeta/cmake/modules/grpc.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This cmake module is adapted from the grpc repo:
# `examples/cpp/cmake/common.cmake`

message(STATUS "Fetching grpc at 'https://github.com/grpc/grpc'")

find_package(Threads REQUIRED)

# See:
# https://github.com/protocolbuffers/protobuf/issues/12185#issuecomment-1594685860
set(ABSL_ENABLE_INSTALL ON)

# To solve:
#
# CMake Warning at build/_deps/grpc-src/third_party/abseil-cpp/CMakeLists.txt:77
# (message): A future Abseil release will default ABSL_PROPAGATE_CXX_STD to ON
# for CMake 3.8 and up. We recommend enabling this option to ensure your
# project still builds correctly
set(ABSL_PROPAGATE_CXX_STD ON)

FetchContent_Declare(
gRPC
GIT_REPOSITORY https://github.com/grpc/grpc
GIT_TAG v1.44.0
GIT_PROGRESS TRUE)

set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(gRPC)

set(_PROTOBUF_LIBPROTOBUF libprotobuf)
set(_REFLECTION grpc++_reflection)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protoc>)
set(_GRPC_GRPCPP grpc++)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:grpc_cpp_plugin>)

message(STATUS "Using grpc at '${gRPC_SOURCE_DIR}'")
14 changes: 14 additions & 0 deletions plugins/k8smeta/cmake/modules/k8s-metacollector.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
message(
STATUS
"Fetching k8s-metacollector at 'https://github.com/falcosecurity/k8s-metacollector.git'"
)

# Download a non cmake project
FetchContent_Declare(
k8s-metacollector
GIT_REPOSITORY https://github.com/falcosecurity/k8s-metacollector.git
GIT_TAG 982c40ac128cc94557b98d81210cbb13e7825129
CONFIGURE_COMMAND "" BUILD_COMMAND "")

FetchContent_Populate(k8s-metacollector)
set(K8S_METACOLLECTOR_DIR "${k8s-metacollector_SOURCE_DIR}")
11 changes: 11 additions & 0 deletions plugins/k8smeta/cmake/modules/libs.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
message(STATUS "Fetching libs at 'https://github.com/falcosecurity/libs.git'")

# Just populate it we don't want to build it
FetchContent_Declare(
libs
GIT_REPOSITORY https://github.com/falcosecurity/libs.git
GIT_TAG 8fee2fb4791d50ec5ee4808e5ed235c8b1b309f3
CONFIGURE_COMMAND "" BUILD_COMMAND "")

FetchContent_Populate(libs)
set(LIBS_DIR "${libs_SOURCE_DIR}")
Loading
Loading