diff --git a/.changelog/5759.bugfix.md b/.changelog/5759.bugfix.md new file mode 100644 index 00000000000..682e0a83ec5 --- /dev/null +++ b/.changelog/5759.bugfix.md @@ -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. diff --git a/go/runtime/host/composite/composite.go b/go/runtime/host/composite/composite.go index 6ca827edef3..92a618fdc6f 100644 --- a/go/runtime/host/composite/composite.go +++ b/go/runtime/host/composite/composite.go @@ -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 diff --git a/go/runtime/host/loadbalance/loadbalance.go b/go/runtime/host/loadbalance/loadbalance.go index 64c69c1668a..6bb1db2901f 100644 --- a/go/runtime/host/loadbalance/loadbalance.go +++ b/go/runtime/host/loadbalance/loadbalance.go @@ -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 diff --git a/go/runtime/host/multi/multi.go b/go/runtime/host/multi/multi.go index 7fca156771a..c3f8694208f 100644 --- a/go/runtime/host/multi/multi.go +++ b/go/runtime/host/multi/multi.go @@ -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 diff --git a/go/runtime/host/protocol/types.go b/go/runtime/host/protocol/types.go index e82013db0b8..caa8675846f 100644 --- a/go/runtime/host/protocol/types.go +++ b/go/runtime/host/protocol/types.go @@ -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"` @@ -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 { diff --git a/go/runtime/host/tests/tester.go b/go/runtime/host/tests/tester.go index 439f7c291d7..c55a843c78b 100644 --- a/go/runtime/host/tests/tester.go +++ b/go/runtime/host/tests/tester.go @@ -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" @@ -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{}, @@ -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 } @@ -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() diff --git a/go/runtime/registry/host.go b/go/runtime/registry/host.go index 6f8206b02fa..1026702a3b1 100644 --- a/go/runtime/registry/host.go +++ b/go/runtime/registry/host.go @@ -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 } } @@ -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 @@ -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)