refactor: create function in crypto package

This commit is contained in:
miampf 2025-04-16 12:29:11 +02:00
parent ef052feee9
commit d671a71f30
No known key found for this signature in database
GPG Key ID: EF039364B5B6886C
2 changed files with 43 additions and 32 deletions

View File

@ -17,6 +17,7 @@ import (
"fmt"
"io"
"math/big"
"time"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/ssh"
@ -77,6 +78,42 @@ func GenerateEmergencySSHCAKey(seed []byte) (ssh.Signer, error) {
return ca, nil
}
// GenerateSignedSSHHostKey creates a host key that is signed by the given CA.
func GenerateSignedSSHHostKey(principal string, ca ssh.Signer) (*pem.Block, *ssh.Certificate, error) {
hostKeyPub, hostKey, err := ed25519.GenerateKey(nil)
if err != nil {
return nil, nil, err
}
hostKeySSHPub, err := ssh.NewPublicKey(hostKeyPub)
if err != nil {
return nil, nil, err
}
hostKeySSH, err := x509.MarshalPKCS8PrivateKey(hostKey)
if err != nil {
return nil, nil, err
}
pemHostKey := &pem.Block{Type: "OPENSSH PRIVATE KEY", Bytes: hostKeySSH}
certificate := ssh.Certificate{
CertType: ssh.HostCert,
ValidPrincipals: []string{principal},
ValidAfter: uint64(time.Now().Unix()),
ValidBefore: ssh.CertTimeInfinity,
Reserved: []byte{},
Key: hostKeySSHPub,
KeyId: "host_key",
Permissions: ssh.Permissions{
CriticalOptions: map[string]string{},
Extensions: map[string]string{},
},
}
if err := certificate.SignCert(rand.Reader, ca); err != nil {
return nil, nil, err
}
return pemHostKey, &certificate, nil
}
// PemToX509Cert takes a list of PEM-encoded certificates, parses the first one and returns it
// as an x.509 certificate.
func PemToX509Cert(raw []byte) (*x509.Certificate, error) {

View File

@ -10,7 +10,7 @@ package server
import (
"context"
"crypto/ed25519"
"crypto/rand"
"encoding/pem"
"fmt"
"log/slog"
"net"
@ -118,38 +118,12 @@ func (s *Server) IssueJoinTicket(ctx context.Context, req *joinproto.IssueJoinTi
p, _ := peer.FromContext(ctx)
nodeIP := p.Addr.String()
hostKey, _, err := ed25519.GenerateKey(nil)
hostKey, hostCertificate, err := crypto.GenerateSignedSSHHostKey(nodeIP, ca)
if err != nil {
log.With(slog.Any("error", err), slog.String("ip", nodeIP)).Error("Failed to generate host key for node")
return nil, status.Errorf(codes.Internal, "generating host key for node: %s", err)
}
hostKeyPub, err := ssh.NewPublicKey(hostKey)
if err != nil {
log.With(slog.Any("error", err), slog.String("ip", nodeIP)).Error("Failed to create public host key")
return nil, status.Errorf(codes.Internal, "generating public host key for node: %s", err)
}
certificate := ssh.Certificate{
CertType: ssh.HostCert,
Nonce: []byte{},
ValidPrincipals: []string{p.Addr.String()},
ValidAfter: uint64(time.Now().Unix()),
ValidBefore: ssh.CertTimeInfinity,
Reserved: []byte{},
Key: hostKeyPub,
KeyId: "host_key",
SignatureKey: ca.PublicKey(),
Permissions: ssh.Permissions{
CriticalOptions: map[string]string{},
Extensions: map[string]string{},
},
}
if certificate.SignCert(rand.Reader, ca) != nil {
log.With(slog.Any("error", err), slog.String("ip", nodeIP)).Error("Failed to sign host key with ssh CA for node")
return nil, status.Errorf(codes.Internal, "signing host key for node with CA: %s", err)
log.With(slog.Any("error", err)).Error("Failed to generate and sign SSH host key")
return nil, status.Errorf(codes.Internal, "generating and signing SSH host key: %s", err)
}
log.Info("Generated host key and certificate for node", "ip", nodeIP)
// TODO: send cert and host key to node for installation
log.Info("Creating Kubernetes join token")
kubeArgs, err := s.joinTokenGetter.GetJoinToken(constants.KubernetesJoinTokenTTL)
@ -219,8 +193,8 @@ func (s *Server) IssueJoinTicket(ctx context.Context, req *joinproto.IssueJoinTi
ControlPlaneFiles: controlPlaneFiles,
KubernetesComponents: components,
AuthorizedCaPublicKey: ssh.MarshalAuthorizedKey(ca.PublicKey()),
HostKey: ssh.MarshalAuthorizedKey(hostKeyPub),
HostCertificate: ssh.MarshalAuthorizedKey(&certificate),
HostKey: pem.EncodeToMemory(hostKey),
HostCertificate: ssh.MarshalAuthorizedKey(hostCertificate),
}, nil
}