diff --git a/cmd/tailproxy/README.md b/cmd/tailproxy/README.md index 23283817ddd99cbf8b264c6c13ab8e6ae7dad5a2..9c3411f19e23477e6d78389ba772970ea3b818d0 100644 --- a/cmd/tailproxy/README.md +++ b/cmd/tailproxy/README.md @@ -6,12 +6,9 @@ ## Config - `hostname`: The tailscale hostname, i.e. "git" would let you use "http://git" assuming you have MagicDNC enabled - `auth-key`: Tailscale/tsnet auth key for authenticating with Tailscale -- `auth-key-file`: Path to a file containing a Tailscale/tsnet auth key for authenticating with Tailscale - `funnel`: Whether to enable as a Tailscale funnel - `data-dir`: The tsnet data directory, where things like authentication information/tsnet logs live (default is a `.tailproxy` dir created in the working directory) - `port`: The port to *proxy* - -[schema.cue](./schema.cue) contains the source of truth for configuration. ## Nix Usage @@ -30,12 +27,10 @@ { services.tailproxy = { "myapp" = { enable = true; - settings = { - hostname = "myapp"; - auth-key = ""; # https://login.tailscale.com/admin/settings/keys - funnel = false; - port = 1234; # The port "myapp" is running on - }; + hostname = "myapp"; + auth-key = ""; # https://login.tailscale.com/admin/settings/keys + funnel = false; + port = 1234; }; "otherapp" = { # ... diff --git a/cmd/tailproxy/args.gen.go b/cmd/tailproxy/args.gen.go deleted file mode 100644 index c15baafe5bd27436a6b2aa05afaa9b1949b7bf3a..0000000000000000000000000000000000000000 --- a/cmd/tailproxy/args.gen.go +++ /dev/null @@ -1,61 +0,0 @@ -// Code generated by gen from schema.cue; DO NOT EDIT. - -package main - -import ( - "errors" - "flag" - "fmt" -) - -type cliArgs struct { - // Tailscale hostname - Hostname string - // Tailscale one-time auth key - AuthKey string - // Path to a file containing a Tailscale auth key (takes precedence over auth-key) - AuthKeyFile string - // Expose on Tailscale funnel - Funnel bool - // tsnet data directory - DataDir string - // Host to proxy - Host string - // Port to proxy - Port int -} - -// defaultArgs returns the defaults from schema.cue. -func defaultArgs() cliArgs { - return cliArgs{ - DataDir: ".tailproxy", - Host: "localhost", - } -} - -// registerFlags defines a flag for every field of c, using c's current -// values as flag defaults. -func registerFlags(fs *flag.FlagSet, c *cliArgs) { - fs.StringVar(&c.Hostname, "hostname", c.Hostname, "Tailscale hostname") - fs.StringVar(&c.AuthKey, "auth-key", c.AuthKey, "Tailscale one-time auth key") - fs.StringVar(&c.AuthKeyFile, "auth-key-file", c.AuthKeyFile, "Path to a file containing a Tailscale auth key (takes precedence over auth-key)") - fs.BoolVar(&c.Funnel, "funnel", c.Funnel, "Expose on Tailscale funnel") - fs.StringVar(&c.DataDir, "data-dir", c.DataDir, "tsnet data directory") - fs.StringVar(&c.Host, "host", c.Host, "Host to proxy") - fs.IntVar(&c.Port, "port", c.Port, "Port to proxy") -} - -// validate checks c against the constraints in schema.cue. -func (c *cliArgs) validate() error { - var errs []error - if c.DataDir == "" { - errs = append(errs, errors.New("data-dir: must not be empty")) - } - if c.Port < 1 { - errs = append(errs, fmt.Errorf("port: must be >= 1, got %v", c.Port)) - } - if c.Port > 65535 { - errs = append(errs, fmt.Errorf("port: must be <= 65535, got %v", c.Port)) - } - return errors.Join(errs...) -} diff --git a/cmd/tailproxy/main.go b/cmd/tailproxy/main.go index 5f2f86e8c4d3488d89e42ff4ee2a4768e2348bef..0980a332edeb205a69b83aeb19d4d1b38fa21650 100644 --- a/cmd/tailproxy/main.go +++ b/cmd/tailproxy/main.go @@ -1,7 +1,5 @@ package main -//go:generate go tool gen --schema schema.cue --go args.gen.go --nix ../../nix/options.gen.nix - import ( "flag" "fmt" @@ -9,30 +7,35 @@ "net/http" "net/http/httputil" "net/url" "os" - "strings" "go.jolheiser.com/tailroute" ) +// Args are commandline arguments +type Args struct { + Hostname string + AuthKey string + Funnel bool + DataDir string + Host string + Port int +} + func main() { + args := &Args{ + DataDir: ".tailproxy", + Host: "localhost", + } fs := flag.NewFlagSet("tailproxy", flag.ExitOnError) - args := defaultArgs() - registerFlags(fs, &args) + fs.StringVar(&args.Hostname, "hostname", args.Hostname, "Tailscale hostname") + fs.StringVar(&args.AuthKey, "auth-key", args.AuthKey, "Tailscale auth key") + fs.BoolVar(&args.Funnel, "funnel", args.Funnel, "Expose on Tailscale funnel") + fs.StringVar(&args.DataDir, "data-dir", args.DataDir, "tsnet data directory") + fs.StringVar(&args.Host, "host", args.Host, "Host to proxy") + fs.IntVar(&args.Port, "port", args.Port, "Port to proxy") if err := fs.Parse(os.Args[1:]); err != nil { panic(err) } - if err := args.validate(); err != nil { - panic(err) - } - - if args.AuthKeyFile != "" { - key, err := os.ReadFile(args.AuthKeyFile) - if err != nil { - panic(err) - } - args.AuthKey = strings.TrimSpace(string(key)) - } - os.Setenv("TS_AUTHKEY", args.AuthKey) proxyURL, err := url.Parse(fmt.Sprintf("http://%s:%d", args.Host, args.Port)) diff --git a/cmd/tailproxy/schema.cue b/cmd/tailproxy/schema.cue deleted file mode 100644 index 63e2e7b8c463e4fce43877036585346c41150376..0000000000000000000000000000000000000000 --- a/cmd/tailproxy/schema.cue +++ /dev/null @@ -1,25 +0,0 @@ -package tailproxy - -#Path: string & !="" -#Port: int & >0 & <65536 @nix(type=types.port) - -// Tailscale hostname -hostname: string - -// Tailscale one-time auth key -"auth-key": string | *"" - -// Path to a file containing a Tailscale auth key (takes precedence over auth-key) -"auth-key-file": string | *"" - -// Expose on Tailscale funnel -funnel: bool | *false - -// tsnet data directory -"data-dir": #Path | *".tailproxy" @nix(default="/var/lib/tailproxy") - -// Host to proxy -host: string | *"localhost" - -// Port to proxy -port: #Port diff --git a/go.mod b/go.mod index b32fabff9229a4cd978fe5fd68a4230d04194726..990f30fce1a83afc24afa03404210afcb0a76358 100644 --- a/go.mod +++ b/go.mod @@ -5,15 +5,11 @@ require tailscale.com v1.90.6 require ( - cuelabs.dev/go/oci/ociregistry v0.0.0-20260601085548-328ff8e2c943 // indirect - cuelang.org/go v0.17.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect - github.com/cockroachdb/apd/v3 v3.2.3 // indirect - github.com/coder/websocket v1.8.14 // indirect + github.com/coder/websocket v1.8.12 // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect - github.com/emicklei/proto v1.14.3 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/gaissmai/bart v0.18.0 // indirect github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect @@ -28,13 +24,7 @@ github.com/klauspost/compress v1.17.11 // indirect github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/socket v0.5.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.1 // indirect - github.com/pelletier/go-toml/v2 v2.3.1 // indirect github.com/prometheus-community/pro-bing v0.4.0 // indirect - github.com/protocolbuffers/txtpbfmt v0.0.0-20260420112717-c39628bde8b5 // indirect - github.com/rogpeppe/go-internal v1.15.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect @@ -44,23 +34,18 @@ github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect github.com/x448/float16 v0.8.4 // indirect - go.jolheiser.com/gen v0.0.0-20260924184449-e423ae92176c // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.53.0 // indirect + golang.org/x/crypto v0.38.0 // indirect golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/net v0.56.0 // indirect - golang.org/x/oauth2 v0.36.0 // indirect - golang.org/x/sync v0.21.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.38.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.14.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect golang.org/x/time v0.11.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/protobuf v1.36.3 // indirect gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect ) - -tool go.jolheiser.com/gen diff --git a/go.mod.sri b/go.mod.sri index acc454f4e7dd600771173ae02df242f8f022a53f..f67f6c88f6e9239c89b3a6e3f4239e7a934654db 100644 --- a/go.mod.sri +++ b/go.mod.sri @@ -1 +1 @@ -sha256-rcidwYILhKnuWYnIEYwzT6zxmbB4gBpSC/Vm4Nqp5so= \ No newline at end of file +sha256-QN+L3mZy2N960LSMZH1WhqFAVpYa1lfo0NqR2ZWx50s= \ No newline at end of file diff --git a/go.sum b/go.sum index 839c1195c61e7acbec88ce3095a36eea5974433f..e56a81ea9666d65ce7e3a48bd1e6319e3334fed5 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ 9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f h1:1C7nZuxUMNz7eiQALRfiqNOm04+m3edWlRff/BYHf0Q= 9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f/go.mod h1:hHyrZRryGqVdqrknjq5OWDLGCTJ2NeEvtrpR96mjraM= -cuelabs.dev/go/oci/ociregistry v0.0.0-20260601085548-328ff8e2c943 h1:XUtzi/yWlmuy8V6kkmVbbmirmUqcFe9Ce3gmEaHXf1Q= -cuelabs.dev/go/oci/ociregistry v0.0.0-20260601085548-328ff8e2c943/go.mod h1:WjmQxb+W6nVNCgj8nXrF24lIz95AHwnSl36tpjDZSU8= -cuelang.org/go v0.17.1 h1:liOkxZDqTHrzq0USJX+6bMYOZ5PSf+wzvQr15AHpDCQ= -cuelang.org/go v0.17.1/go.mod h1:xlly/o1wSLvxOsi5vkQGieU0rLOt7TvUIizOFtnxHRU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= @@ -46,10 +42,8 @@ github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= -github.com/cockroachdb/apd/v3 v3.2.3 h1:4Zx+I3R35bFXMnltzmjP79i2cravE4jTRL6ps9Aux80= -github.com/cockroachdb/apd/v3 v3.2.3/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= -github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= -github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= +github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= +github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoidf0MdVc= @@ -62,8 +56,6 @@ github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= -github.com/emicklei/proto v1.14.3 h1:zEhlzNkpP8kN6utonKMzlPfIvy82t5Kb9mufaJxSe1Q= -github.com/emicklei/proto v1.14.3/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -76,8 +68,6 @@ github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-quicktest/qt v1.102.0 h1:HSQxCeh5YZH3EL3W39ixjtyaEhcWSXQHtHnMBzSs474= -github.com/go-quicktest/qt v1.102.0/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI= github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo= github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= @@ -116,10 +106,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= @@ -132,18 +118,10 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= -github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= -github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= -github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= -github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc= -github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= @@ -154,10 +132,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/protocolbuffers/txtpbfmt v0.0.0-20260420112717-c39628bde8b5 h1:Mckui8l+Wqz2Ve7XQvsE8SbHNmDWu8NA7Xce5NFJ/kM= -github.com/protocolbuffers/txtpbfmt v0.0.0-20260420112717-c39628bde8b5/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= -github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc= -github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= @@ -192,52 +168,45 @@ github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -go.jolheiser.com/gen v0.0.0-20260924184449-e423ae92176c h1:gApMH2cOXXjpYYL9Ca8TgxjUrqloexUCFykO4yfH6sg= -go.jolheiser.com/gen v0.0.0-20260924184449-e423ae92176c/go.mod h1:aAl7GQRWwrUZ2PvefV97hG4fWsQei2c6vzK7ghD0dMQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= -go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek= go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= -golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= -golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= -golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= -golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= -golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= -golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= -golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= -golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= diff --git a/nix/module.nix b/nix/module.nix index d1038b80194f9da9c0edd2332f984dfeaffb62ac..4c8391307d156b2f4c72ee8b714f85cc48151f82 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -7,27 +7,10 @@ }: let cfg = config.services.tailproxy; pkg = pkgs.callPackage ./tailproxy.nix { inherit pkgs; }; - toArgs = - settings: - let - fmt = v: if lib.isBool v then lib.boolToString v else toString v; - in - lib.escapeShellArgs ( - lib.concatLists ( - lib.mapAttrsToList (k: v: map (x: "--${k}=${fmt x}") (lib.toList v)) ( - lib.filterAttrs (_: v: v != null) settings - ) - ) - ); instanceOptions = - { name, ... }: + { name, config, ... }: let - inherit (lib) - mkEnableOption - mkOption - mkDefault - types - ; + inherit (lib) mkEnableOption mkOption types; in { options = { @@ -39,20 +22,41 @@ description = "tailproxy package to use"; default = pkg; }; - settings = lib.mkOption { - type = lib.types.submodule { - options = import ./options.gen.nix { inherit lib; }; - }; - default = { }; - description = "${name} settings, passed to tailproxy as command-line flags."; + hostname = mkOption { + type = types.str; + default = name; + description = "Tailscale hostname"; + }; + + authKey = mkOption { + type = types.nullOr types.str; + default = null; + description = "Tailscale auth key"; + }; + + funnel = mkOption { + type = types.bool; + default = false; + description = "Expose on Tailscale funnel"; }; dataDir = mkOption { type = types.str; - description = "tsnet data directory (takes precedence over the settings data-dir)"; + description = "tsnet data directory"; default = "/var/lib/tailproxy-${name}"; }; + host = mkOption { + type = types.str; + description = "Host to proxy"; + default = "localhost"; + }; + + port = mkOption { + type = types.int; + description = "Port to proxy"; + }; + user = mkOption { type = types.str; default = "tailproxy-${name}"; @@ -65,7 +69,6 @@ default = "tailproxy-${name}"; description = "Group account under which tailproxy runs"; }; }; - config.settings.data-dir = mkDefault "/var/lib/tailproxy-${name}"; }; in { @@ -84,7 +87,21 @@ description = "tailproxy-${name}"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - ExecStart = "${instanceCfg.package}/bin/tailproxy ${toArgs instanceCfg.settings}"; + ExecStart = + let + args = + lib.optionals (instanceCfg.authKey != null) [ + "--auth-key=${instanceCfg.authKey}" + ] + ++ [ + (lib.optionalString instanceCfg.funnel "--funnel") + "--hostname=${instanceCfg.hostname}" + "--host=${instanceCfg.host}" + "--port=${builtins.toString instanceCfg.port}" + "--data-dir=${instanceCfg.dataDir}" + ]; + in + "${instanceCfg.package}/bin/tailproxy ${lib.concatStringsSep " " args}"; User = instanceCfg.user; Restart = "on-failure"; }; @@ -96,7 +113,7 @@ name: instanceCfg: lib.nameValuePair instanceCfg.user { isSystemUser = true; group = instanceCfg.user; - home = instanceCfg.settings.data-dir; + home = instanceCfg.dataDir; createHome = true; } ) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg); diff --git a/nix/options.gen.nix b/nix/options.gen.nix deleted file mode 100644 index 9bb401dc12d160e0e70850598a93574c8d5f0d52..0000000000000000000000000000000000000000 --- a/nix/options.gen.nix +++ /dev/null @@ -1,46 +0,0 @@ -# Code generated by gen from schema.cue; DO NOT EDIT. -{ lib }: -let - inherit (lib) mkOption types; -in -{ - hostname = mkOption { - type = types.str; - description = "Tailscale hostname"; - }; - - auth-key = mkOption { - type = types.str; - default = ""; - description = "Tailscale one-time auth key"; - }; - - auth-key-file = mkOption { - type = types.str; - default = ""; - description = "Path to a file containing a Tailscale auth key (takes precedence over auth-key)"; - }; - - funnel = mkOption { - type = types.bool; - default = false; - description = "Expose on Tailscale funnel"; - }; - - data-dir = mkOption { - type = types.nonEmptyStr; - default = "/var/lib/tailproxy"; - description = "tsnet data directory"; - }; - - host = mkOption { - type = types.str; - default = "localhost"; - description = "Host to proxy"; - }; - - port = mkOption { - type = types.port; - description = "Port to proxy"; - }; -}