From f9844825553965620a844fe148f25f710bc8ae3a Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 12:56:24 +0200 Subject: [PATCH 01/12] ignore bin and github secrets --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1508fd5..2e499a7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ *.so *.dylib +.go/ + # Docker image files *.tar.gz *.tar.xz @@ -23,4 +25,7 @@ .errors/ # Go tests -coverage.out \ No newline at end of file +coverage.out + +# Secret env vars +config/secrets From f01b454cb43fdb6bc98c103c6d814a5fe466ce7c Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 12:56:51 +0200 Subject: [PATCH 02/12] reduce standard ticker time --- cr.yaml | 4 ++-- ct.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cr.yaml b/cr.yaml index 43f404c..0d63514 100644 --- a/cr.yaml +++ b/cr.yaml @@ -5,8 +5,8 @@ chart-dirs: - ./charts chart-repos: - kapparmor=https://tuxerrante.github.io/kapparmor/ -helm-extra-args: --timeout 600s +helm-extra-args: --timeout 60s validate-maintainers: true generate-release-notes: true make-release-latest: false -release-notes-file: CHANGELOG.md \ No newline at end of file +release-notes-file: CHANGELOG.md diff --git a/ct.yaml b/ct.yaml index 7c8e870..27dcc85 100644 --- a/ct.yaml +++ b/ct.yaml @@ -3,5 +3,5 @@ chart-dirs: - ./charts chart-repos: - kapparmor=https://tuxerrante.github.io/kapparmor/ -helm-extra-args: --timeout 600s +helm-extra-args: --timeout 60s validate-maintainers: true From b6cfb9168cf2f181eb53411228718753427e4cf1 Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 13:01:21 +0200 Subject: [PATCH 03/12] todo list --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4875656..3727ce9 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,10 @@ helm upgrade kapparmor --install --atomic --timeout 120s --debug --set image.tag - Not a limitation relative to this project, but if you deny write access in the /bin folder of a privileged container it could not be deleted by Kubernetes even after 'kubectl delete'. The command will succeed but the pod will stay in Terminating state. ## ToDo: -- Intercept Term signal and uninstall profiles before the Helm chart deletion completes. -- Implement the [controller-runtime](https://pkg.go.dev/sigs.k8s.io/controller-runtime#section-readme) design pattern through [Kubebuilder](https://book.kubebuilder.io/quick-start.html). - +- 🌱 Intercept Term signal and uninstall profiles before the Helm chart deletion completes. +- ⚠️ Implement the [controller-runtime](https://pkg.go.dev/sigs.k8s.io/controller-runtime#section-readme) design pattern through [Kubebuilder](https://book.kubebuilder.io/quick-start.html). +- 😁 Find funnier quotes for app starting and ending message (David Zucker, Monty Python, Woody Allen...). +- 🌱 Make the ticker loop thread safe: skip running a new loop if previous run is still ongoing. ## Testing [There is a whole project meant to be a demo for this one](https://github.com/tuxerrante/kapparmor-demo), have fun. From 354ee4280d364057542b67df26dc75f96273b85c Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 13:02:18 +0200 Subject: [PATCH 04/12] update to go 1.20 --- .github/workflows/build-app.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-app.yml b/.github/workflows/build-app.yml index 706f90f..79a4472 100644 --- a/.github/workflows/build-app.yml +++ b/.github/workflows/build-app.yml @@ -15,7 +15,7 @@ on: workflow_dispatch: env: - GO_VERSION: '1.19' + GO_VERSION: '1.20' REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e52c6193db182a53852b1d64a325643b16a23f6b Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 13:02:51 +0200 Subject: [PATCH 05/12] 0.1.3 version --- charts/kapparmor/Chart.yaml | 4 ++-- config/config | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 config/config diff --git a/charts/kapparmor/Chart.yaml b/charts/kapparmor/Chart.yaml index b884942..c1ae23b 100644 --- a/charts/kapparmor/Chart.yaml +++ b/charts/kapparmor/Chart.yaml @@ -5,8 +5,8 @@ type: application home: https://artifacthub.io kubeVersion: ">= 1.23.0-0" -version: "0.1.2" -appVersion: "0.1.2" +version: "0.1.3" +appVersion: "0.1.3" keywords: - kubernetes diff --git a/config/config b/config/config new file mode 100644 index 0000000..2a18a9a --- /dev/null +++ b/config/config @@ -0,0 +1 @@ +APP_VERSION=0.1.3 From fbfbe26f6f6ecf6d40e1bb569a91c1457edd4ab3 Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 13:03:10 +0200 Subject: [PATCH 06/12] local build and deploy CI --- build/build-and-deploy.sh | 34 ++++++++++++++++++++++++++++++++++ build/build-app.sh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 build/build-and-deploy.sh create mode 100644 build/build-app.sh diff --git a/build/build-and-deploy.sh b/build/build-and-deploy.sh new file mode 100644 index 0000000..39bef0f --- /dev/null +++ b/build/build-and-deploy.sh @@ -0,0 +1,34 @@ +#!/bin/bash +set -e + +. ./build/build-app.sh +. ./config/secrets + +echo $GHCR_TOKEN | docker login -u "$(git config user.email)" --password-stdin ghcr.io +docker push ghcr.io/tuxerrante/kapparmor:${APP_VERSION}_dev + +# Install the chart from the local directory + helm upgrade kapparmor --install \ + --atomic \ + --timeout 60s \ + --debug \ + --set image.tag=${APP_VERSION}_dev \ + --set image.pullPolicy=Always \ + --dry-run \ + charts/kapparmor +echo +echo "> Is the previous result the expected one?" +echo "> Current K8S context:" "$(kubectl config current-context)" +read -r -p "> Are you sure? [Y/n] " response +if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then + helm upgrade kapparmor --install \ + --atomic \ + --timeout 60s \ + --debug \ + --set image.tag=${APP_VERSION}_dev \ + --set image.pullPolicy=Always \ + charts/kapparmor +else + echo " Bye." + echo +fi diff --git a/build/build-app.sh b/build/build-app.sh new file mode 100644 index 0000000..200885e --- /dev/null +++ b/build/build-app.sh @@ -0,0 +1,30 @@ +#!/bin/bash +source ./config/config + +# Clean old images +echo "> Removing old and dangling old images..." +docker rmi "$(docker images --filter "reference=ghcr.io/tuxerrante/kapparmor" -q --no-trunc )" + +# go build -o ./.go/bin ./... +# go test -v -coverprofile=coverage.out -covermode=atomic ./go/src/app/... +if [[ ! -f ".go/bin/golangci-lint" ]]; then + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b ./.go/bin +fi +echo "> Linting..." +./.go/bin/golangci-lint run + +echo "> Scanning for suspicious constructs..." +go vet go/... + +echo "> Creating test output..." +docker build --target test-coverage --tag "ghcr.io/tuxerrante/kapparmor:${APP_VERSION}_dev" . + +#### To run it look into docs/testing.md +echo "> Building container image..." +docker build --tag "ghcr.io/tuxerrante/kapparmor:${APP_VERSION}_dev" \ + --no-cache \ + --build-arg POLL_TIME=60 --build-arg PROFILES_DIR=/app/profiles \ + -f Dockerfile \ + . + +# docker run --rm -it --privileged --mount type=bind,source='/sys/kernel/security',target='/sys/kernel/security' --mount type=bind,source='/etc',target='/etc' --name kapparmor ghcr.io/tuxerrante/kapparmor:${APP_VERSION}_dev From 02e9fd6edeb8e5e94611b91085901285e1676419 Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Thu, 4 May 2023 13:04:20 +0200 Subject: [PATCH 07/12] Feature: Check for SIGTERM and SIGINIT signals in order to clean profiles before pods deletion. --- Dockerfile | 86 ++++++++++++++++++++++---------------------- azure-pipelines.yml | 0 go/src/app/main.go | 87 +++++++++++++++++++++++++++++++++++++-------- 3 files changed, 115 insertions(+), 58 deletions(-) delete mode 100644 azure-pipelines.yml diff --git a/Dockerfile b/Dockerfile index 336d852..1ec05d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,44 +1,44 @@ -# --- build stage -FROM golang:1.20 AS builder - -WORKDIR /builder/app -COPY go/src/app/ . -COPY go/src/tests/ /builder/tests/ -COPY go.mod . - -RUN go get -d -v . &&\ - go build -v -o /go/bin/app . - -RUN go test -v -coverprofile=coverage.out -covermode=atomic -# go tool cover -func=coverage.out - - -# --- Publish test coverage results -FROM scratch as test-coverage -COPY --from=builder /builder/app/coverage.out . - - -# --- Production image -FROM ubuntu:latest -LABEL Name=kapparmor -LABEL Author="Affinito Alessandro" - -WORKDIR /app - -RUN apt-get update &&\ - apt-get upgrade -y &&\ - apt-get install --no-install-recommends --yes apparmor apparmor-utils &&\ - rm -rf /var/lib/apt/lists/* &&\ - mkdir --parent --verbose /etc/apparmor.d/custom - -COPY --from=builder /go/bin/app /app/ -COPY ./charts/kapparmor/profiles /app/profiles/ - -ARG PROFILES_DIR -ARG POLL_TIME - -ENV PROFILES_DIR=$PROFILES_DIR -ENV POLL_TIME=$POLL_TIME - -USER root +# --- build stage +FROM golang:1.20 AS builder + +WORKDIR /builder/app +COPY go/src/app/ . +COPY go/src/tests/ /builder/tests/ +COPY go.mod . + +RUN go get -d -v . &&\ + go build -v -o /go/bin/app . + +RUN go test -v -coverprofile=coverage.out -covermode=atomic ./... +# go tool cover -func=coverage.out + + +# --- Publish test coverage results +FROM scratch as test-coverage +COPY --from=builder /builder/app/coverage.out . + + +# --- Production image +FROM ubuntu:latest +LABEL Name=kapparmor +LABEL Author="Affinito Alessandro" + +WORKDIR /app + +RUN apt-get update &&\ + apt-get upgrade -y &&\ + apt-get install --no-install-recommends --yes apparmor apparmor-utils &&\ + rm -rf /var/lib/apt/lists/* &&\ + mkdir --parent --verbose /etc/apparmor.d/custom + +COPY --from=builder /go/bin/app /app/ +COPY ./charts/kapparmor/profiles /app/profiles/ + +ARG PROFILES_DIR +ARG POLL_TIME + +ENV PROFILES_DIR=$PROFILES_DIR +ENV POLL_TIME=$POLL_TIME + +USER root CMD ./app \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index e69de29..0000000 diff --git a/go/src/app/main.go b/go/src/app/main.go index 1697ada..22cd7b3 100644 --- a/go/src/app/main.go +++ b/go/src/app/main.go @@ -3,13 +3,16 @@ package main import ( "bufio" "bytes" + "context" "fmt" "log" "os" "os/exec" + "os/signal" "path" "sort" "strings" + "syscall" "time" ) @@ -30,16 +33,39 @@ func main() { POLL_TIME = preFlightChecks() + keepItRunning := make(chan struct{}) + ctx, cancel := context.WithCancel(context.Background()) + + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) + log.Printf("> Polling directory %s every %d seconds.\n", CONFIGMAP_PATH, POLL_TIME) + go pollProfiles(POLL_TIME, ctx, keepItRunning) - pollProfiles(POLL_TIME) -} + // Manage OS signals for graceful shutdown + go func() { + <-signals + log.Print("> Received stop signal, terminating..") + + // Stop polling new profiles + cancel() -// Profiles will probably change content while keeping the same name, so a digest comparison -// can be useful if we don't want to load everything every time. -func pollProfiles(delay int) { + // Delete all loaded profiles + err := unloadAllProfiles() + checkFatal(err) + + log.Print("> The Eagle has landed.") + }() + + <-keepItRunning +} - ticker := time.NewTicker(time.Duration(delay) * time.Second) +// Every pollTime seconds it will read the mounted volume for profiles, +// it will call loadNewProfiles() then to check if they are new ones or not. +// Executed as go-routine it will run forever until a cancel() is called on the given context. +func pollProfiles(pollTime int, ctx context.Context, keepItRunning chan struct{}) { + log.Print("> Polling started.") + ticker := time.NewTicker(time.Duration(pollTime) * time.Second) pollNow := func() { newProfiles, err := loadNewProfiles() if err != nil { @@ -47,10 +73,16 @@ func pollProfiles(delay int) { } } - pollNow() - - for range ticker.C { - pollNow() + for { + select { + case <-ctx.Done(): + keepItRunning <- struct{}{} + return + case <-ticker.C: + // TODO: check if the function is still running before starting a new one + // Ticker should not execute if already running + pollNow() + } } } @@ -122,7 +154,7 @@ func loadNewProfiles() ([]string, error) { } // Execute apparmor_parser --replace --verbose filteredNewProfiles - log.Println("============================================================") + printLogSeparator() log.Println("> Apparmor REPLACE and apply new profiles..") for _, profilePath := range newProfilesToApply { err := loadProfile(profilePath) @@ -133,7 +165,7 @@ func loadNewProfiles() ([]string, error) { // Execute apparmor_parser --remove obsoleteProfilePath if len(loadedProfilesToUnload) > 0 { - log.Println("============================================================") + printLogSeparator() log.Println("> AppArmor REMOVE orphans profiles..") for _, profileFileName := range loadedProfilesToUnload { err := unloadProfile(profileFileName) @@ -144,6 +176,7 @@ func loadNewProfiles() ([]string, error) { } log.Println("> Done!\n> Waiting next poll..") + printLogSeparator() return newProfilesToApply, nil } @@ -205,15 +238,28 @@ func parseProfileName(profileLine string) string { func loadProfile(profilePath string) error { err := execApparmor("--verbose", "--replace", profilePath) - if err != nil { - log.Fatal(err) - } + checkFatal(err) // Copy the profile definition in the apparmor configuration standard directory log.Printf("Copying profile in %s", ETC_APPARMORD) return CopyFile(profilePath, ETC_APPARMORD) } +// Remove all custom profiles from the kernel, reading from ETC_APPARMORD folder +func unloadAllProfiles() error { + dirEntries, err := os.ReadDir(ETC_APPARMORD) + checkFatal(err) + + for _, entry := range dirEntries { + if !entry.IsDir() && entry.Type().IsRegular() { + err := unloadProfile(entry.Name()) + checkFatal(err) + } + } + return nil +} + +// Remove an apparmor profile from the kernel func unloadProfile(fileName string) error { filePath := path.Join(ETC_APPARMORD, fileName) @@ -240,3 +286,14 @@ func execApparmor(args ...string) error { return nil } + +func checkFatal(err error) { + if err != nil { + log.Fatal(err) + } +} + +// Useless line separator to simplify logs reading. +func printLogSeparator() { + log.Println("============================================================") +} From 5a97ba6071bbae2c75b28eb5969f8022d629afdd Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Fri, 5 May 2023 10:13:09 +0200 Subject: [PATCH 08/12] Fix: profile content checking when they have same name --- build/build-and-deploy.sh | 18 +++++++++--------- build/build-app.sh | 3 ++- go/src/app/main.go | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/build/build-and-deploy.sh b/build/build-and-deploy.sh index 39bef0f..da604c3 100644 --- a/build/build-and-deploy.sh +++ b/build/build-and-deploy.sh @@ -8,14 +8,14 @@ echo $GHCR_TOKEN | docker login -u "$(git config user.email)" --password-stdin g docker push ghcr.io/tuxerrante/kapparmor:${APP_VERSION}_dev # Install the chart from the local directory - helm upgrade kapparmor --install \ - --atomic \ - --timeout 60s \ - --debug \ - --set image.tag=${APP_VERSION}_dev \ - --set image.pullPolicy=Always \ - --dry-run \ - charts/kapparmor +helm upgrade kapparmor --install \ + --atomic \ + --debug \ + --set image.tag=${APP_VERSION}_dev \ + --set image.pullPolicy=Always \ + --dry-run \ + charts/kapparmor + echo echo "> Is the previous result the expected one?" echo "> Current K8S context:" "$(kubectl config current-context)" @@ -23,7 +23,7 @@ read -r -p "> Are you sure? [Y/n] " response if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then helm upgrade kapparmor --install \ --atomic \ - --timeout 60s \ + --timeout 120s \ --debug \ --set image.tag=${APP_VERSION}_dev \ --set image.pullPolicy=Always \ diff --git a/build/build-app.sh b/build/build-app.sh index 200885e..5986afd 100644 --- a/build/build-app.sh +++ b/build/build-app.sh @@ -23,7 +23,8 @@ docker build --target test-coverage --tag "ghcr.io/tuxerrante/kapparmor:${APP_VE echo "> Building container image..." docker build --tag "ghcr.io/tuxerrante/kapparmor:${APP_VERSION}_dev" \ --no-cache \ - --build-arg POLL_TIME=60 --build-arg PROFILES_DIR=/app/profiles \ + --build-arg POLL_TIME=30 \ + --build-arg PROFILES_DIR=/app/profiles \ -f Dockerfile \ . diff --git a/go/src/app/main.go b/go/src/app/main.go index 22cd7b3..24ee6f2 100644 --- a/go/src/app/main.go +++ b/go/src/app/main.go @@ -131,7 +131,7 @@ func loadNewProfiles() ([]string, error) { // If the profile is exactly the same skip the apply log.Printf("Checking %s profile..", path.Join(CONFIGMAP_PATH, newProfileName)) - contentIsTheSame, err := HasTheSameContent(nil, filePath1, path.Join(CONFIGMAP_PATH, newProfileName)) + contentIsTheSame, err := HasTheSameContent(nil, filePath1, path.Join(ETC_APPARMORD, newProfileName)) if err != nil { // Error in checking the content of "/app/profiles/custom.deny-write-outside-app" VS "custom.deny-write-outside-app" log.Printf(">> Error in checking the content of %q VS %q\n", filePath1, newProfileName) From d8cc52cb7f62fa2f9995d56ef4c0a1008bb59203 Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Mon, 8 May 2023 18:27:45 +0200 Subject: [PATCH 09/12] Fix: catch SIGTERM signal --- Dockerfile | 2 +- go/src/app/main.go | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1ec05d5..c2c82fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,4 +41,4 @@ ENV PROFILES_DIR=$PROFILES_DIR ENV POLL_TIME=$POLL_TIME USER root -CMD ./app \ No newline at end of file +ENTRYPOINT ["./app"] \ No newline at end of file diff --git a/go/src/app/main.go b/go/src/app/main.go index 24ee6f2..56e82eb 100644 --- a/go/src/app/main.go +++ b/go/src/app/main.go @@ -35,25 +35,24 @@ func main() { keepItRunning := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) - - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) + defer cancel() log.Printf("> Polling directory %s every %d seconds.\n", CONFIGMAP_PATH, POLL_TIME) go pollProfiles(POLL_TIME, ctx, keepItRunning) // Manage OS signals for graceful shutdown go func() { + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT, os.Interrupt) <-signals log.Print("> Received stop signal, terminating..") - // Stop polling new profiles - cancel() - // Delete all loaded profiles err := unloadAllProfiles() checkFatal(err) + // Stop polling new profiles + cancel() log.Print("> The Eagle has landed.") }() @@ -79,8 +78,6 @@ func pollProfiles(pollTime int, ctx context.Context, keepItRunning chan struct{} keepItRunning <- struct{}{} return case <-ticker.C: - // TODO: check if the function is still running before starting a new one - // Ticker should not execute if already running pollNow() } } From 689fa391970cfd37a9c2410ebd860a3324b9fbd2 Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Mon, 8 May 2023 18:28:15 +0200 Subject: [PATCH 10/12] Feature: Validate app and chart version --- build/build-app.sh | 12 ++++++++++++ charts/kapparmor/Chart.yaml | 3 ++- config/config | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/build/build-app.sh b/build/build-app.sh index 5986afd..37e2f6f 100644 --- a/build/build-app.sh +++ b/build/build-app.sh @@ -1,6 +1,18 @@ #!/bin/bash source ./config/config +# --- Validate App and Chart version +YML_CHART_VERSION="$(grep "version: [\"0-9\.]\+" charts/kapparmor/Chart.yaml |cut -d'"' -f2)" +YML_APP_VERSION="$(grep "appVersion: [\"0-9\.]\+" charts/kapparmor/Chart.yaml |cut -d'"' -f2)" + +if [[ $APP_VERSION != $YML_APP_VERSION ]]; then + echo "The APP version declared in the Chart is different from the one in the config!" + exit 1 +elif [[ $CHART_VERSION != $YML_CHART_VERSION ]]; then + echo "The APP version declared in the Chart is different from the one in the config!" + exit 1 +fi + # Clean old images echo "> Removing old and dangling old images..." docker rmi "$(docker images --filter "reference=ghcr.io/tuxerrante/kapparmor" -q --no-trunc )" diff --git a/charts/kapparmor/Chart.yaml b/charts/kapparmor/Chart.yaml index c1ae23b..421fe34 100644 --- a/charts/kapparmor/Chart.yaml +++ b/charts/kapparmor/Chart.yaml @@ -5,8 +5,9 @@ type: application home: https://artifacthub.io kubeVersion: ">= 1.23.0-0" +# Respect spaces and double quotes since this will be validated by the build-app script. version: "0.1.3" -appVersion: "0.1.3" +appVersion: "0.1.4" keywords: - kubernetes diff --git a/config/config b/config/config index 2a18a9a..4255e27 100644 --- a/config/config +++ b/config/config @@ -1 +1,2 @@ -APP_VERSION=0.1.3 +APP_VERSION=0.1.4 +CHART_VERSION=0.1.3 \ No newline at end of file From 15da4e42893cdaa4412412a23c618ed98108714b Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Wed, 10 May 2023 18:04:49 +0200 Subject: [PATCH 11/12] Feature: validate profile file content --- README.md | 11 +++++++---- charts/kapparmor/Chart.yaml | 2 +- config/config | 2 +- go/src/app/filesystemOperations.go | 10 ++++++++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 3727ce9..7e3d746 100644 --- a/README.md +++ b/README.md @@ -46,13 +46,16 @@ helm upgrade kapparmor --install --atomic --timeout 120s --debug --set image.tag ``` ## Known limitations -- Profiles names are checked on the first line, so if there is some include before that would fail -- Profile names have to start with 'custom.' and to be equal as the filename containing it -- There could be issues if you start the daemonsets on "dirty" nodes, where some old custom profiles were left after stopping or uninstalling Kapparmor. E.g: you stop the pods and then redeploy the app with an empty profiles configmap without removing the previous custom profiles: Kapparmor will try to remove the old profiles but it could fail since there is no definition of them anymore. +- Constraint: Profiles are validated on the "`profile`" keyword presence before of a opening curly bracket `{`. + It must be a [unattached profiles](https://documentation.suse.com/sles/15-SP1/html/SLES-all/cha-apparmor-profiles.html#sec-apparmor-profiles-types-unattached). +- Profile names have to start with 'custom.' and to be equal as the filename containing it. +- There could be issues if you start the daemonsets on "dirty" nodes, where some old custom profiles were left after stopping or uninstalling Kapparmor. + E.G: By default if you delete a pod all the profiles should be automatically deleted from that node, but the app crashes during the process. + - Not a limitation relative to this project, but if you deny write access in the /bin folder of a privileged container it could not be deleted by Kubernetes even after 'kubectl delete'. The command will succeed but the pod will stay in Terminating state. ## ToDo: -- 🌱 Intercept Term signal and uninstall profiles before the Helm chart deletion completes. +- [X] Intercept Term signal and uninstall profiles before the Helm chart deletion completes. - ⚠️ Implement the [controller-runtime](https://pkg.go.dev/sigs.k8s.io/controller-runtime#section-readme) design pattern through [Kubebuilder](https://book.kubebuilder.io/quick-start.html). - 😁 Find funnier quotes for app starting and ending message (David Zucker, Monty Python, Woody Allen...). - 🌱 Make the ticker loop thread safe: skip running a new loop if previous run is still ongoing. diff --git a/charts/kapparmor/Chart.yaml b/charts/kapparmor/Chart.yaml index 421fe34..c4fce56 100644 --- a/charts/kapparmor/Chart.yaml +++ b/charts/kapparmor/Chart.yaml @@ -7,7 +7,7 @@ kubeVersion: ">= 1.23.0-0" # Respect spaces and double quotes since this will be validated by the build-app script. version: "0.1.3" -appVersion: "0.1.4" +appVersion: "0.1.5" keywords: - kubernetes diff --git a/config/config b/config/config index 4255e27..15674b4 100644 --- a/config/config +++ b/config/config @@ -1,2 +1,2 @@ -APP_VERSION=0.1.4 +APP_VERSION=0.1.5 CHART_VERSION=0.1.3 \ No newline at end of file diff --git a/go/src/app/filesystemOperations.go b/go/src/app/filesystemOperations.go index 6b6c4ac..05a98ee 100644 --- a/go/src/app/filesystemOperations.go +++ b/go/src/app/filesystemOperations.go @@ -168,6 +168,16 @@ func IsProfileNameCorrect(directory, filename string) error { } scanner := bufio.NewScanner(fileReader) + // Validate the syntax + // the first index of a curly bracket should be greater than the first occurrence of "profile" + fileBytes, err := os.ReadFile(path.Join(directory, filename)) + checkFatal(err) + profileIndex := bytes.Index(fileBytes, []byte("profile")) + curlyBracketIndex := bytes.Index(fileBytes, []byte("{")) + if curlyBracketIndex < 0 || curlyBracketIndex < profileIndex { + return errors.New("couldn't find a { after 'profile' keyword") + } + // Search for line starting with 'profile' word for scanner.Scan() { fileLine := scanner.Text() From 6e10b49720823930538cb9b86aa4a5f791efcb03 Mon Sep 17 00:00:00 2001 From: Alessandro Affinito Date: Mon, 15 May 2023 16:45:00 +0200 Subject: [PATCH 12/12] Feature: manage custom labels --- charts/kapparmor/Chart.yaml | 2 +- charts/kapparmor/templates/cm-profiles.yaml | 5 +++++ charts/kapparmor/templates/cm-settings.yaml | 5 +++++ charts/kapparmor/templates/daemonset.yaml | 9 +++++++-- charts/kapparmor/templates/service.yaml | 3 +++ charts/kapparmor/values.yaml | 5 +++++ config/config | 2 +- docs/testing.md | 9 +++++++-- 8 files changed, 34 insertions(+), 6 deletions(-) diff --git a/charts/kapparmor/Chart.yaml b/charts/kapparmor/Chart.yaml index c4fce56..5499b0e 100644 --- a/charts/kapparmor/Chart.yaml +++ b/charts/kapparmor/Chart.yaml @@ -6,7 +6,7 @@ home: https://artifacthub.io kubeVersion: ">= 1.23.0-0" # Respect spaces and double quotes since this will be validated by the build-app script. -version: "0.1.3" +version: "0.1.5" appVersion: "0.1.5" keywords: diff --git a/charts/kapparmor/templates/cm-profiles.yaml b/charts/kapparmor/templates/cm-profiles.yaml index 85861c8..977f061 100644 --- a/charts/kapparmor/templates/cm-profiles.yaml +++ b/charts/kapparmor/templates/cm-profiles.yaml @@ -3,5 +3,10 @@ kind: ConfigMap metadata: name: kapparmor-profiles namespace: {{ .Release.Namespace }} + labels: + {{- include "kapparmor.labels" . | nindent 4 }} + {{- with .Values.app.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} data: {{ (.Files.Glob "profiles/*").AsConfig | indent 2 }} \ No newline at end of file diff --git a/charts/kapparmor/templates/cm-settings.yaml b/charts/kapparmor/templates/cm-settings.yaml index ec15981..1e877db 100644 --- a/charts/kapparmor/templates/cm-settings.yaml +++ b/charts/kapparmor/templates/cm-settings.yaml @@ -3,6 +3,11 @@ kind: ConfigMap metadata: name: kapparmor-settings namespace: {{ .Release.Namespace }} + labels: + {{- include "kapparmor.labels" . | nindent 4 }} + {{- with .Values.app.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} data: PROFILES_DIR: "{{ .Values.app.profiles_dir }}" POLL_TIME: "{{ .Values.app.poll_time }}" \ No newline at end of file diff --git a/charts/kapparmor/templates/daemonset.yaml b/charts/kapparmor/templates/daemonset.yaml index ec49aac..56836bd 100644 --- a/charts/kapparmor/templates/daemonset.yaml +++ b/charts/kapparmor/templates/daemonset.yaml @@ -4,7 +4,10 @@ metadata: name: {{ include "kapparmor.fullname" . }} namespace: {{ .Release.Namespace }} labels: - {{- include "kapparmor.labels" . | nindent 4 }} + {{- include "kapparmor.labels" . | nindent 4 }} + {{- with .Values.daemonset.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: selector: matchLabels: @@ -16,9 +19,11 @@ spec: {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} - labels: {{- include "kapparmor.selectorLabels" . | nindent 8 }} + {{- with .Values.app.labels }} + {{- toYaml . | nindent 8 }} + {{- end }} spec: {{- with .Values.imagePullSecrets }} diff --git a/charts/kapparmor/templates/service.yaml b/charts/kapparmor/templates/service.yaml index 4dd8f27..bbb7da0 100644 --- a/charts/kapparmor/templates/service.yaml +++ b/charts/kapparmor/templates/service.yaml @@ -5,6 +5,9 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "kapparmor.labels" . | nindent 4 }} + {{- with .Values.app.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/kapparmor/values.yaml b/charts/kapparmor/values.yaml index c120db3..322268b 100644 --- a/charts/kapparmor/values.yaml +++ b/charts/kapparmor/values.yaml @@ -12,6 +12,8 @@ fullnameOverride: "" app: profiles_dir: "/app/profiles" poll_time: 60 + labels: +# costgroup: "test" serviceAccount: # Specifies whether a service account should be created @@ -22,6 +24,9 @@ serviceAccount: # If not set and create is true, a name is generated using the fullname template name: "" +daemonset: + labels: {} + podAnnotations: {} podSecurityContext: {} diff --git a/config/config b/config/config index 15674b4..bdb6896 100644 --- a/config/config +++ b/config/config @@ -1,2 +1,2 @@ APP_VERSION=0.1.5 -CHART_VERSION=0.1.3 \ No newline at end of file +CHART_VERSION=0.1.5 \ No newline at end of file diff --git a/docs/testing.md b/docs/testing.md index 9117c9c..47c4c3e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -24,8 +24,13 @@ docker run -it --network host --workdir=/data --volume ~/.kube/config:/root/.kub /bin/sh -c "git config --global --add safe.directory /data; ct lint --print-config --charts ./charts/kapparmor" # Replace here a commit id being part of an image tag -export GITHUB_SHA="sha-93d0dc4c597a8ae8a9febe1d68e674daf1fa919a" -helm install --dry-run --atomic --generate-name --timeout 30s --debug --set image.tag=$GITHUB_SHA charts/kapparmor/ +export IMAGE_TAG="0.1.4_dev" +helm upgrade kapparmor --install --dry-run \ + --atomic \ + --timeout 30s \ + --debug \ + --namespace test \ + --set image.tag=$IMAGE_TAG charts/kapparmor/ ```