Skip to content

Commit 0e276a3

Browse files
committed
cmd/litewitness,cmd/witnessctl: remove -bastion flag, add set-bastions command
Fixes #64
1 parent 78bee1d commit 0e276a3

8 files changed

Lines changed: 112 additions & 46 deletions

File tree

NEWS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## Unreleased
2+
3+
### litewitness
4+
5+
- The `-bastion` flag was removed. Configure per-log bastions instead, for
6+
example with the new `set-bastions` witnessctl command.
7+
8+
### witnessctl
9+
10+
- Added `set-bastions` command, which adds the given bastion(s) to every log
11+
that has none configured (for example after `pull-logs`), or replaces the
12+
bastions of every log with `-all`.
13+
114
## v0.9.0
215

316
### torchwood

cmd/litewitness/README.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,17 @@ ssh-agent -a litewitness.sock
5252
SSH_AUTH_SOCK=litewitness.sock ssh-add litewitness.pem
5353
```
5454

55-
-bastion string
56-
address of the bastion(s) to reverse proxy through, comma separated, the first online one is selected
5755
-listen string
5856
address to listen for HTTP requests (default "localhost:7380")
5957
-no-listen
6058
do not open any listening socket, rely exclusively on bastions
6159

62-
Only one of `-bastion` or `-listen` must be specified, or `-no-listen` can be
63-
used to rely exclusively on per-log bastions configured in the database. The
64-
`-bastion` flag will cause litewitness to serve requests through a bastion
65-
reverse proxy (see below). The `-listen` flag will listen for HTTP requests on
66-
the specified port. (HTTPS needs to be terminated outside of litewitness.) The
67-
bastion flag is an optionally comma-separated list of bastions to try in order
68-
until one connects successfully. If the connection drops after establishing,
69-
litewitness exits.
60+
The `-listen` flag will listen for HTTP requests on the specified port. (HTTPS
61+
needs to be terminated outside of litewitness.) Alternatively, `-no-listen` can
62+
be used to rely exclusively on per-log bastions, which are configured in the
63+
database with the `add-bastion`, `del-bastion`, and `set-bastions` witnessctl
64+
commands (see below) and cause litewitness to serve requests through a bastion
65+
reverse proxy.
7066

7167
-obscurity
7268
enable obscurity mode (disable / and /logz and /metrics endpoints)
@@ -111,6 +107,15 @@ for a log. Multiple bastions can be configured for a log and will be used
111107
simultaneously. Bastion configuration is reloaded when litewitness receives a
112108
SIGHUP signal.
113109

110+
witnessctl set-bastions -db <path> -bastion <address:port>[,<address:port>] [-all]
111+
112+
The `set-bastions` command adds the given bastion(s) to every log that has none
113+
configured, for example after `pull-logs` adds new logs. With `-all`, it
114+
replaces the bastions of every log instead.
115+
116+
Use this if the witness is exposed to the internet only through a global
117+
bastion, for logs that don't have a per-log bastion endpoint.
118+
114119
witnessctl add-sigsum-log -db <path> -key <hex-encoded key>
115120

116121
The `add-sigsum-log` command is a helper that adds a new Sigsum log, computing

cmd/litewitness/litewitness.go

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"os"
2323
"os/signal"
2424
"slices"
25-
"strings"
2625
"syscall"
2726
"time"
2827

@@ -45,7 +44,6 @@ var sshAgentFlag = flag.String("ssh-agent", "litewitness.sock", "path to ssh-age
4544
var listenFlag = flag.String("listen", "localhost:7380", "address to listen for HTTP requests")
4645
var noListenFlag = flag.Bool("no-listen", false, "do not open any listening socket, rely exclusively on bastions")
4746
var keyFlag = flag.String("key", "", "SSH fingerprint (with SHA256: prefix) of the witness key")
48-
var bastionFlag = flag.String("bastion", "", "address of the bastion(s) to reverse proxy through, comma separated, the first online one is selected")
4947
var testCertFlag = flag.Bool("testcert", false, "use rootCA.pem for connections to the bastion")
5048
var obscurityFlag = flag.Bool("obscurity", false, "enable obscurity mode (disable / and /logz endpoints)")
5149
var listenMetricsFlag = flag.String("listen-metrics", "", "address to listen for metrics requests, instead of exposing them on the main listener")
@@ -204,7 +202,7 @@ func main() {
204202
retry := 0
205203
for {
206204
startTime := time.Now()
207-
err := connectToBastion(ctx, addr, bastionCert, srv, true)
205+
err := connectToBastion(ctx, addr, bastionCert, srv)
208206
duration := time.Since(startTime)
209207
slog.Warn("bastion connection failed", "bastion", addr, "duration", duration, "err", err)
210208

@@ -256,20 +254,7 @@ func main() {
256254
bastionSet.Configure(ctx, logBastions)
257255
})
258256

259-
if *bastionFlag != "" {
260-
go func() {
261-
for _, bastion := range strings.Split(*bastionFlag, ",") {
262-
err := connectToBastion(ctx, bastion, bastionCert, srv, false)
263-
if err == errBastionDisconnected {
264-
// Connection succeeded and then was interrupted. Restart to
265-
// let the scheduler apply any backoff, and then retry all bastions.
266-
e <- err
267-
return
268-
}
269-
}
270-
e <- errors.New("couldn't connect to any bastion")
271-
}()
272-
} else if !*noListenFlag {
257+
if !*noListenFlag {
273258
go func() {
274259
slog.Info("listening", "addr", *listenFlag)
275260
e <- srv.ListenAndServe()
@@ -418,7 +403,7 @@ func indexHandler(w *witness.Witness) http.HandlerFunc {
418403

419404
var errBastionDisconnected = errors.New("connection to bastion interrupted")
420405

421-
func connectToBastion(ctx context.Context, bastion string, cert tls.Certificate, srv *http.Server, logSpecific bool) error {
406+
func connectToBastion(ctx context.Context, bastion string, cert tls.Certificate, srv *http.Server) error {
422407
slog.Info("connecting to bastion", "bastion", bastion)
423408
dialCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
424409
defer cancel()
@@ -454,9 +439,7 @@ func connectToBastion(ctx context.Context, bastion string, cert tls.Certificate,
454439
}(ctx)
455440

456441
slog.Info("connected to bastion", "bastion", bastion)
457-
if logSpecific {
458-
ctx = witness.ContextWithBastion(ctx, bastion)
459-
}
442+
ctx = witness.ContextWithBastion(ctx, bastion)
460443
// TODO: find a way to surface the fatal error, especially since with
461444
// TLS 1.3 it might be that the bastion rejected the client certificate.
462445
(&http2.Server{

cmd/litewitness/testdata/bastion.txt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
# set up log
44
exec witnessctl add-sigsum-log -key=ffdc2d4d98e4124d3feaf788c0c2f9abfd796083d1f0495437f302ec79cf100f
55

6+
# set the bastions of all logs
7+
exec witnessctl set-bastions -bastion=0.0.0.0:443,localhost:8443
8+
stderr 'Added bastion "0.0.0.0:443" for log "sigsum.org/v1/tree/4d6d8825a6bb689d459628312889dfbb0bcd41b5211d9e1ce768b0ff0309e562"'
9+
stderr 'Added bastion "localhost:8443" for log "sigsum.org/v1/tree/4d6d8825a6bb689d459628312889dfbb0bcd41b5211d9e1ce768b0ff0309e562"'
10+
611
# start bastion
712
exec litebastion -tls-cert localhost.pem -tls-key localhost-key.pem -backends=backends.txt &litebastion&
813
waitfor localhost:8443
@@ -14,15 +19,12 @@ waitfor $SSH_AUTH_SOCK
1419
chmod 600 witness_key.pem
1520
exec ssh-add witness_key.pem
1621

17-
# fail to start litewitness
18-
! exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -bastion=0.0.0.0:443,localhost:8443 -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a
22+
# start litewitness, which can't connect until the backends are reloaded
23+
exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -no-listen -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a &litewitness&
1924

2025
# reload backends
2126
mv correct_backends.txt backends.txt
2227
killall -SIGHUP litebastion
23-
24-
# start litewitness
25-
exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -bastion=0.0.0.0:443,localhost:8443 -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a &litewitness&
2628
waitfor https://localhost:8443/e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a/
2729

2830
# add-checkpoint

cmd/litewitness/testdata/bastionlocal.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# set up log
44
exec witnessctl add-sigsum-log -key=ffdc2d4d98e4124d3feaf788c0c2f9abfd796083d1f0495437f302ec79cf100f
55

6+
# set the bastions of all logs
7+
exec witnessctl set-bastions -bastion=0.0.0.0:443,localhost:8444
8+
69
# start bastion
710
exec litebastion -tls-cert localhost.pem -tls-key localhost-key.pem -backends=backends.txt -listen localhost:8444 -listen-http 8080 &litebastion&
811
waitfor localhost:8444
@@ -14,15 +17,12 @@ waitfor $SSH_AUTH_SOCK
1417
chmod 600 witness_key.pem
1518
exec ssh-add witness_key.pem
1619

17-
# fail to start litewitness
18-
! exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -bastion=0.0.0.0:443,localhost:8444 -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a
20+
# start litewitness, which can't connect until the backends are reloaded
21+
exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -no-listen -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a &litewitness&
1922

2023
# reload backends
2124
mv correct_backends.txt backends.txt
2225
killall -SIGHUP litebastion
23-
24-
# start litewitness
25-
exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -bastion=0.0.0.0:443,localhost:8444 -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a &litewitness&
2626
waitfor http://localhost:8080/e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a/
2727

2828
# add-checkpoint to bastion interface

cmd/litewitness/testdata/bastionlocalhost.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
# set up log
44
exec witnessctl add-sigsum-log -key=ffdc2d4d98e4124d3feaf788c0c2f9abfd796083d1f0495437f302ec79cf100f
55

6+
# set the bastions of all logs
7+
exec witnessctl set-bastions -bastion=0.0.0.0:443,localhost:8445
8+
69
# start bastion with host:port -listen-http
710
exec litebastion -tls-cert localhost.pem -tls-key localhost-key.pem -backends=backends.txt -listen localhost:8445 -listen-http localhost:8081 &litebastion&
811
waitfor localhost:8445
@@ -14,15 +17,12 @@ waitfor $SSH_AUTH_SOCK
1417
chmod 600 witness_key.pem
1518
exec ssh-add witness_key.pem
1619

17-
# fail to start litewitness
18-
! exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -bastion=0.0.0.0:443,localhost:8445 -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a
20+
# start litewitness, which can't connect until the backends are reloaded
21+
exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -no-listen -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a &litewitness&
1922

2023
# reload backends
2124
mv correct_backends.txt backends.txt
2225
killall -SIGHUP litebastion
23-
24-
# start litewitness
25-
exec litewitness -ssh-agent=$SSH_AUTH_SOCK -name=example.com/witness -bastion=0.0.0.0:443,localhost:8445 -testcert -key=e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a &litewitness&
2626
waitfor http://localhost:8081/e933707e0e36c30f01d94b5d81e742da373679d88eb0f85f959ccd80b83b992a/
2727

2828
# add-checkpoint to bastion interface

cmd/litewitness/testdata/loglist.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,23 @@ exec witnessctl list-logs
2525
cmp stdout list-logs.2.jsonl
2626
! stderr .
2727

28+
# set the bastion of logs that don't have one
29+
exec witnessctl set-bastions -bastion bastion-3.example.org:666
30+
stderr 'Added bastion "bastion-3.example.org:666" for log "example.com/foo"'
31+
exec witnessctl list-logs
32+
cmp stdout list-logs.3.jsonl
33+
! stderr .
34+
35+
# running it again is a no-op
36+
exec witnessctl set-bastions -bastion bastion-3.example.org:666
37+
! stderr .
38+
39+
# override the bastions of all logs
40+
exec witnessctl set-bastions -all -bastion bastion-4.example.org:666
41+
exec witnessctl list-logs
42+
cmp stdout list-logs.4.jsonl
43+
! stderr .
44+
2845
-- log_list.0 --
2946
#
3047
# List: 10qps-100klogs
@@ -82,3 +99,11 @@ origin sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4
8299
{"origin":"example.com/foo","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/2ef59132082631d13e353b5ae49b22bc51a9bd59f41a2d570960a9658c1ed151+e2137795+ATp+37IPHc3SbPGzFMyZmPTOUlClk6PYPH+Ce5JiCb/h"],"bastions":[]}
83100
{"origin":"sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4cd2e9b8702","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4cd2e9b8702+9bc54c7f+AVv6q3xDaHxI2aTemqEb7W6ZcbO7QbTqTr20thOqfqsw"],"bastions":[]}
84101
{"origin":"sigsum.org/v1/tree/fae7fd8f084f9e7a1482162da8a3e52b08e6c1bac74ab831d00eb5c983b84120","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/fae7fd8f084f9e7a1482162da8a3e52b08e6c1bac74ab831d00eb5c983b84120+7f693d84+AUlxeri80AO7/4j/+OGo+5M2Sud0ktFg34uZl2fZnjJT"],"bastions":["bastion-1.example.org:666","bastion-2.example.org:666"]}
102+
-- list-logs.3.jsonl --
103+
{"origin":"example.com/foo","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/2ef59132082631d13e353b5ae49b22bc51a9bd59f41a2d570960a9658c1ed151+e2137795+ATp+37IPHc3SbPGzFMyZmPTOUlClk6PYPH+Ce5JiCb/h"],"bastions":["bastion-3.example.org:666"]}
104+
{"origin":"sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4cd2e9b8702","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4cd2e9b8702+9bc54c7f+AVv6q3xDaHxI2aTemqEb7W6ZcbO7QbTqTr20thOqfqsw"],"bastions":["bastion-3.example.org:666"]}
105+
{"origin":"sigsum.org/v1/tree/fae7fd8f084f9e7a1482162da8a3e52b08e6c1bac74ab831d00eb5c983b84120","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/fae7fd8f084f9e7a1482162da8a3e52b08e6c1bac74ab831d00eb5c983b84120+7f693d84+AUlxeri80AO7/4j/+OGo+5M2Sud0ktFg34uZl2fZnjJT"],"bastions":["bastion-1.example.org:666","bastion-2.example.org:666"]}
106+
-- list-logs.4.jsonl --
107+
{"origin":"example.com/foo","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/2ef59132082631d13e353b5ae49b22bc51a9bd59f41a2d570960a9658c1ed151+e2137795+ATp+37IPHc3SbPGzFMyZmPTOUlClk6PYPH+Ce5JiCb/h"],"bastions":["bastion-4.example.org:666"]}
108+
{"origin":"sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4cd2e9b8702","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/f48d4a1d0c6370ec189dc537f648ef3bb347b012fbd3c899a630a4cd2e9b8702+9bc54c7f+AVv6q3xDaHxI2aTemqEb7W6ZcbO7QbTqTr20thOqfqsw"],"bastions":["bastion-4.example.org:666"]}
109+
{"origin":"sigsum.org/v1/tree/fae7fd8f084f9e7a1482162da8a3e52b08e6c1bac74ab831d00eb5c983b84120","size":0,"root_hash":"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=","keys":["sigsum.org/v1/tree/fae7fd8f084f9e7a1482162da8a3e52b08e6c1bac74ab831d00eb5c983b84120+7f693d84+AUlxeri80AO7/4j/+OGo+5M2Sud0ktFg34uZl2fZnjJT"],"bastions":["bastion-4.example.org:666"]}

cmd/witnessctl/witnessctl.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func usage() {
2929
fmt.Println(" del-key -db <path> -origin <origin> -key <verifier key>")
3030
fmt.Println(" add-bastion -db <path> -origin <origin> -bastion <address:port>")
3131
fmt.Println(" del-bastion -db <path> -origin <origin> -bastion <address:port>")
32+
fmt.Println(" set-bastions -db <path> -bastion <address:port>[,<address:port>] [-all]")
3233
fmt.Println(" add-sigsum-log -db <path> -key <hex-encoded key>")
3334
fmt.Println(" pull-logs -db <path> -source <witness url> [-verbose]")
3435
fmt.Println(" list-logs -db <path>")
@@ -83,6 +84,17 @@ func main() {
8384
delBastion(db, *originFlag, *bastionFlag)
8485
log.Printf("Deleted bastion %q for log %q.", *bastionFlag, *originFlag)
8586

87+
case "set-bastions":
88+
bastionFlag := fs.String("bastion", "", "comma-separated address:port list")
89+
allFlag := fs.Bool("all", false, "replace the bastions of all logs, not just those without any")
90+
fs.Parse(os.Args[2:])
91+
bastions := strings.Split(*bastionFlag, ",")
92+
for _, bastion := range bastions {
93+
checkBastion(bastion)
94+
}
95+
db := openDB(*dbFlag)
96+
setBastions(db, bastions, *allFlag)
97+
8698
case "add-sigsum-log":
8799
keyFlag := fs.String("key", "", "hex-encoded key")
88100
fs.Parse(os.Args[2:])
@@ -183,6 +195,32 @@ func delBastion(db *sqlite.Conn, origin string, bastion string) {
183195
}
184196
}
185197

198+
func setBastions(db *sqlite.Conn, bastions []string, all bool) {
199+
query := `SELECT origin FROM log WHERE NOT EXISTS
200+
(SELECT 1 FROM bastion WHERE bastion.origin = log.origin)`
201+
if all {
202+
query = "SELECT origin FROM log"
203+
}
204+
var origins []string
205+
if err := sqlitexExec(db, query, func(stmt *sqlite.Stmt) error {
206+
origins = append(origins, stmt.ColumnText(0))
207+
return nil
208+
}); err != nil {
209+
log.Fatalf("Error listing logs: %v", err)
210+
}
211+
if all {
212+
if err := sqlitexExec(db, "DELETE FROM bastion", nil); err != nil {
213+
log.Fatalf("Error deleting bastions: %v", err)
214+
}
215+
}
216+
for _, origin := range origins {
217+
for _, bastion := range bastions {
218+
addBastion(db, origin, bastion)
219+
log.Printf("Added bastion %q for log %q.", bastion, origin)
220+
}
221+
}
222+
}
223+
186224
func addSigsumLog(db *sqlite.Conn, keyFlag string) {
187225
if len(keyFlag) != sigsum.PublicKeySize*2 {
188226
log.Fatal("Key must be 32 hex-encoded bytes.")

0 commit comments

Comments
 (0)