env: create tailscale-proxy for ingress-private IP with new env
diff --git a/core/headscale/main.go b/core/headscale/main.go
index a2e429c..b9dbc22 100644
--- a/core/headscale/main.go
+++ b/core/headscale/main.go
@@ -6,12 +6,37 @@
"fmt"
"log"
"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 domain = flag.String("domain", "", "Environment domain")
+
+// TODO(gio): ingress-private user name must be configurable
+const defaultACLs = `
+{
+ "hosts": {
+ "private-network": "10.1.0.0/24",
+ },
+ "autoApprovers": {
+ "routes": {
+ "private-network": ["private-network-proxy@{{ .Domain }}"],
+ },
+ },
+ "acls": [
+ { // Everyone can access ingress-private service
+ "action": "accept",
+ "src": ["*"],
+ "dst": ["private-network:*"],
+ },
+ ],
+}
+`
type server struct {
port int
@@ -65,8 +90,24 @@
}
}
+func updateACLs(domain, acls string) error {
+ tmpl, err := template.New("acls").Parse(defaultACLs)
+ if err != nil {
+ return err
+ }
+ out, err := os.Create(acls)
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+ return tmpl.Execute(out, map[string]any{
+ "Domain": domain,
+ })
+}
+
func main() {
flag.Parse()
+ updateACLs(*domain, *acls)
c := newClient(*config)
s := newServer(*port, c)
s.start()
diff --git a/core/installer/values-tmpl/headscale.yaml b/core/installer/values-tmpl/headscale.yaml
index 5b63d7e..c6c04a2 100644
--- a/core/installer/values-tmpl/headscale.yaml
+++ b/core/installer/values-tmpl/headscale.yaml
@@ -34,6 +34,7 @@
ipAddressPool: {{ .Global.Id }}-headscale
api:
port: 8585
+ rootDomain: {{ .Global.Domain }}
image:
repository: giolekva/headscale-api
tag: latest
diff --git a/core/installer/values-tmpl/tailscale-proxy.jsonschema b/core/installer/values-tmpl/tailscale-proxy.jsonschema
index 9452893..11f57c6 100644
--- a/core/installer/values-tmpl/tailscale-proxy.jsonschema
+++ b/core/installer/values-tmpl/tailscale-proxy.jsonschema
@@ -2,7 +2,8 @@
"type": "object",
"properties": {
"Username": { "type": "string", "default": "example" },
- "IPSubnet": { "type": "string", "default": "10.1.0.1" }
+ "IPSubnet": { "type": "string", "default": "10.1.0.1" },
+ "HostnameSuffix": { "type": "string", "default": "10.1.0.1" }
},
"additionalProperties": false
}
diff --git a/core/installer/values-tmpl/tailscale-proxy.yaml b/core/installer/values-tmpl/tailscale-proxy.yaml
index 5ceae75..1774f1e 100644
--- a/core/installer/values-tmpl/tailscale-proxy.yaml
+++ b/core/installer/values-tmpl/tailscale-proxy.yaml
@@ -9,14 +9,14 @@
namespace: {{ .Global.NamespacePrefix }}app-headscale
chart:
spec:
- chart: charts/tailscale
+ chart: charts/tailscale-proxy
sourceRef:
kind: GitRepository
name: pcloud
namespace: {{ .Global.Id }}
interval: 1m0s
values:
- hostname: {{ .Global.PCloudEnvName }}-{{ .Global.Id }}-internal-proxy
+ hostname: {{ .Global.Id }}-{{ .Values.HostnameSuffix }}
apiServer: http://headscale-api.{{ .Global.Id }}-app-headscale.svc.cluster.local
loginServer: https://headscale.{{ .Global.Domain }} # TODO(gio): take headscale subdomain from configuration
ipSubnet: {{ .Values.IPSubnet }}
diff --git a/core/installer/welcome/create-env.html b/core/installer/welcome/create-env.html
index d9f62c5..ea07476 100644
--- a/core/installer/welcome/create-env.html
+++ b/core/installer/welcome/create-env.html
@@ -6,39 +6,34 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
- <div style="display: contents">
- <main class="container">
- <article class="grid">
- <div>
- <form action="/env" method="POST">
- <input
- type="test"
- name="domain"
- placeholder="Domain"
- required
- />
- <input
- type="email"
- name="contact-email"
- placeholder="Contact Email"
- required
- />
- <input
- type="string"
- name="admin-public-key"
- placeholder="Admin SSH Public Key"
- required
- /> <!-- TODO(gio): remove-->
- <textarea
- name="secret-token"
- placeholder="Secret Token"
- required
- ></textarea>
- <button type="submit" class="contrast">Create Environment</button>
- </form>
- </div>
- </article>
- </main>
- </div>
+ <main class="container">
+ <form action="" method="POST">
+ <input
+ type="test"
+ name="domain"
+ placeholder="Domain"
+ required
+ autofocus
+ />
+ <input
+ type="email"
+ name="contact-email"
+ placeholder="Contact Email"
+ required
+ />
+ <input
+ type="string"
+ name="admin-public-key"
+ placeholder="Admin SSH Public Key"
+ required
+ /> <!-- TODO(gio): remove-->
+ <textarea
+ name="secret-token"
+ placeholder="Secret Token"
+ required
+ ></textarea>
+ <button type="submit">Create Environment</button>
+ </form>
+ </main>
</body>
</html>
diff --git a/core/installer/welcome/env.go b/core/installer/welcome/env.go
index 3d0ed70..4e74181 100644
--- a/core/installer/welcome/env.go
+++ b/core/installer/welcome/env.go
@@ -12,6 +12,7 @@
"io/fs"
"log"
"net/http"
+ "net/netip"
"path"
"path/filepath"
"strings"
@@ -502,15 +503,20 @@
r.CommitAndPush("initialize config")
nsGen := installer.NewPrefixGenerator(req.Name + "-")
emptySuffixGen := installer.NewEmptySuffixGenerator()
+ ingressPrivateIP, err := netip.ParseAddr("10.1.0.1")
+ if err != nil {
+ return err
+ }
{
+ headscaleIP := ingressPrivateIP.Next()
app, err := appsRepo.Find("metallb-ipaddresspool")
if err != nil {
return err
}
if err := appManager.Install(*app, nsGen, installer.NewSuffixGenerator("-ingress-private"), map[string]any{
"Name": fmt.Sprintf("%s-ingress-private", req.Name),
- "From": "10.1.0.1",
- "To": "10.1.0.1",
+ "From": ingressPrivateIP.String(),
+ "To": ingressPrivateIP.String(),
"AutoAssign": false,
"Namespace": "metallb-system",
}); err != nil {
@@ -518,8 +524,8 @@
}
if err := appManager.Install(*app, nsGen, installer.NewSuffixGenerator("-headscale"), map[string]any{
"Name": fmt.Sprintf("%s-headscale", req.Name),
- "From": "10.1.0.2",
- "To": "10.1.0.2",
+ "From": headscaleIP.String(),
+ "To": headscaleIP.String(),
"AutoAssign": false,
"Namespace": "metallb-system",
}); err != nil {
@@ -527,7 +533,7 @@
}
if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
"Name": req.Name,
- "From": "10.1.0.100",
+ "From": "10.1.0.100", // TODO(gio): auto-generate
"To": "10.1.0.254",
"AutoAssign": false,
"Namespace": "metallb-system",
@@ -545,6 +551,20 @@
}
}
{
+ app, err := appsRepo.Find("tailscale-proxy")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
+ "Username": "private-network-proxy",
+ "IPSubnet": "10.1.0.0/24",
+ "HostnameSuffix": "private-network-proxy",
+ }); err != nil {
+ return err
+ }
+ // TODO(giolekva): headscale accept routes
+ }
+ {
app, err := appsRepo.Find("certificate-issuer-public")
if err != nil {
return err