Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ func Run(ctx context.Context, configFilePath string, hostDNSServer DNSServer,
if !isActive {
config.EgressPolicy = EgressPolicyAudit
config.DisableSudo = false
config.DisableSudoAndContainers = false
apiclient.DisableTelemetry = true
config.DisableFileMonitoring = true
WriteAnnotation("StepSecurity Harden Runner is disabled. A subscription is required for private repositories. Please start a free trial at https://www.stepsecurity.io")
Expand Down Expand Up @@ -133,6 +134,10 @@ func Run(ctx context.Context, configFilePath string, hostDNSServer DNSServer,
sudo := Sudo{}
var ipAddressEndpoints []ipAddressEndpoint

if config.DisableSudoAndContainers {
go sudo.uninstallDocker()
}

// hydrate dns cache
if config.EgressPolicy == EgressPolicyBlock {
for domainName, endpoints := range allowedEndpoints {
Expand Down Expand Up @@ -247,6 +252,15 @@ func Run(ctx context.Context, configFilePath string, hostDNSServer DNSServer,
}
}

if config.DisableSudoAndContainers {
err := sudo.disableSudoAndContainers(tempDir)
if err != nil {
WriteLog(fmt.Sprintf("%s Unable to disable sudo and docker %v", StepSecurityAnnotationPrefix, err))
} else {
WriteLog("disabled sudo and docker")
}
}

if config.DisableSudo {
err := sudo.disableSudo(tempDir)
if err != nil {
Expand Down
51 changes: 27 additions & 24 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ import (
)

type config struct {
Repo string
CorrelationId string
RunId string
WorkingDirectory string
APIURL string
OneTimeKey string
Endpoints map[string][]Endpoint
EgressPolicy string
DisableTelemetry bool
DisableSudo bool
DisableFileMonitoring bool
Private bool
Repo string
CorrelationId string
RunId string
WorkingDirectory string
APIURL string
OneTimeKey string
Endpoints map[string][]Endpoint
EgressPolicy string
DisableTelemetry bool
DisableSudo bool
DisableSudoAndContainers bool
DisableFileMonitoring bool
Private bool
}

type Endpoint struct {
Expand All @@ -31,18 +32,19 @@ type Endpoint struct {
}

type configFile struct {
Repo string `json:"repo"`
CorrelationId string `json:"correlation_id"`
RunId string `json:"run_id"`
WorkingDirectory string `json:"working_directory"`
APIURL string `json:"api_url"`
OneTimeKey string `json:"one_time_key"`
AllowedEndpoints string `json:"allowed_endpoints"`
EgressPolicy string `json:"egress_policy"`
DisableTelemetry bool `json:"disable_telemetry"`
DisableSudo bool `json:"disable_sudo"`
DisableFileMonitoring bool `json:"disable_file_monitoring"`
Private bool `json:"private"`
Repo string `json:"repo"`
CorrelationId string `json:"correlation_id"`
RunId string `json:"run_id"`
WorkingDirectory string `json:"working_directory"`
APIURL string `json:"api_url"`
OneTimeKey string `json:"one_time_key"`
AllowedEndpoints string `json:"allowed_endpoints"`
EgressPolicy string `json:"egress_policy"`
DisableTelemetry bool `json:"disable_telemetry"`
DisableSudo bool `json:"disable_sudo"`
DisableSudoAndContainers bool `json:"disable_sudo_and_containers"`
DisableFileMonitoring bool `json:"disable_file_monitoring"`
Private bool `json:"private"`
}

// init reads the config file for the agent and initializes config settings
Expand All @@ -67,6 +69,7 @@ func (c *config) init(configFilePath string) error {
c.EgressPolicy = configFile.EgressPolicy
c.DisableTelemetry = configFile.DisableTelemetry
c.DisableSudo = configFile.DisableSudo
c.DisableSudoAndContainers = configFile.DisableSudoAndContainers
c.DisableFileMonitoring = configFile.DisableFileMonitoring
c.Private = configFile.Private
c.OneTimeKey = configFile.OneTimeKey
Expand Down
92 changes: 92 additions & 0 deletions sudo.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package main

import (
"bufio"
"fmt"
"os"
"os/exec"
"path"
"strings"
)

type Sudo struct {
Expand All @@ -12,6 +15,7 @@ type Sudo struct {

const (
sudoersFile = "/etc/sudoers.d/runner"
runnerUser = "runner"
)

func (s *Sudo) disableSudo(tempDir string) error {
Expand Down Expand Up @@ -40,3 +44,91 @@ func (s *Sudo) revertDisableSudo() error {

return nil
}

func (s *Sudo) disableSudoAndContainers(tempDir string) error {

s.removeDockerDirectoriesAndFiles()

// Remove socket permissions if they exist
s.removeSocketPermissions()
var errstrings []string

err := s.disableSudo(tempDir)
if err != nil {
WriteLog(fmt.Sprintf("error disabling sudo: %v", err))
errstrings = append(errstrings, err.Error())
}

//flatten errs
if len(errstrings) > 0 {
return fmt.Errorf("error disabling sudo and containers: %s", strings.Join(errstrings, "\n"))
}
return nil
}

// removeSocketPermissions removes permissions from Docker and containerd sockets if they exist
func (s *Sudo) removeSocketPermissions() {
// Check and remove docker.sock permissions if it exists
if _, err := os.Stat("/var/run/docker.sock"); err == nil {
cmd := exec.Command("sudo", "chmod", "000", "/var/run/docker.sock")
err := cmd.Run()
if err != nil {
WriteLog(fmt.Sprintf("error removing docker.sock permissions: %v", err))
}
}

// Check and remove containerd.sock permissions if it exists
if _, err := os.Stat("/run/containerd/containerd.sock"); err == nil {
cmd := exec.Command("sudo", "chmod", "000", "/run/containerd/containerd.sock")
err := cmd.Run()
if err != nil {
WriteLog(fmt.Sprintf("error removing containerd.sock permissions: %v", err))
}
}
}

func run(cmd string, args ...string) {
WriteLog(fmt.Sprintf("Running: %s %v", cmd, args))
c := exec.Command(cmd, args...)

stdout, _ := c.StdoutPipe()
stderr, _ := c.StderrPipe()

if err := c.Start(); err != nil {
WriteLog(fmt.Sprintf("Failed to start command: %s", err))
}

go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
WriteLog(scanner.Text())
}
}()

// Stream stderr
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
WriteLog(scanner.Text())
}
}()

if err := c.Wait(); err != nil {
WriteLog(fmt.Sprintf("Command failed: %v", err))
}
}

func (s *Sudo) uninstallDocker() error {
WriteLog("Uninstalling docker")
run("sudo", "apt-get", "purge", "-y",
"docker-ce", "docker-ce-cli", "containerd.io")
return nil
}

func (s *Sudo) removeDockerDirectoriesAndFiles() error {
run("sudo", "rm", "-rf", "/var/lib/docker")
run("sudo", "rm", "-rf", "/var/lib/containerd")
run("sudo", "rm", "-f", "/etc/apt/sources.list.d/docker.list")
run("sudo", "rm", "-f", "/etc/apt/keyrings/docker.asc")
return nil
}