aboutsummaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2025-03-25 17:02:48 -0400
committerGitHub <noreply@github.com>2025-03-25 17:02:48 -0400
commit4155719422d416fb9af8cc6266697ebe16264538 (patch)
tree5b788492a2478d7bbdc0d118d94b344b61e5fb77 /cmd
parentf29a200f09ca3f720266164421304ed28de57dc6 (diff)
downloadanubis-4155719422d416fb9af8cc6266697ebe16264538.tar.xz
anubis-4155719422d416fb9af8cc6266697ebe16264538.zip
cmd/anubis: allow setting key bytes in flag/envvar (#97)
* cmd/anubis: allow setting key bytes in flag/envvar Docs are updated to generate a random key on load and when people press the recycle button. Signed-off-by: Xe Iaso <me@xeiaso.net> * review feedback fixups Signed-off-by: Xe Iaso <me@xeiaso.net> * Update cmd/anubis/main.go Signed-off-by: Xe Iaso <me@xeiaso.net> * Apply suggestions from code review Co-authored-by: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Signed-off-by: Xe Iaso <me@xeiaso.net> --------- Signed-off-by: Xe Iaso <me@xeiaso.net> Co-authored-by: Ryan Cao <70191398+ryanccn@users.noreply.github.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/anubis/main.go57
1 files changed, 45 insertions, 12 deletions
diff --git a/cmd/anubis/main.go b/cmd/anubis/main.go
index e493931..551ed61 100644
--- a/cmd/anubis/main.go
+++ b/cmd/anubis/main.go
@@ -2,6 +2,9 @@ package main
import (
"context"
+ "crypto/ed25519"
+ "crypto/rand"
+ "encoding/hex"
"flag"
"fmt"
"log"
@@ -28,20 +31,34 @@ import (
)
var (
- bind = flag.String("bind", ":8923", "network address to bind HTTP to")
- bindNetwork = flag.String("bind-network", "tcp", "network family to bind HTTP to, e.g. unix, tcp")
- challengeDifficulty = flag.Int("difficulty", anubis.DefaultDifficulty, "difficulty of the challenge")
- metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to")
- metricsBindNetwork = flag.String("metrics-bind-network", "tcp", "network family for the metrics server to bind to")
- socketMode = flag.String("socket-mode", "0770", "socket mode (permissions) for unix domain sockets.")
- robotsTxt = flag.Bool("serve-robots-txt", false, "serve a robots.txt file that disallows all robots")
- policyFname = flag.String("policy-fname", "", "full path to anubis policy document (defaults to a sensible built-in policy)")
- slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)")
- target = flag.String("target", "http://localhost:3923", "target to reverse proxy to")
- healthcheck = flag.Bool("healthcheck", false, "run a health check against Anubis")
- debugXRealIPDefault = flag.String("debug-x-real-ip-default", "", "If set, replace empty X-Real-Ip headers with this value, useful only for debugging Anubis and running it locally")
+ bind = flag.String("bind", ":8923", "network address to bind HTTP to")
+ bindNetwork = flag.String("bind-network", "tcp", "network family to bind HTTP to, e.g. unix, tcp")
+ challengeDifficulty = flag.Int("difficulty", anubis.DefaultDifficulty, "difficulty of the challenge")
+ ed25519PrivateKeyHex = flag.String("ed25519-private-key-hex", "", "private key used to sign JWTs, if not set a random one will be assigned")
+ metricsBind = flag.String("metrics-bind", ":9090", "network address to bind metrics to")
+ metricsBindNetwork = flag.String("metrics-bind-network", "tcp", "network family for the metrics server to bind to")
+ socketMode = flag.String("socket-mode", "0770", "socket mode (permissions) for unix domain sockets.")
+ robotsTxt = flag.Bool("serve-robots-txt", false, "serve a robots.txt file that disallows all robots")
+ policyFname = flag.String("policy-fname", "", "full path to anubis policy document (defaults to a sensible built-in policy)")
+ slogLevel = flag.String("slog-level", "INFO", "logging level (see https://pkg.go.dev/log/slog#hdr-Levels)")
+ target = flag.String("target", "http://localhost:3923", "target to reverse proxy to")
+ healthcheck = flag.Bool("healthcheck", false, "run a health check against Anubis")
+ debugXRealIPDefault = flag.String("debug-x-real-ip-default", "", "If set, replace empty X-Real-Ip headers with this value, useful only for debugging Anubis and running it locally")
)
+func keyFromHex(value string) (ed25519.PrivateKey, error) {
+ keyBytes, err := hex.DecodeString(value)
+ if err != nil {
+ return nil, fmt.Errorf("supplied key is not hex-encoded: %w", err)
+ }
+
+ if len(keyBytes) != ed25519.SeedSize {
+ return nil, fmt.Errorf("supplied key is not %d bytes long, got %d bytes", ed25519.SeedSize, len(keyBytes))
+ }
+
+ return ed25519.NewKeyFromSeed(keyBytes), nil
+}
+
func doHealthCheck() error {
resp, err := http.Get("http://localhost" + *metricsBind + "/metrics")
if err != nil {
@@ -156,10 +173,26 @@ func main() {
}
fmt.Println()
+ var priv ed25519.PrivateKey
+ if *ed25519PrivateKeyHex == "" {
+ _, priv, err = ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ log.Fatalf("failed to generate ed25519 key: %v", err)
+ }
+
+ slog.Warn("generating random key, Anubis will have strange behavior when multiple instances are behind the same load balancer target, for more information: see https://anubis.techaro.lol/docs/admin/installation#key-generation")
+ } else {
+ priv, err = keyFromHex(*ed25519PrivateKeyHex)
+ if err != nil {
+ log.Fatalf("failed to parse and validate ED25519_PRIVATE_KEY_HEX: %v", err)
+ }
+ }
+
s, err := libanubis.New(libanubis.Options{
Next: rp,
Policy: policy,
ServeRobotsTXT: *robotsTxt,
+ PrivateKey: priv,
})
if err != nil {
log.Fatalf("can't construct libanubis.Server: %v", err)