blob: 1ca4f6b008514d50559caa3249a4fa19b5630bf7 [file] [log] [blame]
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +04001package main
2
3import (
4 "encoding/json"
5 "flag"
6 "fmt"
7 "log"
8 "net/http"
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +04009 "os"
10 "text/template"
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +040011
12 "github.com/labstack/echo/v4"
13)
14
15var port = flag.Int("port", 3000, "Port to listen on")
16var config = flag.String("config", "", "Path to headscale config")
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +040017var acls = flag.String("acls", "", "Path to the headscale acls file")
18var domain = flag.String("domain", "", "Environment domain")
19
20// TODO(gio): ingress-private user name must be configurable
21const defaultACLs = `
22{
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +040023 "autoApprovers": {
24 "routes": {
Giorgi Lekveishvili39913692023-12-05 08:58:08 +040025 "10.1.0.0/24": ["private-network-proxy@{{ .Domain }}"],
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +040026 },
27 },
28 "acls": [
29 { // Everyone can access ingress-private service
30 "action": "accept",
31 "src": ["*"],
Giorgi Lekveishvili39913692023-12-05 08:58:08 +040032 "dst": ["10.1.0.0/24:*"],
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +040033 },
34 ],
35}
36`
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +040037
38type server struct {
39 port int
40 client *client
41}
42
43func newServer(port int, client *client) *server {
44 return &server{
45 port,
46 client,
47 }
48}
49
50func (s *server) start() {
51 e := echo.New()
52 e.POST("/user/:user/preauthkey", s.createReusablePreAuthKey)
53 e.POST("/user", s.createUser)
54 e.POST("/routes/:id/enable", s.enableRoute)
55 log.Fatal(e.Start(fmt.Sprintf(":%d", s.port)))
56}
57
58type createUserReq struct {
59 Name string `json:"name"`
60}
61
62func (s *server) createUser(c echo.Context) error {
63 var req createUserReq
64 if err := json.NewDecoder(c.Request().Body).Decode(&req); err != nil {
65 return err
66 }
67 if err := s.client.createUser(req.Name); err != nil {
68 return err
69 } else {
70 return c.String(http.StatusOK, "")
71 }
72}
73
74func (s *server) createReusablePreAuthKey(c echo.Context) error {
75 if key, err := s.client.createPreAuthKey(c.Param("user")); err != nil {
76 return err
77 } else {
78 return c.String(http.StatusOK, key)
79 }
80}
81
82func (s *server) enableRoute(c echo.Context) error {
83 if err := s.client.enableRoute(c.Param("id")); err != nil {
84 return err
85 } else {
86 return c.String(http.StatusOK, "")
87 }
88}
89
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +040090func updateACLs(domain, acls string) error {
91 tmpl, err := template.New("acls").Parse(defaultACLs)
92 if err != nil {
93 return err
94 }
95 out, err := os.Create(acls)
96 if err != nil {
97 return err
98 }
99 defer out.Close()
100 return tmpl.Execute(out, map[string]any{
101 "Domain": domain,
102 })
103}
104
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +0400105func main() {
106 flag.Parse()
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +0400107 updateACLs(*domain, *acls)
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +0400108 c := newClient(*config)
109 s := newServer(*port, c)
110 s.start()
111}