From 671d8587315b37fc6fb8e7f82b6535d748ad203f Mon Sep 17 00:00:00 2001 From: Kat Inskip Date: Fri, 27 Jan 2023 15:21:35 -0800 Subject: [PATCH] ops: refactor + CA stuff --- go.mod | 5 +- go.sum | 5 ++ iac/ca.go | 41 ++++++++++ iac/config.go | 5 ++ iac/dns.go | 45 +++++++++++ iac/helpers.go | 21 +++++ iac/record.go | 93 ++++++++++++++++++++++ iac/tailscale.go | 104 ++++++++++++++++++++++++ iac/tls.go | 54 +++++++++++++ iac/zone.go | 24 ++++++ main.go | 200 +++++++---------------------------------------- 11 files changed, 426 insertions(+), 171 deletions(-) create mode 100644 iac/ca.go create mode 100644 iac/config.go create mode 100644 iac/dns.go create mode 100644 iac/helpers.go create mode 100644 iac/record.go create mode 100644 iac/tailscale.go create mode 100644 iac/tls.go create mode 100644 iac/zone.go diff --git a/go.mod b/go.mod index ac92b102..002deca3 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,11 @@ go 1.18 require ( github.com/creasty/defaults v1.6.0 github.com/pulumi/pulumi-cloudflare/sdk/v4 v4.15.0 + github.com/pulumi/pulumi-command/sdk v0.7.0 github.com/pulumi/pulumi-tailscale/sdk v0.11.0 + github.com/pulumi/pulumi-tls/sdk/v4 v4.6.1 github.com/pulumi/pulumi/sdk/v3 v3.52.1 + golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 gopkg.in/yaml.v3 v3.0.1 ) @@ -45,6 +48,7 @@ require ( github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect + github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.4.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6 // indirect @@ -53,7 +57,6 @@ require ( github.com/uber/jaeger-lib v2.2.0+incompatible // indirect github.com/xanzy/ssh-agent v0.3.2 // indirect go.uber.org/atomic v1.6.0 // indirect - golang.org/x/crypto v0.0.0-20220824171710-5757bc0c5503 // indirect golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect diff --git a/go.sum b/go.sum index 0ad4753c..9b90ae91 100644 --- a/go.sum +++ b/go.sum @@ -131,8 +131,12 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/pulumi/pulumi-cloudflare/sdk/v4 v4.15.0 h1:qfebMdTdCfeaSAW/gGeLlSkHI+K7v44AcIj5FEwzwMU= github.com/pulumi/pulumi-cloudflare/sdk/v4 v4.15.0/go.mod h1:V1v0FFcbK5rzT62Qgg6eMHBgHeo3mBkSuAjtHTCFWyA= +github.com/pulumi/pulumi-command/sdk v0.7.0 h1:gBxTtg6lY29wbu/XZHsLo6Syoc2yieDmTrSAuxLBRb4= +github.com/pulumi/pulumi-command/sdk v0.7.0/go.mod h1:YX0Ri1ezMr4mk8j4S/S1gjJpidt63mMG2C+VXDoTlpU= github.com/pulumi/pulumi-tailscale/sdk v0.11.0 h1:OmWHFLlSaMOc31jkWGvyaDa+HuW7biJ6R4L+/l/gwTQ= github.com/pulumi/pulumi-tailscale/sdk v0.11.0/go.mod h1:H1FaTimvK+hdaHa0rcfw2+DPYQnewBnI5eCcw9DEDXU= +github.com/pulumi/pulumi-tls/sdk/v4 v4.6.1 h1:/6DaTsUlz9fuNuJYVMRDwgdTSlp5U2wZ5IXD83iBx8c= +github.com/pulumi/pulumi-tls/sdk/v4 v4.6.1/go.mod h1:fG7bnaoul00zCW3rrpS/dwWfko4sZxFVhP+3ml1Jqj0= github.com/pulumi/pulumi/sdk/v3 v3.30.0/go.mod h1:hGo/+AL1L4sPL9Ukd/i5bNFM3WHs3dHcA+GKEW7M3RA= github.com/pulumi/pulumi/sdk/v3 v3.52.1 h1:Q61zRZvph+RLgWlPagsyuWXtOcF1IcNlqWNvV1LE+vQ= github.com/pulumi/pulumi/sdk/v3 v3.52.1/go.mod h1:IYcBrkAwKEGRVq7R1ne3XJKB5bcux5eL3M/zqco7d6Y= @@ -150,6 +154,7 @@ github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= diff --git a/iac/ca.go b/iac/ca.go new file mode 100644 index 00000000..d12125e0 --- /dev/null +++ b/iac/ca.go @@ -0,0 +1,41 @@ +package iac + +import( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" + "log" +) + +func GenerateTLSCA(ctx *pulumi.Context) (key *tls.PrivateKey, cert *tls.SelfSignedCert, err error) { + key, err = tls.NewPrivateKey(ctx, "kat-root-ca-key", &tls.PrivateKeyArgs{ + Algorithm: pulumi.String("RSA"), + RsaBits: pulumi.Int(4096), + }) + + if err != nil { + log.Fatal(err) + } + + cert, err = tls.NewSelfSignedCert(ctx, "kat-root-ca-pem-cert", &tls.SelfSignedCertArgs{ + PrivateKeyPem: key.PrivateKeyPem, + AllowedUses: goStringArrayToPulumiStringArray([]string{"digital_signature", + "cert_signing", + "crl_signing"}), + IsCaCertificate: pulumi.Bool(true), + ValidityPeriodHours: pulumi.Int(2562047), + Subject: &tls.SelfSignedCertSubjectArgs{ + CommonName: pulumi.String("inskip.me"), + Organization: pulumi.String("Kat Inskip"), + }, + }) + + if err != nil { + log.Fatal(err) + } + + ctx.Export("tls_ca_pem_key", key.PrivateKeyPem) + ctx.Export("tls_ca_os_key", key.PrivateKeyOpenssh) + ctx.Export("tls_ca_cert", cert.CertPem) + + return key, cert, err +} diff --git a/iac/config.go b/iac/config.go new file mode 100644 index 00000000..072bea85 --- /dev/null +++ b/iac/config.go @@ -0,0 +1,5 @@ +package iac + +type KatConfig struct { + Zones map[string]Zone `yaml:"zones"` +} diff --git a/iac/dns.go b/iac/dns.go new file mode 100644 index 00000000..3c0ab307 --- /dev/null +++ b/iac/dns.go @@ -0,0 +1,45 @@ +package iac + +import( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + "fmt" +) + +func HandleDNS(ctx *pulumi.Context, config KatConfig) (zones map[string]*cloudflare.Zone, dnssec map[string]*cloudflare.ZoneDnssec, records map[string][]*cloudflare.Record, err error) { + zones = make(map[string]*cloudflare.Zone) + dnssec = make(map[string]*cloudflare.ZoneDnssec) + records = make(map[string][]*cloudflare.Record) + + for name, zone := range config.Zones { + ctx.Log.Info(fmt.Sprintf("Handling zone %s", name), nil) + zones[name], err = zone.handle(ctx, name) + if err != nil { + return nil, nil, nil, err + } + dnssec[name], err = cloudflare.NewZoneDnssec(ctx, fmt.Sprintf("%s-dnssec", name), &cloudflare.ZoneDnssecArgs{ + ZoneId: zones[name].ID(), + }) + if err != nil { + return nil, nil, nil, err + } + for _, record := range zone.Records { + _, exists := records[name] + if exists { + record_, err := record.handle(ctx, name, zones[name]) + if err != nil { + return nil, nil, nil, err + } + records[name] = append(records[name], record_) + } else { + record_, err := record.handle(ctx, name, zones[name]) + if err != nil { + return nil, nil, nil, err + } + records[name] = []*cloudflare.Record{record_} + } + } + } + + return zones, dnssec, records, err +} diff --git a/iac/helpers.go b/iac/helpers.go new file mode 100644 index 00000000..4b352157 --- /dev/null +++ b/iac/helpers.go @@ -0,0 +1,21 @@ +package iac + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +func goStringArrayToPulumiStringArray(ss []string) pulumi.StringArray { + var elems []pulumi.StringInput + for _, s := range ss { + elems = append(elems, pulumi.String(s)) + } + return pulumi.StringArray(elems) +} + +func goMapToPulumiMap(m map[string]string) pulumi.StringMap { + ret := make(pulumi.StringMap) + for k, v := range m { + ret[k] = pulumi.String(v) + } + return ret +} diff --git a/iac/record.go b/iac/record.go new file mode 100644 index 00000000..cf93772d --- /dev/null +++ b/iac/record.go @@ -0,0 +1,93 @@ +package iac + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + "github.com/creasty/defaults" + "fmt" + "strings" + "crypto/md5" + "encoding/hex" +) + +type DNSRecordType string + +const ( + A DNSRecordType = "a" + AAAA = "aaaa" + MX = "mx" + TXT = "txt" + CAA = "caa" +) + +type DNSRecord struct { + Name string `default:"@" yaml:"name"` + Kind DNSRecordType `yaml:"kind"` + Value string `yaml:"value,omitempty"` + Priority int `yaml:"priority,omitempty"` + Flags string `yaml:"flags,omitempty"` + Tag string `yaml:"tag,omitempty"` + Ttl int `default:"3600" yaml:"ttl,omitempty"` +} + +func (r *DNSRecord) UnmarshalYAML(unmarshal func(interface{}) error) error { + defaults.Set(r) + + type plain DNSRecord + if err := unmarshal((*plain)(r)); err != nil { + return err + } + + return nil +} + +func (r *DNSRecord) getZone(Zone *cloudflare.Zone) (pulumi.StringOutput) { + return Zone.ID().ToStringOutput() +} + +func (r *DNSRecord) getName(ZoneName string, Zone *cloudflare.Zone) (string) { + base := fmt.Sprintf("%s-%s-%s", ZoneName, r.Kind, r.Name) + + hash := md5.Sum([]byte(r.Value)) + hashString := hex.EncodeToString(hash[:])[:5] + suffix := "" + switch r.Kind { + case MX: + suffix = fmt.Sprintf("-%d-%s", r.Priority, hashString) + case CAA: + suffix = fmt.Sprintf("%s-%s", r.Flags, r.Tag) + case A, AAAA, TXT: + suffix = fmt.Sprintf("-%s", hashString) + } + + built := base + suffix + return built +} + +func (r *DNSRecord) handle(ctx *pulumi.Context, ZoneName string, zone *cloudflare.Zone) (*cloudflare.Record, error) { + var recordArgs *cloudflare.RecordArgs + switch r.Kind { + case CAA: + recordArgs = &cloudflare.RecordArgs{ + ZoneId: r.getZone(zone), + Name: pulumi.String(r.Name), + Type: pulumi.String(strings.ToUpper(string(r.Kind))), + Ttl: pulumi.Int(r.Ttl), + Data: &cloudflare.RecordDataArgs{ + Flags: pulumi.String(r.Flags), + Tag: pulumi.String(r.Tag), + Value: pulumi.String(r.Value), + }, + } + default: + recordArgs = &cloudflare.RecordArgs{ + ZoneId: r.getZone(zone), + Name: pulumi.String(r.Name), + Type: pulumi.String(strings.ToUpper(string(r.Kind))), + Ttl: pulumi.Int(r.Ttl), + Priority: pulumi.Int(r.Priority), + Value: pulumi.String(r.Value), + } + } + return cloudflare.NewRecord(ctx, r.getName(ZoneName, zone), recordArgs) +} diff --git a/iac/tailscale.go b/iac/tailscale.go new file mode 100644 index 00000000..a9df5309 --- /dev/null +++ b/iac/tailscale.go @@ -0,0 +1,104 @@ +package iac + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + tailscale "github.com/pulumi/pulumi-tailscale/sdk/go/tailscale" + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" + "strings" + "net" + "fmt" +) + +func MakeRecord(ctx *pulumi.Context, zones map[string]*cloudflare.Zone, name string, address string) (record *cloudflare.Record, err error) { + ip := net.ParseIP(address) + kind := A; + if ip.To4() != nil { + kind = AAAA; + } + record_ := DNSRecord{ + Name: name, + Kind: kind, + Value: ip.String(), + Ttl: 3600, + } + record, err = record_.handle(ctx, "inskip", zones["inskip"]) + if err != nil { + return nil, err + } + return record, err +} + +func HandleTSRecord(ctx *pulumi.Context, zones map[string]*cloudflare.Zone, device tailscale.GetDevicesDevice) (records []*cloudflare.Record, err error) { + if device.User != "kat@inskip.me" { + return []*cloudflare.Record{}, nil + } + name := strings.Split(device.Name, ".")[0] + for _, address := range device.Addresses { + record, err := MakeRecord(ctx, zones, name, address) + if err != nil { + return nil, err + } + records = append(records, record) + } + return records, err +} + +func HandleTSRecords(ctx *pulumi.Context, + tailnet *tailscale.GetDevicesResult, + zones map[string]*cloudflare.Zone, + records map[string][]*cloudflare.Record, +) (records_ map[string][]*cloudflare.Record, err error) { + for _, device := range tailnet.Devices { + record, err := HandleTSRecord(ctx, zones, device) + if err != nil { + return nil, err + } + records["inskip"] = append(records["inskip"], record...) + } + records_ = records + return records_, err +} + +func HandleTSHostCert(ctx *pulumi.Context, + device tailscale.GetDevicesDevice, + ca_key *tls.PrivateKey, + ca_cert *tls.SelfSignedCert) (key *tls.PrivateKey, + cr *tls.CertRequest, + cert *tls.LocallySignedCert, + err error) { + name := strings.Split(device.Name, ".")[0] + key, cr, cert, err = generateKeyPair( + ctx, + fmt.Sprintf("ts-%s-host", name), + ca_key, + ca_cert, + device.Addresses, + []string{fmt.Sprintf("%s.inskip.me", name)}, + ) + if err != nil { + return nil, nil, nil, err + } + return key, cr, cert, err +} + +func HandleTSHostCerts(ctx *pulumi.Context, + tailnet *tailscale.GetDevicesResult, + ca_key *tls.PrivateKey, + ca_cert *tls.SelfSignedCert) (keys map[string]*tls.PrivateKey, + crs map[string]*tls.CertRequest, + certs map[string]*tls.LocallySignedCert, + err error) { + keys = make(map[string]*tls.PrivateKey) + crs = make(map[string]*tls.CertRequest) + certs = make(map[string]*tls.LocallySignedCert) + + for _, device := range tailnet.Devices { + name := strings.Split(device.Name, ".")[0] + keys[name], crs[name], certs[name], err = HandleTSHostCert(ctx, device, ca_key, ca_cert) + if err != nil { + return nil, nil, nil, err + } + } + return keys, crs, certs, err +} diff --git a/iac/tls.go b/iac/tls.go new file mode 100644 index 00000000..7f505625 --- /dev/null +++ b/iac/tls.go @@ -0,0 +1,54 @@ +package iac + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" + "fmt" +) + +func generateKeyPair(ctx *pulumi.Context, + purpose string, + ca_key *tls.PrivateKey, + ca_cert *tls.SelfSignedCert, + dns_names []string, + ip_addresses []string) (key *tls.PrivateKey, + cr *tls.CertRequest, + cert *tls.LocallySignedCert, + err error) { + key, err = tls.NewPrivateKey(ctx, fmt.Sprintf("%s-key", purpose), &tls.PrivateKeyArgs{ + Algorithm: pulumi.String("RSA"), + RsaBits: pulumi.Int(4096), + }) + if err != nil { + return nil, nil, nil, err + } + cr, err = tls.NewCertRequest(ctx, fmt.Sprintf("%s-cr", purpose), &tls.CertRequestArgs{ + PrivateKeyPem: key.PrivateKeyPem, + DnsNames: goStringArrayToPulumiStringArray(dns_names), + IpAddresses: goStringArrayToPulumiStringArray(ip_addresses), + Subject: &tls.CertRequestSubjectArgs{ + CommonName: pulumi.String("inskip.me"), + Organization: pulumi.String("Kat Inskip"), + }, + }) + if err != nil { + return nil, nil, nil, err + } + cert, err = tls.NewLocallySignedCert(ctx, fmt.Sprintf("%s-cert", purpose), &tls.LocallySignedCertArgs{ + AllowedUses: goStringArrayToPulumiStringArray([]string{"digital_signature", + "digital_signature", + "key_encipherment", + "key_agreement", + "email_protection", + }), + CaPrivateKeyPem: ca_key.PrivateKeyPem, + CaCertPem: ca_cert.CertPem, + CertRequestPem: cr.CertRequestPem, + ValidityPeriodHours: pulumi.Int(1440), + EarlyRenewalHours: pulumi.Int(168), + }) + if err != nil { + return nil, nil, nil, err + } + return key, cr, cert, err +} diff --git a/iac/zone.go b/iac/zone.go new file mode 100644 index 00000000..8190674c --- /dev/null +++ b/iac/zone.go @@ -0,0 +1,24 @@ +package iac + +import ( + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" +) + +type Zone struct { + Zone string `yaml:"name"` + Records []DNSRecord `yaml:"records"` +} + +func (z *Zone) handle(ctx *pulumi.Context, name string) (zone *cloudflare.Zone, err error) { + zone, err = cloudflare.NewZone(ctx, name, &cloudflare.ZoneArgs{ + AccountId: pulumi.ID("0467b993b65d8fd4a53fe24ed2fbb2a1"), + Zone: pulumi.String(z.Zone), + Plan: pulumi.String("free"), + }) + if err != nil { + return nil, err + } + return zone, err +} + diff --git a/main.go b/main.go index 991e5e2d..f82161a4 100644 --- a/main.go +++ b/main.go @@ -3,196 +3,56 @@ package main import ( "github.com/pulumi/pulumi/sdk/v3/go/pulumi" tailscale "github.com/pulumi/pulumi-tailscale/sdk/go/tailscale" - cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" "gopkg.in/yaml.v3" - "github.com/creasty/defaults" "log" - "fmt" "os" - "strings" - "crypto/md5" - "encoding/hex" + iac "kittywitch/iac" ) -type DNSRecordType string - -const ( - A DNSRecordType = "a" - AAAA = "aaaa" - MX = "mx" - TXT = "txt" - CAA = "caa" -) - -type DNSRecord struct { - Name string `default:"@" yaml:"name"` - Kind DNSRecordType `yaml:"kind"` - Value string `yaml:"value,omitempty"` - Priority int `yaml:"priority,omitempty"` - Flags string `yaml:"flags,omitempty"` - Tag string `yaml:"tag,omitempty"` - Ttl int `default:"3600" yaml:"ttl,omitempty"` -} - -func (r *DNSRecord) UnmarshalYAML(unmarshal func(interface{}) error) error { - defaults.Set(r) - - type plain DNSRecord - if err := unmarshal((*plain)(r)); err != nil { - return err - } - - return nil -} - -func (r *DNSRecord) getZone( Zone *cloudflare.Zone) (pulumi.StringOutput) { - return Zone.ID().ToStringOutput() -} - -func (r *DNSRecord) getName(ZoneName string, Zone *cloudflare.Zone) (string) { - base := fmt.Sprintf("%s-%s-%s", ZoneName, r.Kind, r.Name) - - hash := md5.Sum([]byte(r.Value)) - hashString := hex.EncodeToString(hash[:])[:5] - suffix := "" - switch r.Kind { - case MX: - suffix = fmt.Sprintf("-%d-%s", r.Priority, hashString) - case CAA: - suffix = fmt.Sprintf("%s-%s", r.Flags, r.Tag) - case A, AAAA, TXT: - suffix = fmt.Sprintf("-%s", hashString) - } - - built := base + suffix - return built -} - -func (r *DNSRecord) handle(ctx *pulumi.Context, ZoneName string, zone *cloudflare.Zone) (*cloudflare.Record, error) { - var recordArgs *cloudflare.RecordArgs - switch r.Kind { - case CAA: - recordArgs = &cloudflare.RecordArgs{ - ZoneId: r.getZone(zone), - Name: pulumi.String(r.Name), - Type: pulumi.String(strings.ToUpper(string(r.Kind))), - Ttl: pulumi.Int(r.Ttl), - Data: &cloudflare.RecordDataArgs{ - Flags: pulumi.String(r.Flags), - Tag: pulumi.String(r.Tag), - Value: pulumi.String(r.Value), - }, - } - default: - recordArgs = &cloudflare.RecordArgs{ - ZoneId: r.getZone(zone), - Name: pulumi.String(r.Name), - Type: pulumi.String(strings.ToUpper(string(r.Kind))), - Ttl: pulumi.Int(r.Ttl), - Priority: pulumi.Int(r.Priority), - Value: pulumi.String(r.Value), - } - } - return cloudflare.NewRecord(ctx, r.getName(ZoneName, zone), recordArgs) -} - -type Zone struct { - Zone string `yaml:"name"` - Records []DNSRecord `yaml:"records"` -} - -type Config struct { - Zones map[string]Zone `yaml:"zones"` -} - -func (z *Zone) handle(ctx *pulumi.Context, name string) (*cloudflare.Zone, error) { - return cloudflare.NewZone(ctx, name, &cloudflare.ZoneArgs{ - Zone: pulumi.String(z.Zone), - Plan: pulumi.String("free"), - }) -} - func main() { - config := Config{} + katConfig := iac.KatConfig{} + + configFile, err := os.ReadFile("config.yaml") - configfile, err := os.ReadFile("config.yaml") if err != nil { log.Fatal(err) } - if err := yaml.Unmarshal(configfile, &config); err != nil { + + if err := yaml.Unmarshal(configFile, &katConfig); err != nil { log.Fatal(err) } pulumi.Run(func(ctx *pulumi.Context) error { - ctx.Log.Info(fmt.Sprintf("%v\n", config), nil) tailnet, err := tailscale.GetDevices(ctx, &tailscale.GetDevicesArgs{}, nil) if err != nil { return err } - zones := make(map[string]*cloudflare.Zone) - dnssec := make(map[string]*cloudflare.ZoneDnssec) - records := make(map[string][]*cloudflare.Record) - for name, zone := range config.Zones { - ctx.Log.Info(name, nil) - zones[name], err = zone.handle(ctx, name) - if err != nil { - return err - } - dnssec[name], err = cloudflare.NewZoneDnssec(ctx, fmt.Sprintf("%s-dnssec", name), &cloudflare.ZoneDnssecArgs{ - ZoneId: zones[name].ID(), - }) - if err != nil { - return err - } - for _, record := range zone.Records { - _, exists := records[name] - if exists { - record_, err := record.handle(ctx, name, zones[name]) - if err != nil { - log.Fatal(err) - } - records[name] = append(records[name], record_) - } else { - record_, err := record.handle(ctx, name, zones[name]) - if err != nil { - log.Fatal(err) - } - records[name] = []*cloudflare.Record{record_} - } - } + + // zones, dnssec, records + zones, _, records, err := iac.HandleDNS(ctx, katConfig) + + if err != nil { + log.Fatal(err) } - for _, device := range tailnet.Devices { - if device.User != "kat@inskip.me" { - continue - } - device_name := strings.Split(device.Name, ".")[0] - ipv4 := DNSRecord{ - Name: device_name, - Kind: A, - Value: device.Addresses[0], - Ttl: 3600, - } - recv4, err := ipv4.handle(ctx, "inskip", zones["inskip"]) - if err != nil { - log.Fatal(err) - } - ipv6 := DNSRecord{ - Name: device_name, - Kind: AAAA, - Value: device.Addresses[1], - Ttl: 3600, - } - recv6, err := ipv6.handle(ctx, "inskip", zones["inskip"]) - if err != nil { - log.Fatal(err) - } - records["inskip"] = append(records["inskip"], recv4, recv6) + records, err = iac.HandleTSRecords(ctx, tailnet, zones, records) + + if err != nil { + log.Fatal(err) } - if err != nil { - log.Fatal(err) - } - return nil - }) + ca_key, ca_cert, err := iac.GenerateTLSCA(ctx) + + if err != nil { + log.Fatal(err) + } + + // keys, crs, certs + _, _, _, err = iac.HandleTSHostCerts(ctx, tailnet, ca_key, ca_cert) + + if err != nil { + log.Fatal(err) + } + return nil + }) }