mirror of
https://github.com/kittywitch/nixfiles.git
synced 2026-02-09 12:29:19 -08:00
feat: many things...
This commit is contained in:
parent
3fe6f591e1
commit
0778f24b18
22 changed files with 842 additions and 153 deletions
64
iac/assimilate.sh
Normal file
64
iac/assimilate.sh
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
[ ! -z "$DEBUG" ] && set -x
|
||||
|
||||
USAGE(){
|
||||
echo "Usage: `basename $0` <server_name>"
|
||||
exit 2
|
||||
}
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
USAGE
|
||||
fi
|
||||
|
||||
server_name="$1"
|
||||
public_ip="$2"
|
||||
|
||||
ssh_ignore(){
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $*
|
||||
}
|
||||
|
||||
ssh_victim(){
|
||||
ssh_ignore root@"${public_ip}" $*
|
||||
}
|
||||
|
||||
mkdir -p "./hosts/${server_name}"
|
||||
echo "${public_ip}" >> ./hosts/"${server_name}"/public-ip
|
||||
|
||||
until ssh_ignore "root@${server_name}" uname -av
|
||||
do
|
||||
sleep 30
|
||||
done
|
||||
|
||||
scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "root@${server_name}:/etc/nixos/hardware-configuration.nix" "../systems/${server_name}.nix" ||:
|
||||
|
||||
|
||||
rm -f ./hosts/"${server_name}"/default.nix
|
||||
cat <<-EOC >> ./hosts/"${server_name}"/default.nix
|
||||
{ ... }: {
|
||||
imports = [ ./hardware-configuration.nix ];
|
||||
|
||||
boot.cleanTmpDir = true;
|
||||
zramSwap.enable = true;
|
||||
networking.hostName = "${server_name}";
|
||||
services.openssh.enable = true;
|
||||
services.tailscale.enable = true;
|
||||
networking.firewall.checkReversePath = "loose";
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM6NPbPIcCTzeEsjyx0goWyj6fr2qzcfKCCdOUqg0N/v" # alrest
|
||||
];
|
||||
system.stateVersion = "23.05";
|
||||
}
|
||||
EOC
|
||||
|
||||
git add .
|
||||
git commit -sm "add machine ${server_name}: ${public_ip}"
|
||||
nix build .#nixosConfigurations."${server_name}".config.system.build.toplevel
|
||||
|
||||
export NIX_SSHOPTS='-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
|
||||
nix-copy-closure -s root@"${public_ip}" $(readlink ./result)
|
||||
ssh_victim nix-env --profile /nix/var/nix/profiles/system --set $(readlink ./result)
|
||||
ssh_victim $(readlink ./result)/bin/switch-to-configuration switch
|
||||
|
||||
git push
|
||||
9
iac/base.nix
Normal file
9
iac/base.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
_: let
|
||||
hostConfig = {HOSTCONFIG};
|
||||
in {
|
||||
arch = "{ARCHITECTURE}";
|
||||
type = "NixOS";
|
||||
modules = [
|
||||
hostConfig
|
||||
];
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package iac
|
||||
|
||||
type KatConfig struct {
|
||||
Zones map[string]Zone `yaml:"zones"`
|
||||
Zones map[string]Zone `yaml:"zones"`
|
||||
Machines map[string]Machine `yaml:"machines"`
|
||||
}
|
||||
|
|
|
|||
228
iac/device.go
228
iac/device.go
|
|
@ -1,7 +1,9 @@
|
|||
package iac
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"fmt"
|
||||
"github.com/pulumi/pulumi-command/sdk/go/command/remote"
|
||||
"github.com/pulumi/pulumi-tailscale/sdk/go/tailscale"
|
||||
|
|
@ -42,20 +44,27 @@ func (t *Tailnet) handle(ctx *pulumi.Context, zone *Zone, CAKey *tls.PrivateKey,
|
|||
}
|
||||
|
||||
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
|
||||
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
|
||||
PrivateKeyED25519 *tls.PrivateKey
|
||||
PrivateKeyUser *tls.PrivateKey
|
||||
PrivateKeyED25519User *tls.PrivateKey
|
||||
TLSCertRequest *tls.CertRequest
|
||||
TLSCert *tls.LocallySignedCert
|
||||
OSHCertificate pulumi.StringOutput
|
||||
OSHCertificateED25519 pulumi.StringOutput
|
||||
OSHCertificateUser pulumi.StringOutput
|
||||
OSHCertificateED25519User pulumi.StringOutput
|
||||
OSHCACert pulumi.StringOutput
|
||||
}
|
||||
|
||||
func (d *Device) handle(ctx *pulumi.Context, zone *Zone, CAKey *tls.PrivateKey, CACert *tls.SelfSignedCert) (err error) {
|
||||
|
|
@ -71,9 +80,9 @@ func (d *Device) handle(ctx *pulumi.Context, zone *Zone, CAKey *tls.PrivateKey,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d.Hostname != "koishi" && d.Hostname != "tewi" {
|
||||
return err
|
||||
}
|
||||
if d.Hostname != "koishi" && d.Hostname != "tewi" {
|
||||
return err
|
||||
}
|
||||
err = d.handleTLS(CAKey, CACert)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -85,7 +94,30 @@ func (d *Device) handle(ctx *pulumi.Context, zone *Zone, CAKey *tls.PrivateKey,
|
|||
return err
|
||||
}
|
||||
|
||||
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 PrivateKeyOpenSSHToED25519PrivateKey(keyPEM string) (key *ed25519.PrivateKey, err error) {
|
||||
key_int, err := ssh.ParseRawPrivateKey([]byte(keyPEM))
|
||||
key_raw := key_int.(*ed25519.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key_raw, err
|
||||
}
|
||||
|
||||
/*
|
||||
*/
|
||||
func (d *Device) handleOSH(CAKey *tls.PrivateKey) (err error) {
|
||||
d.OSHCACert = CAKey.PublicKeyOpenssh
|
||||
file, err := CreatePulumiFile(d.Context, fmt.Sprintf("%s-osh-ca-cert", d.Hostname), d.Tailskip, pulumi.Sprintf("@certificate-authority * %s", d.OSHCACert), []pulumi.Resource{CAKey})
|
||||
d.Files = append(d.Files, file)
|
||||
d.OSHCertificate = CAKey.PrivateKeyOpenssh.ApplyT(func(CAPriv string) pulumi.StringOutput {
|
||||
OSHCertificate_ := d.PrivateKey.PrivateKeyOpenssh.ApplyT(func(UserPriv string) pulumi.String {
|
||||
CARSAPriv, err := PrivateKeyOpenSSHToRSAPrivateKey(CAPriv)
|
||||
|
|
@ -122,7 +154,121 @@ func (d *Device) handleOSH(CAKey *tls.PrivateKey) (err error) {
|
|||
}).(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.OSHCertificateED25519 = CAKey.PrivateKeyOpenssh.ApplyT(func(CAPriv string) pulumi.StringOutput {
|
||||
OSHCertificate_ := d.PrivateKeyED25519.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
|
||||
UserED25519Priv, err := PrivateKeyOpenSSHToED25519PrivateKey(UserPriv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert.Key, err = ssh.NewPublicKey(UserED25519Priv.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)
|
||||
file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-osh-ed25519-cert", d.Hostname), d.Tailskip, d.OSHCertificateED25519, []pulumi.Resource{d.PrivateKeyED25519, CAKey})
|
||||
d.Files = append(d.Files, file)
|
||||
d.OSHCertificateUser = CAKey.PrivateKeyOpenssh.ApplyT(func(CAPriv string) pulumi.StringOutput {
|
||||
OSHCertificate_ := d.PrivateKeyUser.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 = 1
|
||||
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)
|
||||
d.OSHCertificateED25519User = CAKey.PrivateKeyOpenssh.ApplyT(func(CAPriv string) pulumi.StringOutput {
|
||||
OSHCertificate_ := d.PrivateKeyED25519User.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
|
||||
UserED25519Priv, err := PrivateKeyOpenSSHToED25519PrivateKey(UserPriv)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cert.Key, err = ssh.NewPublicKey(UserED25519Priv.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-user-cert", d.Hostname), d.Tailskip, d.OSHCertificateUser, []pulumi.Resource{d.PrivateKey, CAKey})
|
||||
d.Files = append(d.Files, file)
|
||||
file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-osh-ed25519-user-cert", d.Hostname), d.Tailskip, d.OSHCertificateED25519User, []pulumi.Resource{d.PrivateKeyED25519, CAKey})
|
||||
d.Files = append(d.Files, file)
|
||||
return err
|
||||
}
|
||||
|
|
@ -155,10 +301,41 @@ func (d *Device) handleTLS(CAKey *tls.PrivateKey, CACert *tls.SelfSignedCert) (e
|
|||
Algorithm: pulumi.String("RSA"),
|
||||
RsaBits: pulumi.Int(4096),
|
||||
}, pulumi.DependsOn(PrivateKeyDepends))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.PrivateKeyUser, err = tls.NewPrivateKey(d.Context, fmt.Sprintf("%s-user-key", d.Hostname), &tls.PrivateKeyArgs{
|
||||
Algorithm: pulumi.String("RSA"),
|
||||
RsaBits: pulumi.Int(4096),
|
||||
}, pulumi.DependsOn(PrivateKeyDepends))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.PrivateKeyED25519, err = tls.NewPrivateKey(d.Context, fmt.Sprintf("%s-ed25519-key", d.Hostname), &tls.PrivateKeyArgs{
|
||||
Algorithm: pulumi.String("ED25519"),
|
||||
RsaBits: pulumi.Int(4096),
|
||||
}, pulumi.DependsOn(PrivateKeyDepends))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.PrivateKeyED25519User, err = tls.NewPrivateKey(d.Context, fmt.Sprintf("%s-ed25519-user-key", d.Hostname), &tls.PrivateKeyArgs{
|
||||
Algorithm: pulumi.String("ED25519"),
|
||||
RsaBits: pulumi.Int(4096),
|
||||
}, pulumi.DependsOn(PrivateKeyDepends))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
PrivateKeyED25519Depends := append(PrivateKeyDepends, d.PrivateKeyED25519)
|
||||
PrivateKeyDepends = append(PrivateKeyDepends, d.PrivateKey)
|
||||
PrivateKeyED25519UserDepends := append(PrivateKeyDepends, d.PrivateKeyED25519User)
|
||||
PrivateKeyUserDepends := append(PrivateKeyDepends, d.PrivateKeyUser)
|
||||
|
||||
file, err := CreatePulumiFile(d.Context, fmt.Sprintf("%s-pem-pk", d.Hostname), d.Tailskip, d.PrivateKey.PrivateKeyPem, PrivateKeyDepends)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -169,6 +346,21 @@ func (d *Device) handleTLS(CAKey *tls.PrivateKey, CACert *tls.SelfSignedCert) (e
|
|||
return err
|
||||
}
|
||||
d.Files = append(d.Files, file)
|
||||
file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-osh-user-pk", d.Hostname), d.Tailskip, d.PrivateKeyUser.PrivateKeyOpenssh, PrivateKeyUserDepends)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Files = append(d.Files, file)
|
||||
file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-ed25519-osh-pk", d.Hostname), d.Tailskip, d.PrivateKeyED25519.PrivateKeyOpenssh, PrivateKeyED25519Depends)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Files = append(d.Files, file)
|
||||
file, err = CreatePulumiFile(d.Context, fmt.Sprintf("%s-ed25519-osh-user-pk", d.Hostname), d.Tailskip, d.PrivateKeyED25519User.PrivateKeyOpenssh, PrivateKeyED25519UserDepends)
|
||||
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,
|
||||
|
|
|
|||
29
iac/files.go
29
iac/files.go
|
|
@ -6,24 +6,25 @@ import (
|
|||
)
|
||||
|
||||
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",
|
||||
})
|
||||
port := 22
|
||||
user := "deploy"
|
||||
if fqdn == "tewi.inskip.me" {
|
||||
port = 62954
|
||||
user = "root"
|
||||
}
|
||||
return remote.NewCommand(ctx, name, &remote.CommandArgs{
|
||||
port := 22
|
||||
user := "deploy"
|
||||
if fqdn == "tewi.inskip.me" {
|
||||
port = 62954
|
||||
user = "root"
|
||||
}
|
||||
ctx.Export(name, value)
|
||||
return remote.NewCommand(ctx, name, &remote.CommandArgs{
|
||||
Connection: &remote.ConnectionArgs{
|
||||
Host: pulumi.String(fqdn),
|
||||
Port: pulumi.Float64Ptr(float64(port)),
|
||||
User: pulumi.String(user),
|
||||
AgentSocketPath: pulumi.String("/Users/kat/.gnupg/S.gpg-agent.ssh"),
|
||||
},
|
||||
Create: pulumi.Sprintf("sudo mkdir -p /var/lib/secrets && cd /var/lib/secrets && echo \"%s\" | sudo tee \"%s\"", value, name),
|
||||
Delete: pulumi.Sprintf("cd /var/lib/secrets && rm %s", name),
|
||||
Environment: environment,
|
||||
}, pulumi.DependsOn(resources))
|
||||
Triggers: pulumi.All(resources),
|
||||
Create: pulumi.Sprintf("sudo mkdir -p /var/lib/secrets && echo \"%s\" | sudo tee \"/var/lib/secrets/%s\"", value, name),
|
||||
Delete: pulumi.Sprintf("cd /var/lib/secrets && rm %s", name),
|
||||
Environment: pulumi.StringMap{
|
||||
"PULUMI_SKIP_UPDATE_CHECK": pulumi.String("true"),
|
||||
},
|
||||
}, pulumi.DependsOn(resources), pulumi.IgnoreChanges([]string{"create"}))
|
||||
}
|
||||
|
|
|
|||
212
iac/hcloud.go
Normal file
212
iac/hcloud.go
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
package iac
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pulumi/pulumi-cloudflare/sdk/v4/go/cloudflare"
|
||||
"github.com/pulumi/pulumi-cloudinit/sdk/go/cloudinit"
|
||||
"github.com/pulumi/pulumi-hcloud/sdk/go/hcloud"
|
||||
"github.com/pulumi/pulumi-tailscale/sdk/go/tailscale"
|
||||
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Machine struct {
|
||||
Hostname string
|
||||
Network *hcloud.Network
|
||||
NetworkSubnet *hcloud.NetworkSubnet
|
||||
NetworkID pulumi.IntOutput
|
||||
TailnetKey *tailscale.TailnetKey
|
||||
CloudInit *cloudinit.Config
|
||||
IPv4 *hcloud.PrimaryIp
|
||||
IPv6 *hcloud.PrimaryIp
|
||||
RDNSv4 *hcloud.Rdns
|
||||
RDNSv6 *hcloud.Rdns
|
||||
Server *hcloud.Server
|
||||
Recordv4 DNSRecord
|
||||
Recordv6 DNSRecord
|
||||
}
|
||||
|
||||
func (m *Machine) Handle(ctx *pulumi.Context, name string) (err error) {
|
||||
m.Hostname = name
|
||||
|
||||
m.Network, err = hcloud.NewNetwork(ctx, "network", &hcloud.NetworkArgs{
|
||||
IpRange: pulumi.String("10.0.0.0/16"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.NetworkID = m.Network.ID().ApplyT(func(content pulumi.ID) (content_ int, err error) {
|
||||
return strconv.Atoi(string(content))
|
||||
}).(pulumi.IntOutput)
|
||||
|
||||
m.NetworkSubnet, err = hcloud.NewNetworkSubnet(ctx, "network-subnet", &hcloud.NetworkSubnetArgs{
|
||||
NetworkId: m.NetworkID,
|
||||
Type: pulumi.String("cloud"),
|
||||
NetworkZone: pulumi.String("us-west"),
|
||||
IpRange: pulumi.String("10.0.1.0/24"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.TailnetKey, err = tailscale.NewTailnetKey(ctx, "tailscaleKey", &tailscale.TailnetKeyArgs{
|
||||
Ephemeral: pulumi.Bool(false),
|
||||
Preauthorized: pulumi.Bool(true),
|
||||
Reusable: pulumi.Bool(true),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.CloudInit, err = cloudinit.NewConfig(ctx, "ran", &cloudinit.ConfigArgs{
|
||||
Gzip: pulumi.Bool(false),
|
||||
Base64Encode: pulumi.Bool(false),
|
||||
Parts: cloudinit.ConfigPartArray{
|
||||
&cloudinit.ConfigPartArgs{
|
||||
Content: pulumi.Sprintf(`#cloud-config
|
||||
write_files:
|
||||
- path: /etc/tailscale/authkey
|
||||
permissions: '0600'
|
||||
content: "%s"
|
||||
- path: /etc/nixos/katdefaults.nix
|
||||
permissions: '0644'
|
||||
content: |
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.tailscale.enable = true;
|
||||
|
||||
systemd.services.tailscale-autoconnect = {
|
||||
description = "Automatic connection to Tailscale";
|
||||
after = [ "network-pre.target" "tailscale.service" ];
|
||||
wants = [ "network-pre.target" "tailscale.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
path = with pkgs; [ jq tailscale ];
|
||||
script = ''
|
||||
sleep 2
|
||||
status="$(tailscale status -json | jq -r .BackendState)"
|
||||
if [ $status = "Running" ]; then # if so, then do nothing
|
||||
exit 0
|
||||
fi
|
||||
tailscale up --authkey $(cat /etc/tailscale/authkey) --ssh
|
||||
'';
|
||||
};
|
||||
}
|
||||
runcmd:
|
||||
- sed -i 's:#.*$::g' /root/.ssh/authorized_keys
|
||||
- curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | NIXOS_IMPORT=./katdefaults.nix NIX_CHANNEL=nixos-unstable bash 2>&1 | tee /tmp/infect.log
|
||||
- nixos-generate-config --dir ./
|
||||
`, m.TailnetKey.Key),
|
||||
ContentType: pulumi.String("text/x-shellscript"),
|
||||
Filename: pulumi.String("nixos-infect"),
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.IPv4, err = hcloud.NewPrimaryIp(ctx, "ran-v4", &hcloud.PrimaryIpArgs{
|
||||
Datacenter: pulumi.String("hil-dc1"),
|
||||
Type: pulumi.String("ipv4"),
|
||||
AssigneeType: pulumi.String("server"),
|
||||
AutoDelete: pulumi.Bool(true),
|
||||
Labels: pulumi.Map{
|
||||
"host": pulumi.Any("ran"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.IPv6, err = hcloud.NewPrimaryIp(ctx, "ran-v6", &hcloud.PrimaryIpArgs{
|
||||
Datacenter: pulumi.String("hil-dc1"),
|
||||
Type: pulumi.String("ipv6"),
|
||||
AssigneeType: pulumi.String("server"),
|
||||
AutoDelete: pulumi.Bool(true),
|
||||
Labels: pulumi.Map{
|
||||
"host": pulumi.Any("ran"),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Server, err = hcloud.NewServer(ctx, m.Hostname, &hcloud.ServerArgs{
|
||||
Name: pulumi.String(m.Hostname),
|
||||
ServerType: pulumi.String("cpx21"),
|
||||
Image: pulumi.String("ubuntu-22.04"),
|
||||
Datacenter: pulumi.String("hil-dc1"),
|
||||
UserData: m.CloudInit.Rendered,
|
||||
PublicNets: hcloud.ServerPublicNetArray{
|
||||
&hcloud.ServerPublicNetArgs{
|
||||
Ipv4Enabled: pulumi.Bool(true),
|
||||
Ipv4: m.IPv4.ID().ApplyT(func(content pulumi.ID) (content_ int, err error) {
|
||||
return strconv.Atoi(string(content))
|
||||
}).(pulumi.IntOutput),
|
||||
Ipv6Enabled: pulumi.Bool(true),
|
||||
Ipv6: m.IPv6.ID().ApplyT(func(content pulumi.ID) (content_ int, err error) {
|
||||
return strconv.Atoi(string(content))
|
||||
}).(pulumi.IntOutput),
|
||||
},
|
||||
},
|
||||
Networks: hcloud.ServerNetworkTypeArray{
|
||||
&hcloud.ServerNetworkTypeArgs{
|
||||
NetworkId: m.NetworkID,
|
||||
Ip: pulumi.String("10.0.1.5"),
|
||||
AliasIps: pulumi.StringArray{
|
||||
pulumi.String("10.0.1.6"),
|
||||
pulumi.String("10.0.1.7"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}, pulumi.DependsOn([]pulumi.Resource{
|
||||
m.NetworkSubnet,
|
||||
}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.RDNSv4, err = hcloud.NewRdns(ctx, fmt.Sprintf("%s-v4", m.Hostname), &hcloud.RdnsArgs{
|
||||
ServerId: m.Server.ID().ApplyT(func(content pulumi.ID) (content_ int, err error) {
|
||||
return strconv.Atoi(string(content))
|
||||
}).(pulumi.IntOutput),
|
||||
IpAddress: m.Server.Ipv4Address,
|
||||
DnsPtr: pulumi.String("ran.gensokyo.zone"),
|
||||
})
|
||||
m.RDNSv6, err = hcloud.NewRdns(ctx, fmt.Sprintf("%s-v6", m.Hostname), &hcloud.RdnsArgs{
|
||||
ServerId: m.Server.ID().ApplyT(func(content pulumi.ID) (content_ int, err error) {
|
||||
return strconv.Atoi(string(content))
|
||||
}).(pulumi.IntOutput),
|
||||
IpAddress: m.Server.Ipv6Address,
|
||||
DnsPtr: pulumi.String("ran.gensokyo.zone"),
|
||||
})
|
||||
|
||||
zoneName := "gensokyo.zone"
|
||||
|
||||
gensokyo, err := cloudflare.LookupZone(ctx, &cloudflare.LookupZoneArgs{
|
||||
Name: &zoneName,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Recordv4 = DNSRecord{
|
||||
Higher: String,
|
||||
Name: m.Hostname,
|
||||
Kind: A,
|
||||
RawValue: m.Server.Ipv4Address,
|
||||
Ttl: 3600,
|
||||
}
|
||||
m.Recordv4.handleValue(ctx, gensokyo)
|
||||
|
||||
m.Recordv6 = DNSRecord{
|
||||
Higher: String,
|
||||
Name: m.Hostname,
|
||||
Kind: AAAA,
|
||||
RawValue: m.Server.Ipv6Address,
|
||||
Ttl: 3600,
|
||||
}
|
||||
m.Recordv6.handleValue(ctx, gensokyo)
|
||||
|
||||
return err
|
||||
}
|
||||
122
iac/record.go
122
iac/record.go
|
|
@ -12,25 +12,32 @@ import (
|
|||
|
||||
type DNSRecordType string
|
||||
|
||||
type HigherType uint16
|
||||
|
||||
const (
|
||||
A DNSRecordType = "a"
|
||||
AAAA = "aaaa"
|
||||
MX = "mx"
|
||||
TXT = "txt"
|
||||
CAA = "caa"
|
||||
CNAME = "cname"
|
||||
A DNSRecordType = "a"
|
||||
AAAA = "aaaa"
|
||||
MX = "mx"
|
||||
TXT = "txt"
|
||||
CAA = "caa"
|
||||
CNAME = "cname"
|
||||
IDOutput HigherType = 0
|
||||
RawValue = 1
|
||||
String = 2
|
||||
)
|
||||
|
||||
type DNSRecord struct {
|
||||
CFRecord *cloudflare.Record
|
||||
Zone *Zone
|
||||
Higher HigherType `default:"0""`
|
||||
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"`
|
||||
RawValue pulumi.StringOutput
|
||||
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) (err error) {
|
||||
|
|
@ -48,14 +55,21 @@ func (r *DNSRecord) UnmarshalYAML(unmarshal func(interface{}) error) (err error)
|
|||
return err
|
||||
}
|
||||
|
||||
func (r *DNSRecord) getZone() pulumi.StringOutput {
|
||||
return r.Zone.CFZone.ID().ToStringOutput()
|
||||
func (r *DNSRecord) getZone() pulumi.IDOutput {
|
||||
return r.Zone.CFZone.ID()
|
||||
}
|
||||
|
||||
func (r *DNSRecord) getName() string {
|
||||
base := fmt.Sprintf("%s-%s-%s", r.Zone.Alias, r.Kind, r.Name)
|
||||
var base string
|
||||
var hash [16]byte
|
||||
if r.Higher == 0 {
|
||||
base = fmt.Sprintf("%s-%s-%s", r.Zone.Alias, r.Kind, r.Name)
|
||||
hash = md5.Sum([]byte(r.Value))
|
||||
} else {
|
||||
base = fmt.Sprintf("%s-%s", r.Kind, r.Name)
|
||||
hash = md5.Sum([]byte(r.Name))
|
||||
}
|
||||
|
||||
hash := md5.Sum([]byte(r.Value))
|
||||
hashString := hex.EncodeToString(hash[:])[:5]
|
||||
suffix := ""
|
||||
switch r.Kind {
|
||||
|
|
@ -71,13 +85,83 @@ func (r *DNSRecord) getName() string {
|
|||
return built
|
||||
}
|
||||
|
||||
func (r *DNSRecord) handle(ctx *pulumi.Context, zone *Zone) (err error) {
|
||||
func (r *DNSRecord) handleOutput(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(),
|
||||
ZoneId: r.Zone.CFZone.ID(),
|
||||
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: r.RawValue,
|
||||
},
|
||||
}
|
||||
default:
|
||||
recordArgs = &cloudflare.RecordArgs{
|
||||
ZoneId: r.Zone.CFZone.ID(),
|
||||
Name: pulumi.String(r.Name),
|
||||
Type: pulumi.String(strings.ToUpper(string(r.Kind))),
|
||||
Ttl: pulumi.Int(r.Ttl),
|
||||
Priority: pulumi.Int(r.Priority),
|
||||
Value: r.RawValue,
|
||||
}
|
||||
}
|
||||
r.CFRecord, err = cloudflare.NewRecord(ctx, r.getName(), recordArgs, pulumi.DependsOn([]pulumi.Resource{r.Zone.CFZone}))
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *DNSRecord) handle(ctx *pulumi.Context, zone *Zone) (err error) {
|
||||
r.Zone = zone
|
||||
cfzone := zone.CFZone
|
||||
return r.handleCF(ctx, cfzone)
|
||||
}
|
||||
|
||||
func (r *DNSRecord) handleCF(ctx *pulumi.Context, zone *cloudflare.Zone) (err error) {
|
||||
zoneID := zone.ID()
|
||||
depends := pulumi.DependsOn([]pulumi.Resource{zone})
|
||||
return r.handleID(ctx, zoneID, depends)
|
||||
}
|
||||
|
||||
func (r *DNSRecord) handleValue(ctx *pulumi.Context, zone *cloudflare.LookupZoneResult) (err error) {
|
||||
var recordArgs *cloudflare.RecordArgs
|
||||
switch r.Kind {
|
||||
case CAA:
|
||||
recordArgs = &cloudflare.RecordArgs{
|
||||
ZoneId: pulumi.String(zone.ZoneId),
|
||||
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: r.RawValue,
|
||||
},
|
||||
}
|
||||
default:
|
||||
recordArgs = &cloudflare.RecordArgs{
|
||||
ZoneId: pulumi.String(zone.ZoneId),
|
||||
Name: pulumi.String(r.Name),
|
||||
Type: pulumi.String(strings.ToUpper(string(r.Kind))),
|
||||
Ttl: pulumi.Int(r.Ttl),
|
||||
Priority: pulumi.Int(r.Priority),
|
||||
Value: r.RawValue,
|
||||
}
|
||||
}
|
||||
r.CFRecord, err = cloudflare.NewRecord(ctx, r.getName(), recordArgs)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *DNSRecord) handleID(ctx *pulumi.Context, zoneID pulumi.IDOutput, depends pulumi.ResourceOption) (err error) {
|
||||
var recordArgs *cloudflare.RecordArgs
|
||||
switch r.Kind {
|
||||
case CAA:
|
||||
recordArgs = &cloudflare.RecordArgs{
|
||||
ZoneId: zoneID,
|
||||
Name: pulumi.String(r.Name),
|
||||
Type: pulumi.String(strings.ToUpper(string(r.Kind))),
|
||||
Ttl: pulumi.Int(r.Ttl),
|
||||
|
|
@ -89,7 +173,7 @@ func (r *DNSRecord) handle(ctx *pulumi.Context, zone *Zone) (err error) {
|
|||
}
|
||||
default:
|
||||
recordArgs = &cloudflare.RecordArgs{
|
||||
ZoneId: r.getZone(),
|
||||
ZoneId: zoneID,
|
||||
Name: pulumi.String(r.Name),
|
||||
Type: pulumi.String(strings.ToUpper(string(r.Kind))),
|
||||
Ttl: pulumi.Int(r.Ttl),
|
||||
|
|
@ -97,6 +181,6 @@ func (r *DNSRecord) handle(ctx *pulumi.Context, zone *Zone) (err error) {
|
|||
Value: pulumi.String(r.Value),
|
||||
}
|
||||
}
|
||||
r.CFRecord, err = cloudflare.NewRecord(ctx, r.getName(), recordArgs, pulumi.DependsOn([]pulumi.Resource{r.Zone.CFZone}))
|
||||
r.CFRecord, err = cloudflare.NewRecord(ctx, r.getName(), recordArgs, depends)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
91
iac/ssh.go
91
iac/ssh.go
|
|
@ -1,91 +0,0 @@
|
|||
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
|
||||
}
|
||||
|
|
@ -25,6 +25,9 @@ func (z *Zone) Handle(ctx *pulumi.Context) (err error) {
|
|||
Zone: pulumi.String(z.Zone),
|
||||
Plan: pulumi.String("free"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if z.Alias == "inskip-me" {
|
||||
z.CertAuth = CertificateAuthority{}
|
||||
err = z.CertAuth.handle(ctx)
|
||||
|
|
@ -39,6 +42,7 @@ func (z *Zone) Handle(ctx *pulumi.Context) (err error) {
|
|||
for _, record := range z.ExtraRecords {
|
||||
err = record.handle(ctx, z)
|
||||
}
|
||||
err = z.dnssec()
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue