mirror of
https://github.com/roddhjav/apparmor.d.git
synced 2024-11-14 23:43:56 +01:00
Rewrite aa-log.
This commit is contained in:
parent
2cc4d69e9e
commit
ac2386957b
@ -1,5 +1,8 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
|
include:
|
||||||
|
- template: Security/SAST.gitlab-ci.yml
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
PKGDEST: $CI_PROJECT_DIR/packages
|
PKGDEST: $CI_PROJECT_DIR/packages
|
||||||
PACKAGER: 'Alexandre Pujol <alexandre@pujol.io>'
|
PACKAGER: 'Alexandre Pujol <alexandre@pujol.io>'
|
||||||
@ -21,6 +24,28 @@ bash:
|
|||||||
PKGBUILD
|
PKGBUILD
|
||||||
debian/apparmor.d.postinst debian/apparmor.d.postrm
|
debian/apparmor.d.postinst debian/apparmor.d.postrm
|
||||||
|
|
||||||
|
golangci-lint:
|
||||||
|
stage: lint
|
||||||
|
image: golangci/golangci-lint
|
||||||
|
script:
|
||||||
|
- cd src && golangci-lint run
|
||||||
|
|
||||||
|
goreport:
|
||||||
|
stage: lint
|
||||||
|
image: golang
|
||||||
|
before_script:
|
||||||
|
- cd /tmp
|
||||||
|
- git clone https://github.com/gojp/goreportcard.git
|
||||||
|
- cd goreportcard
|
||||||
|
- make install
|
||||||
|
- go install ./cmd/goreportcard-cli
|
||||||
|
- cd $CI_PROJECT_DIR
|
||||||
|
script:
|
||||||
|
- goreportcard-cli -v -t 90
|
||||||
|
|
||||||
|
sast:
|
||||||
|
stage: lint
|
||||||
|
|
||||||
|
|
||||||
# Package Build
|
# Package Build
|
||||||
# -------------
|
# -------------
|
||||||
|
17
PKGBUILD
17
PKGBUILD
@ -5,10 +5,11 @@ pkgname=apparmor.d
|
|||||||
pkgver=0.001
|
pkgver=0.001
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Full set of apparmor profiles"
|
pkgdesc="Full set of apparmor profiles"
|
||||||
arch=("any")
|
arch=("x86_64")
|
||||||
url="https://github.com/roddhjav/$pkgname"
|
url="https://github.com/roddhjav/$pkgname"
|
||||||
license=('GPL2')
|
license=('GPL2')
|
||||||
depends=('apparmor')
|
depends=('apparmor')
|
||||||
|
makedepends=('go' 'git')
|
||||||
|
|
||||||
pkgver() {
|
pkgver() {
|
||||||
cd "$srcdir/$pkgname"
|
cd "$srcdir/$pkgname"
|
||||||
@ -22,6 +23,16 @@ prepare() {
|
|||||||
./configure --distribution=archlinux
|
./configure --distribution=archlinux
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "$srcdir/$pkgname/src"
|
||||||
|
export CGO_CPPFLAGS="${CPPFLAGS}"
|
||||||
|
export CGO_CFLAGS="${CFLAGS}"
|
||||||
|
export CGO_CXXFLAGS="${CXXFLAGS}"
|
||||||
|
export CGO_LDFLAGS="${LDFLAGS}"
|
||||||
|
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
|
||||||
|
go build -o ../.build/ ./cmd/aa-log
|
||||||
|
}
|
||||||
|
|
||||||
package() {
|
package() {
|
||||||
local _build='.build/apparmor.d'
|
local _build='.build/apparmor.d'
|
||||||
cd "$srcdir/$pkgname"
|
cd "$srcdir/$pkgname"
|
||||||
@ -45,6 +56,6 @@ package() {
|
|||||||
"$pkgdir/usr/lib/systemd/system/$service.d/apparmor.conf"
|
"$pkgdir/usr/lib/systemd/system/$service.d/apparmor.conf"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Set special access rights
|
# Internal tool
|
||||||
chmod 0755 "$pkgdir"/usr/bin/*
|
install -Dm755 .build/aa-log "$pkgdir"/usr/bin/aa-log
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,9 @@ profile aa-log @{exec_path} {
|
|||||||
|
|
||||||
@{exec_path} mr,
|
@{exec_path} mr,
|
||||||
|
|
||||||
/{usr/,}bin/{,ba,da}sh rix,
|
|
||||||
/{usr/,}bin/awk rix,
|
|
||||||
/{usr/,}bin/env rix,
|
|
||||||
/{usr/,}bin/gawk rix,
|
|
||||||
/{usr/,}bin/grep rix,
|
|
||||||
/{usr/,}bin/mawk rix,
|
|
||||||
/{usr/,}bin/sed rix,
|
|
||||||
|
|
||||||
/usr/share/terminfo/x/xterm-256color r,
|
|
||||||
|
|
||||||
/var/log/audit/audit.log r,
|
/var/log/audit/audit.log r,
|
||||||
|
|
||||||
/dev/tty rw,
|
@{sys}/kernel/mm/transparent_hugepage/hpage_pmd_size r,
|
||||||
|
|
||||||
include if exists <local/aa-log>
|
include if exists <local/aa-log>
|
||||||
}
|
}
|
@ -1,24 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Review AppArmor generated messages
|
|
||||||
# Copyright (C) 2021 Alexandre Pujol <alexandre@pujol.io>
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
#
|
|
||||||
|
|
||||||
readonly LOGFILE=/var/log/audit/audit.log
|
|
||||||
|
|
||||||
# Parses AppArmor logs to hide unnecessary information and remove duplicates.
|
|
||||||
_apparmor_log() {
|
|
||||||
local state="$1" profile="$2"
|
|
||||||
grep -a "$state" "$LOGFILE" \
|
|
||||||
| grep "profile=\"$profile.*\"" \
|
|
||||||
| sed -e 's/AVC //' \
|
|
||||||
-e "s/apparmor=\"$state\"/$state/" \
|
|
||||||
-e 's/type=msg=audit(.*): //' \
|
|
||||||
-e 's/pid=.* comm/comm/' \
|
|
||||||
-e 's/ fsuid.*//' \
|
|
||||||
| awk '!x[$0]++'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_apparmor_log DENIED "$@"
|
|
||||||
_apparmor_log ALLOWED "$@"
|
|
143
src/cmd/aa-log/main.go
Normal file
143
src/cmd/aa-log/main.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
// aa-log - Review AppArmor generated messages
|
||||||
|
// Copyright (C) 2021 Alexandre Pujol <alexandre@pujol.io>
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogFile is the path to the file to query
|
||||||
|
const LogFile = "/var/log/audit/audit.log"
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
const (
|
||||||
|
Reset = "\033[0m"
|
||||||
|
FgYellow = "\033[33m"
|
||||||
|
FgBlue = "\033[34m"
|
||||||
|
FgMagenta = "\033[35m"
|
||||||
|
BoldRed = "\033[1;31m"
|
||||||
|
BoldGreen = "\033[1;32m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AppArmorLog describes a apparmor log entry
|
||||||
|
type AppArmorLog struct {
|
||||||
|
State string
|
||||||
|
Profile string
|
||||||
|
Operation string
|
||||||
|
Name string
|
||||||
|
Content string
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDuplicateLog(logs []string) []string {
|
||||||
|
list := []string{}
|
||||||
|
keys := make(map[string]interface{})
|
||||||
|
keys[""] = true
|
||||||
|
for _, log := range logs {
|
||||||
|
if _, v := keys[log]; !v {
|
||||||
|
keys[log] = true
|
||||||
|
list = append(list, log)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseApparmorLogs(file *os.File, profile string) []AppArmorLog {
|
||||||
|
log := ""
|
||||||
|
exp := fmt.Sprintf("^.*apparmor=(\"DENIED\"|\"ALLOWED\").* profile=\"%s.*\".*$", profile)
|
||||||
|
isAppArmorLog := regexp.MustCompile(exp)
|
||||||
|
|
||||||
|
// Select Apparmor logs
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if isAppArmorLog.MatchString(line) {
|
||||||
|
log += line + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean logs
|
||||||
|
cleanAppArmorLogs := []*regexp.Regexp{
|
||||||
|
regexp.MustCompile(`type=AVC msg=audit(.*): `),
|
||||||
|
regexp.MustCompile(` fsuid.*`),
|
||||||
|
}
|
||||||
|
for _, clean := range cleanAppArmorLogs {
|
||||||
|
log = clean.ReplaceAllLiteralString(log, "")
|
||||||
|
}
|
||||||
|
replaceAppArmorLogs := regexp.MustCompile(`pid=.* comm`)
|
||||||
|
log = replaceAppArmorLogs.ReplaceAllLiteralString(log, "comm")
|
||||||
|
|
||||||
|
// Remove doublon in logs
|
||||||
|
logs := strings.Split(log, "\n")
|
||||||
|
logs = removeDuplicateLog(logs)
|
||||||
|
|
||||||
|
// Parse log into ApparmorLog struct
|
||||||
|
aaLogs := make([]AppArmorLog, 0)
|
||||||
|
getState := regexp.MustCompile(`apparmor=\"([A-Z]*)\"`)
|
||||||
|
getProfile := regexp.MustCompile(`profile=\"([A-Za-z0-9_.\-/]*)\" `)
|
||||||
|
getOperation := regexp.MustCompile(`operation="(\w+)"`)
|
||||||
|
getName := regexp.MustCompile(` name=([A-Za-z0-9_.\-/#"]*)`)
|
||||||
|
cleanContent := []*regexp.Regexp{getState, getProfile, getOperation, getName}
|
||||||
|
for _, log := range logs {
|
||||||
|
name := ""
|
||||||
|
names := getName.FindStringSubmatch(log)
|
||||||
|
if len(names) >= 2 {
|
||||||
|
name = strings.Trim(names[1], `"`)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := log
|
||||||
|
for _, clean := range cleanContent {
|
||||||
|
content = clean.ReplaceAllLiteralString(content, "")
|
||||||
|
}
|
||||||
|
aaLogs = append(aaLogs,
|
||||||
|
AppArmorLog{
|
||||||
|
State: getState.FindStringSubmatch(log)[1],
|
||||||
|
Profile: getProfile.FindStringSubmatch(log)[1],
|
||||||
|
Operation: getOperation.FindStringSubmatch(log)[1],
|
||||||
|
Name: name,
|
||||||
|
Content: content[2:],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return aaLogs
|
||||||
|
}
|
||||||
|
|
||||||
|
func printFormatedApparmorLogs(aaLogs []AppArmorLog) {
|
||||||
|
state := map[string]string{
|
||||||
|
"DENIED": BoldRed + "DENIED " + Reset,
|
||||||
|
"ALLOWED": BoldGreen + "ALLOWED" + Reset,
|
||||||
|
}
|
||||||
|
for _, log := range aaLogs {
|
||||||
|
fmt.Println(state[log.State],
|
||||||
|
FgBlue+log.Profile,
|
||||||
|
FgYellow+log.Operation,
|
||||||
|
FgMagenta+log.Name+Reset,
|
||||||
|
log.Content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
profile := ""
|
||||||
|
if len(os.Args) >= 2 {
|
||||||
|
profile = os.Args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(LogFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := file.Close(); err != nil {
|
||||||
|
fmt.Println("Error closing file:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
aaLogs := parseApparmorLogs(file, profile)
|
||||||
|
printFormatedApparmorLogs(aaLogs)
|
||||||
|
}
|
3
src/go.mod
Normal file
3
src/go.mod
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module gitlab.com/roddhjav/apparmor.d
|
||||||
|
|
||||||
|
go 1.17
|
0
src/go.sum
Normal file
0
src/go.sum
Normal file
Loading…
Reference in New Issue
Block a user