-
Notifications
You must be signed in to change notification settings - Fork 9.8k
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
protecting lease revoking with auth #8031
Conversation
3b743fe
to
27e9afc
Compare
e2e/ctl_v3_auth_test.go
Outdated
@@ -739,3 +740,36 @@ func authTestWatch(cx ctlCtx) { | |||
} | |||
|
|||
} | |||
|
|||
func authTestLease(cx ctlCtx) { |
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.
this should probably be in integration/v3_auth_test.go
using raw grpc calls since it's testing etcdserver behavior, not etcdctl
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.
OK I'll move the test to integration
approach looks OK, test should be an |
If userB creates an entry at a key which userA doesn't have writer permission, but with a lease userA have created, userA cannot revoke the lease any longer? |
The check seems to be reasonable but it isn't perfect because the write permission can be revoked after attaching the lease and before revoking it. Anyway there wouldn't be a clean solution so I'll add the checking mechanism to |
@heyitsanthony updated and now the test is moved to |
Codecov Report
@@ Coverage Diff @@
## master #8031 +/- ##
=========================================
Coverage ? 76.25%
=========================================
Files ? 341
Lines ? 26502
Branches ? 0
=========================================
Hits ? 20210
Misses ? 4820
Partials ? 1472
Continue to review full report at Codecov.
|
etcdserver/apply_auth.go
Outdated
if !lc.Expire { | ||
// If lc.Expire == true, it means LeaseRevoke() is invoked by time progress, | ||
// no permission check is required. | ||
lease := aa.lessor.Lookup(lease.LeaseID(lc.ID)) |
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.
dedup this code into if err := aa.checkLeasePuts(leaseId); err != nil { return nil, err }
?
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.
ok
etcdserver/etcdserverpb/rpc.proto
Outdated
@@ -679,6 +679,9 @@ message LeaseGrantResponse { | |||
message LeaseRevokeRequest { | |||
// ID is the lease ID to revoke. When the ID is revoked, all associated keys will be deleted. | |||
int64 ID = 1; | |||
// expire is the flag for indicating that the revoke request is invoked by expire. | |||
// In such a case, permission checking can be skipped. | |||
bool expire = 2; |
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.
would it be cleaner to submit the expire request with root creds instead of having a flag in the rpc message?
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.
yes, in addition, having a flag in rpc struct is a bad idea because user can specify it even though the API layer can overwrite it...
@heyitsanthony updated based on your comments, PTAL. |
etcdserver/server.go
Outdated
@@ -747,7 +747,8 @@ func (s *EtcdServer) run() { | |||
} | |||
lid := lease.ID | |||
s.goAttach(func() { | |||
s.LeaseRevoke(s.ctx, &pb.LeaseRevokeRequest{ID: int64(lid)}) | |||
ctx := context.WithValue(s.ctx, "LeaseRevokeExpire", struct{}{}) |
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.
Checking for a context value each time in AuthInfoFromCtx just for lease expiration seems wasteful. How about something like:
ctx := s.authStore.WithRoot(s.ctx)
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.
You mean generating a dummy token and attach it to the context? I'm not sure it is effective than current approach because in a case of simple token, it needs to generate and install a token just for one lease revoking, and in a case of jwt token, it needs to sign on the temporal token. Of course adding the branch just for revoking is ugly so I don't have strong opinions about these two options. How do you think?
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.
generating a token should be OK; expiration will be a little more expensive but puts/gets/etc don't have to pay for the context value check. If generating the token is too expensive, it could be amortized by reusing the token/context across multiple lease revoke calls.
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.
ok, then I'll change it in the next update.
@heyitsanthony updated for internal token generation, PTAL. |
etcdserver/apply_auth.go
Outdated
@@ -63,6 +65,15 @@ func (aa *authApplierV3) Put(txn mvcc.TxnWrite, r *pb.PutRequest) (*pb.PutRespon | |||
if err := aa.as.IsPutPermitted(&aa.authInfo, r.Key); err != nil { | |||
return nil, err | |||
} | |||
|
|||
if err := aa.checkLeasePuts(lease.LeaseID(r.Lease)); err != nil { | |||
// The especified lease is already attached with a key that cannot |
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.
s/especified/specified
lgtm thanks |
Currently clients can revoke any lease without permission. This commit lets etcdserver protect revoking with write permission. This commit adds a mechanism for generating internal token. It is used for indicating that LeaseRevoke was issued internally so it should be able to delete any attached keys.
Current leases can be revoked by anyone. This PR limits the users who can revoke leases. If the user isn't granted write permission of keys which are attached the lease, the revoking request will be denied.
/cc @yudai