Skip to content

Commit

Permalink
Merge pull request #5759 from oasisprotocol/peternose/bugfix/no-km-po…
Browse files Browse the repository at this point in the history
…licy-updates

go/runtime/registry/host: Ignore key manager quote policy update feature
  • Loading branch information
peternose committed Jul 4, 2024
2 parents 7962ac9 + f993133 commit 5b94237
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 68 deletions.
7 changes: 7 additions & 0 deletions .changelog/5759.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
go/runtime/registry/host: Ignore key manager quote policy update feature

If the key manager policy and status update watcher started before
the runtime active version was ready, it failed to fetch the runtime
info and stopped. Therefore, the key manager status and quote policy
were never updated, causing the key manager runtime client to reject
incoming Noise session requests since the policy was not set.
3 changes: 1 addition & 2 deletions go/runtime/host/composite/composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ func shouldPropagateToComponent(body *protocol.Body) bool {
// Consensus view of all components should be up to date as otherwise signed attestations
// will be stale, resulting in them being rejected.
return true
case body.RuntimeKeyManagerPolicyUpdateRequest != nil,
body.RuntimeKeyManagerStatusUpdateRequest != nil,
case body.RuntimeKeyManagerStatusUpdateRequest != nil,
body.RuntimeKeyManagerQuotePolicyUpdateRequest != nil:
// Key manager updates should be propagated.
return true
Expand Down
3 changes: 1 addition & 2 deletions go/runtime/host/loadbalance/loadbalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ func shouldPropagateToAll(body *protocol.Body) bool {
// Consensus view of all instances should be up to date as otherwise signed attestations
// will be stale, resulting in them being rejected.
return true
case body.RuntimeKeyManagerPolicyUpdateRequest != nil,
body.RuntimeKeyManagerStatusUpdateRequest != nil,
case body.RuntimeKeyManagerStatusUpdateRequest != nil,
body.RuntimeKeyManagerQuotePolicyUpdateRequest != nil:
// Key manager updates should be propagated.
return true
Expand Down
3 changes: 1 addition & 2 deletions go/runtime/host/multi/multi.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ func shouldPropagateToNextVersion(body *protocol.Body) bool {
// Consensus view of the next version should be up to date as otherwise signed attestations
// will be stale, resulting in them being rejected by the consensus layer.
return true
case body.RuntimeKeyManagerPolicyUpdateRequest != nil,
body.RuntimeKeyManagerStatusUpdateRequest != nil,
case body.RuntimeKeyManagerStatusUpdateRequest != nil,
body.RuntimeKeyManagerQuotePolicyUpdateRequest != nil:
// Key manager updates should be propagated so that the runtime is ready when activated.
return true
Expand Down
7 changes: 0 additions & 7 deletions go/runtime/host/protocol/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ type Body struct {
RuntimeAbortResponse *Empty `json:",omitempty"`
RuntimeKeyManagerStatusUpdateRequest *RuntimeKeyManagerStatusUpdateRequest `json:",omitempty"`
RuntimeKeyManagerStatusUpdateResponse *Empty `json:",omitempty"`
RuntimeKeyManagerPolicyUpdateRequest *RuntimeKeyManagerPolicyUpdateRequest `json:",omitempty"`
RuntimeKeyManagerPolicyUpdateResponse *Empty `json:",omitempty"`
RuntimeKeyManagerQuotePolicyUpdateRequest *RuntimeKeyManagerQuotePolicyUpdateRequest `json:",omitempty"`
RuntimeKeyManagerQuotePolicyUpdateResponse *Empty `json:",omitempty"`
RuntimeQueryRequest *RuntimeQueryRequest `json:",omitempty"`
Expand Down Expand Up @@ -447,11 +445,6 @@ type RuntimeKeyManagerStatusUpdateRequest struct {
Status secrets.Status `json:"status"`
}

// RuntimeKeyManagerPolicyUpdateRequest is a runtime key manager policy update request message body.
type RuntimeKeyManagerPolicyUpdateRequest struct {
SignedPolicyRaw []byte `json:"signed_policy_raw"`
}

// RuntimeKeyManagerQuotePolicyUpdateRequest is a runtime key manager quote policy update request
// message body.
type RuntimeKeyManagerQuotePolicyUpdateRequest struct {
Expand Down
34 changes: 26 additions & 8 deletions go/runtime/host/tests/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"github.com/stretchr/testify/require"

"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
"github.com/oasisprotocol/oasis-core/go/common/logging"
Expand Down Expand Up @@ -90,8 +91,13 @@ func TestProvisioner(
}
}

func mockKeyManagerPolicyRequest() (*protocol.Body, error) {
// Generate a dummy key manager policy for tests.
func mockRuntimeKeyManagerStatusUpdateRequest() (*protocol.Body, error) {
// Generate a dummy key manager status for tests.
var keymanagerID common.Namespace
if err := keymanagerID.UnmarshalHex("c000000000000000fffffffffffffffffffffffffffffffffffffffffffffffe"); err != nil {
return nil, err
}

policy := secrets.PolicySGX{
Serial: 1,
Enclaves: map[sgx.EnclaveIdentity]*secrets.EnclavePolicySGX{},
Expand All @@ -108,8 +114,20 @@ func mockKeyManagerPolicyRequest() (*protocol.Body, error) {
sigPolicy.Signatures = append(sigPolicy.Signatures, *sig)
}

return &protocol.Body{RuntimeKeyManagerPolicyUpdateRequest: &protocol.RuntimeKeyManagerPolicyUpdateRequest{
SignedPolicyRaw: cbor.Marshal(sigPolicy),
status := secrets.Status{
ID: keymanagerID,
IsInitialized: true,
IsSecure: true,
Generation: 1,
RotationEpoch: 0,
Checksum: []byte{1, 2, 3},
Nodes: nil,
Policy: &sigPolicy,
RSK: nil,
}

return &protocol.Body{RuntimeKeyManagerStatusUpdateRequest: &protocol.RuntimeKeyManagerStatusUpdateRequest{
Status: status,
}}, nil
}

Expand Down Expand Up @@ -139,12 +157,12 @@ func testBasic(t *testing.T, cfg host.Config, p host.Provisioner) {
require.NoError(err, "Call")
require.NotNil(rsp.Empty, "runtime response to RuntimePingRequest should return an Empty body")

req, err := mockKeyManagerPolicyRequest()
require.NoError(err, "mockKeyManagerPolicyRequest")
req, err := mockRuntimeKeyManagerStatusUpdateRequest()
require.NoError(err, "mockKeyManagerStatusRequest")

rsp, err = r.Call(ctx, req)
require.NoError(err, "KeyManagerPolicyRequest Call")
require.NotNil(rsp.RuntimeKeyManagerPolicyUpdateResponse, "runtime response to KeyManagerPolicyRequest should return an RuntimeKeyManagerPolicyUpdateResponse body")
require.NoError(err, "KeyManagerStatusRequest Call")
require.NotNil(rsp.RuntimeKeyManagerStatusUpdateResponse, "runtime response to RuntimeKeyManagerStatusUpdate should return a RuntimeKeyManagerStatusUpdateResponse body")

// Request the runtime to stop.
r.Stop()
Expand Down
59 changes: 12 additions & 47 deletions go/runtime/registry/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,46 +663,34 @@ func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *
var (
statusUpdated = true
quotePolicyUpdated = true
runtimeInfoUpdated = false
)

var (
st *secrets.Status
sc *node.SGXConstraints
vi *registry.VersionInfo
ri *protocol.RuntimeInfoResponse
)

for {
// Fetch runtime info so that we know which features the current runtime version supports.
if !runtimeInfoUpdated {
if ri, err = n.host.GetInfo(ctx); err != nil {
n.logger.Error("failed to fetch runtime info",
"err", err,
)
return
}
runtimeInfoUpdated = true
}

// Make sure that we actually have a new status.
if !statusUpdated && st != nil {
switch {
case ri.Features.KeyManagerStatusUpdates:
if err = n.updateKeyManagerStatus(ctx, st); err == nil {
statusUpdated = true
}
case st.Policy != nil:
if err = n.updateKeyManagerPolicy(ctx, st.Policy); err == nil {
statusUpdated = true
}
if err = n.updateKeyManagerStatus(ctx, st); err != nil {
n.logger.Error("failed to update key manager status",
"err", err,
)
} else {
statusUpdated = true
}
}

// Make sure that we actually have a new quote policy and that the current runtime version
// supports quote policy updates.
if !quotePolicyUpdated && sc != nil && sc.Policy != nil && ri.Features.KeyManagerQuotePolicyUpdates {
if err = n.updateKeyManagerQuotePolicy(ctx, sc.Policy); err == nil {
if !quotePolicyUpdated && sc != nil && sc.Policy != nil {
if err = n.updateKeyManagerQuotePolicy(ctx, sc.Policy); err != nil {
n.logger.Error("failed to update key manager quote policy",
"err", err,
)
} else {
quotePolicyUpdated = true
}
}
Expand Down Expand Up @@ -763,7 +751,6 @@ func (n *runtimeHostNotifier) watchKmPolicyUpdates(ctx context.Context, kmRtID *

statusUpdated = false
quotePolicyUpdated = false
runtimeInfoUpdated = false
case <-retryTicker.C:
// Retry updates if some of them failed. When using CometBFT as a backend service
// the host will see the new state one block before the consensus verifier as the former
Expand Down Expand Up @@ -795,28 +782,6 @@ func (n *runtimeHostNotifier) updateKeyManagerStatus(ctx context.Context, status
return nil
}

func (n *runtimeHostNotifier) updateKeyManagerPolicy(ctx context.Context, policy *secrets.SignedPolicySGX) error {
n.logger.Debug("got key manager policy update", "policy", policy)

raw := cbor.Marshal(policy)
req := &protocol.Body{RuntimeKeyManagerPolicyUpdateRequest: &protocol.RuntimeKeyManagerPolicyUpdateRequest{
SignedPolicyRaw: raw,
}}

ctx, cancel := context.WithTimeout(ctx, notifyTimeout)
defer cancel()

if _, err := n.host.Call(ctx, req); err != nil {
n.logger.Error("failed dispatching key manager policy update to runtime",
"err", err,
)
return err
}

n.logger.Debug("key manager policy update dispatched")
return nil
}

func (n *runtimeHostNotifier) updateKeyManagerQuotePolicy(ctx context.Context, policy *quote.Policy) error {
n.logger.Debug("got key manager quote policy update", "policy", policy)

Expand Down

0 comments on commit 5b94237

Please sign in to comment.