bastion 0.53.2
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
//go:build !windows
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOpViewDecideKeepsTheBaseAndWhatIsDeclaredAndCoversTheRest(t *testing.T) {
|
||||
m := &opManifest{Effects: opEffects{Files: []string{"/srv/app/"}}, Reads: []string{"/etc/nginx/*.conf"}}
|
||||
segs := opViewSegments(opViewVisible(opViewDeclared(m)))
|
||||
for p, want := range map[string]opViewAction{
|
||||
"/usr/bin/python3": opViewKeep,
|
||||
"/usr": opViewDescend, // /usr/local/sbin and friends are covered
|
||||
"/usr/local/sbin": opViewHide,
|
||||
"/etc": opViewDescend,
|
||||
"/etc/passwd": opViewKeep,
|
||||
"/etc/shadow": opViewHide,
|
||||
"/etc/ssl": opViewDescend,
|
||||
"/etc/ssl/certs/ca.pem": opViewKeep,
|
||||
"/etc/ssl/private": opViewHide,
|
||||
"/etc/nginx": opViewDescend,
|
||||
"/etc/nginx/site.conf": opViewKeep,
|
||||
"/etc/nginx/site.key": opViewHide,
|
||||
"/srv": opViewDescend,
|
||||
"/srv/app": opViewKeep,
|
||||
"/srv/app/deep/file": opViewKeep,
|
||||
"/srv/other": opViewHide,
|
||||
"/root": opViewHide,
|
||||
"/home": opViewHide,
|
||||
"/var": opViewDescend, // for /var/tmp
|
||||
"/var/tmp": opViewKeep,
|
||||
"/var/lib": opViewHide,
|
||||
"/opt": opViewDescend, // for the op's own directory
|
||||
"/opt/bastion-op/run": opViewKeep,
|
||||
"/opt/acme": opViewHide,
|
||||
"/proc/1/environ": opViewKeep, // a fresh proc of the op's own pid namespace
|
||||
"/boot": opViewHide,
|
||||
"/etc/systemd/system/x.sh": opViewHide,
|
||||
} {
|
||||
if got := opViewDecide(p, segs); got != want {
|
||||
t.Errorf("%s: got %d, want %d", p, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpSensitivePathsAreRefusedAtUnderOrAboveAndThroughLinks(t *testing.T) {
|
||||
setupBox(t)
|
||||
for _, p := range []string{
|
||||
"/etc/shadow", "/etc/", "/etc/*", "/etc/ssh/sshd_config", "/etc/systemd/system/app.service",
|
||||
"/root/.git-credentials", "/home/alice/.ssh/authorized_keys", "/home/*/.docker/config.json",
|
||||
"/etc/wireguard/wg0.conf", "/var/lib/rancher/k3s/agent/client.key", "/etc/privatae/config.json",
|
||||
"/var/lib/", "/home/",
|
||||
} {
|
||||
sens, err := opSensitiveMatch(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sens == "" {
|
||||
t.Errorf("%s must reach a sensitive path", p)
|
||||
}
|
||||
// Refused either as sensitive or, above the record (/etc/, /var/lib/),
|
||||
// by the record's own rule first — refused either way.
|
||||
if err := effectOK(p); err == nil {
|
||||
t.Errorf("%s: effectOK must refuse it", p)
|
||||
}
|
||||
}
|
||||
for _, p := range []string{"/etc/nginx/", "/etc/*.conf", "/srv/app/", "/opt/acme/app/main.py", "/home/alice/site/"} {
|
||||
sens, err := opSensitiveMatch(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sens != "" {
|
||||
t.Errorf("%s reaches no credential store, got %s", p, sens)
|
||||
}
|
||||
}
|
||||
// A plain path that is a link onto a store the person named is refused as
|
||||
// what it resolves to.
|
||||
store := t.TempDir()
|
||||
cfg, _ := configDirPath()
|
||||
_ = os.MkdirAll(cfg, 0o700)
|
||||
if err := os.WriteFile(filepath.Join(cfg, opSensitiveFileName), []byte("# ours\n"+store+" # the vault\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
link := filepath.Join(t.TempDir(), "innocent")
|
||||
if err := os.Symlink(store, link); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sens, _ := opSensitiveMatch(link + "/token"); sens == "" {
|
||||
t.Fatal("a link onto a sensitive path is refused as what it names")
|
||||
}
|
||||
// A line that is not an absolute path refuses every op rather than drop
|
||||
// the store the person meant to name.
|
||||
_ = os.WriteFile(filepath.Join(cfg, opSensitiveFileName), []byte("relative/path\n"), 0o600)
|
||||
if _, err := opSensitiveMatch("/srv/app/"); err == nil {
|
||||
t.Fatal("a malformed sensitive_paths refuses every op")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpManifestReadsAreJudgedLikeEffects(t *testing.T) {
|
||||
setupBox(t)
|
||||
base := strings.Replace(opTestManifest, "modes:", "reads: [%s]\nmodes:", 1)
|
||||
for read, ok := range map[string]bool{
|
||||
`"/etc/nginx/site.conf"`: true,
|
||||
`"/etc/shadow"`: false,
|
||||
`"relative"`: false,
|
||||
`"/proc/1/environ"`: false,
|
||||
`"/"`: false,
|
||||
} {
|
||||
_, err := parseOpManifest([]byte(strings.Replace(strings.Replace(base, "%s/", "/srv/work/optest/x/", 1), "%s", read, 1)))
|
||||
if (err == nil) != ok {
|
||||
t.Errorf("reads %s: ok=%v err=%v", read, ok, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user