Skip to content

Commit fa4903c

Browse files
authored
Merge pull request #8031 from mitake/lease-revoke-auth
protecting lease revoking with auth
2 parents 3df9352 + 7b68318 commit fa4903c

File tree

6 files changed

+230
-9
lines changed

6 files changed

+230
-9
lines changed

auth/simple_token.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,15 @@ func (t *tokenSimple) genTokenPrefix() (string, error) {
118118

119119
func (t *tokenSimple) assignSimpleTokenToUser(username, token string) {
120120
t.simpleTokensMu.Lock()
121+
defer t.simpleTokensMu.Unlock()
122+
121123
_, ok := t.simpleTokens[token]
122124
if ok {
123125
plog.Panicf("token %s is alredy used", token)
124126
}
125127

126128
t.simpleTokens[token] = username
127129
t.simpleTokenKeeper.addSimpleToken(token)
128-
t.simpleTokensMu.Unlock()
129130
}
130131

131132
func (t *tokenSimple) invalidateUser(username string) {

auth/store.go

+35
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ type AuthStore interface {
162162

163163
// AuthInfoFromTLS gets AuthInfo from TLS info of gRPC's context
164164
AuthInfoFromTLS(ctx context.Context) *AuthInfo
165+
166+
// WithRoot generates and installs a token that can be used as a root credential
167+
WithRoot(ctx context.Context) context.Context
165168
}
166169

167170
type TokenProvider interface {
@@ -1057,3 +1060,35 @@ func NewTokenProvider(tokenOpts string, indexWaiter func(uint64) <-chan struct{}
10571060
return nil, ErrInvalidAuthOpts
10581061
}
10591062
}
1063+
1064+
func (as *authStore) WithRoot(ctx context.Context) context.Context {
1065+
if !as.isAuthEnabled() {
1066+
return ctx
1067+
}
1068+
1069+
var ctxForAssign context.Context
1070+
if ts := as.tokenProvider.(*tokenSimple); ts != nil {
1071+
ctx1 := context.WithValue(ctx, "index", uint64(0))
1072+
prefix, err := ts.genTokenPrefix()
1073+
if err != nil {
1074+
plog.Errorf("failed to generate prefix of internally used token")
1075+
return ctx
1076+
}
1077+
ctxForAssign = context.WithValue(ctx1, "simpleToken", prefix)
1078+
} else {
1079+
ctxForAssign = ctx
1080+
}
1081+
1082+
token, err := as.tokenProvider.assign(ctxForAssign, "root", as.Revision())
1083+
if err != nil {
1084+
// this must not happen
1085+
plog.Errorf("failed to assign token for lease revoking: %s", err)
1086+
return ctx
1087+
}
1088+
1089+
mdMap := map[string]string{
1090+
"token": token,
1091+
}
1092+
tokenMD := metadata.New(mdMap)
1093+
return metadata.NewContext(ctx, tokenMD)
1094+
}

etcdserver/apply.go

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func (s *EtcdServer) newApplierV3() applierV3 {
8484
return newAuthApplierV3(
8585
s.AuthStore(),
8686
newQuotaApplierV3(s, &applierV3backend{s}),
87+
s.lessor,
8788
)
8889
}
8990

etcdserver/apply_auth.go

+34-3
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import (
1919

2020
"github.com/coreos/etcd/auth"
2121
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
22+
"github.com/coreos/etcd/lease"
2223
"github.com/coreos/etcd/mvcc"
2324
)
2425

2526
type authApplierV3 struct {
2627
applierV3
27-
as auth.AuthStore
28+
as auth.AuthStore
29+
lessor lease.Lessor
2830

2931
// mu serializes Apply so that user isn't corrupted and so that
3032
// serialized requests don't leak data from TOCTOU errors
@@ -33,8 +35,8 @@ type authApplierV3 struct {
3335
authInfo auth.AuthInfo
3436
}
3537

36-
func newAuthApplierV3(as auth.AuthStore, base applierV3) *authApplierV3 {
37-
return &authApplierV3{applierV3: base, as: as}
38+
func newAuthApplierV3(as auth.AuthStore, base applierV3, lessor lease.Lessor) *authApplierV3 {
39+
return &authApplierV3{applierV3: base, as: as, lessor: lessor}
3840
}
3941

4042
func (aa *authApplierV3) Apply(r *pb.InternalRaftRequest) *applyResult {
@@ -63,6 +65,15 @@ func (aa *authApplierV3) Put(txn mvcc.TxnWrite, r *pb.PutRequest) (*pb.PutRespon
6365
if err := aa.as.IsPutPermitted(&aa.authInfo, r.Key); err != nil {
6466
return nil, err
6567
}
68+
69+
if err := aa.checkLeasePuts(lease.LeaseID(r.Lease)); err != nil {
70+
// The specified lease is already attached with a key that cannot
71+
// be written by this user. It means the user cannot revoke the
72+
// lease so attaching the lease to the newly written key should
73+
// be forbidden.
74+
return nil, err
75+
}
76+
6677
if r.PrevKv {
6778
err := aa.as.IsRangePermitted(&aa.authInfo, r.Key, nil)
6879
if err != nil {
@@ -158,6 +169,26 @@ func (aa *authApplierV3) Txn(rt *pb.TxnRequest) (*pb.TxnResponse, error) {
158169
return aa.applierV3.Txn(rt)
159170
}
160171

172+
func (aa *authApplierV3) LeaseRevoke(lc *pb.LeaseRevokeRequest) (*pb.LeaseRevokeResponse, error) {
173+
if err := aa.checkLeasePuts(lease.LeaseID(lc.ID)); err != nil {
174+
return nil, err
175+
}
176+
return aa.applierV3.LeaseRevoke(lc)
177+
}
178+
179+
func (aa *authApplierV3) checkLeasePuts(leaseID lease.LeaseID) error {
180+
lease := aa.lessor.Lookup(leaseID)
181+
if lease != nil {
182+
for _, key := range lease.Keys() {
183+
if err := aa.as.IsPutPermitted(&aa.authInfo, []byte(key)); err != nil {
184+
return err
185+
}
186+
}
187+
}
188+
189+
return nil
190+
}
191+
161192
func needAdminPermission(r *pb.InternalRaftRequest) bool {
162193
switch {
163194
case r.AuthEnable != nil:

etcdserver/server.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -747,7 +747,8 @@ func (s *EtcdServer) run() {
747747
}
748748
lid := lease.ID
749749
s.goAttach(func() {
750-
s.LeaseRevoke(s.ctx, &pb.LeaseRevokeRequest{ID: int64(lid)})
750+
ctx := s.authStore.WithRoot(s.ctx)
751+
s.LeaseRevoke(ctx, &pb.LeaseRevokeRequest{ID: int64(lid)})
751752
<-c
752753
})
753754
}

integration/v3_auth_test.go

+156-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"golang.org/x/net/context"
2222

23+
"github.com/coreos/etcd/auth/authpb"
2324
"github.com/coreos/etcd/clientv3"
2425
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
2526
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
@@ -104,16 +105,167 @@ func TestV3AuthRevision(t *testing.T) {
104105
}
105106
}
106107

107-
func authSetupRoot(t *testing.T, auth pb.AuthClient) {
108-
if _, err := auth.UserAdd(context.TODO(), &pb.AuthUserAddRequest{Name: "root", Password: "123"}); err != nil {
108+
type user struct {
109+
name string
110+
password string
111+
role string
112+
key string
113+
end string
114+
}
115+
116+
func TestV3AuthWithLeaseRevoke(t *testing.T) {
117+
defer testutil.AfterTest(t)
118+
clus := NewClusterV3(t, &ClusterConfig{Size: 1})
119+
defer clus.Terminate(t)
120+
121+
users := []user{
122+
{
123+
name: "user1",
124+
password: "user1-123",
125+
role: "role1",
126+
key: "k1",
127+
end: "k2",
128+
},
129+
}
130+
authSetupUsers(t, toGRPC(clus.Client(0)).Auth, users)
131+
132+
authSetupRoot(t, toGRPC(clus.Client(0)).Auth)
133+
134+
rootc, cerr := clientv3.New(clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "root", Password: "123"})
135+
if cerr != nil {
136+
t.Fatal(cerr)
137+
}
138+
defer rootc.Close()
139+
140+
leaseResp, err := rootc.Grant(context.TODO(), 90)
141+
if err != nil {
109142
t.Fatal(err)
110143
}
111-
if _, err := auth.RoleAdd(context.TODO(), &pb.AuthRoleAddRequest{Name: "root"}); err != nil {
144+
leaseID := leaseResp.ID
145+
// permission of k3 isn't granted to user1
146+
_, err = rootc.Put(context.TODO(), "k3", "val", clientv3.WithLease(leaseID))
147+
if err != nil {
112148
t.Fatal(err)
113149
}
114-
if _, err := auth.UserGrantRole(context.TODO(), &pb.AuthUserGrantRoleRequest{User: "root", Role: "root"}); err != nil {
150+
151+
userc, cerr := clientv3.New(clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user1", Password: "user1-123"})
152+
if cerr != nil {
153+
t.Fatal(cerr)
154+
}
155+
defer userc.Close()
156+
_, err = userc.Revoke(context.TODO(), leaseID)
157+
if err == nil {
158+
t.Fatal("revoking from user1 should be failed with permission denied")
159+
}
160+
}
161+
162+
func TestV3AuthWithLeaseAttach(t *testing.T) {
163+
defer testutil.AfterTest(t)
164+
clus := NewClusterV3(t, &ClusterConfig{Size: 1})
165+
defer clus.Terminate(t)
166+
167+
users := []user{
168+
{
169+
name: "user1",
170+
password: "user1-123",
171+
role: "role1",
172+
key: "k1",
173+
end: "k3",
174+
},
175+
{
176+
name: "user2",
177+
password: "user2-123",
178+
role: "role2",
179+
key: "k2",
180+
end: "k4",
181+
},
182+
}
183+
authSetupUsers(t, toGRPC(clus.Client(0)).Auth, users)
184+
185+
authSetupRoot(t, toGRPC(clus.Client(0)).Auth)
186+
187+
user1c, cerr := clientv3.New(clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user1", Password: "user1-123"})
188+
if cerr != nil {
189+
t.Fatal(cerr)
190+
}
191+
defer user1c.Close()
192+
193+
user2c, cerr := clientv3.New(clientv3.Config{Endpoints: clus.Client(0).Endpoints(), Username: "user2", Password: "user2-123"})
194+
if cerr != nil {
195+
t.Fatal(cerr)
196+
}
197+
defer user2c.Close()
198+
199+
leaseResp, err := user1c.Grant(context.TODO(), 90)
200+
if err != nil {
201+
t.Fatal(err)
202+
}
203+
leaseID := leaseResp.ID
204+
// permission of k2 is also granted to user2
205+
_, err = user1c.Put(context.TODO(), "k2", "val", clientv3.WithLease(leaseID))
206+
if err != nil {
207+
t.Fatal(err)
208+
}
209+
210+
_, err = user2c.Revoke(context.TODO(), leaseID)
211+
if err != nil {
212+
t.Fatal(err)
213+
}
214+
215+
leaseResp, err = user1c.Grant(context.TODO(), 90)
216+
if err != nil {
217+
t.Fatal(err)
218+
}
219+
leaseID = leaseResp.ID
220+
// permission of k1 isn't granted to user2
221+
_, err = user1c.Put(context.TODO(), "k1", "val", clientv3.WithLease(leaseID))
222+
if err != nil {
115223
t.Fatal(err)
116224
}
225+
226+
_, err = user2c.Revoke(context.TODO(), leaseID)
227+
if err == nil {
228+
t.Fatal("revoking from user2 should be failed with permission denied")
229+
}
230+
}
231+
232+
func authSetupUsers(t *testing.T, auth pb.AuthClient, users []user) {
233+
for _, user := range users {
234+
if _, err := auth.UserAdd(context.TODO(), &pb.AuthUserAddRequest{Name: user.name, Password: user.password}); err != nil {
235+
t.Fatal(err)
236+
}
237+
if _, err := auth.RoleAdd(context.TODO(), &pb.AuthRoleAddRequest{Name: user.role}); err != nil {
238+
t.Fatal(err)
239+
}
240+
if _, err := auth.UserGrantRole(context.TODO(), &pb.AuthUserGrantRoleRequest{User: user.name, Role: user.role}); err != nil {
241+
t.Fatal(err)
242+
}
243+
244+
if len(user.key) == 0 {
245+
continue
246+
}
247+
248+
perm := &authpb.Permission{
249+
PermType: authpb.READWRITE,
250+
Key: []byte(user.key),
251+
RangeEnd: []byte(user.end),
252+
}
253+
if _, err := auth.RoleGrantPermission(context.TODO(), &pb.AuthRoleGrantPermissionRequest{Name: user.role, Perm: perm}); err != nil {
254+
t.Fatal(err)
255+
}
256+
}
257+
}
258+
259+
func authSetupRoot(t *testing.T, auth pb.AuthClient) {
260+
root := []user{
261+
{
262+
name: "root",
263+
password: "123",
264+
role: "root",
265+
key: "",
266+
},
267+
}
268+
authSetupUsers(t, auth, root)
117269
if _, err := auth.AuthEnable(context.TODO(), &pb.AuthEnableRequest{}); err != nil {
118270
t.Fatal(err)
119271
}

0 commit comments

Comments
 (0)