Files
privatae-bastion/client-go/ops_action_local_test.go
Privatae 01889e2a48
ci / personal-data (push) Successful in 4s
ci / test (push) Successful in 4m5s
ci / fuzz (push) Successful in 4m10s
bastion 0.58.0
2026-10-29 15:54:51 +00:00

123 lines
4.6 KiB
Go

//go:build !windows
package main
import (
"crypto/ed25519"
"encoding/base64"
"os"
"strings"
"testing"
"time"
)
// An action op on a person's own machine (local, unanchored) reaches the
// public internet and nothing around the machine; an anchored fleet keeps its
// private destinations, because its ship steps reach private control planes.
// The addresses are documentation and private examples, invented here.
// localOpBox: a local machine, anchored by nobody, with one pairing whose
// pairing dir pins a signing key we hold.
func localOpBox(t *testing.T) (dcn string, priv ed25519.PrivateKey) {
t.Helper()
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
p, _ := modePath()
if err := os.WriteFile(p, []byte(`{"mode":"local"}`), 0o600); err != nil {
t.Fatal(err)
}
writePairing(t, tAnchor)
if currentAnchor() != nil {
t.Fatal("the local box must not be anchored")
}
dcn = t.TempDir()
pub, priv, _ := ed25519.GenerateKey(nil)
if err := dcnSaveFile(dcn, &dcnGrantFile{Stores: map[string]dcnGrantRec{},
VerifyPubkey: base64.StdEncoding.EncodeToString(pub)}); err != nil {
t.Fatal(err)
}
return dcn, priv
}
// actionBundle: an unprivileged action op declaring one destination.
func actionBundle(dest string) []opFile {
man := `name: optest-reach
version: 1.0.0
summary: An action op that reaches one destination.
kind: action
target: machine
privilege: user
interpreter: /bin/sh
time_limit: 30
destinations: ["` + dest + `"]
modes: [dry_run, apply, verify]
undo: none
`
return []opFile{
{Path: "op.yaml", Mode: 0o644, B64: base64.StdEncoding.EncodeToString([]byte(man))},
{Path: "run", Mode: 0o755, B64: base64.StdEncoding.EncodeToString([]byte("#!/bin/sh\ntrue\n"))},
}
}
// syncAction drives op_sync for an action op declaring dest, under op_run
// terms signed by priv; it returns the op's output, its error text and code.
func syncAction(t *testing.T, dcn string, priv ed25519.PrivateKey, dest string) (string, string, int) {
t.Helper()
files := actionBundle(dest)
sha, err := opDirDigest(files)
if err != nil {
t.Fatal(err)
}
terms := opTerm(opKindRun, sha, `{}`, "", 1, time.Hour, "user")
terms["op"] = "optest-reach"
pair := signTermsPair(t, priv, terms)
return driveJob(t, tAnchor, mgmtJob{Op: "op_sync", Args: append(pair, bundleB64(files))}, "", dcn)
}
// RESULT: red before opLocalNetworkDest — a local box held an op declaring
// 10.0.0.2:80 (a home network's address), and its apply would have reached it.
func TestALocalBoxRefusesAnActionOpThatDeclaresAPrivateNetwork(t *testing.T) {
dcn, priv := localOpBox(t)
for _, dest := range []string{
"10.0.0.2:80", // RFC 1918
"192.168.1.2:443", // a home router's range
"172.16.0.2:8080", // RFC 1918
"100.64.0.2:22", // carrier NAT, and VPN meshes that use it
"[fd00::2]:80", // ULA
"[64:ff9b::a00:2]:80", // 10.0.0.2 through NAT64
"[2002:a00:2::1]:80", // 10.0.0.2 through 6to4
"198.18.0.2:80", // benchmarking, never a public host
} {
out, errOut, code := syncAction(t, dcn, priv, dest)
if code == 0 || strings.Contains(out, `"held"`) {
t.Errorf("%s: a local box held an op declaring it: %d %s %s", dest, code, out, errOut)
continue
}
if !strings.Contains(errOut, "private network") || !strings.Contains(errOut, "install a bastion on that computer") {
t.Errorf("%s: the refusal must say why and what to do instead: %q", dest, errOut)
}
}
// The public internet is still a destination.
if out, errOut, code := syncAction(t, dcn, priv, "203.0.113.10:443"); code != 0 || !strings.Contains(out, `"held"`) {
t.Fatalf("a public destination is held on a local box: %d %s %s", code, out, errOut)
}
// A name is judged at apply, by every address it resolves to
// (opResolveDests); at sync it is only a name.
if out, errOut, code := syncAction(t, dcn, priv, "forge.example.com:443"); code != 0 || !strings.Contains(out, `"held"`) {
t.Fatalf("a destination by name is held on a local box: %d %s %s", code, out, errOut)
}
}
func TestAnAnchoredFleetKeepsItsPrivateDestinations(t *testing.T) {
dcn, priv := opTestBox(t)
enrollFactor(t, dcn)
for _, dest := range []string{"10.0.0.2:80", "100.64.0.2:6443", "[fd00::2]:80"} {
if out, errOut, code := syncAction(t, dcn, priv, dest); code != 0 || !strings.Contains(out, `"held"`) {
t.Errorf("%s: an anchored box holds a ship step to a private control plane: %d %s %s", dest, code, out, errOut)
}
}
// What every box refuses stays refused.
if _, errOut, code := syncAction(t, dcn, priv, "127.0.0.1:80"); code == 0 || !strings.Contains(errOut, "loopback") {
t.Fatalf("loopback stays refused on an anchored box: %d %q", code, errOut)
}
}