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
Allow non admin users to manage BSL #6589
Allow non admin users to manage BSL #6589
Conversation
|
||
_, err := userInfoGetter(ctx, req.ProjectID) | ||
|
||
if 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.
I think this essentially only queries the user roles and so on, but since you are not using them to check for anything (like in CreateCSBL), I believe it can be removed
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.
same for the GetCSBL
func
if user.Roles.Has("viewers") { | ||
return fmt.Errorf("user with a viewer role is not permitted to delete storage locations.") | ||
} |
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.
my understanding from other code is that it is possible for a user to have both "viewer" as well as another role. As a result we also need to check if viewers is the only role the user has.
For example like this is done here
if userInfo.Roles.Has("viewers") && userInfo.Roles.Len() == 1 { |
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.
Same for Create and Patch as well
6d591f8
to
b7ead75
Compare
/retest |
dc913a9
to
0cc2373
Compare
I changed the approach to using an Impersonated Client, so there is no need to check the role in the API. |
@SimonTheLeg sorry but this PR is blocked by kubermatic/kubermatic#13174 |
55fed9e
to
c340ace
Compare
c340ace
to
543798f
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.
Overall I think this should all work and is in spec what we are doing in other parts of the API. I have some questions regarding the usage of the privileged client in some places. ptal.
But overall I think we are on the right track.
client := p.privilegedClient | ||
|
||
if err := client.List(ctx, cbslList, listOpts); err != nil { |
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.
nit: just to keep this uniform with other code. Let's go back to the previous p.privilegedClient.List notation from before
cbslList, err := p.List(ctx, userInfo, labelSet) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to list ClusterBackupStorageLocations: %w", err) | ||
return nil, err | ||
} | ||
for _, cbsl := range cbslList.Items { | ||
if cbsl.Name == name { | ||
return &cbsl, nil |
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.
I know this is not part of this PR, but I would appreciate if we could create a ticket to investigate this. Judging from just the code I think it should be fine to create the impersonated client and run a client.Get.
See
dashboard/modules/api/pkg/provider/kubernetes/project.go
Lines 128 to 135 in 03648c6
masterImpersonatedClient, err := createImpersonationClientWrapperFromUserInfo(userInfo, p.createMasterImpersonatedClient) | |
if err != nil { | |
return nil, err | |
} | |
existingProject := &kubermaticv1.Project{} | |
if err := masterImpersonatedClient.Get(ctx, ctrlruntimeclient.ObjectKey{Name: projectInternalName}, existingProject); 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.
The reason we didn't do a direct Get() here is not because of the client. The problem here is that the CBSL is a project-scoped resources. We assign it to the project using a label. We need the API to only list CBSL's that belong to the correct project. So, we use List() with a label selector and loop over the results. Unfortunately the Get() API doesn't support label selectors.
if userInfo == nil { | ||
return nil, errors.New("a user is missing but required") | ||
} |
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.
I think since you are checking for userInfo to not be nil always before calling this func, this can be removed.
@@ -110,57 +141,78 @@ func (p *BackupStorageProvider) CreateUnsecured(ctx context.Context, cbslName, p | |||
}, | |||
Key: "cloud-credentials", |
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.
I would recommend to move this into a global const, since we are using this in multiple places in this provider
} | ||
} | ||
|
||
func (p *BackupStorageProvider) ListUnsecured(ctx context.Context, labelSet map[string]string) (*kubermaticv1.ClusterBackupStorageLocationList, error) { | ||
func (p *BackupStorageProvider) List(ctx context.Context, userInfo *provider.UserInfo, labelSet map[string]string) (*kubermaticv1.ClusterBackupStorageLocationList, 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.
In my opinion this should still be called ListUnsecured, because it uses the priviledged client to access the info
func (p *BackupStorageProvider) GetUnsecured(ctx context.Context, name string, labelSet map[string]string) (*kubermaticv1.ClusterBackupStorageLocation, error) { | ||
// we use List() to filter CBSLs with labels easily, to keep scoped into the owner project. | ||
cbslList, err := p.ListUnsecured(ctx, labelSet) | ||
func (p *BackupStorageProvider) Get(ctx context.Context, userInfo *provider.UserInfo, name string, labelSet map[string]string) (*kubermaticv1.ClusterBackupStorageLocation, 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.
In my opinion this should still be called GetUnsecured, because it calls the List which in turn uses the priviledged client.
cbsl := &kubermaticv1.ClusterBackupStorageLocation{} | ||
if err := p.privilegedClient.Get(ctx, types.NamespacedName{Name: name, Namespace: resources.KubermaticNamespace}, cbsl); err != nil { | ||
if err := client.Get(ctx, types.NamespacedName{Name: name, Namespace: resources.KubermaticNamespace}, cbsl); err != nil { | ||
if apierrors.IsNotFound(err) { | ||
return nil | ||
} | ||
return 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.
Is there a reason why the priviledged client is needed for getting the ClusterBackupStorageLocation? Couldn't the impersonated client be used for 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.
refactored to use the same client for both operations based on the user role.
existing := &kubermaticv1.ClusterBackupStorageLocation{} | ||
if err := p.privilegedClient.Get(ctx, types.NamespacedName{Name: cbslName, Namespace: resources.KubermaticNamespace}, existing); err != nil { | ||
if err := client.Get(ctx, types.NamespacedName{Name: cbslName, Namespace: resources.KubermaticNamespace}, existing); 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.
same here. Is the priviledged client required, or could we just use the impersonated client for getting it?
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.
done
/approve |
LGTM label has been added. Git tree hash: 30e151f61a5867a76a0f97eaf83a81a7a6a78952
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: SimonTheLeg The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What this PR does / why we need it:
Allow non admin users to manage backup storage location.
Which issue(s) this PR fixes:
Fixes #6563
What type of PR is this?
/kind bug