blob: 987ff9cd6e8784ed5ef8f1535073257016333aa1 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
3import (
4 "fmt"
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +04005 "net"
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04006 "net/netip"
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +04007 "strings"
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04008
9 "github.com/miekg/dns"
10
11 "github.com/giolekva/pcloud/core/installer"
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040012)
13
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +040014var initGroups = []string{"admin"}
15
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040016func CreateRepoClient(env Env, st *state) Task {
17 t := newLeafTask("Create repo client", func() error {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040018 repo, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040019 if err != nil {
20 return err
21 }
gio3af43942024-04-16 08:13:50 +040022 r, err := installer.NewRepoIO(repo, st.ssClient.Signer)
23 if err != nil {
24 return err
25 }
gio308105e2024-04-19 13:12:13 +040026 appManager, err := installer.NewAppManager(r, st.nsCreator, "/apps")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040027 if err != nil {
28 return err
29 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040030 st.appManager = appManager
31 st.appsRepo = installer.NewInMemoryAppRepository(installer.CreateAllApps())
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040032 return nil
33 })
Giorgi Lekveishviliab7ff6e2024-03-29 13:11:30 +040034 t.beforeStart = func() {
35 st.infoListener("Setting up core infrastructure services.")
36 }
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040037 return &t
38}
39
40func SetupInfra(env Env, startIP net.IP, st *state) Task {
41 return newConcurrentParentTask(
42 "Setup core services",
43 true,
44 SetupNetwork(env, startIP, st),
45 SetupCertificateIssuers(env, st),
46 SetupAuth(env, st),
47 SetupGroupMemberships(env, st),
48 SetupHeadscale(env, startIP, st),
49 SetupWelcome(env, st),
50 SetupAppStore(env, st),
Davit Tabidze56f86a42024-04-09 19:15:25 +040051 SetupLauncher(env, st),
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040052 )
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040053}
54
55func CommitEnvironmentConfiguration(env Env, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +040056 t := newLeafTask("commit config", func() error {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040057 repo, err := st.ssClient.GetRepo("config")
58 if err != nil {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040059 return err
60 }
gio3af43942024-04-16 08:13:50 +040061 r, err := installer.NewRepoIO(repo, st.ssClient.Signer)
62 if err != nil {
63 return err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +040064 }
gio308105e2024-04-19 13:12:13 +040065 r.Do(func(r installer.RepoFS) (string, error) {
gio3af43942024-04-16 08:13:50 +040066 {
67 // TODO(giolekva): private domain can be configurable as well
gio3cdee592024-04-17 10:15:56 +040068 config := installer.AppEnvConfig{
69 Id: env.Name,
70 InfraName: env.PCloudEnvName,
71 Domain: env.Domain,
72 PrivateDomain: fmt.Sprintf("p.%s", env.Domain),
73 ContactEmail: env.ContactEmail,
74 PublicIP: st.publicIPs,
75 NamespacePrefix: fmt.Sprintf("%s-", env.Name),
gio3af43942024-04-16 08:13:50 +040076 }
77 if err := installer.WriteYaml(r, "config.yaml", config); err != nil {
78 return "", err
79 }
80 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040081 out, err := r.Writer("pcloud-charts.yaml")
82 if err != nil {
gio3af43942024-04-16 08:13:50 +040083 return "", err
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040084 }
85 defer out.Close()
86 _, err = fmt.Fprintf(out, `
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040087apiVersion: source.toolkit.fluxcd.io/v1
88kind: GitRepository
89metadata:
90 name: pcloud
91 namespace: %s
92spec:
93 interval: 1m0s
94 url: https://github.com/giolekva/pcloud
95 ref:
gio3cdee592024-04-17 10:15:56 +040096 branch: main
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040097`, env.Name)
98 if err != nil {
gio3af43942024-04-16 08:13:50 +040099 return "", err
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400100 }
gio3af43942024-04-16 08:13:50 +0400101 rootKust, err := installer.ReadKustomization(r, "kustomization.yaml")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400102 if err != nil {
gio3af43942024-04-16 08:13:50 +0400103 return "", err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400104 }
105 rootKust.AddResources("pcloud-charts.yaml")
gio3af43942024-04-16 08:13:50 +0400106 if err := installer.WriteYaml(r, "kustomization.yaml", rootKust); err != nil {
107 return "", err
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400108 }
gio3af43942024-04-16 08:13:50 +0400109 return "configure charts repo", nil
110 })
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400111 return nil
112 })
113 return &t
114}
115
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400116type firstAccount struct {
117 Created bool `json:"created"`
118 Groups []string `json:"groups"`
119}
120
121func ConfigureFirstAccount(env Env, st *state) Task {
122 t := newLeafTask("Configure first account settings", func() error {
123 repo, err := st.ssClient.GetRepo("config")
124 if err != nil {
125 return err
126 }
gio3af43942024-04-16 08:13:50 +0400127 r, err := installer.NewRepoIO(repo, st.ssClient.Signer)
128 if err != nil {
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400129 return err
130 }
gio308105e2024-04-19 13:12:13 +0400131 return r.Do(func(r installer.RepoFS) (string, error) {
gio3af43942024-04-16 08:13:50 +0400132 fa := firstAccount{false, initGroups}
133 if err := installer.WriteYaml(r, "first-account.yaml", fa); err != nil {
134 return "", err
135 }
136 return "first account membership configuration", nil
137 })
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400138 })
139 return &t
140}
141
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400142func SetupNetwork(env Env, startIP net.IP, st *state) Task {
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400143 t := newLeafTask("Setup private and public networks", func() error {
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400144 startAddr, err := netip.ParseAddr(startIP.String())
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400145 if err != nil {
146 return err
147 }
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400148 if !startAddr.Is4() {
149 return fmt.Errorf("Expected IPv4, got %s instead", startAddr)
150 }
151 addr := startAddr.AsSlice()
152 if addr[3] != 0 {
153 return fmt.Errorf("Expected last byte to be zero, got %d instead", addr[3])
154 }
155 addr[3] = 10
156 fromIP, ok := netip.AddrFromSlice(addr)
157 if !ok {
158 return fmt.Errorf("Must not reach")
159 }
160 addr[3] = 254
161 toIP, ok := netip.AddrFromSlice(addr)
162 if !ok {
163 return fmt.Errorf("Must not reach")
164 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400165 {
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400166 ingressPrivateIP := startAddr
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400167 headscaleIP := ingressPrivateIP.Next()
gio3cdee592024-04-17 10:15:56 +0400168 app, err := installer.FindEnvApp(st.appsRepo, "metallb-ipaddresspool")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400169 if err != nil {
170 return err
171 }
gio3af43942024-04-16 08:13:50 +0400172 {
gio3cdee592024-04-17 10:15:56 +0400173 instanceId := fmt.Sprintf("%s-ingress-private", app.Name())
174 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400175 namespace := fmt.Sprintf("%s%s-ingress-private", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400176 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio3af43942024-04-16 08:13:50 +0400177 "name": fmt.Sprintf("%s-ingress-private", env.Name),
178 "from": ingressPrivateIP.String(),
179 "to": ingressPrivateIP.String(),
180 "autoAssign": false,
181 "namespace": "metallb-system",
182 }); err != nil {
183 return err
184 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400185 }
gio3af43942024-04-16 08:13:50 +0400186 {
gio3cdee592024-04-17 10:15:56 +0400187 instanceId := fmt.Sprintf("%s-headscale", app.Name())
188 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400189 namespace := fmt.Sprintf("%s%s-ingress-private", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400190 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio3af43942024-04-16 08:13:50 +0400191 "name": fmt.Sprintf("%s-headscale", env.Name),
192 "from": headscaleIP.String(),
193 "to": headscaleIP.String(),
194 "autoAssign": false,
195 "namespace": "metallb-system",
196 }); err != nil {
197 return err
198 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400199 }
gio3af43942024-04-16 08:13:50 +0400200 {
gio3cdee592024-04-17 10:15:56 +0400201 instanceId := app.Name()
202 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400203 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400204 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
gio3af43942024-04-16 08:13:50 +0400205 "name": env.Name,
206 "from": fromIP.String(),
207 "to": toIP.String(),
208 "autoAssign": false,
209 "namespace": "metallb-system",
210 }); err != nil {
211 return err
212 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400213 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400214 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400215 {
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400216 keys, err := installer.NewSSHKeyPair("port-allocator")
217 if err != nil {
218 return err
219 }
220 user := fmt.Sprintf("%s-port-allocator", env.Name)
221 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
222 return err
223 }
224 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
225 return err
226 }
gio3cdee592024-04-17 10:15:56 +0400227 app, err := installer.FindEnvApp(st.appsRepo, "private-network")
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400228 if err != nil {
229 return err
230 }
gio3cdee592024-04-17 10:15:56 +0400231 instanceId := app.Name()
232 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400233 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400234 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400235 "privateNetwork": map[string]any{
236 "hostname": "private-network-proxy",
237 "username": "private-network-proxy",
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400238 "ipSubnet": fmt.Sprintf("%s/24", startIP.String()),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400239 },
Giorgi Lekveishvilib59b7c22024-04-03 22:17:50 +0400240 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400241 }); err != nil {
242 return err
243 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400244 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400245 return nil
246 })
247 return &t
248}
249
250func SetupCertificateIssuers(env Env, st *state) Task {
251 pub := newLeafTask(fmt.Sprintf("Public %s", env.Domain), func() error {
gio3cdee592024-04-17 10:15:56 +0400252 app, err := installer.FindEnvApp(st.appsRepo, "certificate-issuer-public")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400253 if err != nil {
254 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400255 }
gio3cdee592024-04-17 10:15:56 +0400256 instanceId := app.Name()
257 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400258 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400259 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{}); err != nil {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400260 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400261 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400262 return nil
263 })
264 priv := newLeafTask(fmt.Sprintf("Private p.%s", env.Domain), func() error {
gio3cdee592024-04-17 10:15:56 +0400265 app, err := installer.FindEnvApp(st.appsRepo, "certificate-issuer-private")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400266 if err != nil {
267 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400268 }
gio3cdee592024-04-17 10:15:56 +0400269 instanceId := app.Name()
270 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400271 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400272 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400273 "apiConfigMap": map[string]any{
274 "name": "api-config", // TODO(gio): take from global pcloud config
275 "namespace": fmt.Sprintf("%s-dns-zone-manager", env.PCloudEnvName),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400276 },
277 }); err != nil {
278 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400279 }
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400280 return nil
281 })
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400282 return newSequentialParentTask("Configure TLS certificate issuers", false, &pub, &priv)
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400283}
284
285func SetupAuth(env Env, st *state) Task {
286 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400287 app, err := installer.FindEnvApp(st.appsRepo, "core-auth")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400288 if err != nil {
289 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400290 }
gio3cdee592024-04-17 10:15:56 +0400291 instanceId := app.Name()
292 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400293 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400294 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400295 "subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400296 }); err != nil {
297 return err
298 }
299 return nil
300 })
301 return newSequentialParentTask(
302 "Authentication services",
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400303 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400304 &t,
305 waitForAddr(fmt.Sprintf("https://accounts-ui.%s", env.Domain)),
306 )
307}
308
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400309func SetupGroupMemberships(env Env, st *state) Task {
310 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400311 app, err := installer.FindEnvApp(st.appsRepo, "memberships")
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400312 if err != nil {
313 return err
314 }
gio3cdee592024-04-17 10:15:56 +0400315 instanceId := app.Name()
316 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400317 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400318 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilid542b732024-03-25 18:17:39 +0400319 "authGroups": strings.Join(initGroups, ","),
320 }); err != nil {
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400321 return err
322 }
323 return nil
324 })
325 return newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400326 "Group membership",
327 false,
Giorgi Lekveishvilia09fad72024-03-21 15:24:35 +0400328 &t,
329 waitForAddr(fmt.Sprintf("https://memberships.p.%s", env.Domain)),
330 )
331}
332
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400333func SetupHeadscale(env Env, startIP net.IP, st *state) Task {
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400334 t := newLeafTask("Setup", func() error {
gio3cdee592024-04-17 10:15:56 +0400335 app, err := installer.FindEnvApp(st.appsRepo, "headscale")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400336 if err != nil {
337 return err
338 }
gio3cdee592024-04-17 10:15:56 +0400339 instanceId := app.Name()
340 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400341 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400342 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400343 "subdomain": "headscale",
Giorgi Lekveishvili9d5e3f52024-03-13 15:02:50 +0400344 "ipSubnet": fmt.Sprintf("%s/24", startIP),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400345 }); err != nil {
346 return err
347 }
348 return nil
349 })
350 return newSequentialParentTask(
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400351 "Setup mesh VPN",
352 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400353 &t,
354 waitForAddr(fmt.Sprintf("https://headscale.%s/apple", env.Domain)),
355 )
356}
357
358func SetupWelcome(env Env, st *state) Task {
359 t := newLeafTask("Setup", func() error {
360 keys, err := installer.NewSSHKeyPair("welcome")
361 if err != nil {
362 return err
363 }
364 user := fmt.Sprintf("%s-welcome", env.Name)
365 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
366 return err
367 }
368 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
369 return err
370 }
gio3cdee592024-04-17 10:15:56 +0400371 app, err := installer.FindEnvApp(st.appsRepo, "welcome")
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400372 if err != nil {
373 return err
374 }
gio3cdee592024-04-17 10:15:56 +0400375 instanceId := app.Name()
376 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400377 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400378 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400379 "repoAddr": st.ssClient.GetRepoAddress("config"),
380 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400381 }); err != nil {
382 return err
383 }
384 return nil
385 })
386 return newSequentialParentTask(
387 "Welcome service",
Giorgi Lekveishvili5c1b06e2024-03-28 15:19:44 +0400388 false,
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400389 &t,
390 waitForAddr(fmt.Sprintf("https://welcome.%s", env.Domain)),
391 )
392}
393
394func SetupAppStore(env Env, st *state) Task {
395 t := newLeafTask("Application marketplace", func() error {
396 user := fmt.Sprintf("%s-appmanager", env.Name)
397 keys, err := installer.NewSSHKeyPair(user)
398 if err != nil {
399 return err
400 }
401 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
402 return err
403 }
404 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
405 return err
406 }
gio3cdee592024-04-17 10:15:56 +0400407 app, err := installer.FindEnvApp(st.appsRepo, "app-manager") // TODO(giolekva): configure
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400408 if err != nil {
409 return err
410 }
gio3cdee592024-04-17 10:15:56 +0400411 instanceId := app.Name()
412 appDir := fmt.Sprintf("/apps/%s", instanceId)
gio3af43942024-04-16 08:13:50 +0400413 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
gio3cdee592024-04-17 10:15:56 +0400414 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
Giorgi Lekveishvilie009a5d2024-01-05 14:10:11 +0400415 "repoAddr": st.ssClient.GetRepoAddress("config"),
416 "sshPrivateKey": string(keys.RawPrivateKey()),
Giorgi Lekveishvili3c91e8b2024-03-25 20:20:14 +0400417 "authGroups": strings.Join(initGroups, ","),
Giorgi Lekveishvili378ea882023-12-12 13:59:18 +0400418 }); err != nil {
419 return err
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400420 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400421 return nil
422 })
423 return &t
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400424}
425
Davit Tabidze56f86a42024-04-09 19:15:25 +0400426func SetupLauncher(env Env, st *state) Task {
427 t := newLeafTask("Application Launcher", func() error {
428 user := fmt.Sprintf("%s-launcher", env.Name)
429 keys, err := installer.NewSSHKeyPair(user)
430 if err != nil {
431 return err
432 }
433 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
434 return err
435 }
436 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil { //TODO(gio): add read only
437 return err
438 }
439 app, err := installer.FindEnvApp(st.appsRepo, "launcher") // TODO(giolekva): configure
440 if err != nil {
441 return err
442 }
443 instanceId := app.Name()
444 appDir := fmt.Sprintf("/apps/%s", instanceId)
445 namespace := fmt.Sprintf("%s%s", env.NamespacePrefix, app.Namespace())
446 if err := st.appManager.Install(app, instanceId, appDir, namespace, map[string]any{
447 "repoAddr": st.ssClient.GetRepoAddress("config"),
448 "sshPrivateKey": string(keys.RawPrivateKey()),
449 }); err != nil {
450 return err
451 }
452 return nil
453 })
454 return &t
455}
456
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400457type DNSSecKey struct {
458 Basename string `json:"basename,omitempty"`
459 Key []byte `json:"key,omitempty"`
460 Private []byte `json:"private,omitempty"`
461 DS []byte `json:"ds,omitempty"`
462}
463
464func newDNSSecKey(zone string) (DNSSecKey, error) {
465 key := &dns.DNSKEY{
466 Hdr: dns.RR_Header{Name: dns.Fqdn(zone), Class: dns.ClassINET, Ttl: 3600, Rrtype: dns.TypeDNSKEY},
467 Algorithm: dns.ECDSAP256SHA256, Flags: 257, Protocol: 3,
468 }
469 priv, err := key.Generate(256)
470 if err != nil {
471 return DNSSecKey{}, err
472 }
473 return DNSSecKey{
474 Basename: fmt.Sprintf("K%s+%03d+%05d", key.Header().Name, key.Algorithm, key.KeyTag()),
475 Key: []byte(key.String()),
476 Private: []byte(key.PrivateKeyString(priv)),
477 DS: []byte(key.ToDS(dns.SHA256).String()),
478 }, nil
479}