Skip to content

Commit

Permalink
Merge pull request #19 from zuBux/master
Browse files Browse the repository at this point in the history
Fixes #9, #17, #18. Refactored `checkAuditRule` so the auditd checks are smaller
  • Loading branch information
zuBux committed May 17, 2016
2 parents f4982b1 + fc947c1 commit 2ebb121
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ COPY . $GOPATH/src/github.com/diogomonica/actuary
WORKDIR $GOPATH/src/github.com/diogomonica/actuary
RUN go get github.com/tools/godep
RUN $GOPATH/bin/godep restore
RUN go install github.com/diogomonica/actuary
RUN go install github.com/diogomonica/actuary/cmd/actuary

ENTRYPOINT ["/go/bin/actuary"]
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ When using the `-f` flag, Actuary will attempt to run a local file, which should

Actuary has the ability of running against a remote Docker api. You will need to point Actuary to the remote API, and provide your TLS credentials, in case you are using them for Authentication:

`# actuary --tlscacert=ca.pem --tlskey=key.pem --tlscert=cert.pem --server=tcp://<docker host>:<port> <hash>`
`# actuary --tlspath=<path to load certs from> --server=tcp://<docker host>:<port> <hash>`

## Running a local check

Expand All @@ -58,4 +58,4 @@ Running it against your Docker instance by mounting in the Docker socket:

By default, Actuary outputs the results to the console. If you wish to parse the results using any kind of program or script, you can tell Actuary to output the results in either XML or JSON:

`# actuary --output=json <hash>`
`# actuary --output=<json/xml> <hash>`
4 changes: 4 additions & 0 deletions actuary_test.go → actuary_test-local.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/* This test suite should NOT run on CircleCI due to elevated privilege
requirements. You should run this on a local machine with full access
to a Docker server*/

package actuary

import (
Expand Down
16 changes: 11 additions & 5 deletions checks/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ func (r *Result) Info(s string) {
return
}

type auditdError struct {
Error error
Message string
Code int //1: Cannot read auditd rules. 2: Rule does not exist
}

var checklist = map[string]Check{
//Docker Host
"kernel_version": CheckKernelVersion,
Expand Down Expand Up @@ -244,23 +250,23 @@ func getFileOwner(info os.FileInfo) (uid, gid string) {
}

//Helper function to check rules in auditctl
func checkAuditRule(rule string) bool {
func checkAuditRule(rule string) *auditdError {
auditctlPath, err := exec.LookPath("auditctl")
if err != nil || auditctlPath == "" {
log.Panicf("Could not find auditctl tool")
return &auditdError{err, "Could not find auditctl", 1}
}
cmd := exec.Command(auditctlPath, "-l")
output, err := cmd.Output()
if err != nil {
log.Panicf("Auditctl command returned with errors")
return &auditdError{err, "Unable to retrieve rule list", 1}
}
for _, line := range strings.Split(string(output), "\n") {
line = strings.TrimSpace(line)
if strings.Contains(line, rule) {
return true
return nil
}
}
return false
return &auditdError{nil, "Rule not found", 2}
}

func stringInSlice(a string, list []string) bool {
Expand Down
103 changes: 54 additions & 49 deletions checks/dockerhost.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,113 +134,118 @@ func CheckTrustedUsers(client *client.Client) (res Result) {
}

func AuditDockerDaemon(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.7 Audit docker daemon"
ruleExists = checkAuditRule("/usr/bin/docker")

if ruleExists {
res.Pass()
err := checkAuditRule("/usr/bin/docker")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}

return
}

func AuditLibDocker(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.8 Audit Docker files and directories - /var/lib/docker"
ruleExists = checkAuditRule("/var/lib/docker")

if ruleExists {
res.Pass()
err := checkAuditRule("/var/lib/docker")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}

return
}

func AuditEtcDocker(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.9 Audit Docker files and directories - /etc/docker"
ruleExists = checkAuditRule("/etc/docker")
if ruleExists {
res.Pass()
err := checkAuditRule("/etc/docker")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}

func AuditDockerService(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.10 Audit Docker files and directories - docker.service"
ruleExists = checkAuditRule("/usr/lib/systemd/system/docker.service")
if ruleExists {
res.Pass()
err := checkAuditRule("/usr/lib/systemd/system/docker.service")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}

func AuditDockerSocket(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.11 Audit Docker files and directories - docker.socket"
ruleExists = checkAuditRule("/usr/lib/systemd/system/docker.socket")
if ruleExists {
res.Pass()
err := checkAuditRule("/usr/lib/systemd/system/docker.socket")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}

func AuditDockerDefault(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.12 Audit Docker files and directories - /etc/default/docker"
ruleExists = checkAuditRule("/etc/default/docker")
if ruleExists {
res.Pass()
err := checkAuditRule("/etc/default/docker")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}

func AuditDaemonJSON(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.13 Audit Docker files and directories - /etc/docker/daemon.json"
ruleExists = checkAuditRule("/etc/docker/daemon.json")
if ruleExists {
res.Pass()
err := checkAuditRule("/etc/docker/daemon.json")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}

func AuditContainerd(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.14 Audit Docker files and directories - /usr/bin/docker-containerd"
ruleExists = checkAuditRule("/usr/bin/docker-containerd")
if ruleExists {
res.Pass()
err := checkAuditRule("/usr/bin/docker-containerd")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}

func AuditRunc(client *client.Client) (res Result) {
var ruleExists bool
res.Name = "1.15 Audit Docker files and directories - /usr/bin/docker-runc"
ruleExists = checkAuditRule("/usr/bin/docker-runc")
if ruleExists {
res.Pass()
err := checkAuditRule("/usr/bin/docker-runc")
if err == nil {
defer res.Pass()
} else if err.Code == 1 {
defer res.Skip(err.Message)
} else {
res.Fail("")
defer res.Fail("")
}
return
}
18 changes: 13 additions & 5 deletions cmd/actuary/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,34 @@ import (
var profile = flag.String("profile", "", "Actuary profile file path")
var output = flag.String("output", "", "output filename")
var outputType = flag.String("type", "json", "output type - XML or JSON")
var tlsPath = flag.String("tlspath", "", "Path to load certificates from")
var server = flag.String("server", "", "Docker server to connect to tcp://<docker host>:<port>")
var tomlProfile profileutils.Profile
var clientHeaders map[string]string
var results []checks.Result
var actions map[string]checks.Check

func init() {
flag.StringVar(profile, "f", "", "Actuary profile file path")
flag.StringVar(output, "o", "", "output filename")
flag.StringVar(outputType, "", "json", "output type - XML or JSON")

clientHeaders = make(map[string]string)
clientHeaders["User-Agent"] = "engine-api-cli-1.0"
flag.StringVar(tlsPath, "tls", "", "Path to load certificates from")
flag.StringVar(server, "s", "", "Docker server to connect to tcp://<docker host>:<port>")
}

func main() {
var cmdArgs []string
var hash string

flag.Parse()
cli, err := client.NewClient("unix:///var/run/docker.sock", "v1.20", nil, clientHeaders)
if *tlsPath != "" {
os.Setenv("DOCKER_CERT_PATH", *tlsPath)
}
if *server != "" {
os.Setenv("DOCKER_HOST", *server)
} else {
os.Setenv("DOCKER_HOST", "unix:///var/run/docker.sock")
}
cli, err := client.NewEnvClient()
if err != nil {
log.Fatalf("Unable to connect to Docker daemon: %s", err)
}
Expand Down

0 comments on commit 2ebb121

Please sign in to comment.