-
Notifications
You must be signed in to change notification settings - Fork 388
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
✨ PoC: Implement user warrants #3156
base: main
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
4b188ca
to
2ca96c3
Compare
logger.V(4).Info("authorization step", | ||
"reason", reason, |
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.
Should this not be auditReasonMsg
? We add this into annotations but remove from logs? Intentional?
|
||
// withWarrantsInChainCallingDelegateWithOriginalUser could be named shorter, but then it would | ||
// look innocent which it isn't. It produces one level of the chain with the wrapper called | ||
// for the base and all warrents. The delegate though is called only once with the original user. |
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/warrents/warrants
Groups: []string{bootstrap.SystemKcpAdminGroup}, | ||
// Add a warrant of a fake local service account giving full access | ||
warrant := validation.Warrant{ | ||
User: "system:serviceaccount:default:rest", |
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.
Just of interest, what is somebody creates an account like this?
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.
totally possible. Same as today: you can create any kind of client cert faking a service account or oidc user or whatever you like. In other words, control over an authn provider is always critical.
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.
But don't think you can impersonate this in any way.
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.
Impersonation is a good point. Please double check that this is properly e2e tested. Escalating permissions due to impersonation in a workspace must not be possible.
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.
deal. will try to spin some tests scenarios for this manually too.
In general just a questions. looks good, |
@@ -44,7 +44,7 @@ const ( | |||
|
|||
// NewMaximalPermissionPolicyAuthorizer returns an authorizer that first checks if the request is for a | |||
// bound resource or not. If the resource is bound it checks the maximal permission policy of the underlying API export. | |||
func NewMaximalPermissionPolicyAuthorizer(kubeInformers, globalKubeInformers kcpkubernetesinformers.SharedInformerFactory, kcpInformers, globalKcpInformers kcpinformers.SharedInformerFactory, delegate authorizer.Authorizer) authorizer.Authorizer { | |||
func NewMaximalPermissionPolicyAuthorizer(kubeInformers, globalKubeInformers kcpkubernetesinformers.SharedInformerFactory, kcpInformers, globalKcpInformers kcpinformers.SharedInformerFactory) func(delegate authorizer.Authorizer) authorizer.Authorizer { |
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.
Just mental note:
func NewMaximalPermissionPolicyAuthorizer(
kubeInformers, globalKubeInformers kcpkubernetesinformers.SharedInformerFactory,
kcpInformers, globalKcpInformers kcpinformers.SharedInformerFactory,
) func(delegate authorizer.Authorizer) authorizer.Authorizer {
easier to read. Took me a second to absorb the signature.
impersonatedClient, err := kcpkubernetesclientset.NewForConfig(impersonationConfig) | ||
require.NoError(t, err) | ||
|
||
t.Log("As user-2 with system:masters, we should be able to read secrets") |
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.
As user-1 with impersonation of user-2 with system:masters, we should be able to read secrets
?
|
||
t.Logf("Check SelfSubjectReview as user-2 with system:masters") | ||
req := &authenticationv1.SelfSubjectReview{} | ||
resp, err := impersonatedClient.Cluster(wsPath).AuthenticationV1().SelfSubjectReviews().Create(ctx, req, metav1.CreateOptions{}) |
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 impersonation not return system:masters group? Why its not expecting it?
@@ -44,25 +44,27 @@ const ( | |||
WorkspaceAccessNotPermittedReason = "workspace access not permitted" | |||
) | |||
|
|||
func NewWorkspaceContentAuthorizer(localInformers, globalInformers kcpkubernetesinformers.SharedInformerFactory, localLogicalClusterLister, globalLogicalClusterLister corev1alpha1listers.LogicalClusterClusterLister, delegate authorizer.Authorizer) authorizer.Authorizer { |
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.
Im starting to wonder if we should duplicate this code (2 content authorizer implementations) and make all this warrant code feature-flag gated? But might be a lot of if-else statements, not sure if this worth the effort.
My inner me - says - lets just go.
But OSS me - says - better safe than sorry.
|
||
// protect status updates to apiexport and apibinding | ||
systemCRDAuth := authz.NewSystemCRDAuthorizer(maxPermissionPolicyAuth) | ||
systemCRDAuth = authz.NewDecorator("03-systemcrd", systemCRDAuth).AddAuditLogging().AddAnonymization().AddReasonAnnotation() | ||
chain = withWarrantsInChainCallingDelegateWithOriginalUser(authz.NewSystemCRDAuthorizer, chain) |
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.
@mjudeikis to feature gate it, we could have a noop withWarrantsInChainCallingDelegateWithOriginalUser
.
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
…for the target workspace Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
59654d8
to
8ad6d50
Compare
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
Signed-off-by: Dr. Stefan Schimanski <[email protected]>
8ad6d50
to
cca5a21
Compare
@sttts: The following tests failed, say
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Summary
Needs kcp-dev/kubernetes#145.
From Slack:
🧵 long ago @sur presented a problem (if I remember right) in our current auth model of serviceaccounts only being valid locally, and with that the inability to create workspaces through an APIExport virtual workspace. The steps are these:
system:masters
user with a fakesystem:kcp:admin
serviceaccount (S1) for L1 namedsystem:serviceaccount:default:rest
.Now assume a modified system that
The steps from above would turn into:
system:masters
user as U with a warrant for a fakesystem:kcp:admin
serviceaccount (S1) for L1 namedsystem:serviceaccount:default:rest
.By giving use permission to everybody, tThis goes through.denies access because S1 is a foreign service accountgrants access because U with warrant S1 is admin in L2.Now assume in addition that U is actually a controller serviceaccount S0 in workspace root. Step (7) would 💥 because S0 is foreign for L2. We further modify the system to authenticate serviceaccount as
system:kcp:serviceaccount:<logicalcluster>:<ns>:<name>
with a warrant forsystem:serviceaccount:<ns>:<name>
restricted to their defining logicalcluster.Now, U becomes
system:kcp:serviceaccount:root:default:controller
with warrantsystem:serviceaccount:default:controller
restricted to root. With that (4) becomessystem:kcp:serviceaccount:root:default:controller
with warrantsystem:serviceaccount:default:controller
restricted to root with warrant S1 as owner on the workspace object, to be used by initialization later.I.e. the user has two warrants. With that (7) becomes:
system:kcp:serviceaccount:root:default:controller
with the TWO warrants including S1 is admin in L2.Related issue(s)
Fixes #
Release Notes