Skip to content

Commit 2282bcd

Browse files
committed
go/runtime/registry: Decouple host provisioner from runtime registry
1 parent 3a6f27a commit 2282bcd

File tree

10 files changed

+220
-219
lines changed

10 files changed

+220
-219
lines changed

.changelog/6073.trivial.md

Whitespace-only changes.

go/oasis-node/cmd/node/node.go

+8-9
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ import (
2222
controlAPI "github.com/oasisprotocol/oasis-core/go/control/api"
2323
genesisAPI "github.com/oasisprotocol/oasis-core/go/genesis/api"
2424
governanceAPI "github.com/oasisprotocol/oasis-core/go/governance/api"
25-
"github.com/oasisprotocol/oasis-core/go/ias"
26-
iasAPI "github.com/oasisprotocol/oasis-core/go/ias/api"
2725
keymanagerAPI "github.com/oasisprotocol/oasis-core/go/keymanager/api"
2826
cmdCommon "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common"
2927
"github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/background"
@@ -33,6 +31,8 @@ import (
3331
p2pAPI "github.com/oasisprotocol/oasis-core/go/p2p/api"
3432
registryAPI "github.com/oasisprotocol/oasis-core/go/registry/api"
3533
roothashAPI "github.com/oasisprotocol/oasis-core/go/roothash/api"
34+
"github.com/oasisprotocol/oasis-core/go/runtime/host"
35+
"github.com/oasisprotocol/oasis-core/go/runtime/host/provisioner"
3636
runtimeRegistry "github.com/oasisprotocol/oasis-core/go/runtime/registry"
3737
scheduler "github.com/oasisprotocol/oasis-core/go/scheduler/api"
3838
"github.com/oasisprotocol/oasis-core/go/sentry"
@@ -76,9 +76,9 @@ type Node struct {
7676
Genesis genesisAPI.Provider
7777
Identity *identity.Identity
7878
Sentry sentryAPI.Backend
79-
IAS []iasAPI.Endpoint
8079

8180
RuntimeRegistry runtimeRegistry.Registry
81+
Provisioner host.Provisioner
8282

8383
CommonWorker *workerCommon.Worker
8484
ExecutorWorker *executor.Worker
@@ -218,17 +218,14 @@ func (n *Node) initRuntimeWorkers() error {
218218
return err
219219
}
220220

221-
// Initialize the IAS proxy client.
222-
n.IAS, err = ias.New(n.Identity)
221+
// Initialize runtime provisioner.
222+
n.Provisioner, err = provisioner.New(n.dataDir, n.commonStore, n.Identity, n.Consensus)
223223
if err != nil {
224-
n.logger.Error("failed to initialize IAS proxy client",
225-
"err", err,
226-
)
227224
return err
228225
}
229226

230227
// Initialize the node's runtime registry.
231-
n.RuntimeRegistry, err = runtimeRegistry.New(n.svcMgr.Ctx, n.dataDir, n.commonStore, n.Identity, n.Consensus, n.IAS)
228+
n.RuntimeRegistry, err = runtimeRegistry.New(n.svcMgr.Ctx, n.dataDir, n.Consensus)
232229
if err != nil {
233230
return err
234231
}
@@ -245,6 +242,7 @@ func (n *Node) initRuntimeWorkers() error {
245242
n.P2P,
246243
n.Consensus.KeyManager(),
247244
n.RuntimeRegistry,
245+
n.Provisioner,
248246
)
249247
if err != nil {
250248
n.logger.Error("failed to initialize common worker",
@@ -306,6 +304,7 @@ func (n *Node) initRuntimeWorkers() error {
306304
n.CommonWorker,
307305
n.RegistrationWorker,
308306
n.Consensus.KeyManager(),
307+
n.Provisioner,
309308
)
310309
if err != nil {
311310
return err

go/oasis-node/cmd/node/node_control.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,7 @@ func (n *Node) getRuntimeStatus(ctx context.Context) (map[common.Namespace]contr
342342
}
343343

344344
// Fetch provisioner type.
345-
status.Provisioner = "none"
346-
if provisioner := rt.HostProvisioner(); provisioner != nil {
347-
status.Provisioner = provisioner.Name()
348-
}
345+
status.Provisioner = n.Provisioner.Name()
349346

350347
// Fetch the status of all components associated with the runtime.
351348
for _, comp := range n.RuntimeRegistry.GetBundleRegistry().Components(rt.ID()) {
+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package provisioner
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"path/filepath"
7+
8+
"github.com/oasisprotocol/oasis-core/go/common/identity"
9+
"github.com/oasisprotocol/oasis-core/go/common/persistent"
10+
"github.com/oasisprotocol/oasis-core/go/common/sgx/pcs"
11+
"github.com/oasisprotocol/oasis-core/go/config"
12+
consensus "github.com/oasisprotocol/oasis-core/go/consensus/api"
13+
"github.com/oasisprotocol/oasis-core/go/ias"
14+
iasAPI "github.com/oasisprotocol/oasis-core/go/ias/api"
15+
cmdFlags "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/flags"
16+
"github.com/oasisprotocol/oasis-core/go/runtime/bundle/component"
17+
rtConfig "github.com/oasisprotocol/oasis-core/go/runtime/config"
18+
runtimeHost "github.com/oasisprotocol/oasis-core/go/runtime/host"
19+
hostComposite "github.com/oasisprotocol/oasis-core/go/runtime/host/composite"
20+
hostLoadBalance "github.com/oasisprotocol/oasis-core/go/runtime/host/loadbalance"
21+
hostMock "github.com/oasisprotocol/oasis-core/go/runtime/host/mock"
22+
hostProtocol "github.com/oasisprotocol/oasis-core/go/runtime/host/protocol"
23+
hostSandbox "github.com/oasisprotocol/oasis-core/go/runtime/host/sandbox"
24+
hostSgx "github.com/oasisprotocol/oasis-core/go/runtime/host/sgx"
25+
hostTdx "github.com/oasisprotocol/oasis-core/go/runtime/host/tdx"
26+
"github.com/oasisprotocol/oasis-core/go/runtime/registry"
27+
)
28+
29+
func New(
30+
dataDir string,
31+
commonStore *persistent.CommonStore,
32+
identity *identity.Identity,
33+
consensus consensus.Backend,
34+
) (runtimeHost.Provisioner, error) {
35+
// Initialize the IAS proxy client.
36+
ias, err := ias.New(identity)
37+
if err != nil {
38+
return nil, fmt.Errorf("failed to initialize IAS proxy client: %w", err)
39+
}
40+
41+
// Configure host environment information.
42+
hostInfo, err := createHostInfo(consensus)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
// Create the PCS client and quote service.
48+
qs, err := createCachingQuoteService(commonStore)
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
// Create runtime provisioner.
54+
return createProvisioner(dataDir, commonStore, identity, consensus, hostInfo, ias, qs)
55+
}
56+
57+
func createHostInfo(consensus consensus.Backend) (*hostProtocol.HostInfo, error) {
58+
cs, err := consensus.GetStatus(context.Background())
59+
if err != nil {
60+
return nil, fmt.Errorf("failed to get consensus layer status: %w", err)
61+
}
62+
63+
chainCtx, err := consensus.GetChainContext(context.Background())
64+
if err != nil {
65+
return nil, fmt.Errorf("failed to get chain context: %w", err)
66+
}
67+
68+
return &hostProtocol.HostInfo{
69+
ConsensusBackend: cs.Backend,
70+
ConsensusProtocolVersion: cs.Version,
71+
ConsensusChainContext: chainCtx,
72+
}, nil
73+
}
74+
75+
func createCachingQuoteService(commonStore *persistent.CommonStore) (pcs.QuoteService, error) {
76+
pc, err := pcs.NewHTTPClient(&pcs.HTTPClientConfig{
77+
// TODO: Support configuring the API key.
78+
})
79+
if err != nil {
80+
return nil, fmt.Errorf("failed to create PCS HTTP client: %w", err)
81+
}
82+
83+
qs := pcs.NewCachingQuoteService(pc, commonStore)
84+
85+
return qs, nil
86+
}
87+
88+
func createProvisioner(
89+
dataDir string,
90+
commonStore *persistent.CommonStore,
91+
identity *identity.Identity,
92+
consensus consensus.Backend,
93+
hostInfo *hostProtocol.HostInfo,
94+
ias []iasAPI.Endpoint,
95+
qs pcs.QuoteService,
96+
) (runtimeHost.Provisioner, error) {
97+
var err error
98+
var insecureNoSandbox bool
99+
100+
attestInterval := config.GlobalConfig.Runtime.AttestInterval
101+
sandboxBinary := config.GlobalConfig.Runtime.SandboxBinary
102+
sgxLoader := config.GlobalConfig.Runtime.SGXLoader
103+
insecureMock := config.GlobalConfig.Runtime.DebugMockTEE
104+
105+
// Support legacy configuration where the runtime environment determines
106+
// whether the TEE should be mocked.
107+
if config.GlobalConfig.Runtime.Environment == rtConfig.RuntimeEnvironmentSGXMock {
108+
insecureMock = true
109+
}
110+
111+
// Register provisioners based on the configured provisioner.
112+
provisioners := make(map[component.TEEKind]runtimeHost.Provisioner)
113+
switch p := config.GlobalConfig.Runtime.Provisioner; p {
114+
case rtConfig.RuntimeProvisionerMock:
115+
// Mock provisioner, only supported when the runtime requires no TEE hardware.
116+
if !cmdFlags.DebugDontBlameOasis() {
117+
return nil, fmt.Errorf("mock provisioner requires use of unsafe debug flags")
118+
}
119+
120+
provisioners[component.TEEKindNone] = hostMock.NewProvisioner()
121+
case rtConfig.RuntimeProvisionerUnconfined:
122+
// Unconfined provisioner, can be used with no TEE or with Intel SGX.
123+
if !cmdFlags.DebugDontBlameOasis() {
124+
return nil, fmt.Errorf("unconfined provisioner requires use of unsafe debug flags")
125+
}
126+
127+
insecureNoSandbox = true
128+
129+
fallthrough
130+
case rtConfig.RuntimeProvisionerSandboxed:
131+
// Sandboxed provisioner, can be used with no TEE or with Intel SGX.
132+
133+
// Configure the non-TEE provisioner.
134+
provisioners[component.TEEKindNone], err = hostSandbox.NewProvisioner(hostSandbox.Config{
135+
HostInfo: hostInfo,
136+
InsecureNoSandbox: insecureNoSandbox,
137+
SandboxBinaryPath: sandboxBinary,
138+
})
139+
if err != nil {
140+
return nil, fmt.Errorf("failed to create runtime provisioner: %w", err)
141+
}
142+
143+
// Configure the Intel SGX provisioner.
144+
if insecureMock && !cmdFlags.DebugDontBlameOasis() {
145+
return nil, fmt.Errorf("mock SGX requires use of unsafe debug flags")
146+
}
147+
148+
if !insecureMock && sgxLoader == "" {
149+
// SGX may be needed, but we don't have a loader configured.
150+
break
151+
}
152+
153+
provisioners[component.TEEKindSGX], err = hostSgx.NewProvisioner(hostSgx.Config{
154+
HostInfo: hostInfo,
155+
CommonStore: commonStore,
156+
LoaderPath: sgxLoader,
157+
IAS: ias,
158+
PCS: qs,
159+
Consensus: consensus,
160+
Identity: identity,
161+
SandboxBinaryPath: sandboxBinary,
162+
InsecureNoSandbox: insecureNoSandbox,
163+
InsecureMock: insecureMock,
164+
RuntimeAttestInterval: attestInterval,
165+
})
166+
if err != nil {
167+
return nil, fmt.Errorf("failed to create SGX runtime provisioner: %w", err)
168+
}
169+
default:
170+
return nil, fmt.Errorf("unsupported runtime provisioner: %s", p)
171+
}
172+
173+
// Configure TDX provisioner.
174+
// TODO: Allow provisioner selection in the future, currently we only have QEMU.
175+
provisioners[component.TEEKindTDX], err = hostTdx.NewQemuProvisioner(hostTdx.QemuConfig{
176+
DataDir: filepath.Join(dataDir, registry.RuntimesDir),
177+
HostInfo: hostInfo,
178+
CommonStore: commonStore,
179+
PCS: qs,
180+
Consensus: consensus,
181+
Identity: identity,
182+
RuntimeAttestInterval: attestInterval,
183+
})
184+
if err != nil {
185+
return nil, fmt.Errorf("failed to create TDX runtime provisioner: %w", err)
186+
}
187+
188+
// Configure optional load balancing.
189+
for tee, rp := range provisioners {
190+
numInstances := int(config.GlobalConfig.Runtime.LoadBalancer.NumInstances)
191+
provisioners[tee] = hostLoadBalance.NewProvisioner(rp, numInstances)
192+
}
193+
194+
// Create a composite provisioner to provision the individual components.
195+
provisioner := hostComposite.NewProvisioner(provisioners)
196+
197+
return provisioner, nil
198+
}

0 commit comments

Comments
 (0)