From ccf6a6f704b754601ef4a96b8723ab889b1918bb Mon Sep 17 00:00:00 2001 From: Kat Inskip Date: Sat, 4 Feb 2023 14:18:40 -0800 Subject: [PATCH] feat: SSH CA --- .idea/.gitignore | 8 ++ .idea/kittywitch.iml | 9 ++ .idea/modules.xml | 8 ++ .idea/vcs.xml | 6 + Pulumi.mew.yaml | 2 +- config.yaml | 2 + darwin/distributed.nix | 13 ++- flake.lock | 30 ++--- iac/ca.go | 75 ++++++------ iac/config.go | 2 +- iac/device.go | 205 +++++++++++++++++++++++++++++++++ iac/dns.go | 37 ------ iac/files.go | 54 +++------ iac/inskip.go | 93 +++++++++++++++ iac/record.go | 147 ++++++++++++----------- iac/ssh.go | 91 +++++++++++++++ iac/tailscale.go | 110 ------------------ iac/tls.go | 54 --------- iac/zone.go | 67 ++++++++--- kat/user/nixos.nix | 1 + main.go | 80 ++++--------- modules/common/distributed.nix | 4 +- systems/sumireko.nix | 11 ++ 23 files changed, 678 insertions(+), 431 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/kittywitch.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 iac/device.go delete mode 100644 iac/dns.go create mode 100644 iac/inskip.go delete mode 100644 iac/tailscale.go delete mode 100644 iac/tls.go diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/kittywitch.iml b/.idea/kittywitch.iml new file mode 100644 index 00000000..5e764c4f --- /dev/null +++ b/.idea/kittywitch.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..3473b4e6 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Pulumi.mew.yaml b/Pulumi.mew.yaml index d61fcb9b..3c707a12 100644 --- a/Pulumi.mew.yaml +++ b/Pulumi.mew.yaml @@ -1,6 +1,6 @@ config: cloudflare:apiToken: - secure: AAABACPPwldgPSVHPYdh4lQnYR+baaGsnQRwGw/qwNke8wuFnCTdZIqj6yXu0CCGaYBu0+66LTALNNl9mo9HXs/PMLmoOqLo + secure: AAABAFcufTX7tZZf2gcK6hML2tgovDEfcPAJcgjfYkV3GMS4Ilwzuco5p+hCpyj3vCm7cqm3tmdwOLlOFxGqKZGRj+ESXAzv tailscale:apiKey: secure: AAABAGc7s7XJ+voSUNcMmRuVwrUdx3kojn0fdEl6qpUy0WmhgHbk6cEz2/kGSEGhuLGwo3mzOGVTI+NVu6/Xz4PmE9FME++VfE8cz5DFjDrMJ4JdX0DR tailscale:tailnet: inskip.me diff --git a/config.yaml b/config.yaml index fccebd0c..6880e924 100644 --- a/config.yaml +++ b/config.yaml @@ -6,6 +6,8 @@ zones: flags: 0 tag: iodef value: mailto:acme@inskip.me + - kind: cname + value: inskip-root.pages.dev - kind: caa flags: 0 tag: issue diff --git a/darwin/distributed.nix b/darwin/distributed.nix index 36b43168..73a306eb 100644 --- a/darwin/distributed.nix +++ b/darwin/distributed.nix @@ -1,5 +1,16 @@ -_: { +{ pkgs, ... }: { nix.envVars = { "SSH_AUTH_SOCK" = "/Users/kat/.gnupg/S.gpg-agent.ssh"; }; + + launchd.daemons.start_nixos_native = { + serviceConfig.ProgramArguments = [ + "/bin/sh" "-c" + "/bin/wait4path /nix/store && ${pkgs.writeScript "start_nixos_native" '' + /usr/bin/open "utm://start?name=NixOS Native" + ''}" + ]; + serviceConfig.Label = "org.kittywitch.start_nixos_native"; + serviceConfig.RunAtLoad = true; + }; } diff --git a/flake.lock b/flake.lock index ebb48eb1..800c0dda 100644 --- a/flake.lock +++ b/flake.lock @@ -24,11 +24,11 @@ "arcexprs": { "flake": false, "locked": { - "lastModified": 1674878824, - "narHash": "sha256-skuyKtydzGFtd2UQB2BZW2bMaUcS+fvHEEz+H4MNQ4g=", + "lastModified": 1675107003, + "narHash": "sha256-ao5OLwhC7+T3O2ixRrt76gIg9uZR3c17SJL3Wvx0EpQ=", "owner": "arcnmx", "repo": "nixexprs", - "rev": "ab1bd348da95d6f33ad28992b5d8c636d2330cc9", + "rev": "5b7d1eb5e578da7ed36b2105f80f82f9ad11244d", "type": "github" }, "original": { @@ -126,11 +126,11 @@ ] }, "locked": { - "lastModified": 1674771519, - "narHash": "sha256-U0W3S1nX6yEvLh3Vq70EORbmXecAKXfmEfCfaA4A+I8=", + "lastModified": 1675181178, + "narHash": "sha256-jymSUUjKoArptU7LJ1i4boysXptnpuETiUTenKgs2fM=", "owner": "nix-community", "repo": "home-manager", - "rev": "bb4b25b302dbf0f527f190461b080b5262871756", + "rev": "69696fe53940562a047bf2ec675cc1dcd1bc09b3", "type": "github" }, "original": { @@ -173,11 +173,11 @@ ] }, "locked": { - "lastModified": 1674357402, - "narHash": "sha256-oxOCYORXBh0KW4KEwKpzs2LThDdVmEwREV+SsP4CIpg=", + "lastModified": 1674962474, + "narHash": "sha256-qEXdgW5fnMSdQwP1zQYa0fVtI0f3G1f2qNRjUEherCs=", "owner": "Mic92", "repo": "nix-index-database", - "rev": "e9e7c5c62965e7e656febb5ba578d53f751eb41f", + "rev": "a385f6192f5471c4cebeeb0d2e966b5ccf123df5", "type": "github" }, "original": { @@ -188,11 +188,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1674641431, - "narHash": "sha256-qfo19qVZBP4qn5M5gXc/h1MDgAtPA5VxJm9s8RUAkVk=", + "lastModified": 1675115703, + "narHash": "sha256-4zetAPSyY0D77x+Ww9QBe8RHn1akvIvHJ/kgg8kGDbk=", "owner": "nixos", "repo": "nixpkgs", - "rev": "9b97ad7b4330aacda9b2343396eb3df8a853b4fc", + "rev": "2caf4ef5005ecc68141ecb4aac271079f7371c44", "type": "github" }, "original": { @@ -205,11 +205,11 @@ "pypi-deps-db": { "flake": false, "locked": { - "lastModified": 1674855014, - "narHash": "sha256-SMUq72uWWs+KAlcRB7UXzI1QHNTGiUTpQK2qj1evHXQ=", + "lastModified": 1675156620, + "narHash": "sha256-lmnsBYJz2Fgm0WFNUgSqskpwa0ffbFOr9YGDZpUXptk=", "owner": "DavHau", "repo": "pypi-deps-db", - "rev": "a375715227007ca768d372b2b09bcb76f8f19d78", + "rev": "2e236bb32e6e3ef13cd56fc6d9aee8c89059a1ac", "type": "github" }, "original": { diff --git a/iac/ca.go b/iac/ca.go index 0e65ba5b..c5bad50a 100644 --- a/iac/ca.go +++ b/iac/ca.go @@ -1,40 +1,45 @@ package iac -import( - "github.com/pulumi/pulumi/sdk/v3/go/pulumi" - tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" +import ( + tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) -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 { - return nil, nil, 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 { - return nil, nil, 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 +type CertificateAuthority struct { + Key *tls.PrivateKey + Cert *tls.SelfSignedCert +} + +func (ca *CertificateAuthority) handle(ctx *pulumi.Context) (err error) { + ca.Key, err = tls.NewPrivateKey(ctx, "ca-root", &tls.PrivateKeyArgs{ + Algorithm: pulumi.String("RSA"), + RsaBits: pulumi.Int(4096), + }) + + if err != nil { + return err + } + + ca.Cert, err = tls.NewSelfSignedCert(ctx, "ca-root", &tls.SelfSignedCertArgs{ + PrivateKeyPem: ca.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 { + return err + } + + ctx.Export("ca_pem_privkey", ca.Key.PrivateKeyPem) + ctx.Export("ca_os_privkey", ca.Key.PrivateKeyOpenssh) + ctx.Export("ca_pem_cert", ca.Cert.CertPem) + + return err } diff --git a/iac/config.go b/iac/config.go index 072bea85..0cd46194 100644 --- a/iac/config.go +++ b/iac/config.go @@ -1,5 +1,5 @@ package iac type KatConfig struct { - Zones map[string]Zone `yaml:"zones"` + Zones map[string]Zone `yaml:"zones"` } diff --git a/iac/device.go b/iac/device.go new file mode 100644 index 00000000..ddf83fa1 --- /dev/null +++ b/iac/device.go @@ -0,0 +1,205 @@ +package iac + +import ( + "crypto/rand" + "fmt" + "github.com/pulumi/pulumi-command/sdk/go/command/remote" + "github.com/pulumi/pulumi-tailscale/sdk/go/tailscale" + "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "golang.org/x/crypto/ssh" + "net" + "strings" + "time" +) + +type Tailnet struct { + Devices []Device + Zone *Zone +} + +func (t *Tailnet) handle(ctx *pulumi.Context, zone *Zone, CAKey *tls.PrivateKey, CACert *tls.SelfSignedCert) (err error) { + t.Zone = zone + tailnet, err := tailscale.GetDevices(ctx, &tailscale.GetDevicesArgs{}, nil) + if err != nil { + return err + } + for _, device := range tailnet.Devices { + device_ := Device{ + Addresses: device.Addresses, + Id: device.Id, + Name: device.Name, + Tags: device.Tags, + User: device.User, + } + err = device_.handle(ctx, zone, CAKey, CACert) + if err != nil { + return err + } + t.Devices = append(t.Devices, device_) + } + return err +} + +type Device struct { + Addresses []string + Id string + Name string + Hostname string + Tailskip string + Tags []string + User string + Files []*remote.Command + Context *pulumi.Context + Records []DNSRecord + PrivateKey *tls.PrivateKey + TLSCertRequest *tls.CertRequest + TLSCert *tls.LocallySignedCert + OSHCertificate pulumi.StringOutput +} + +func (d *Device) handle(ctx *pulumi.Context, zone *Zone, CAKey *tls.PrivateKey, CACert *tls.SelfSignedCert) (err error) { + d.Context = ctx + d.Records = make([]DNSRecord, 0, 50) + d.Files = make([]*remote.Command, 0, 20) + d.Hostname = strings.Split(d.Name, ".")[0] + d.Tailskip = fmt.Sprintf("%s.inskip.me", d.Hostname) + if d.User != "kat@inskip.me" { + return nil + } + err = d.record(zone) + if err != nil { + return err + } + if d.Hostname != "koishi" { + return err + } + err = d.handleTLS(CAKey, CACert) + if err != nil { + return err + } + err = d.handleOSH(CAKey) + if err != nil { + return err + } + return err +} + +func (d *Device) handleOSH(CAKey *tls.PrivateKey) (err error) { + d.OSHCertificate = CAKey.PrivateKeyOpenssh.ApplyT(func(CAPriv string) pulumi.StringOutput { + OSHCertificate_ := d.PrivateKey.PrivateKeyOpenssh.ApplyT(func(UserPriv string) pulumi.String { + CARSAPriv, err := PrivateKeyOpenSSHToRSAPrivateKey(CAPriv) + if err != nil { + panic(err) + } + signer, err := ssh.NewSignerFromKey(CARSAPriv) + if err != nil { + panic(err) + } + var cert ssh.Certificate + cert.Nonce = make([]byte, 32) + cert.CertType = 2 + UserRSAPriv, err := PrivateKeyOpenSSHToRSAPrivateKey(UserPriv) + if err != nil { + panic(err) + } + cert.Key, err = ssh.NewPublicKey(UserRSAPriv.Public()) + if err != nil { + panic(err) + } + cert.Serial = 0 + cert.KeyId = d.Tailskip + cert.ValidPrincipals = []string{d.Tailskip} + cert.ValidAfter = 60 + threeMonths, err := time.ParseDuration("730h") + if err != nil { + panic(err) + } + threeMonthsInSeconds := uint64(threeMonths.Seconds()) + cert.ValidBefore = threeMonthsInSeconds + err = cert.SignCert(rand.Reader, signer) + return pulumi.String(string(ssh.MarshalAuthorizedKey(&cert))) + }).(pulumi.StringOutput) + return OSHCertificate_ + }).(pulumi.StringOutput) + file, err := CreatePulumiFile(d.Context, fmt.Sprintf("%s-osh-cert", d.Hostname), d.Tailskip, d.OSHCertificate, []pulumi.Resource{d.PrivateKey, CAKey}) + d.Files = append(d.Files, file) + return err +} + +func (d *Device) record(zone *Zone) (err error) { + for _, address := range d.Addresses { + ip := net.ParseIP(address) + kind := A + if ip.To4() == nil { + kind = AAAA + } + record := DNSRecord{ + Name: d.Hostname, + Kind: kind, + Value: ip.String(), + Ttl: 3600, + } + err = record.handle(d.Context, zone) + if err != nil { + return err + } + d.Records = append(d.Records, record) + } + return err +} + +func (d *Device) handleTLS(CAKey *tls.PrivateKey, CACert *tls.SelfSignedCert) (err error) { + PrivateKeyDepends := []pulumi.Resource{CAKey, CACert} + d.PrivateKey, err = tls.NewPrivateKey(d.Context, fmt.Sprintf("%s-key", d.Hostname), &tls.PrivateKeyArgs{ + Algorithm: pulumi.String("RSA"), + RsaBits: pulumi.Int(4096), + }, pulumi.DependsOn(PrivateKeyDepends)) + if err != nil { + return err + } + PrivateKeyDepends = append(PrivateKeyDepends, d.PrivateKey) + file, err := CreatePulumiFile(d.Context, fmt.Sprintf("%s-pem-pk", d.Hostname), d.Tailskip, d.PrivateKey.PrivateKeyPem, PrivateKeyDepends) + if err != nil { + return err + } + d.Files = append(d.Files, file) + file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-osh-pk", d.Hostname), d.Tailskip, d.PrivateKey.PrivateKeyOpenssh, PrivateKeyDepends) + if err != nil { + return err + } + d.Files = append(d.Files, file) + TLSCertRequestDepends := []pulumi.Resource{CAKey, CACert, d.PrivateKey} + d.TLSCertRequest, err = tls.NewCertRequest(d.Context, fmt.Sprintf("%s-tls-cr", d.Hostname), &tls.CertRequestArgs{ + PrivateKeyPem: d.PrivateKey.PrivateKeyPem, + DnsNames: goStringArrayToPulumiStringArray([]string{d.Hostname}), + IpAddresses: goStringArrayToPulumiStringArray(d.Addresses), + Subject: &tls.CertRequestSubjectArgs{ + CommonName: pulumi.String("inskip.me"), + Organization: pulumi.String("Kat Inskip"), + }, + }, pulumi.DependsOn(TLSCertRequestDepends)) + if err != nil { + return err + } + TLSCertDepends := []pulumi.Resource{CAKey, CACert, d.TLSCertRequest, d.PrivateKey} + d.TLSCert, err = tls.NewLocallySignedCert(d.Context, fmt.Sprintf("%s-tls-cert", d.Hostname), &tls.LocallySignedCertArgs{ + AllowedUses: goStringArrayToPulumiStringArray([]string{"digital_signature", + "digital_signature", + "key_encipherment", + "key_agreement", + "email_protection", + }), + CaPrivateKeyPem: CAKey.PrivateKeyPem, + CaCertPem: CACert.CertPem, + CertRequestPem: d.TLSCertRequest.CertRequestPem, + ValidityPeriodHours: pulumi.Int(1440), + EarlyRenewalHours: pulumi.Int(168), + }, pulumi.DependsOn(TLSCertDepends)) + file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-pem-cert", d.Hostname), d.Tailskip, d.TLSCert.CertPem, TLSCertDepends) + d.Files = append(d.Files, file) + if err != nil { + return err + } + return err +} diff --git a/iac/dns.go b/iac/dns.go deleted file mode 100644 index 301234f7..00000000 --- a/iac/dns.go +++ /dev/null @@ -1,37 +0,0 @@ -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 { - record_, err := record.handle(ctx, name, zones[name]) - if err != nil { - return nil, nil, nil, err - } - record_index := record.getName(name, zones[name]) - records[record_index] = record_ - } - } - - return zones, dnssec, records, err -} diff --git a/iac/files.go b/iac/files.go index ada8a01e..a42f1600 100644 --- a/iac/files.go +++ b/iac/files.go @@ -1,43 +1,23 @@ package iac import ( - "github.com/pulumi/pulumi-command/sdk/go/command/local" - "github.com/pulumi/pulumi/sdk/v3/go/pulumi" - "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" - "fmt" - "os" - "path" + "github.com/pulumi/pulumi-command/sdk/go/command/remote" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" ) -func createPulumiFile(ctx *pulumi.Context, name string, value pulumi.StringOutput, resource pulumi.Resource) (*local.Command, error) { - repo_root := os.Getenv("REPO_ROOT") - data_root := path.Join(repo_root, "./data") - ctx.Export(name, value) - return local.NewCommand(ctx, name, &local.CommandArgs{ - Create: pulumi.String(fmt.Sprintf("pulumi stack output %s --non-interactive --show-secrets > %s", name, name)), - Update: pulumi.String(fmt.Sprintf("pulumi stack output %s --non-interactive --show-secrets > %s", name, name)), - Delete: pulumi.String(fmt.Sprintf("rm %s", name)), - Dir: pulumi.String(data_root), - Environment: goMapToPulumiMap(map[string]string{ - "PULUMI_SKIP_UPDATE_CHECK": "true", - }), - }, pulumi.DependsOn([]pulumi.Resource{resource})) -} - -func PKITLSFiles(ctx *pulumi.Context, files_ map[string]*local.Command, keys map[string]*tls.PrivateKey, certs map[string]*tls.LocallySignedCert) (files map[string]*local.Command, err error) { - for name_, key := range keys { - name := fmt.Sprintf("%s-file", name_) - files_[name], err = createPulumiFile(ctx, name, key.PrivateKeyPem, key) - if err != nil { - return nil, err - } - } - for name_, cert := range certs { - name := fmt.Sprintf("%s-file", name_) - files_[name], err = createPulumiFile(ctx, name, cert.CertPem, cert) - if err != nil { - return nil, err - } - } - return files_, err +func CreatePulumiFile(ctx *pulumi.Context, name string, fqdn string, value pulumi.StringOutput, resources []pulumi.Resource) (*remote.Command, error) { + environment := goMapToPulumiMap(map[string]string{ + "PULUMI_SKIP_UPDATE_CHECK": "true", + }) + return remote.NewCommand(ctx, name, &remote.CommandArgs{ + Connection: &remote.ConnectionArgs{ + Host: pulumi.String(fqdn), + Port: pulumi.Float64Ptr(22), + User: pulumi.String("deploy"), + AgentSocketPath: pulumi.String("/Users/kat/.gnupg/S.gpg-agent.ssh"), + }, + Create: pulumi.Sprintf("sudo mkdir -p /var/lib/secrets && sudo chown deploy:users -R /var/lib/secrets && cd /var/lib/secrets && echo \"%s\" > \"%s\"", value, name), + Delete: pulumi.Sprintf("cd /var/lib/secrets && rm %s", name), + Environment: environment, + }, pulumi.DependsOn(resources)) } diff --git a/iac/inskip.go b/iac/inskip.go new file mode 100644 index 00000000..b9953f97 --- /dev/null +++ b/iac/inskip.go @@ -0,0 +1,93 @@ +package iac + +import ( + "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" +) + +func InskipPage(ctx *pulumi.Context) error { + _, err := cloudflare.NewPagesProject(ctx, "inskip-root", &cloudflare.PagesProjectArgs{ + AccountId: pulumi.ID("0467b993b65d8fd4a53fe24ed2fbb2a1"), + Name: pulumi.String("inskip-root"), + ProductionBranch: pulumi.String("main"), + BuildConfig: &cloudflare.PagesProjectBuildConfigArgs{ + BuildCommand: pulumi.String("hugo"), + DestinationDir: pulumi.String("public"), + RootDir: pulumi.String("/"), + }, + Source: &cloudflare.PagesProjectSourceArgs{ + Type: pulumi.String("github"), + Config: &cloudflare.PagesProjectSourceConfigArgs{ + DeploymentsEnabled: pulumi.Bool(true), + Owner: pulumi.String("kittywitch"), + PrCommentsEnabled: pulumi.Bool(false), + PreviewBranchExcludes: pulumi.StringArray{ + pulumi.String("main"), + pulumi.String("prod"), + }, + PreviewBranchIncludes: pulumi.StringArray{ + pulumi.String("dev"), + pulumi.String("preview"), + }, + PreviewDeploymentSetting: pulumi.String("custom"), + ProductionBranch: pulumi.String("main"), + ProductionDeploymentEnabled: pulumi.Bool(true), + RepoName: pulumi.String("inskip.me"), + }, + }, + DeploymentConfigs: &cloudflare.PagesProjectDeploymentConfigsArgs{ + Preview: &cloudflare.PagesProjectDeploymentConfigsPreviewArgs{ + CompatibilityDate: pulumi.String("2022-08-15"), + CompatibilityFlags: pulumi.StringArray{}, + /* D1Databases: pulumi.AnyMap{ + "D1BINDING": pulumi.Any("445e2955-951a-4358-a35b-a4d0c813f63"), + }, + DurableObjectNamespaces: pulumi.AnyMap{ + "DOBINDING": pulumi.Any("5eb63bbbe01eeed093cb22bb8f5acdc3"), + }, + EnvironmentVariables: pulumi.AnyMap{ + "ENVIRONMENT": pulumi.Any("preview"), + }, + KvNamespaces: pulumi.AnyMap{ + "KVBINDING": pulumi.Any("5eb63bbbe01eeed093cb22bb8f5acdc3"), + }, + R2Buckets: pulumi.AnyMap{ + "R2BINDING": pulumi.Any("some-bucket"), + }, */ + }, + Production: &cloudflare.PagesProjectDeploymentConfigsProductionArgs{ + CompatibilityDate: pulumi.String("2022-08-16"), + CompatibilityFlags: pulumi.StringArray{}, + /*D1Databases: pulumi.AnyMap{ + "D1BINDING1": pulumi.Any("445e2955-951a-4358-a35b-a4d0c813f63"), + "D1BINDING2": pulumi.Any("a399414b-c697-409a-a688-377db6433cd9"), + }, + DurableObjectNamespaces: pulumi.AnyMap{ + "DOBINDING1": pulumi.Any("5eb63bbbe01eeed093cb22bb8f5acdc3"), + "DOBINDING2": pulumi.Any("3cdca5f8bb22bc390deee10ebbb36be5"), + }, + EnvironmentVariables: pulumi.AnyMap{ + "ENVIRONMENT": pulumi.Any("production"), + "OTHERVALUE": pulumi.Any("other value"), + }, + KvNamespaces: pulumi.AnyMap{ + "KVBINDING1": pulumi.Any("5eb63bbbe01eeed093cb22bb8f5acdc3"), + "KVBINDING2": pulumi.Any("3cdca5f8bb22bc390deee10ebbb36be5"), + }, + R2Buckets: pulumi.AnyMap{ + "R2BINDING1": pulumi.Any("some-bucket"), + "R2BINDING2": pulumi.Any("other-bucket"), + },*/ + }, + }, + }) + _, err = cloudflare.NewPagesDomain(ctx, "inskip-root", &cloudflare.PagesDomainArgs{ + AccountId: pulumi.String("0467b993b65d8fd4a53fe24ed2fbb2a1"), + Domain: pulumi.String("inskip.me"), + ProjectName: pulumi.String("inskip-root"), + }) + if err != nil { + return err + } + return nil +} diff --git a/iac/record.go b/iac/record.go index cf93772d..70695230 100644 --- a/iac/record.go +++ b/iac/record.go @@ -1,93 +1,102 @@ 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" + "crypto/md5" + "encoding/hex" + "fmt" + "github.com/creasty/defaults" + "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "strings" ) type DNSRecordType string const ( - A DNSRecordType = "a" - AAAA = "aaaa" - MX = "mx" - TXT = "txt" - CAA = "caa" + A DNSRecordType = "a" + AAAA = "aaaa" + MX = "mx" + TXT = "txt" + CAA = "caa" + CNAME = "cname" ) 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"` + CFRecord *cloudflare.Record + Zone *Zone + 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) +func (r *DNSRecord) UnmarshalYAML(unmarshal func(interface{}) error) (err error) { + err = defaults.Set(r) - type plain DNSRecord - if err := unmarshal((*plain)(r)); err != nil { - return err - } + if err != nil { + return err + } - return nil + type plain DNSRecord + if err := unmarshal((*plain)(r)); err != nil { + return err + } + + return err } -func (r *DNSRecord) getZone(Zone *cloudflare.Zone) (pulumi.StringOutput) { - return Zone.ID().ToStringOutput() +func (r *DNSRecord) getZone() pulumi.StringOutput { + return r.Zone.CFZone.ID().ToStringOutput() } -func (r *DNSRecord) getName(ZoneName string, Zone *cloudflare.Zone) (string) { - base := fmt.Sprintf("%s-%s-%s", ZoneName, r.Kind, r.Name) +func (r *DNSRecord) getName() string { + base := fmt.Sprintf("%s-%s-%s", r.Zone.Alias, 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) - } + 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, CNAME: + suffix = fmt.Sprintf("-%s", hashString) + } - built := base + suffix - return built + 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) +func (r *DNSRecord) handle(ctx *pulumi.Context, zone *Zone) (err error) { + r.Zone = zone + var recordArgs *cloudflare.RecordArgs + switch r.Kind { + case CAA: + recordArgs = &cloudflare.RecordArgs{ + ZoneId: r.getZone(), + 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(), + 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), + } + } + r.CFRecord, err = cloudflare.NewRecord(ctx, r.getName(), recordArgs, pulumi.DependsOn([]pulumi.Resource{r.Zone.CFZone})) + return err } diff --git a/iac/ssh.go b/iac/ssh.go index e69de29b..5831d87a 100644 --- a/iac/ssh.go +++ b/iac/ssh.go @@ -0,0 +1,91 @@ +package iac + +import ( + "crypto/rand" + "crypto/rsa" + "fmt" + tls "github.com/pulumi/pulumi-tls/sdk/v4/go/tls" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "golang.org/x/crypto/ssh" + "time" +) + +// ca_key *tls.PrivateKey, +// ca_cert *tls.SelfSignedCert) (key *tls.PrivateKey, +// ca_key, ca_cert, err := iac.GenerateTLSCA(ctx) + +// parseprivatekey +// newsignerfromkey + +func MakeCertificate() ssh.Certificate { + var newCert ssh.Certificate + // The sign() method fills in Nonce for us + newCert.Nonce = make([]byte, 32) + return newCert +} + +func PrivateKeyOpenSSHToRSAPrivateKey(keyPEM string) (key *rsa.PrivateKey, err error) { + key_int, err := ssh.ParseRawPrivateKey([]byte(keyPEM)) + key_raw := key_int.(*rsa.PrivateKey) + if err != nil { + return nil, err + } + return key_raw, err +} + +func GenerateOpenSSHHost(caKey *tls.PrivateKey, userKey *tls.PrivateKey, keyID string, name string) (certificate pulumi.StringOutput, err error) { + return GenerateOpenSSH(caKey, userKey, keyID, ssh.HostCert, name) +} + +func GenerateOpenSSHUser(caKey *tls.PrivateKey, userKey *tls.PrivateKey, keyID string, name string) (certificate pulumi.StringOutput, err error) { + return GenerateOpenSSH(caKey, userKey, keyID, ssh.UserCert, name) +} + +func GenerateOpenSSH(caKey *tls.PrivateKey, userKey *tls.PrivateKey, keyID string, certType uint32, name string) (certificate pulumi.StringOutput, err error) { + var caKeyPem *rsa.PrivateKey + var signer ssh.Signer + + newCert := caKey.PrivateKeyOpenssh.ApplyT(func(capriv string) (cert pulumi.StringOutput) { + newCertS := userKey.PrivateKeyOpenssh.ApplyT(func(content string) (cert pulumi.String) { + caKeyPem, err = PrivateKeyOpenSSHToRSAPrivateKey(capriv) + if err != nil { + panic(err) + } + signer, err = ssh.NewSignerFromKey(caKeyPem) + if err != nil { + panic(err) + } + newCert := MakeCertificate() + newCert.CertType = certType + key, err := PrivateKeyOpenSSHToRSAPrivateKey(content) + if err != nil { + panic(err) + } + newCert.Key, err = ssh.NewPublicKey(key.Public()) + if err != nil { + panic(err) + } + newCert.Serial = 0 + newCert.KeyId = keyID + newCert.ValidPrincipals = []string{fmt.Sprintf("%s.inskip.me", name)} + newCert.ValidAfter = 60 + threemo, err := time.ParseDuration("730h") + if err != nil { + panic(err) + } + threemosecs := uint64(threemo.Seconds()) + newCert.ValidBefore = threemosecs + err = newCert.SignCert(rand.Reader, signer) + return pulumi.String(string(ssh.MarshalAuthorizedKey(&newCert))) + }).(pulumi.StringOutput) + if err != nil { + panic(err) + } + return newCertS + }).(pulumi.StringOutput) + + if err != nil { + return pulumi.StringOutput{}, err + } + return newCert, err +} diff --git a/iac/tailscale.go b/iac/tailscale.go deleted file mode 100644 index e469d5d1..00000000 --- a/iac/tailscale.go +++ /dev/null @@ -1,110 +0,0 @@ -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, index string, 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"]) - index = record_.getName("inskip", zones["inskip"]) - if err != nil { - return nil, "", err - } - return record, index, err -} - -func HandleTSRecord(ctx *pulumi.Context, zones map[string]*cloudflare.Zone, device tailscale.GetDevicesDevice) (new_records map[string]*cloudflare.Record, err error) { - if device.User != "kat@inskip.me" { - return nil, nil - } - new_records = make(map[string]*cloudflare.Record) - name := strings.Split(device.Name, ".")[0] - for _, address := range device.Addresses { - new_record, index, err := MakeRecord(ctx, zones, name, address) - new_records[index] = new_record - if err != nil { - return nil, err - } - } - return new_records, err -} - -func HandleTSRecords(ctx *pulumi.Context, - tailnet *tailscale.GetDevicesResult, - zones map[string]*cloudflare.Zone, - input_records map[string]*cloudflare.Record, -) (records map[string]*cloudflare.Record, err error) { - for _, device := range tailnet.Devices { - new_records, err := HandleTSRecord(ctx, zones, device) - if err != nil { - return nil, err - } - for k,v := range new_records { - input_records[k] = v - } - records = input_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, - []string{fmt.Sprintf("%s.inskip.me", name)}, - device.Addresses, - ) - 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 { - if device.User != "kat@inskip.me" { - continue - } - name := strings.Split(device.Name, ".")[0] - keys[fmt.Sprintf("ts-%s-host-key", name)], crs[fmt.Sprintf("ts-%s-host-cr", name)], certs[fmt.Sprintf("ts-%s-host-cert", 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 deleted file mode 100644 index cce3867a..00000000 --- a/iac/tls.go +++ /dev/null @@ -1,54 +0,0 @@ -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), - }, pulumi.DependsOn([]pulumi.Resource{ca_key, ca_cert})) - 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"), - }, - }, pulumi.DependsOn([]pulumi.Resource{ca_key, ca_cert, key})) - 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), - }, pulumi.DependsOn([]pulumi.Resource{ca_key, ca_cert, key, cr})) - if err != nil { - return nil, nil, nil, err - } - return key, cr, cert, err -} diff --git a/iac/zone.go b/iac/zone.go index 8190674c..4927a8a5 100644 --- a/iac/zone.go +++ b/iac/zone.go @@ -1,24 +1,63 @@ package iac import ( - "github.com/pulumi/pulumi/sdk/v3/go/pulumi" - cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + cloudflare "github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "strings" ) type Zone struct { - Zone string `yaml:"name"` - Records []DNSRecord `yaml:"records"` + Context *pulumi.Context + Alias string + Zone string `yaml:"name"` + ExtraRecords []DNSRecord `yaml:"records"` + CFZone *cloudflare.Zone + Devices []Device + CertAuth CertificateAuthority + DNSSec *cloudflare.ZoneDnssec } -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 +func (z *Zone) Handle(ctx *pulumi.Context) (err error) { + z.Context = ctx + z.Alias = strings.ReplaceAll(z.Zone, ".", "-") + z.CFZone, err = cloudflare.NewZone(ctx, z.Alias, &cloudflare.ZoneArgs{ + AccountId: pulumi.ID("0467b993b65d8fd4a53fe24ed2fbb2a1"), + Zone: pulumi.String(z.Zone), + Plan: pulumi.String("free"), + }) + if z.Alias == "inskip-me" { + z.CertAuth = CertificateAuthority{} + err = z.CertAuth.handle(ctx) + if err != nil { + return err + } + err = z.handleTailscale() + if err != nil { + return err + } + } + for _, record := range z.ExtraRecords { + err = record.handle(ctx, z) + } + return err } +func (z *Zone) dnssec() (err error) { + z.DNSSec, err = cloudflare.NewZoneDnssec(z.Context, z.Alias, &cloudflare.ZoneDnssecArgs{ + ZoneId: z.CFZone.ID(), + }) + if err != nil { + return err + } + return err +} + +func (z *Zone) handleTailscale() (err error) { + tailnet := Tailnet{} + err = tailnet.handle(z.Context, z, z.CertAuth.Key, z.CertAuth.Cert) + if err != nil { + return err + } + z.Devices = tailnet.Devices + return err +} diff --git a/kat/user/nixos.nix b/kat/user/nixos.nix index 173e728c..128653a4 100644 --- a/kat/user/nixos.nix +++ b/kat/user/nixos.nix @@ -2,6 +2,7 @@ users.users.kat = { uid = 1000; isNormalUser = true; + hashedPassword = "$6$G26zDwcywO6$YzHK1YI6X0d7x/mV6maCx6B7V3M1JdE3VqxxjNc7muxUPkZo0YYwniAB2"; openssh.authorizedKeys = { inherit (tree.kat.user.data) keys; }; diff --git a/main.go b/main.go index 7d5cd480..52d45ac6 100644 --- a/main.go +++ b/main.go @@ -1,68 +1,38 @@ package main import ( - "github.com/pulumi/pulumi/sdk/v3/go/pulumi" - "github.com/pulumi/pulumi-tailscale/sdk/go/tailscale" - "gopkg.in/yaml.v3" - "os" - "kittywitch/iac" - "github.com/pulumi/pulumi-command/sdk/go/command/local" + "github.com/pulumi/pulumi/sdk/v3/go/pulumi" + "gopkg.in/yaml.v3" + "kittywitch/iac" + "os" ) func main() { - katConfig := iac.KatConfig{} + store := iac.KatConfig{} - configFile, err := os.ReadFile("config.yaml") + configFile, err := os.ReadFile("config.yaml") - if err != nil { - return - } + if err != nil { + return + } - if err := yaml.Unmarshal(configFile, &katConfig); err != nil { - return - } + if err := yaml.Unmarshal(configFile, &store); err != nil { + return + } - pulumi.Run(func(ctx *pulumi.Context) error { - tailnet, err := tailscale.GetDevices(ctx, &tailscale.GetDevicesArgs{}, nil) - if err != nil { - return err - } + pulumi.Run(func(ctx *pulumi.Context) error { + for _, zone := range store.Zones { + err = zone.Handle(ctx) + if err != nil { + return err + } + } - // zones, dnssec, records - zones, _, records, err := iac.HandleDNS(ctx, katConfig) + err = iac.InskipPage(ctx) + if err != nil { + return err + } - if err != nil { - return err - } - - records, err = iac.HandleTSRecords(ctx, tailnet, zones, records) - - if err != nil { - return err - } - - ca_key, ca_cert, err := iac.GenerateTLSCA(ctx) - - if err != nil { - return err - } - - keys, _, certs, err := iac.HandleTSHostCerts(ctx, tailnet, ca_key, ca_cert) - - if err != nil { - return err - } - - // files for those certs - - files := make(map[string]*local.Command) - - files, err = iac.PKITLSFiles(ctx, files, keys, certs) - - if err != nil { - return err - } - - return err - }) + return err + }) } diff --git a/modules/common/distributed.nix b/modules/common/distributed.nix index 824baa79..1ed3cf02 100644 --- a/modules/common/distributed.nix +++ b/modules/common/distributed.nix @@ -1,6 +1,6 @@ { lib, config, inputs, ... }: let # TODO: convert to nix-std - inherit (lib.attrsets) mapAttrsToList mapAttrs; + inherit (lib.attrsets) mapAttrsToList mapAttrs filterAttrs; inherit (lib.lists) optionals; inherit (lib.options) mkOption; inherit (lib.types) int attrsOf submodule; @@ -13,7 +13,7 @@ maxJobs = 100; speedFactor = config.distributed.outputs.${name}; supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ]; - } ) (inputs.self.nixosConfigurations // inputs.self.darwinConfigurations); + } ) (filterAttrs (n: _: n != config.networking.hostName) (inputs.self.nixosConfigurations // inputs.self.darwinConfigurations)); daiyousei = { hostName = "daiyousei.inskip.me"; sshUser = "root"; diff --git a/systems/sumireko.nix b/systems/sumireko.nix index 29e02fb9..c440c4ea 100644 --- a/systems/sumireko.nix +++ b/systems/sumireko.nix @@ -9,6 +9,17 @@ _: let distributed.systems.renko.preference = 5; + environment.systemPackages = with pkgs; [ + fd # fd, better fine! + ripgrep # rg, better grep! + go # Required for pulumi + pulumi-bin # Infrastructure as code + deadnix # dead-code scanner + alejandra # code formatter + statix # anti-pattern finder + deploy-rs.deploy-rs # deployment system + ]; + homebrew = { brewPrefix = "/opt/homebrew/bin"; brews = [