mirror of
https://github.com/kemko/nomad.git
synced 2026-01-05 09:55:44 +03:00
This adds artifact inspection after download to detect any issues with the content fetched. Currently this means checking for any symlinks within the artifact that resolve outside the task or allocation directories. On platforms where lockdown is available (some Linux) this inspection is not performed. The inspection can be disabled with the DisableArtifactInspection option. A dedicated option for disabling this behavior allows the DisableFilesystemIsolation option to be enabled but still have artifacts inspected after download.
160 lines
4.1 KiB
Go
160 lines
4.1 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
//go:build linux
|
|
|
|
package getter
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/mitchellh/go-homedir"
|
|
"github.com/shoenig/go-landlock"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// findHomeDir returns the home directory as provided by os.UserHomeDir. In case
|
|
// os.UserHomeDir returns an error, we return /root if the current process is being
|
|
// run by root, or /dev/null otherwise.
|
|
func findHomeDir() string {
|
|
// When running as a systemd unit the process may not have the $HOME
|
|
// environment variable set, and os.UserHomeDir will return an error.
|
|
|
|
// if home is set, just use that
|
|
if home, err := homedir.Dir(); err == nil {
|
|
return home
|
|
}
|
|
|
|
// if we are the root user, use "/root"
|
|
if unix.Getuid() == 0 {
|
|
return "/root"
|
|
}
|
|
|
|
// nothing safe to do
|
|
return "/nonexistent"
|
|
}
|
|
|
|
// defaultEnvironment is the default minimal environment variables for Linux.
|
|
func defaultEnvironment(taskDir string) map[string]string {
|
|
tmpDir := filepath.Join(taskDir, "tmp")
|
|
homeDir := findHomeDir()
|
|
return map[string]string{
|
|
"PATH": "/usr/local/bin:/usr/bin:/bin",
|
|
"TMPDIR": tmpDir,
|
|
"HOME": homeDir,
|
|
}
|
|
}
|
|
|
|
// lockdownAvailable returns if lockdown is implemented for
|
|
// the current platform.
|
|
func lockdownAvailable() bool {
|
|
return landlock.Available()
|
|
}
|
|
|
|
// lockdown isolates this process to only be able to write and
|
|
// create files in the task's task directory.
|
|
// dir - the task directory
|
|
//
|
|
// Only applies to Linux, when available.
|
|
func lockdown(allocDir, taskDir string, extra []string) error {
|
|
// landlock not present in the kernel, do not sandbox
|
|
if !landlock.Available() {
|
|
return nil
|
|
}
|
|
paths := []*landlock.Path{
|
|
landlock.DNS(),
|
|
landlock.Certs(),
|
|
landlock.Shared(),
|
|
landlock.Dir("/bin", "rx"),
|
|
landlock.Dir("/usr/bin", "rx"),
|
|
landlock.Dir("/usr/local/bin", "rx"),
|
|
landlock.Dir("/usr/libexec", "rx"),
|
|
landlock.Dir(allocDir, "rwc"),
|
|
landlock.Dir(taskDir, "rwc"),
|
|
}
|
|
|
|
for _, p := range extra {
|
|
path, err := landlock.ParsePath(p)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
paths = append(paths, path)
|
|
}
|
|
paths = append(paths, additionalFilesForVCS()...)
|
|
locker := landlock.New(paths...)
|
|
return locker.Lock(landlock.Mandatory)
|
|
}
|
|
|
|
func additionalFilesForVCS() []*landlock.Path {
|
|
const (
|
|
homeSSHDir = ".ssh" // git ssh
|
|
homeKnownHosts = ".ssh/known_hosts" // git ssh
|
|
etcPasswd = "/etc/passwd" // git ssh
|
|
etcKnownHosts = "/etc/ssh/ssh_known_hosts" // git ssh
|
|
gitGlobalFile = "/etc/gitconfig" // https://git-scm.com/docs/git-config#SCOPES
|
|
hgGlobalFile = "/etc/mercurial/hgrc" // https://www.mercurial-scm.org/doc/hgrc.5.html#files
|
|
hgGlobalDir = "/etc/mercurial/hgrc.d" // https://www.mercurial-scm.org/doc/hgrc.5.html#files
|
|
urandom = "/dev/urandom" // git
|
|
)
|
|
return filesForVCS(
|
|
homeSSHDir,
|
|
homeKnownHosts,
|
|
etcPasswd,
|
|
etcKnownHosts,
|
|
gitGlobalFile,
|
|
hgGlobalFile,
|
|
hgGlobalDir,
|
|
urandom,
|
|
)
|
|
}
|
|
|
|
func filesForVCS(
|
|
homeSSHDir,
|
|
homeKnownHosts,
|
|
etcPasswd,
|
|
etcKnownHosts,
|
|
gitGlobalFile,
|
|
hgGlobalFile,
|
|
hgGlobalDir,
|
|
urandom string) []*landlock.Path {
|
|
|
|
// omit ssh if there is no home directory
|
|
home := findHomeDir()
|
|
homeSSHDir = filepath.Join(home, homeSSHDir)
|
|
homeKnownHosts = filepath.Join(home, homeKnownHosts)
|
|
|
|
// detect if p exists
|
|
exists := func(p string) bool {
|
|
_, err := os.Stat(p)
|
|
return err == nil
|
|
}
|
|
|
|
result := make([]*landlock.Path, 0, 6)
|
|
if exists(homeSSHDir) {
|
|
result = append(result, landlock.Dir(homeSSHDir, "r"))
|
|
}
|
|
if exists(homeKnownHosts) {
|
|
result = append(result, landlock.File(homeKnownHosts, "rw"))
|
|
}
|
|
if exists(etcPasswd) {
|
|
result = append(result, landlock.File(etcPasswd, "r"))
|
|
}
|
|
if exists(etcKnownHosts) {
|
|
result = append(result, landlock.File(etcKnownHosts, "r"))
|
|
}
|
|
if exists(gitGlobalFile) {
|
|
result = append(result, landlock.File(gitGlobalFile, "r"))
|
|
}
|
|
if exists(hgGlobalFile) {
|
|
result = append(result, landlock.File(hgGlobalFile, "r"))
|
|
}
|
|
if exists(hgGlobalDir) {
|
|
result = append(result, landlock.Dir(hgGlobalDir, "r"))
|
|
}
|
|
if exists(urandom) {
|
|
result = append(result, landlock.File(urandom, "r"))
|
|
}
|
|
return result
|
|
}
|