blob: b9dbc2253996f3e589bb08aeb98262a70b86a989 [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{
23 "hosts": {
24 "private-network": "10.1.0.0/24",
25 },
26 "autoApprovers": {
27 "routes": {
28 "private-network": ["private-network-proxy@{{ .Domain }}"],
29 },
30 },
31 "acls": [
32 { // Everyone can access ingress-private service
33 "action": "accept",
34 "src": ["*"],
35 "dst": ["private-network:*"],
36 },
37 ],
38}
39`
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +040040
41type server struct {
42 port int
43 client *client
44}
45
46func newServer(port int, client *client) *server {
47 return &server{
48 port,
49 client,
50 }
51}
52
53func (s *server) start() {
54 e := echo.New()
55 e.POST("/user/:user/preauthkey", s.createReusablePreAuthKey)
56 e.POST("/user", s.createUser)
57 e.POST("/routes/:id/enable", s.enableRoute)
58 log.Fatal(e.Start(fmt.Sprintf(":%d", s.port)))
59}
60
61type createUserReq struct {
62 Name string `json:"name"`
63}
64
65func (s *server) createUser(c echo.Context) error {
66 var req createUserReq
67 if err := json.NewDecoder(c.Request().Body).Decode(&req); err != nil {
68 return err
69 }
70 if err := s.client.createUser(req.Name); err != nil {
71 return err
72 } else {
73 return c.String(http.StatusOK, "")
74 }
75}
76
77func (s *server) createReusablePreAuthKey(c echo.Context) error {
78 if key, err := s.client.createPreAuthKey(c.Param("user")); err != nil {
79 return err
80 } else {
81 return c.String(http.StatusOK, key)
82 }
83}
84
85func (s *server) enableRoute(c echo.Context) error {
86 if err := s.client.enableRoute(c.Param("id")); err != nil {
87 return err
88 } else {
89 return c.String(http.StatusOK, "")
90 }
91}
92
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +040093func updateACLs(domain, acls string) error {
94 tmpl, err := template.New("acls").Parse(defaultACLs)
95 if err != nil {
96 return err
97 }
98 out, err := os.Create(acls)
99 if err != nil {
100 return err
101 }
102 defer out.Close()
103 return tmpl.Execute(out, map[string]any{
104 "Domain": domain,
105 })
106}
107
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +0400108func main() {
109 flag.Parse()
Giorgi Lekveishvili6ae65d12023-12-04 15:37:53 +0400110 updateACLs(*domain, *acls)
Giorgi Lekveishvili52814d92023-06-15 19:30:32 +0400111 c := newClient(*config)
112 s := newServer(*port, c)
113 s.start()
114}