-
Notifications
You must be signed in to change notification settings - Fork 1.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
Adds impersonation as a first class citizen #6009
Conversation
klizhentas
commented
Mar 16, 2021
e86d27d
to
f7341c4
Compare
0d26a83
to
fb7d9dc
Compare
@r0mant @fspmarshall can you folks please review? I'm adding more tests, but largely done with the implementation |
9f3d37e
to
fed4970
Compare
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.
General thoughts:
- It should be possible to differentiate regular and impersonation certs in some manner (and possibly at least recover the root identity's name for audit log purposes).
- An impersonated identity probably should not be able to perform impersonation itself (i.e. impersonation should not be recursive).
- The lifetime of the impersonated cert should be limited by
min(root_cert_exp, now + impersonated_identity_session_ttl)
. If folks want impersonation that escapes the expiry of the root identity's cert, that should be opt-in behavior (and if we do allow an escape mechanism, then impersonation definitely can't be recursive, or else you could just "ping-pong" between identities and your certs would never go invalid).
Additionally, I think we should have a rough idea of how we want this to interact with the upcoming locking feature before this gets merged. IMO impersonated identities should be affected both by locks that affect the impersonated identity, and locks that affect the root identity. If we think there is a chance that we will permit locks based on roles (likely I think), then things get extra tricky. Consider this scenario:
kind: user
metadata:
name: alice
spec:
roles: ['patriot']
---
kind: role
metadata:
name: patriot
spec:
allow:
request:
roles: ['spy']
options:
lockable: true # hypothetical
---
kind: role
metadata:
name: spy
spec:
allow:
impersonate:
users: ['bob']
roles: ['enemy']
If alice
assumes role spy
via the access request system, she will now be able to impersonate bob
with role enemy
(assuming thats a valid user+role combination). Now say that a lock is applied which affects all users with role spy
. Since alice
's ability to act as bob
is dependent upon role spy
, she should probably lose the ability to act as bob
.
Since alice
holding role spy
isn't a static assignment, we can't just say "this lock applies to the root identity behind this cert". We need to be able to say "this lock applies to the exact identity used to issue this impersonation cert".
lib/services/role.go
Outdated
// newMatcherFn returns a matcher function based | ||
// on incoming values - if there is a wildcard matcher | ||
// present, it returns a wildcard matcher | ||
func newMatcherFn(in []string) func(in string) bool { | ||
var set map[string]struct{} | ||
for _, v := range in { | ||
// there is no need to build a set if there is a wildcard | ||
if v == Wildcard { | ||
return matchAny | ||
} | ||
if set == nil { | ||
set = make(map[string]struct{}, len(in)) | ||
} | ||
set[v] = struct{}{} | ||
} | ||
return func(in string) bool { _, ok := set[in]; return ok } | ||
} |
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.
Unless there is some specific reason to only support literal + full wildcard matches, its probably preferable to user parse.NewMatcher
, which will allow impersonate.roles
to maintain parity with request.roles
.
fed4970
to
d496435
Compare
if r.Spec.Deny.Impersonate.Where != "" { | ||
return trace.BadParameter("'where' is not supported in deny.impersonate conditions") | ||
} |
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.
Why not? Seems like that would be useful.
d496435
to
ec09beb
Compare
Good points. I will bake in the impersonator in the cert, will add to the audit event and prevent recursive impersonation.
Good point, I will restrict the TTL |
Re: locks If we create a lock per identity, it should apply to certs of the impersonator. In your example, if we lock Alice by identity, then Alice's certs, including impersonated certs will be locked out, because her identity will be baked in the cert as impersonator. If we create a lock per role, Alice's cert impersonating role that is not locked will not be locked as well, which I think is OK. |
c6c5bb1
to
426e6ca
Compare
@fspmarshall take another look, I have:
|
426e6ca
to
0fe9ef4
Compare
0fe9ef4
to
e500f9b
Compare
@fspmarshall applied your comments on renewal of impersonated users, made sure they are not escaping, but allowed them to renew their own certs |
dbdf4cc
to
c6d957b
Compare
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.
@klizhentas LGMT.
(linking #5441 here to remind me that these are gonna need some care when merging)
5085237
to
e53a97b
Compare
lib/tlsca/parsegen.go
Outdated
@@ -218,6 +218,21 @@ func ParsePublicKeyDER(der []byte) (crypto.PublicKey, error) { | |||
return generalKey, nil | |||
} | |||
|
|||
// MarshalPrivateKeyPEM marshals RSA private key to PEM. | |||
// Current implementation returns error for any other type of private key. | |||
func MarshalPrivateKeyPEM(key interface{}) ([]byte, error) { |
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 is implemented in utils.MarshalPrivateKey
.
req.Expires = a.authServer.GetClock().Now().Add(ttl) | ||
if err != nil { | ||
log.Warning(err) | ||
err := trace.AccessDenied("user %q has requested to generate certs for %q.", a.context.User.GetName(), roles) |
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.
How will admins using Cloud debug this?
I don't have a good answer to that question at the moment either, but @alex-kovoy has mentioned that he has to fetch process logs to help customers debug SAML connectors. I imagine a similar situation will happen here.
Fixes #5352 ```yaml allow: impersonate: users: ['alice', 'bob'] roles: ['*'] where: 'contains(user.spec.traits["groups"], impersonate_role.traits)' ``` Adds "impersonator" to all X.509 and SSH client certs issued using impersonation and does best effort to track requests by impersonators in audit events. Limits certs TTL to the impersonator's max session TTL. Prevents impersonating users to recursively impersonate other users. Allows impersonating users to renew their own certificate, for example to set route to cluster. Adds missing token permission for editor role.
e53a97b
to
cb6e697
Compare
Fixes #5352 ```yaml allow: impersonate: users: ['alice', 'bob'] roles: ['*'] where: 'contains(user.spec.traits["groups"], impersonate_role.traits)' ``` Adds "impersonator" to all X.509 and SSH client certs issued using impersonation and does best effort to track requests by impersonators in audit events. Limits certs TTL to the impersonator's max session TTL. Prevents impersonating users to recursively impersonate other users. Allows impersonating users to renew their own certificate, for example to set route to cluster. Adds missing token permission for editor role.
Fixes #5352 ```yaml allow: impersonate: users: ['alice', 'bob'] roles: ['*'] where: 'contains(user.spec.traits["groups"], impersonate_role.traits)' ``` Adds "impersonator" to all X.509 and SSH client certs issued using impersonation and does best effort to track requests by impersonators in audit events. Limits certs TTL to the impersonator's max session TTL. Prevents impersonating users to recursively impersonate other users. Allows impersonating users to renew their own certificate, for example to set route to cluster. Adds missing token permission for editor role.