224 lines
6.0 KiB
Go
224 lines
6.0 KiB
Go
/*
|
|
©AngelaMos | 2026
|
|
daemon.go
|
|
|
|
DaemonAnalyzer inspects Docker daemon configuration for CIS Section 2
|
|
violations
|
|
|
|
Calls the Docker daemon Info endpoint and checks for seccomp support,
|
|
user namespace remapping, live restore, experimental mode, logging
|
|
driver, and cgroup driver. Each check maps to a specific CIS Section
|
|
2 control and produces a finding with remediation guidance.
|
|
|
|
Key exports:
|
|
DaemonAnalyzer - implements Analyzer for the Docker daemon
|
|
NewDaemonAnalyzer - constructor taking a docker.Client
|
|
|
|
Connects to:
|
|
analyzer.go - implements Analyzer interface, uses CategoryDaemon
|
|
docker/client.go - calls Info() to get daemon metadata
|
|
benchmark/controls.go - fetches CIS Section 2 controls by ID
|
|
finding.go - creates findings with CISControl references
|
|
*/
|
|
|
|
package analyzer
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/CarterPerez-dev/docksec/internal/benchmark"
|
|
"github.com/CarterPerez-dev/docksec/internal/docker"
|
|
"github.com/CarterPerez-dev/docksec/internal/finding"
|
|
)
|
|
|
|
type DaemonAnalyzer struct {
|
|
client *docker.Client
|
|
}
|
|
|
|
func NewDaemonAnalyzer(client *docker.Client) *DaemonAnalyzer {
|
|
return &DaemonAnalyzer{client: client}
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) Name() string {
|
|
return "daemon"
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) Analyze(
|
|
ctx context.Context,
|
|
) (finding.Collection, error) {
|
|
info, err := a.client.Info(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
target := finding.Target{
|
|
Type: finding.TargetDaemon,
|
|
Name: "docker-daemon",
|
|
ID: info.ID,
|
|
}
|
|
|
|
var findings finding.Collection
|
|
|
|
findings = append(
|
|
findings,
|
|
a.checkSeccompDefault(target, info.SecurityOptions)...)
|
|
findings = append(
|
|
findings,
|
|
a.checkLiveRestore(target, info.LiveRestoreEnabled)...)
|
|
findings = append(
|
|
findings,
|
|
a.checkExperimental(target, info.ExperimentalBuild)...)
|
|
findings = append(
|
|
findings,
|
|
a.checkUsernsRemap(target, info.SecurityOptions)...)
|
|
findings = append(
|
|
findings,
|
|
a.checkLoggingDriver(target, info.LoggingDriver)...)
|
|
findings = append(
|
|
findings,
|
|
a.checkCgroupDriver(target, info.CgroupDriver)...)
|
|
|
|
return findings, nil
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) checkSeccompDefault(
|
|
target finding.Target,
|
|
securityOpts []string,
|
|
) finding.Collection {
|
|
var findings finding.Collection
|
|
|
|
seccompEnabled := false
|
|
for _, opt := range securityOpts {
|
|
if strings.HasPrefix(opt, "seccomp") {
|
|
seccompEnabled = true
|
|
if strings.Contains(opt, "unconfined") {
|
|
control, _ := benchmark.Get("2.7")
|
|
f := finding.New("CIS-2.7", control.Title, finding.SeverityHigh, target).
|
|
WithDescription(control.Description).
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation(control.Remediation).
|
|
WithReferences(control.References...).
|
|
WithCISControl(control.ToCISControl())
|
|
findings = append(findings, f)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
if !seccompEnabled {
|
|
control, _ := benchmark.Get("2.7")
|
|
f := finding.New("CIS-2.7", "Seccomp not enabled on daemon", finding.SeverityMedium, target).
|
|
WithDescription("Docker daemon is not configured with seccomp support.").
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation(control.Remediation).
|
|
WithReferences(control.References...).
|
|
WithCISControl(control.ToCISControl())
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
return findings
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) checkLiveRestore(
|
|
target finding.Target,
|
|
enabled bool,
|
|
) finding.Collection {
|
|
var findings finding.Collection
|
|
|
|
if !enabled {
|
|
control, _ := benchmark.Get("2.14")
|
|
f := finding.New("CIS-2.14", control.Title, finding.SeverityLow, target).
|
|
WithDescription(control.Description).
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation(control.Remediation).
|
|
WithReferences(control.References...).
|
|
WithCISControl(control.ToCISControl())
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
return findings
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) checkExperimental(
|
|
target finding.Target,
|
|
enabled bool,
|
|
) finding.Collection {
|
|
var findings finding.Collection
|
|
|
|
if enabled {
|
|
control, _ := benchmark.Get("2.8")
|
|
f := finding.New("CIS-2.8", control.Title, finding.SeverityLow, target).
|
|
WithDescription(control.Description).
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation(control.Remediation).
|
|
WithReferences(control.References...).
|
|
WithCISControl(control.ToCISControl())
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
return findings
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) checkUsernsRemap(
|
|
target finding.Target,
|
|
securityOpts []string,
|
|
) finding.Collection {
|
|
var findings finding.Collection
|
|
|
|
usernsEnabled := false
|
|
for _, opt := range securityOpts {
|
|
if strings.HasPrefix(opt, "userns") {
|
|
usernsEnabled = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !usernsEnabled {
|
|
f := finding.New("CIS-2.8", "User namespace remapping not enabled", finding.SeverityInfo, target).
|
|
WithDescription("User namespace remapping provides additional isolation by mapping container users to unprivileged host users.").
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation("Configure --userns-remap in daemon.json for additional container isolation.")
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
return findings
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) checkLoggingDriver(
|
|
target finding.Target,
|
|
driver string,
|
|
) finding.Collection {
|
|
var findings finding.Collection
|
|
|
|
if driver == "" || driver == "none" {
|
|
control, _ := benchmark.Get("2.3")
|
|
f := finding.New("CIS-2.3", control.Title, finding.SeverityMedium, target).
|
|
WithDescription(control.Description).
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation(control.Remediation).
|
|
WithReferences(control.References...).
|
|
WithCISControl(control.ToCISControl())
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
return findings
|
|
}
|
|
|
|
func (a *DaemonAnalyzer) checkCgroupDriver(
|
|
target finding.Target,
|
|
driver string,
|
|
) finding.Collection {
|
|
var findings finding.Collection
|
|
|
|
if driver == "" {
|
|
f := finding.New("DS-CGROUP-001", "No cgroup driver configured", finding.SeverityInfo, target).
|
|
WithDescription("Docker daemon has no explicit cgroup driver configured. This is informational.").
|
|
WithCategory(string(CategoryDaemon)).
|
|
WithRemediation("Consider explicitly configuring cgroup driver for consistency.")
|
|
findings = append(findings, f)
|
|
}
|
|
|
|
return findings
|
|
}
|