-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
30 changed files
with
1,721 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
name: Lint | ||
|
||
on: | ||
push: | ||
tags: | ||
- v* | ||
branches: | ||
- main | ||
pull_request: | ||
|
||
jobs: | ||
golangci: | ||
name: lint | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: golangci-lint | ||
uses: golangci/golangci-lint-action@v2 | ||
with: | ||
version: v1.41.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Release | ||
on: | ||
push: | ||
# The idea here is to trigger a release upon receiving a release-like tag | ||
tags: | ||
- 'v[0-9]+.[0-9]+.[0-9]+' | ||
|
||
jobs: | ||
release: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout source code | ||
uses: actions/checkout@v2 | ||
- name: Install Go | ||
uses: actions/setup-go@v2 | ||
with: | ||
go-version: 1.16 | ||
- name: Unshallow | ||
run: git fetch --prune --unshallow | ||
- name: Create release | ||
uses: goreleaser/goreleaser-action@v2 | ||
with: | ||
version: latest | ||
args: release --rm-dist | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
name: Test | ||
|
||
on: [push, pull_request] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout source code | ||
uses: actions/checkout@v2 | ||
- name: Run tests | ||
run: make test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,2 @@ | ||
# Generated by Cargo | ||
# will have compiled files and executables | ||
/target/ | ||
|
||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries | ||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html | ||
Cargo.lock | ||
|
||
# These are backup files generated by rustfmt | ||
**/*.rs.bk | ||
bin/* | ||
.coverage.out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
linters: | ||
enable: | ||
- bodyclose | ||
- deadcode | ||
- depguard | ||
- dogsled | ||
- dupl | ||
- funlen | ||
- gochecknoinits | ||
- goconst | ||
- gocritic | ||
- gocyclo | ||
- gofmt | ||
- goimports | ||
- revive | ||
- goprintffuncname | ||
- gosec | ||
- gosimple | ||
- govet | ||
- ineffassign | ||
- misspell | ||
- nakedret | ||
- rowserrcheck | ||
- exportloopref | ||
- staticcheck | ||
- structcheck | ||
- stylecheck | ||
- typecheck | ||
- unconvert | ||
- unparam | ||
- unused | ||
- varcheck | ||
- whitespace | ||
disable: | ||
# Some errors are just logged when found, but not checked | ||
- errcheck | ||
issues: | ||
exclude-rules: | ||
- linters: | ||
- revive | ||
text: "don't use ALL_CAPS in Go names" | ||
- linters: | ||
- stylecheck | ||
text: "ST1003: should not use ALL_CAPS in Go names" | ||
# Exclude some linters from running on tests files. | ||
- path: _test\.go | ||
linters: | ||
- gocyclo | ||
- dupl | ||
- gosec | ||
- funlen | ||
linters-settings: | ||
funlen: | ||
lines: 100 | ||
statements: 40 | ||
misspell: | ||
locale: US |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
builds: | ||
- goos: | ||
- linux |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# The go toolchain version we want to use | ||
GOVERSION = 1.16.5 | ||
|
||
# Where we will install a modern go if none is available (note that this | ||
# variable can be overriden in the environment, if needed) | ||
INSTALL_PATH ?= $(HOME)/goroot | ||
|
||
# Go commands | ||
GOCMD = go | ||
GOFMT = gofmt -l | ||
GOBUILD = $(GOCMD) build | ||
GOTEST = $(GOCMD) test | ||
GOLINT = golangci-lint run | ||
|
||
PROJECT = github.com/juan-leon/fetter | ||
GOBIN = bin | ||
EXEC = bin/fetter | ||
|
||
export PATH := $(INSTALL_PATH)/go/bin:$(HOME)/bin:$(PATH) | ||
|
||
# PATH is not inherited by shells spawned by "shell" function | ||
go_version := $(shell PATH=$(PATH) go version 2>/dev/null) | ||
linter_version := $(shell PATH=$(PATH) golangci-lint --version 2>/dev/null) | ||
now := $(shell date +'%Y-%m-%dT%T') | ||
src := $(shell find -name '*.go') | ||
sha := $(shell git log -1 --pretty=%H 2>/dev/null || echo unknown) | ||
|
||
# Version can be overwritten via env var. If not present, we figure it out from | ||
# git. The "word 1" is an ultra paranoid protection against spaces in tag name: | ||
# those are not liked by the linker unless escaped. | ||
version ?= $(word 1, $(shell git describe --abbrev --tags 2>/dev/null || echo unknown)) | ||
|
||
define install_go | ||
@echo Installing Go $(GOVERSION) | ||
mkdir -p $(INSTALL_PATH) | ||
curl -s https://storage.googleapis.com/golang/go$(GOVERSION).linux-amd64.tar.gz | tar -C $(INSTALL_PATH) -xz | ||
@echo Done installing Go $(GOVERSION) | ||
endef | ||
|
||
define install_linter | ||
@echo Installing linter | ||
mkdir -p $(HOME)/bin | ||
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(HOME)/bin v1.41.1 | ||
@echo Done installing linter | ||
endef | ||
|
||
.PHONY: clean test toolchain linter lint | ||
|
||
|
||
build: $(EXEC) | ||
|
||
$(EXEC): $(src) | ||
$(GOBUILD) \ | ||
--ldflags "-X main.Commit=$(sha) -X main.BuildDate=$(now) -X main.Version=$(version)" \ | ||
-o $(EXEC) \ | ||
github.com/juan-leon/fetter | ||
|
||
clean: | ||
rm -f $(EXEC) | ||
|
||
# Format source code files | ||
fmt: toolchain | ||
$(GOFMT) -w . | ||
|
||
# Prints the source code files poorly formatted | ||
lint: | ||
@echo Linting code | ||
$(GOLINT) | ||
|
||
# Run tests | ||
test: | ||
$(GOTEST) -coverprofile=.coverage.out $(PROJECT)/... | ||
@echo Code coverage | ||
@go tool cover -func=.coverage.out | tail -n 1 | ||
@echo "Use 'go tool cover -html=.coverage.out' to inspect results" | ||
|
||
# Make sure we have go installed, or install it otherwise | ||
toolchain: | ||
ifeq (, $(findstring $(GOVERSION), $(go_version))) | ||
$(call install_go) | ||
endif | ||
|
||
# Make sure we have go 1.24 installed, or install it otherwise | ||
linter: toolchain | ||
ifeq (, $(findstring 1.41, $(linter_version))) | ||
$(call install_linter) | ||
endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,14 @@ | ||
# fetter | ||
|
||
Move processes into control groups based on configurable actions | ||
|
||
[![Test status](https://github.com/juan-leon/fetter/actions/workflows/test.yml/badge.svg)](https://github.com/juan-leon/fetter/actions/fetter/test.yml) | ||
[![Lint status](https://github.com/juan-leon/fetter/actions/workflows/lint.yaml/badge.svg)](https://github.com/juan-leon/fetter/actions/fetter/lint.yaml) | ||
[![Release](https://img.shields.io/github/release/juan-leon/fetter.svg)](https://github.com/juan-leon/fetter/releases/latest) | ||
|
||
## TODO | ||
|
||
Write documentation. | ||
|
||
In the meanwhile, this example of configuration will give you a hint of what the | ||
tool can be used for: [![Sample configuration file](examples/documented-example.yaml)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
* TODO tests | ||
* TODO unit tests | ||
* TODO docs | ||
* TODO badges | ||
* TODO CI pipeline (release, coverage) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
--- | ||
# Two basic modes are supported: audit and scanner. | ||
# | ||
# Audit mode is recommended: it sets audit rules to the kernel and keep a | ||
# netlink connection open so that as soon as a rule is matched the process can | ||
# be moved to a control group. This mode supports detection of running | ||
# applications by path, writing or reading specific files (or directories). | ||
# This mode consumes few resources, since program is just listening. | ||
# | ||
# Scanner mode only works for 'execute' actions. The running processes will be | ||
# scanned every second, and matches, if any, will be distributed on groups. | ||
# Scanning is more expensive than listening to a netlink socket. This mode is | ||
# recommended for those scenarios where audit rules are locked by administrator | ||
# (once locked, they cannot be unlocked without rebooting the machine), or the | ||
# Linux kernel is ancient and does not support multicast for Netlink | ||
# | ||
# Default is audit | ||
mode: audit | ||
audit: | ||
# There are three audit modes (meaningless in scanner mode) that dictates how | ||
# to setup the audit rules in the kernel: override, preserve and reuse | ||
# | ||
# * When override is used, program will delete any existing rules and leave | ||
# only the ones configured | ||
# | ||
# * When preserve is used, program will add its rules over whatever rule | ||
# already configured. This is useful for coexisting with auditd. However, | ||
# if a lot of rule rewriting rules is done, old rules are not removed. and | ||
# that can lead to surprises. | ||
# | ||
# * When reuse is used, no rules will be set up. The use case if for those | ||
# scenarios where you want to configure the rules in separate runs of this | ||
# program (on run to configure rules, other to run as daemon) | ||
mode: override | ||
|
||
logging: | ||
# File name where logs will be written | ||
file: /tmp/fetter.log | ||
# Standard error levels available. Debug shows interesting info and it is not | ||
# too verbose. | ||
level: info | ||
|
||
# This is the name of the cgroup path used by application (all cgroups created | ||
# by this program will belong to it). Default is 'fetter'; there is no reason | ||
# to change it other than doing experiments or using several fetter applications | ||
# in parallel. | ||
name: fetter | ||
|
||
# These are the rules. By default there is none; the ones below are just | ||
# examples. | ||
rules: | ||
# Following rule will use a cgroup named browser for firefox. Notice that you | ||
# need to know the name of the firefox executable (if in doubt, you can figure | ||
# it out by doing `ls -l /proc/PID/exe` to know the path, and 'ps -u | grep | ||
# firefox' to know the PID) | ||
- path: /usr/lib/firefox/firefox | ||
# Supported actions are execute (the most useful one: the process executing | ||
# a file will be moved to a control group), read, and write. | ||
action: execute | ||
# Name of the group should match one of the groups defined in their section. | ||
group: browsers | ||
|
||
# You can make several applications to share same cgroup, if you want. That | ||
# way, the limits for that cgroup apply to both at once | ||
- path: /usr/lib/chromium-browser/chromium-browser | ||
action: execute | ||
group: browsers | ||
|
||
- path: /usr/bin/emacs | ||
action: execute | ||
group: ides | ||
|
||
- path: /my/forbidden/file | ||
action: write | ||
# KILL is not a real cgroup, but a way to say fetter: kill whatever process | ||
# doing that action. In this case, whenever a process writes to the file in | ||
# path, process will be killed | ||
group: KILL | ||
|
||
# This is an example where a process reading a file will be frozen in place by | ||
# the operating system (group honeypot has "freeze: true"). Process execution | ||
# will not continue, and it cannot be killed unless removed from cgroup, or | ||
# cgroup is manually thawed. This will allow you to detect what processes | ||
# read/write to a file and examine them. | ||
- path: /my/forbidden/file | ||
action: read | ||
group: honeypot | ||
|
||
|
||
# These control groups will be created by the application, with the limits | ||
# specified for any of them. By default there is none; the ones below are just | ||
# examples. | ||
# | ||
# Note that while it is safe to cap CPU to any application, capping pids and or | ||
# RAM might make those applications malfunction. That would depend on how the | ||
# applications manage error codes of operations that are denied by operating | ||
# system. Those operations would be the ones related to asking more RAM we | ||
# allow them to use, or trying to spawn more children. Think of a browser that | ||
# uses a process-per-tab approach: if we cap processes to 20, the tab 21st would | ||
# fail to display correctly | ||
groups: | ||
- name: browsers | ||
# Max RAM, in Mbs, that all the processes in the group together can use. | ||
ram: 2000 | ||
# Max number of processes that can be spawned simultaneously by processes in | ||
# the group. A process spawned by a process of a group will remain in the | ||
# group. | ||
pids: 30 | ||
# Max single-CPU %-age that processes in the group will be able to use. For | ||
# instance, if you want to make sure your massively heavy parallel local | ||
# compilations do not make your UI unusable, you can create a group for | ||
# 'make' with a CPU limit. Note that if you have N CPUs, you might want to | ||
# use values higher than 100. For instance, in a machine with 8 CPUs | ||
# meaningful values are those between 0 (no juice) and 800 (no limit). A | ||
# value of 400 would mean half of the CPU power would be available for other | ||
# tasks. | ||
cpu: 250 | ||
# Default is false. true means that the group is a freezer: processes | ||
# cannot continue execution or be killed by their owners (unless they are | ||
# root and familiar with the freeze subsystem). Use of this feature is to | ||
# allow to detect and examine processes that do some action. Use with | ||
# caution. | ||
freeze: false | ||
# Default is false. true means that instead of moving the process to a | ||
# cgroup the process will be killed. It is a way of making sure (or | ||
# enforcing) some actions are never done. Use with caution. | ||
kill: false | ||
|
||
- name: ides | ||
ram: 1000 | ||
pids: 50 | ||
cpu: 80 | ||
|
||
- name: email | ||
ram: 2000 | ||
pids: 5 | ||
cpu: 50 | ||
|
||
- name: music | ||
ram: 500 | ||
pids: 5 | ||
cpu: 80 | ||
|
||
# This example has unlimited ram, as it is not specified | ||
- name: shell | ||
cpu: 95 | ||
pids: 100 | ||
|
||
# Example of a group to freeze processes | ||
- name: honeypot | ||
freeze: true |
Oops, something went wrong.