mirror of
https://github.com/kittywitch/nixfiles.git
synced 2026-02-10 04:49:19 -08:00
133 lines
3.9 KiB
Go
133 lines
3.9 KiB
Go
package provider
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/blang/semver"
|
|
p "github.com/pulumi/pulumi-go-provider"
|
|
"github.com/pulumi/pulumi-go-provider/infer"
|
|
"github.com/pulumi/pulumi-go-provider/integration"
|
|
"github.com/pulumi/pulumi-go-provider/middleware/schema"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
|
|
"golang.org/x/crypto/ssh"
|
|
)
|
|
|
|
func Provider() p.Provider {
|
|
return infer.Provider(infer.Options{
|
|
Metadata: schema.Metadata{
|
|
DisplayName: "OpenSSH Cert",
|
|
Description: "I hope the people who worked on pulumi stub their toe every day",
|
|
Keywords: []string{
|
|
"pulumi",
|
|
"openssh",
|
|
"category/utility",
|
|
"kind/native",
|
|
},
|
|
Homepage: "https://kittywit.ch",
|
|
License: "WTFPL",
|
|
Repository: "https://github.com/kittywitch/kittywitch",
|
|
Publisher: "Pulumi",
|
|
LogoURL: "https://raw.githubusercontent.com/pulumi/pulumi-command/master/assets/logo.svg",
|
|
// This contains language specific details for generating the provider's SDKs
|
|
LanguageMap: map[string]any{
|
|
"go": map[string]any{
|
|
"generateResourceContainerTypes": true,
|
|
"importBasePath": "github.com/kittywitch/provider-opensshcertificate/sdk/go/provider",
|
|
},
|
|
},
|
|
},
|
|
Resources: []infer.InferredResource{infer.Resource[*OpenSSHCertificate, OpenSSHCertificateArgs, OpenSSHCertificateState]()},
|
|
ModuleMap: map[tokens.ModuleName]tokens.ModuleName{
|
|
"opensshcertificate": "index",
|
|
},
|
|
})
|
|
}
|
|
|
|
type OpenSSHCertificate struct{}
|
|
|
|
type OpenSSHCertificateArgs struct {
|
|
Algorithm string `pulumi:"algorithm"`
|
|
Kind string `pulumi:"kind"`
|
|
Hostname string `pulumi:"hostname"`
|
|
CAPrivateKey string `pulumi:"cakey"`
|
|
UserPrivateKey string `pulumi:"userkey"`
|
|
Duration string `pulumi:"duration"`
|
|
}
|
|
type OpenSSHCertificateState struct {
|
|
OpenSSHCertificateArgs
|
|
Content string `pulumi:"content"`
|
|
}
|
|
|
|
func (c *OpenSSHCertificate) Create(ctx p.Context, name string, input OpenSSHCertificateArgs, preview bool) (string, OpenSSHCertificateState, error) {
|
|
state := OpenSSHCertificateState{OpenSSHCertificateArgs: input}
|
|
if preview {
|
|
return name, state, nil
|
|
}
|
|
caPrivateKeyInterface, err := ssh.ParseRawPrivateKey([]byte(input.CAPrivateKey))
|
|
if err != nil {
|
|
return name, state, err
|
|
}
|
|
userPrivateKeyInterface, err := ssh.ParseRawPrivateKey([]byte(input.UserPrivateKey))
|
|
if err != nil {
|
|
return name, state, err
|
|
}
|
|
var signer ssh.Signer
|
|
var userPublicKey crypto.PublicKey
|
|
caPrivateKey := caPrivateKeyInterface.(*rsa.PrivateKey)
|
|
switch input.Algorithm {
|
|
case "rsa":
|
|
userPrivateKey := userPrivateKeyInterface.(*rsa.PrivateKey)
|
|
userPublicKey = userPrivateKey.Public()
|
|
signer, err = ssh.NewSignerFromKey(caPrivateKey)
|
|
case "ed25519":
|
|
userPrivateKey := userPrivateKeyInterface.(*ed25519.PrivateKey)
|
|
userPublicKey = userPrivateKey.Public()
|
|
signer, err = ssh.NewSignerFromKey(caPrivateKey)
|
|
default:
|
|
panic("unsupported key algorithm")
|
|
}
|
|
if err != nil {
|
|
return name, state, err
|
|
}
|
|
var cert ssh.Certificate
|
|
switch input.Kind {
|
|
case "user":
|
|
cert.CertType = ssh.UserCert
|
|
case "host":
|
|
cert.CertType = ssh.HostCert
|
|
default:
|
|
panic("unsupported key kind")
|
|
}
|
|
cert.Key, err = ssh.NewPublicKey(userPublicKey)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
now := time.Now()
|
|
nowunix := uint64(now.Unix())
|
|
cert.Serial = nowunix
|
|
cert.KeyId = input.Hostname
|
|
cert.ValidPrincipals = []string{input.Hostname}
|
|
cert.ValidAfter = nowunix
|
|
duration, err := time.ParseDuration(input.Duration)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
cert.ValidBefore = uint64(now.Add(duration).Unix())
|
|
err = cert.SignCert(rand.Reader, signer)
|
|
state.Content = string(ssh.MarshalAuthorizedKey(&cert))
|
|
return name, state, nil
|
|
}
|
|
|
|
func Schema(version string) (string, error) {
|
|
if strings.HasPrefix(version, "v") {
|
|
version = version[1:]
|
|
}
|
|
s, err := integration.NewServer("opensshcertificate", semver.MustParse(version), Provider()).
|
|
GetSchema(p.GetSchemaRequest{})
|
|
return s.Schema, err
|
|
}
|