-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ADR 0019: Key Manager Policy Improvements #10
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# ADR 0019: Key Manager Policy Improvements | ||
|
||
## Component | ||
|
||
Oasis Core | ||
|
||
## Changelog | ||
|
||
- {date}: {changelog} | ||
|
||
## Status | ||
|
||
Proposed | ||
|
||
## Context | ||
|
||
The initial key manager design uses a dynamic policy for access control, | ||
that is signed by a hard-coded set of signers. While the current design | ||
is functional, there are several "ease of use" type improvements that can | ||
be made to how policies and their signatures are handled. | ||
|
||
## Decision | ||
|
||
### KM Enclave Status changes | ||
|
||
To facilitate extra verification at the consensus layer, the per-key manager | ||
instance runtime status field is to be extended as follows: | ||
|
||
```golang | ||
type Status struct { | ||
// ... existing fields omitted ... | ||
|
||
// BaseSigners is the list of allowed policy signers, as hard-coded in | ||
// the enclave binary. | ||
BaseSigners []signature.PublicKey `json:"base_signers,omitempty"` | ||
|
||
// BaseSignerThreshold is the number of valid signatures that are required | ||
// for a policy, as hard-coded in the enclave binary. | ||
BaseSignerThreshold uint32 `json:"base_signer_threshold,omitempty"` | ||
} | ||
``` | ||
|
||
The ordering of the elements in the `BaseSigners` list is not explicitly | ||
specified beyond the fact that it MUST be globally consistent across all | ||
deployments of a given enclave binary. | ||
|
||
It is also emphasized that, the list is of the hard-coded policy signers, | ||
as of the time the enclave binary was built. | ||
|
||
### KM Policy Updates | ||
|
||
The existing key manager `UpdatePolicy` method is to be deprecated, and | ||
replaced with the following methods. | ||
|
||
```golang | ||
|
||
type PolicyProposal struct { | ||
// The unsigned policy. | ||
Policy PolicySGX `json:"policy"` | ||
|
||
// Manually collected signatures. | ||
Signatures []signature.Signatures `json:"signatures,omitempty"` | ||
|
||
// XXX: Specify some sort of voting period... or hardcode it? idk. | ||
} | ||
|
||
type PolicyVote struct { | ||
// The policy serial number that this vote is for. | ||
Serial uint32 `json:"serial"` | ||
// The runtime ID that this vote is for. | ||
ID common.Namespace `json:"id"` | ||
|
||
// The signature over the PolicyProposal.Policy. | ||
Signature signature.Signature `json:"signature"` | ||
} | ||
|
||
// TODO: Document the backend extensions. | ||
|
||
var ( | ||
MethodPolicyPropose = transaction.NewMethodName(ModuleName, "PolicyPropose", PolicyProposal{}) | ||
MethodPolicyVote = transaction.NewMethodName(ModuleName, "PolicyVote", PolicyVote{}) | ||
) | ||
``` | ||
|
||
Like with `UpdatePolicy`, the new update process is initiated by the owner | ||
of the KM runtime in question, but now with a `PolicyProposal`. | ||
|
||
If other entities support the update, they will sign the policy and submit | ||
the signature as a `PolicyVote` transaction. | ||
|
||
On the consensus side, votes: | ||
- Must be for an open (not expired) `PolicyProposal` | ||
- Must be signed by a public key that is part of `Status.BaseSigners` | ||
|
||
Once the number of signatures (be them from `PolicyProposal.Signatures` or | ||
`PolicyVote`s) is greater than `Status.BaseSignerThreshold`, the policy | ||
is considered ratified, and will take effect on the key managers nodes. | ||
|
||
As a special case to support legacy KM runtime deployments, `UpdatePolicy` | ||
transactions submitted for existing runtimes, that both have an empty | ||
`Status.BaseSigners` list AND a `0` `Status.BaseSignerThreshold`, are | ||
treated as ratified iff `UpdatePolicy.Signatures` contains more than one | ||
valid signature. | ||
|
||
### KM Key Revocation | ||
|
||
A new key manager method `PolicyRevokeKey` is to be added. | ||
|
||
```golang | ||
var ( | ||
MethodPolicyRevokeKey = transaction.NewMethodName(ModuleName, "PolicyRevokeKey", struct{}) | ||
) | ||
|
||
type Backend interface { | ||
// Existing methods omitted.... | ||
|
||
GetRevocations(context.Context, int64) ([]signature.PublicKey, error) | ||
} | ||
``` | ||
|
||
Submitting a `PolicyRevokeKey` transaction, will invalidate the signing key | ||
for the purpose of ratifying key manager policies. Note that revocations | ||
are expected to take effect the next time various nodes re-attest (the light | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably the enclave should fetch the latest revocation list each time before accepting any policy update (similar to how policy publication is checked) instead of on re-attestation? Obviously the consensus layer will also enforce the revocation policy before accepting I guess the question is what happens with existing policies signed by the revoked key? Could they become invalid retroactively? I think this would be bad. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking of allowing for revoking existing policies, but in retrospect that probably isn't the best of ideas. I am not entirely convinced that revocation is actually useful either. I would say "Surely people store their keys properly, and we use a large/disjoint enough committee size", but this industry is full of morons like those involved in the Ronin Bridge stupidity, so that's probably not realistic. |
||
client MUST pull down the revocation list). | ||
|
||
## Consequences | ||
|
||
### Positive | ||
|
||
It will be significantly easier to update key manager policies as the tabulation | ||
of signatures will be done on-chain. | ||
|
||
Revocation may be a more expedient emergency halt mechanism than the alternatives. | ||
|
||
### Negative | ||
|
||
This adds non-trivial amount of complexity for, what realitically is a process | ||
that a handful of people will ever need to do. | ||
|
||
### Neutral | ||
|
||
## References | ||
|
||
> Are there any relevant PR comments, issues that led up to this, or articles | ||
> referenced for why we made the given design choice? If so, link them here. | ||
|
||
- {reference link} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also the key must not be revoked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we do revocation, yeah. Like I said, I'm not convinced it's worth the complexity.