blob: 87d245b650f5b3afc22f9c961d02fecc26847ab1 [file] [log] [blame]
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"text/template"
"github.com/labstack/echo/v4"
)
var port = flag.Int("port", 3000, "Port to listen on")
var config = flag.String("config", "", "Path to headscale config")
var acls = flag.String("acls", "", "Path to the headscale acls file")
var ipSubnet = flag.String("ip-subnet", "10.1.0.0/24", "IP subnet of the private network")
// TODO(gio): make internal network cidr and proxy user configurable
const defaultACLs = `
{
"autoApprovers": {
"routes": {
"{{ .ipSubnet }}": ["*"],
},
},
"acls": [
{ // Everyone has passthough access to private-network-proxy node
"action": "accept",
"src": ["*"],
"dst": ["{{ .ipSubnet }}:*", "private-network-proxy:0"],
},
],
}
`
type server struct {
port int
client *client
}
func newServer(port int, client *client) *server {
return &server{
port,
client,
}
}
func (s *server) start() {
e := echo.New()
e.POST("/user/:user/preauthkey", s.createReusablePreAuthKey)
e.POST("/user", s.createUser)
e.POST("/routes/:id/enable", s.enableRoute)
log.Fatal(e.Start(fmt.Sprintf(":%d", s.port)))
}
type createUserReq struct {
Name string `json:"name"`
}
func (s *server) createUser(c echo.Context) error {
var req createUserReq
if err := json.NewDecoder(c.Request().Body).Decode(&req); err != nil {
return err
}
if err := s.client.createUser(req.Name); err != nil {
return err
} else {
return c.String(http.StatusOK, "")
}
}
func (s *server) createReusablePreAuthKey(c echo.Context) error {
if key, err := s.client.createPreAuthKey(c.Param("user")); err != nil {
return err
} else {
return c.String(http.StatusOK, key)
}
}
func (s *server) enableRoute(c echo.Context) error {
if err := s.client.enableRoute(c.Param("id")); err != nil {
return err
} else {
return c.String(http.StatusOK, "")
}
}
func updateACLs(cidr net.IPNet, aclsPath string) error {
tmpl, err := template.New("acls").Parse(defaultACLs)
if err != nil {
return err
}
out, err := os.Create(aclsPath)
if err != nil {
return err
}
defer out.Close()
return tmpl.Execute(out, map[string]any{
"ipSubnet": cidr.String(),
})
}
func main() {
flag.Parse()
_, cidr, err := net.ParseCIDR(*ipSubnet)
if err != nil {
panic(err)
}
updateACLs(*cidr, *acls)
c := newClient(*config)
s := newServer(*port, c)
s.start()
}