diff --git a/bootstrapper/internal/initserver/BUILD.bazel b/bootstrapper/internal/initserver/BUILD.bazel index 3ad04343c..f45aad1e6 100644 --- a/bootstrapper/internal/initserver/BUILD.bazel +++ b/bootstrapper/internal/initserver/BUILD.bazel @@ -11,6 +11,7 @@ go_library( "//bootstrapper/internal/journald", "//internal/atls", "//internal/attestation", + "//internal/constants", "//internal/crypto", "//internal/file", "//internal/grpc/atlscredentials", @@ -26,6 +27,7 @@ go_library( "@org_golang_google_grpc//keepalive", "@org_golang_google_grpc//status", "@org_golang_x_crypto//bcrypt", + "@org_golang_x_crypto//ssh", ], ) diff --git a/bootstrapper/internal/initserver/initserver.go b/bootstrapper/internal/initserver/initserver.go index a65a5f8b7..7fb454b75 100644 --- a/bootstrapper/internal/initserver/initserver.go +++ b/bootstrapper/internal/initserver/initserver.go @@ -19,7 +19,9 @@ package initserver import ( "bufio" + "bytes" "context" + "crypto/ed25519" "errors" "fmt" "io" @@ -33,6 +35,7 @@ import ( "github.com/edgelesssys/constellation/v2/bootstrapper/internal/journald" "github.com/edgelesssys/constellation/v2/internal/atls" "github.com/edgelesssys/constellation/v2/internal/attestation" + "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/crypto" "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/grpc/atlscredentials" @@ -44,6 +47,7 @@ import ( "github.com/edgelesssys/constellation/v2/internal/role" "github.com/edgelesssys/constellation/v2/internal/versions/components" "golang.org/x/crypto/bcrypt" + "golang.org/x/crypto/ssh" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/keepalive" @@ -222,6 +226,35 @@ func (s *Server) Init(req *initproto.InitRequest, stream initproto.API_InitServe return err } + // Derive the emergency ssh CA key + key, err := cloudKms.GetDEK(stream.Context(), crypto.DEKPrefix+constants.SSHCAKeySuffix, 256) + if err != nil { + if e := s.sendLogsWithMessage(stream, status.Errorf(codes.Internal, "retrieving DEK for key derivation: %s", err)); e != nil { + err = errors.Join(err, e) + } + return err + } + _, priv, err := ed25519.GenerateKey(bytes.NewReader(key)) + if err != nil { + if e := s.sendLogsWithMessage(stream, status.Errorf(codes.Internal, "generating signing key for emergency ssh CA: %s", err)); e != nil { + err = errors.Join(err, e) + } + return err + } + ca, err := ssh.NewSignerFromSigner(priv) + if err != nil { + if e := s.sendLogsWithMessage(stream, status.Errorf(codes.Internal, "signing emergency ssh CA key: %s", err)); e != nil { + err = errors.Join(err, e) + } + return err + } + if err := s.fileHandler.Write(constants.SSHCAKeyPath, ssh.MarshalAuthorizedKey(ca.PublicKey()), file.OptMkdirAll); err != nil { + if e := s.sendLogsWithMessage(stream, status.Errorf(codes.Internal, "writing ssh CA pubkey: %s", err)); e != nil { + err = errors.Join(err, e) + } + return err + } + clusterName := req.ClusterName if clusterName == "" { clusterName = "constellation"