Skip to content
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

Merged
merged 2 commits into from
Jun 8, 2017
Merged

Conversation

mitake
Copy link
Contributor

@mitake mitake commented Jun 5, 2017

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

@mitake mitake force-pushed the lease-revoke-auth branch 2 times, most recently from 3b743fe to 27e9afc Compare June 5, 2017 13:40
@@ -739,3 +740,36 @@ func authTestWatch(cx ctlCtx) {
}

}

func authTestLease(cx ctlCtx) {
Copy link
Contributor

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

Copy link
Contributor Author

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

@heyitsanthony
Copy link
Contributor

approach looks OK, test should be an integration test though

@yudai
Copy link
Contributor

yudai commented Jun 5, 2017

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?
You might want to add a similar check on Put(), like if the lease is already used by an entry where the user doesn't have write permission, make the Put() request fail.

@mitake
Copy link
Contributor Author

mitake commented Jun 6, 2017

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 Put() in the next update. Assuming that admins don't change the permission during the operation would be realistic.

@mitake
Copy link
Contributor Author

mitake commented Jun 6, 2017

@heyitsanthony updated and now the test is moved to integration. Also I added a new field Expire to LeaseRevokeRequest for distinguishing lease revoking triggered by time progress from explicit requests. In the case of time triggered revoking, permission checking isn't required.

@codecov-io
Copy link

codecov-io commented Jun 6, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@a36d62a). Click here to learn what that means.
The diff coverage is 50%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #8031   +/-   ##
=========================================
  Coverage          ?   76.25%           
=========================================
  Files             ?      341           
  Lines             ?    26502           
  Branches          ?        0           
=========================================
  Hits              ?    20210           
  Misses            ?     4820           
  Partials          ?     1472
Impacted Files Coverage Δ
etcdserver/server.go 80.13% <100%> (ø)
auth/simple_token.go 86.79% <100%> (ø)
etcdserver/apply.go 89.04% <100%> (ø)
auth/store.go 80.41% <14.28%> (ø)
etcdserver/apply_auth.go 75.2% <86.66%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a36d62a...7b68318. Read the comment docs.

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))
Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

@@ -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;
Copy link
Contributor

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?

Copy link
Contributor Author

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

@mitake
Copy link
Contributor Author

mitake commented Jun 7, 2017

@heyitsanthony updated based on your comments, PTAL.

@@ -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{}{})
Copy link
Contributor

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)

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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.

@mitake
Copy link
Contributor Author

mitake commented Jun 7, 2017

@heyitsanthony updated for internal token generation, PTAL.

@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/especified/specified

@heyitsanthony
Copy link
Contributor

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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants