COCOS-199 - Enable testing of SEV features on any machine (#205)

* make attestation embeddable

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* mock backend info

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* embed files

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

* finish up

Signed-off-by: Sammy Oina <sammyoina@gmail.com>

---------

Signed-off-by: Sammy Oina <sammyoina@gmail.com>
This commit is contained in:
Sammy Kerata Oina
2024-08-23 17:52:07 +03:00
committed by GitHub
parent c402248515
commit bdbeb4e976
14 changed files with 159 additions and 49 deletions
+7 -5
View File
@@ -1,11 +1,12 @@
BUILD_DIR = build
SERVICES = manager agent cli
PLATFORM_INFO = platform_info
BACKEND_INFO = backend_info
CGO_ENABLED ?= 0
GOARCH ?= amd64
VERSION ?= $(shell git describe --abbrev=0 --tags --always)
COMMIT ?= $(shell git rev-parse HEAD)
TIME ?= $(shell date +%F_%T)
EMBED_ENABLED ?= 0
define compile_service
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
@@ -13,18 +14,19 @@ define compile_service
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
$(if $(filter 1,$(EMBED_ENABLED)),-tags "embed",) \
-o ${BUILD_DIR}/cocos-$(1) cmd/$(1)/main.go
endef
.PHONY: all $(SERVICES) $(PLATFORM_INFO)
.PHONY: all $(SERVICES) $(BACKEND_INFO)
all: $(SERVICES)
$(SERVICES):
$(call compile_service,$(@))
$(call compile_service,$@)
$(PLATFORM_INFO):
$(MAKE) -C ./scripts/platform_info
$(BACKEND_INFO):
$(MAKE) -C ./scripts/backend_info
protoc:
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative agent/agent.proto
+38
View File
@@ -0,0 +1,38 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build embed
// +build embed
package quoteprovider
import (
"github.com/google/go-sev-guest/client"
pb "github.com/google/go-sev-guest/proto/sevsnp"
cocosai "github.com/ultravioletrs/cocos"
)
var _ client.QuoteProvider = (*embeddedQuoteProvider)(nil)
type embeddedQuoteProvider struct {
}
func GetQuoteProvider() (client.QuoteProvider, error) {
return &embeddedQuoteProvider{}, nil
}
// GetQuote returns the SEV quote for the given report data.
func (e *embeddedQuoteProvider) GetRawQuote(reportData [64]byte) ([]byte, error) {
return cocosai.EmbeddedAttestation, nil
}
// IsSupported returns true if the SEV platform is supported.
func (e *embeddedQuoteProvider) IsSupported() bool {
return true
}
// Product returns the SEV product information.
// unimplemented since it is deprecated and not used.
func (e *embeddedQuoteProvider) Product() *pb.SevProduct {
panic("unimplemented")
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build !embed
// +build !embed
package quoteprovider
import "github.com/google/go-sev-guest/client"
func GetQuoteProvider() (client.QuoteProvider, error) {
return client.GetQuoteProvider()
}
+12 -14
View File
@@ -68,21 +68,23 @@ type Service interface {
}
type agentService struct {
computation Computation // Holds the current computation manifest.
algorithm algorithm.Algorithm // Filepath to the algorithm received for the computation.
result []byte // Stores the result of the computation.
sm *StateMachine // Manages the state transitions of the agent service.
runError error // Stores any error encountered during the computation run.
eventSvc events.Service // Service for publishing events related to computation.
computation Computation // Holds the current computation request details.
algorithm algorithm.Algorithm // Filepath to the algorithm received for the computation.
result []byte // Stores the result of the computation.
sm *StateMachine // Manages the state transitions of the agent service.
runError error // Stores any error encountered during the computation run.
eventSvc events.Service // Service for publishing events related to computation.
quoteProvider client.QuoteProvider // Provider for generating attestation quotes.
}
var _ Service = (*agentService)(nil)
// New instantiates the agent service implementation.
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp Computation) Service {
func New(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp Computation, quoteProvider client.QuoteProvider) Service {
svc := &agentService{
sm: NewStateMachine(logger, cmp),
eventSvc: eventSvc,
sm: NewStateMachine(logger, cmp),
eventSvc: eventSvc,
quoteProvider: quoteProvider,
}
go svc.sm.Start(ctx)
@@ -252,11 +254,7 @@ func (as *agentService) Result(ctx context.Context) ([]byte, error) {
}
func (as *agentService) Attestation(ctx context.Context, reportData [ReportDataSize]byte) ([]byte, error) {
provider, err := client.GetQuoteProvider()
if err != nil {
return []byte{}, err
}
rawQuote, err := provider.GetRawQuote(reportData)
rawQuote, err := as.quoteProvider.GetRawQuote(reportData)
if err != nil {
return []byte{}, err
}
BIN
View File
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build embed
// +build embed
package cocosai
import _ "embed"
//go:embed attestation.bin
var EmbeddedAttestation []byte
+12 -4
View File
@@ -11,12 +11,14 @@ import (
"log/slog"
"github.com/absmach/magistrala/pkg/prometheus"
"github.com/google/go-sev-guest/client"
"github.com/mdlayher/vsock"
"github.com/ultravioletrs/cocos/agent"
"github.com/ultravioletrs/cocos/agent/api"
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
"github.com/ultravioletrs/cocos/agent/auth"
"github.com/ultravioletrs/cocos/agent/events"
"github.com/ultravioletrs/cocos/agent/quoteprovider"
agentlogger "github.com/ultravioletrs/cocos/internal/logger"
"github.com/ultravioletrs/cocos/internal/server"
grpcserver "github.com/ultravioletrs/cocos/internal/server/grpc"
@@ -62,7 +64,13 @@ func main() {
}
defer eventSvc.Close()
svc := newService(ctx, logger, eventSvc, cfg)
qp, err := quoteprovider.GetQuoteProvider()
if err != nil {
logger.Error(fmt.Sprintf("failed to create quote provider %s", err.Error()))
return
}
svc := newService(ctx, logger, eventSvc, cfg, qp)
grpcServerConfig := server.Config{
Port: cfg.AgentConfig.Port,
@@ -85,7 +93,7 @@ func main() {
return
}
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger, svc, authSvc)
gs := grpcserver.New(ctx, cancel, svcName, grpcServerConfig, registerAgentServiceServer, logger, qp, authSvc)
g.Go(func() error {
return gs.Start()
@@ -100,8 +108,8 @@ func main() {
}
}
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp agent.Computation) agent.Service {
svc := agent.New(ctx, logger, eventSvc, cmp)
func newService(ctx context.Context, logger *slog.Logger, eventSvc events.Service, cmp agent.Computation, qp client.QuoteProvider) agent.Service {
svc := agent.New(ctx, logger, eventSvc, cmp, qp)
svc = api.LoggingMiddleware(svc, logger)
counter, latency := prometheus.MakeMetrics(svcName, "api")
+1
View File
@@ -71,3 +71,4 @@ BR2_TOOLCHAIN_BUILDROOT_LIBSTDCPP=y
BR2_PACKAGE_GCC=y
BR2_PACKAGE_GCC_TARGET=y
BR2_PACKAGE_LIBSTDCPP=y
+1 -1
View File
@@ -8,7 +8,7 @@ AGENT_VERSION = main
AGENT_SITE = $(call github,ultravioletrs,cocos,$(AGENT_VERSION))
define AGENT_BUILD_CMDS
$(MAKE) -C $(@D) agent
$(MAKE) -C $(@D) agent EMBED_ENABLED=$(AGENT_EMBED_ENABLED)
endef
define AGENT_INSTALL_TARGET_CMDS
+7 -7
View File
@@ -20,7 +20,7 @@ import (
"os"
"time"
"github.com/ultravioletrs/cocos/agent"
"github.com/google/go-sev-guest/client"
agentgrpc "github.com/ultravioletrs/cocos/agent/api/grpc"
"github.com/ultravioletrs/cocos/agent/auth"
"github.com/ultravioletrs/cocos/internal/server"
@@ -48,7 +48,7 @@ type Server struct {
server.BaseServer
server *grpc.Server
registerService serviceRegister
agent agent.Service
quoteProvider client.QuoteProvider
authSvc auth.Authenticator
}
@@ -56,7 +56,7 @@ type serviceRegister func(srv *grpc.Server)
var _ server.Server = (*Server)(nil)
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.Config, registerService serviceRegister, logger *slog.Logger, agentSvc agent.Service, authSvc auth.Authenticator) server.Server {
func New(ctx context.Context, cancel context.CancelFunc, name string, config server.Config, registerService serviceRegister, logger *slog.Logger, qp client.QuoteProvider, authSvc auth.Authenticator) server.Server {
listenFullAddress := fmt.Sprintf("%s:%s", config.Host, config.Port)
return &Server{
BaseServer: server.BaseServer{
@@ -68,7 +68,7 @@ func New(ctx context.Context, cancel context.CancelFunc, name string, config ser
Logger: logger,
},
registerService: registerService,
agent: agentSvc,
quoteProvider: qp,
authSvc: authSvc,
}
}
@@ -93,7 +93,7 @@ func (s *Server) Start() error {
switch {
case s.Config.AttestedTLS:
certificateBytes, privateKeyBytes, err := generateCertificatesForATLS(s.agent)
certificateBytes, privateKeyBytes, err := generateCertificatesForATLS(s.quoteProvider)
if err != nil {
return fmt.Errorf("failed to create certificate: %w", err)
}
@@ -228,7 +228,7 @@ func loadX509KeyPair(certfile, keyfile string) (tls.Certificate, error) {
return tls.X509KeyPair(cert, key)
}
func generateCertificatesForATLS(svc agent.Service) ([]byte, []byte, error) {
func generateCertificatesForATLS(qp client.QuoteProvider) ([]byte, []byte, error) {
curve := elliptic.P256()
privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
@@ -241,7 +241,7 @@ func generateCertificatesForATLS(svc agent.Service) ([]byte, []byte, error) {
}
// The Attestation Report will be added as an X.509 certificate extension
attestationReport, err := svc.Attestation(context.Background(), sha3.Sum512(publicKeyBytes))
attestationReport, err := qp.GetRawQuote(sha3.Sum512(publicKeyBytes))
if err != nil {
return nil, nil, fmt.Errorf("failed to fetch the attestation report: %w", err)
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build !embed
// +build !embed
package manager
import (
"fmt"
"os"
"os/exec"
)
func (ms *managerService) FetchBackendInfo() ([]byte, error) {
cmd := exec.Command("sudo", fmt.Sprintf("%s/backend_info", ms.backendMeasurementBinaryPath), "--policy", "1966081")
_, err := cmd.Output()
if err != nil {
return nil, err
}
f, err := os.ReadFile("./backend_info.json")
if err != nil {
return nil, err
}
return f, nil
}
+13
View File
@@ -0,0 +1,13 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build embed
// +build embed
package manager
import backendinfo "github.com/ultravioletrs/cocos/scripts/backend_info"
func (ms *managerService) FetchBackendInfo() ([]byte, error) {
return backendinfo.BackendInfo, nil
}
-18
View File
@@ -9,8 +9,6 @@ import (
"fmt"
"log/slog"
"net"
"os"
"os/exec"
"regexp"
"strconv"
"sync"
@@ -179,22 +177,6 @@ func (ms *managerService) Stop(ctx context.Context, computationID string) error
return nil
}
func (ms *managerService) FetchBackendInfo() ([]byte, error) {
cmd := exec.Command("sudo", fmt.Sprintf("%s/backend_info", ms.backendMeasurementBinaryPath), "--policy", "1966081")
_, err := cmd.Output()
if err != nil {
return nil, err
}
f, err := os.ReadFile("./backend_info.json")
if err != nil {
return nil, err
}
return f, nil
}
func getFreePort(minPort, maxPort int) (int, error) {
if checkPortisFree(minPort) {
return minPort, nil
+14
View File
@@ -0,0 +1,14 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
//go:build embed
// +build embed
package backendinfo
import (
_ "embed"
)
//go:embed backend_info.json
var BackendInfo []byte