Skip to content

Commit

Permalink
go/runtime/registry: Decouple host provisioner from runtime registry
Browse files Browse the repository at this point in the history
  • Loading branch information
peternose committed Feb 21, 2025
1 parent 3a6f27a commit bf142b9
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 219 deletions.
Empty file added .changelog/6073.trivial.md
Empty file.
17 changes: 8 additions & 9 deletions go/oasis-node/cmd/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import (
controlAPI "github.com/oasisprotocol/oasis-core/go/control/api"
genesisAPI "github.com/oasisprotocol/oasis-core/go/genesis/api"
governanceAPI "github.com/oasisprotocol/oasis-core/go/governance/api"
"github.com/oasisprotocol/oasis-core/go/ias"
iasAPI "github.com/oasisprotocol/oasis-core/go/ias/api"
keymanagerAPI "github.com/oasisprotocol/oasis-core/go/keymanager/api"
cmdCommon "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common"
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/background"
Expand All @@ -33,6 +31,8 @@ import (
p2pAPI "github.com/oasisprotocol/oasis-core/go/p2p/api"
registryAPI "github.com/oasisprotocol/oasis-core/go/registry/api"
roothashAPI "github.com/oasisprotocol/oasis-core/go/roothash/api"
"github.com/oasisprotocol/oasis-core/go/runtime/host"
"github.com/oasisprotocol/oasis-core/go/runtime/host/provisioner"
runtimeRegistry "github.com/oasisprotocol/oasis-core/go/runtime/registry"
scheduler "github.com/oasisprotocol/oasis-core/go/scheduler/api"
"github.com/oasisprotocol/oasis-core/go/sentry"
Expand Down Expand Up @@ -76,9 +76,9 @@ type Node struct {
Genesis genesisAPI.Provider
Identity *identity.Identity
Sentry sentryAPI.Backend
IAS []iasAPI.Endpoint

RuntimeRegistry runtimeRegistry.Registry
Provisioner host.Provisioner

CommonWorker *workerCommon.Worker
ExecutorWorker *executor.Worker
Expand Down Expand Up @@ -218,17 +218,14 @@ func (n *Node) initRuntimeWorkers() error {
return err
}

// Initialize the IAS proxy client.
n.IAS, err = ias.New(n.Identity)
// Initialize runtime provisioner.
n.Provisioner, err = provisioner.New(n.dataDir, n.commonStore, n.Identity, n.Consensus)
if err != nil {
n.logger.Error("failed to initialize IAS proxy client",
"err", err,
)
return err
}

// Initialize the node's runtime registry.
n.RuntimeRegistry, err = runtimeRegistry.New(n.svcMgr.Ctx, n.dataDir, n.commonStore, n.Identity, n.Consensus, n.IAS)
n.RuntimeRegistry, err = runtimeRegistry.New(n.svcMgr.Ctx, n.dataDir, n.Consensus)
if err != nil {
return err
}
Expand All @@ -245,6 +242,7 @@ func (n *Node) initRuntimeWorkers() error {
n.P2P,
n.Consensus.KeyManager(),
n.RuntimeRegistry,
n.Provisioner,
)
if err != nil {
n.logger.Error("failed to initialize common worker",
Expand Down Expand Up @@ -306,6 +304,7 @@ func (n *Node) initRuntimeWorkers() error {
n.CommonWorker,
n.RegistrationWorker,
n.Consensus.KeyManager(),
n.Provisioner,
)
if err != nil {
return err
Expand Down
5 changes: 1 addition & 4 deletions go/oasis-node/cmd/node/node_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,7 @@ func (n *Node) getRuntimeStatus(ctx context.Context) (map[common.Namespace]contr
}

// Fetch provisioner type.
status.Provisioner = "none"
if provisioner := rt.HostProvisioner(); provisioner != nil {
status.Provisioner = provisioner.Name()
}
status.Provisioner = n.Provisioner.Name()

// Fetch the status of all components associated with the runtime.
for _, comp := range n.RuntimeRegistry.GetBundleRegistry().Components(rt.ID()) {
Expand Down
203 changes: 203 additions & 0 deletions go/runtime/host/provisioner/provisioner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package provisioner

import (
"context"
"fmt"
"path/filepath"

"github.com/oasisprotocol/oasis-core/go/common/identity"
"github.com/oasisprotocol/oasis-core/go/common/persistent"
"github.com/oasisprotocol/oasis-core/go/common/sgx/pcs"
"github.com/oasisprotocol/oasis-core/go/config"
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
"github.com/oasisprotocol/oasis-core/go/ias"
iasAPI "github.com/oasisprotocol/oasis-core/go/ias/api"
cmdFlags "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/flags"
"github.com/oasisprotocol/oasis-core/go/runtime/bundle/component"
rtConfig "github.com/oasisprotocol/oasis-core/go/runtime/config"
runtimeHost "github.com/oasisprotocol/oasis-core/go/runtime/host"
hostComposite "github.com/oasisprotocol/oasis-core/go/runtime/host/composite"
hostLoadBalance "github.com/oasisprotocol/oasis-core/go/runtime/host/loadbalance"
hostMock "github.com/oasisprotocol/oasis-core/go/runtime/host/mock"
hostProtocol "github.com/oasisprotocol/oasis-core/go/runtime/host/protocol"
hostSandbox "github.com/oasisprotocol/oasis-core/go/runtime/host/sandbox"
hostSgx "github.com/oasisprotocol/oasis-core/go/runtime/host/sgx"
hostTdx "github.com/oasisprotocol/oasis-core/go/runtime/host/tdx"
"github.com/oasisprotocol/oasis-core/go/runtime/registry"
)

// New creates a new runtime provisioner.
//
// This helper function creates a provisioner capable of provisioning runtimes
// with or without a Trusted Execution Environment (TEE), such as Intel SGX
// or TDX. If the debug mock flag is enabled, the TEE will be mocked.
func New(
dataDir string,
commonStore *persistent.CommonStore,
identity *identity.Identity,
consensus consensus.Backend,
) (runtimeHost.Provisioner, error) {
// Initialize the IAS proxy client.
ias, err := ias.New(identity)
if err != nil {
return nil, fmt.Errorf("failed to initialize IAS proxy client: %w", err)
}

// Configure host environment information.
hostInfo, err := createHostInfo(consensus)
if err != nil {
return nil, err
}

// Create the PCS client and quote service.
qs, err := createCachingQuoteService(commonStore)
if err != nil {
return nil, err
}

// Create runtime provisioner.
return createProvisioner(dataDir, commonStore, identity, consensus, hostInfo, ias, qs)
}

func createHostInfo(consensus consensus.Backend) (*hostProtocol.HostInfo, error) {
cs, err := consensus.GetStatus(context.Background())
if err != nil {
return nil, fmt.Errorf("failed to get consensus layer status: %w", err)
}

chainCtx, err := consensus.GetChainContext(context.Background())
if err != nil {
return nil, fmt.Errorf("failed to get chain context: %w", err)
}

return &hostProtocol.HostInfo{
ConsensusBackend: cs.Backend,
ConsensusProtocolVersion: cs.Version,
ConsensusChainContext: chainCtx,
}, nil
}

func createCachingQuoteService(commonStore *persistent.CommonStore) (pcs.QuoteService, error) {
pc, err := pcs.NewHTTPClient(&pcs.HTTPClientConfig{
// TODO: Support configuring the API key.
})
if err != nil {
return nil, fmt.Errorf("failed to create PCS HTTP client: %w", err)
}

qs := pcs.NewCachingQuoteService(pc, commonStore)

return qs, nil
}

func createProvisioner(
dataDir string,
commonStore *persistent.CommonStore,
identity *identity.Identity,
consensus consensus.Backend,
hostInfo *hostProtocol.HostInfo,
ias []iasAPI.Endpoint,
qs pcs.QuoteService,
) (runtimeHost.Provisioner, error) {
var err error
var insecureNoSandbox bool

attestInterval := config.GlobalConfig.Runtime.AttestInterval
sandboxBinary := config.GlobalConfig.Runtime.SandboxBinary
sgxLoader := config.GlobalConfig.Runtime.SGXLoader
insecureMock := config.GlobalConfig.Runtime.DebugMockTEE

// Support legacy configuration where the runtime environment determines
// whether the TEE should be mocked.
if config.GlobalConfig.Runtime.Environment == rtConfig.RuntimeEnvironmentSGXMock {
insecureMock = true
}

// Register provisioners based on the configured provisioner.
provisioners := make(map[component.TEEKind]runtimeHost.Provisioner)
switch p := config.GlobalConfig.Runtime.Provisioner; p {
case rtConfig.RuntimeProvisionerMock:
// Mock provisioner, only supported when the runtime requires no TEE hardware.
if !cmdFlags.DebugDontBlameOasis() {
return nil, fmt.Errorf("mock provisioner requires use of unsafe debug flags")
}

provisioners[component.TEEKindNone] = hostMock.NewProvisioner()
case rtConfig.RuntimeProvisionerUnconfined:
// Unconfined provisioner, can be used with no TEE or with Intel SGX.
if !cmdFlags.DebugDontBlameOasis() {
return nil, fmt.Errorf("unconfined provisioner requires use of unsafe debug flags")
}

insecureNoSandbox = true

fallthrough
case rtConfig.RuntimeProvisionerSandboxed:
// Sandboxed provisioner, can be used with no TEE or with Intel SGX.

// Configure the non-TEE provisioner.
provisioners[component.TEEKindNone], err = hostSandbox.NewProvisioner(hostSandbox.Config{
HostInfo: hostInfo,
InsecureNoSandbox: insecureNoSandbox,
SandboxBinaryPath: sandboxBinary,
})
if err != nil {
return nil, fmt.Errorf("failed to create runtime provisioner: %w", err)
}

// Configure the Intel SGX provisioner.
if insecureMock && !cmdFlags.DebugDontBlameOasis() {
return nil, fmt.Errorf("mock SGX requires use of unsafe debug flags")
}

if !insecureMock && sgxLoader == "" {
// SGX may be needed, but we don't have a loader configured.
break
}

provisioners[component.TEEKindSGX], err = hostSgx.NewProvisioner(hostSgx.Config{
HostInfo: hostInfo,
CommonStore: commonStore,
LoaderPath: sgxLoader,
IAS: ias,
PCS: qs,
Consensus: consensus,
Identity: identity,
SandboxBinaryPath: sandboxBinary,
InsecureNoSandbox: insecureNoSandbox,
InsecureMock: insecureMock,
RuntimeAttestInterval: attestInterval,
})
if err != nil {
return nil, fmt.Errorf("failed to create SGX runtime provisioner: %w", err)
}
default:
return nil, fmt.Errorf("unsupported runtime provisioner: %s", p)
}

// Configure TDX provisioner.
// TODO: Allow provisioner selection in the future, currently we only have QEMU.
provisioners[component.TEEKindTDX], err = hostTdx.NewQemuProvisioner(hostTdx.QemuConfig{
DataDir: filepath.Join(dataDir, registry.RuntimesDir),
HostInfo: hostInfo,
CommonStore: commonStore,
PCS: qs,
Consensus: consensus,
Identity: identity,
RuntimeAttestInterval: attestInterval,
})
if err != nil {
return nil, fmt.Errorf("failed to create TDX runtime provisioner: %w", err)
}

// Configure optional load balancing.
for tee, rp := range provisioners {
numInstances := int(config.GlobalConfig.Runtime.LoadBalancer.NumInstances)
provisioners[tee] = hostLoadBalance.NewProvisioner(rp, numInstances)
}

// Create a composite provisioner to provision the individual components.
provisioner := hostComposite.NewProvisioner(provisioners)

return provisioner, nil
}
Loading

0 comments on commit bf142b9

Please sign in to comment.