feat: many things...

This commit is contained in:
Kat Inskip 2023-02-12 05:49:50 -08:00
parent 3fe6f591e1
commit 0778f24b18
Signed by: kat
GPG key ID: 465E64DECEA8CF0F
22 changed files with 842 additions and 153 deletions

64
iac/assimilate.sh Normal file
View 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
View file

@ -0,0 +1,9 @@
_: let
hostConfig = {HOSTCONFIG};
in {
arch = "{ARCHITECTURE}";
type = "NixOS";
modules = [
hostConfig
];
}

View file

@ -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"`
}

View file

@ -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,

View file

@ -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
View 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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}