|
| 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