blob: 06de0dcf20e6bb7648352446d32fe9a76d525372 [file] [log] [blame]
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +04001package tasks
2
3import (
4 "fmt"
5 "net/netip"
6
7 "github.com/miekg/dns"
8
9 "github.com/giolekva/pcloud/core/installer"
10 "github.com/giolekva/pcloud/core/installer/soft"
11)
12
13type setupInfraAppsTask struct {
14 basicTask
15 env Env
16 st *state
17}
18
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040019func (t *setupInfraAppsTask) initNewEnv(
20 ss *soft.Client,
21 r installer.RepoIO,
22 nsCreator installer.NamespaceCreator,
23 pcloudEnvName string,
24 pcloudPublicIP string,
25) error {
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040026 return nil
27}
28
29func NewSetupInfraAppsTask(env Env, st *state) Task {
30 t := newLeafTask("Configure environment infrastructure", func() error {
31 repo, err := st.ssClient.GetRepo("config")
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040032 if err != nil {
33 return err
34 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040035 r := installer.NewRepoIO(repo, st.ssClient.Signer)
36 appManager, err := installer.NewAppManager(r, st.nsCreator)
37 if err != nil {
38 return err
39 }
40 appsRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
41 // TODO(giolekva): private domain can be configurable as well
42 config := installer.Config{
43 Values: installer.Values{
44 PCloudEnvName: env.PCloudEnvName,
45 Id: env.Name,
46 ContactEmail: env.ContactEmail,
47 Domain: env.Domain,
48 PrivateDomain: fmt.Sprintf("p.%s", env.Domain),
49 PublicIP: st.publicIPs[0].String(),
50 NamespacePrefix: fmt.Sprintf("%s-", env.Name),
51 },
52 }
53 if err := r.WriteYaml("config.yaml", config); err != nil {
54 return err
55 }
56 {
57 out, err := r.Writer("pcloud-charts.yaml")
58 if err != nil {
59 return err
60 }
61 defer out.Close()
62 _, err = fmt.Fprintf(out, `
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040063apiVersion: source.toolkit.fluxcd.io/v1
64kind: GitRepository
65metadata:
66 name: pcloud
67 namespace: %s
68spec:
69 interval: 1m0s
70 url: https://github.com/giolekva/pcloud
71 ref:
72 branch: main
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040073`, env.Name)
74 if err != nil {
75 return err
76 }
77 }
78 rootKust, err := r.ReadKustomization("kustomization.yaml")
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040079 if err != nil {
80 return err
81 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040082 rootKust.AddResources("pcloud-charts.yaml")
83 if err := r.WriteKustomization("kustomization.yaml", *rootKust); err != nil {
84 return err
85 }
86 r.CommitAndPush("configure charts repo")
87 nsGen := installer.NewPrefixGenerator(env.Name + "-")
88 emptySuffixGen := installer.NewEmptySuffixGenerator()
89 ingressPrivateIP, err := netip.ParseAddr("10.1.0.1")
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +040090 if err != nil {
91 return err
92 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +040093 {
94 headscaleIP := ingressPrivateIP.Next()
95 app, err := appsRepo.Find("metallb-ipaddresspool")
96 if err != nil {
97 return err
98 }
99 if err := appManager.Install(*app, nsGen, installer.NewSuffixGenerator("-ingress-private"), map[string]any{
100 "Name": fmt.Sprintf("%s-ingress-private", env.Name),
101 "From": ingressPrivateIP.String(),
102 "To": ingressPrivateIP.String(),
103 "AutoAssign": false,
104 "Namespace": "metallb-system",
105 }); err != nil {
106 return err
107 }
108 if err := appManager.Install(*app, nsGen, installer.NewSuffixGenerator("-headscale"), map[string]any{
109 "Name": fmt.Sprintf("%s-headscale", env.Name),
110 "From": headscaleIP.String(),
111 "To": headscaleIP.String(),
112 "AutoAssign": false,
113 "Namespace": "metallb-system",
114 }); err != nil {
115 return err
116 }
117 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
118 "Name": env.Name,
119 "From": "10.1.0.100", // TODO(gio): auto-generate
120 "To": "10.1.0.254",
121 "AutoAssign": false,
122 "Namespace": "metallb-system",
123 }); err != nil {
124 return err
125 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400126 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400127 {
128 app, err := appsRepo.Find("private-network")
129 if err != nil {
130 return err
131 }
132 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
133 "PrivateNetwork": map[string]any{
134 "Hostname": "private-network-proxy",
135 "Username": "private-network-proxy",
136 "IPSubnet": "10.1.0.0/24",
137 },
138 }); err != nil {
139 return err
140 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400141 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400142 {
143 app, err := appsRepo.Find("certificate-issuer-public")
144 if err != nil {
145 return err
146 }
147 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{}); err != nil {
148 return err
149 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400150 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400151 {
152 app, err := appsRepo.Find("certificate-issuer-private")
153 if err != nil {
154 return err
155 }
156 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
157 "APIConfigMap": map[string]any{
158 "Name": "api-config", // TODO(gio): take from global pcloud config
159 "Namespace": fmt.Sprintf("%s-dns-zone-manager", env.PCloudEnvName),
160 },
161 }); err != nil {
162 return err
163 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400164 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400165 {
166 app, err := appsRepo.Find("core-auth")
167 if err != nil {
168 return err
169 }
170 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
171 "Subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
172 }); err != nil {
173 return err
174 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400175 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400176 {
177 app, err := appsRepo.Find("headscale")
178 if err != nil {
179 return err
180 }
181 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
182 "Subdomain": "headscale",
183 }); err != nil {
184 return err
185 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400186 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400187 {
188 keys, err := installer.NewSSHKeyPair("welcome")
189 if err != nil {
190 return err
191 }
192 user := fmt.Sprintf("%s-welcome", env.Name)
193 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
194 return err
195 }
196 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
197 return err
198 }
199 app, err := appsRepo.Find("welcome")
200 if err != nil {
201 return err
202 }
203 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
204 "RepoAddr": st.ssClient.GetRepoAddress("config"),
205 "SSHPrivateKey": string(keys.RawPrivateKey()),
206 }); err != nil {
207 return err
208 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400209 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400210 {
211 user := fmt.Sprintf("%s-appmanager", env.Name)
212 keys, err := installer.NewSSHKeyPair(user)
213 if err != nil {
214 return err
215 }
216 if err := st.ssClient.AddUser(user, keys.AuthorizedKey()); err != nil {
217 return err
218 }
219 if err := st.ssClient.AddReadWriteCollaborator("config", user); err != nil {
220 return err
221 }
222 app, err := appsRepo.Find("app-manager") // TODO(giolekva): configure
223 if err != nil {
224 return err
225 }
226 if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
227 "RepoAddr": st.ssClient.GetRepoAddress("config"),
228 "SSHPrivateKey": string(keys.RawPrivateKey()),
229 }); err != nil {
230 return err
231 }
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400232 }
Giorgi Lekveishvili77ee2dc2023-12-11 16:51:10 +0400233 return nil
234 })
235 return &t
Giorgi Lekveishvili46743d42023-12-10 15:47:23 +0400236}
237
238type DNSSecKey struct {
239 Basename string `json:"basename,omitempty"`
240 Key []byte `json:"key,omitempty"`
241 Private []byte `json:"private,omitempty"`
242 DS []byte `json:"ds,omitempty"`
243}
244
245func newDNSSecKey(zone string) (DNSSecKey, error) {
246 key := &dns.DNSKEY{
247 Hdr: dns.RR_Header{Name: dns.Fqdn(zone), Class: dns.ClassINET, Ttl: 3600, Rrtype: dns.TypeDNSKEY},
248 Algorithm: dns.ECDSAP256SHA256, Flags: 257, Protocol: 3,
249 }
250 priv, err := key.Generate(256)
251 if err != nil {
252 return DNSSecKey{}, err
253 }
254 return DNSSecKey{
255 Basename: fmt.Sprintf("K%s+%03d+%05d", key.Header().Name, key.Algorithm, key.KeyTag()),
256 Key: []byte(key.String()),
257 Private: []byte(key.PrivateKeyString(priv)),
258 DS: []byte(key.ToDS(dns.SHA256).String()),
259 }, nil
260}