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

Auth: Add storage volume and bucket location to URL in access check #13517

Merged
merged 15 commits into from
Jul 29, 2024

Conversation

markylaing
Copy link
Contributor

This PR fixes fine grained authorization for storage volumes and storage buckets in clustered LXD.

When listing volumes, we can use the Location field of the storage volume or bucket to perform an access check.

When performing an action on a single storage volume, we need to perform the following checks:

  1. Is the pool containing the volume remote? If so, the target query parameter may have been used to target a particular cluster member, but should not be used in the URL for the volume (volumes in remote pools do not have a location).
  2. Is the volume located on another cluster member? If so, and the target parameter is set, use the target parameter as the location. If so, and the target parameter is unset, use the cluster member name as the location. If not, use the server name as the location.

To prevent extra queries from being performed when a request is forwarded to another node. Each node will assume that forwarded requests have already reached their intended destination. This is done by checking for request.CtxForwardedProtocol in the request context (I tried this originally by setting the target parameter but this broke storage volume migrations).

Closes #13365

@markylaing markylaing added the Bug Confirmed to be a bug label May 30, 2024
@markylaing markylaing self-assigned this May 30, 2024
@markylaing markylaing requested a review from tomponline as a code owner May 30, 2024 14:12
Copy link
Contributor Author

@markylaing markylaing left a comment

Choose a reason for hiding this comment

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

I've added a few comments on things I noticed while working on this that might be worth revisiting.

lxd/storage_volumes.go Outdated Show resolved Hide resolved
lxd/storage_volumes_backup.go Outdated Show resolved Hide resolved
lxd/storage_volumes_backup.go Outdated Show resolved Hide resolved
lxd/storage_buckets.go Outdated Show resolved Hide resolved
@tomponline tomponline changed the title Auth: Add storage volume and bucket location to URL in access check. Auth: Add storage volume and bucket location to URL in access check Jun 4, 2024
@markylaing markylaing force-pushed the bug-auth-storage-location branch from e72d043 to c253ded Compare June 5, 2024 08:51
@tomponline
Copy link
Member

Please can you rebase

@tomponline tomponline marked this pull request as draft June 11, 2024 08:51
@markylaing markylaing force-pushed the bug-auth-storage-location branch from c253ded to 9d5193f Compare June 13, 2024 08:22
@markylaing markylaing marked this pull request as ready for review June 13, 2024 08:22
@markylaing
Copy link
Contributor Author

@tomponline rebased and ready for review

@markylaing markylaing requested a review from roosterfish June 13, 2024 08:23
lxd/storage_volumes.go Outdated Show resolved Hide resolved
lxd/storage_buckets.go Outdated Show resolved Hide resolved
@tomponline
Copy link
Member

When performing an action on a single storage volume, we need to perform the following checks:

1. Is the pool containing the volume remote? If so, the `target` query parameter may have been used to target a particular cluster member, but should not be used in the URL for the volume (volumes in remote pools do not have a location).

2. Is the volume located on another cluster member? If so, and the target parameter is set, use the target parameter as the location. If so, and the target parameter is unset, use the cluster member name as the location. If not, use the server name as the location.

Before reviewing further I just wanted to check and understand this statement, as it seems over complicated to me for an access check of a volume (which in my understanding ultimately boils down to loading the volume record to get its ID before doing an access check on that resource).

Or is this just the existing logic that is used to load a specific volume already?

@markylaing
Copy link
Contributor Author

When performing an action on a single storage volume, we need to perform the following checks:

1. Is the pool containing the volume remote? If so, the `target` query parameter may have been used to target a particular cluster member, but should not be used in the URL for the volume (volumes in remote pools do not have a location).

2. Is the volume located on another cluster member? If so, and the target parameter is set, use the target parameter as the location. If so, and the target parameter is unset, use the cluster member name as the location. If not, use the server name as the location.

Before reviewing further I just wanted to check and understand this statement, as it seems over complicated to me for an access check of a volume (which in my understanding ultimately boils down to loading the volume record to get its ID before doing an access check on that resource).

Or is this just the existing logic that is used to load a specific volume already?

This is the logic that is used to figure out where to forward the request. Coming back to this I think it can probably be simplified by writing a custom query and bypassing all this complication.

The main issue is that there can be multiple volumes with the same name, just located on different members.

@markylaing
Copy link
Contributor Author

markylaing commented Jul 4, 2024

@tomponline summarising here my remarks about this PR in the core daily stand up:

As far as fine-grained auth is concerned, we can call CheckPermission on a URL if that URL represents a single unique resource. We are using cluster.GetEntityReferenceFromURL to do this in the OpenFGA storage driver.

For storage buckets and volumes, this represents a challenge because bucket/volumes can have the same name if they are in a local pool and located on different cluster members. Additionally, a target query parameter can be provided if the caller wants to make the request to a specific member, regardless of the actual location of the bucket/volume.

There are a few cases to consider:

  1. Volume in remote pool, target parameter provided.
  2. Volume in remote pool, target parameter not provided.
  3. Volume in local pool, target parameter provided.
  4. Volume in local pool, target parameter not provided.

To catch all these cases, we need to*:

  1. Load the storage pool and check if it is remote or not.
  2. If it is remote:
    i. Omit the target parameter from the URL used in the access check.
  3. If it is local:
    i. If the target parameter was provided, use it in the URL for the access check.
    ii. Otherwise, find the node that the volume is located on and use that member name in the access check.

*For all of these cases, we additionally need to check for the effective project of the bucket/volume and substitute the project parameter if it differs from that of the request.

In figuring out all of these steps, we've already done a lot of the work that would normally be done in the handler for forwarding requests to appropriate nodes. This PR adds the effective project, the storage pool, and forwarding node info (name & address) to the request context so that the handlers don't need to perform these queries again. Additionally, if the request has already been forwarded, the query for forwarding node info is skipped (we assume the other node has already correctly handled this).

I think this PR is the way forward because it overall reduces the number of queries (by skipping the remote volume check when it's a forwarded request) but does not change the queries themselves. (We can optimise these later if it becomes necessary).

@markylaing markylaing force-pushed the bug-auth-storage-location branch from 9d5193f to 878605c Compare July 4, 2024 14:53
@markylaing
Copy link
Contributor Author

@tomponline have updated this to address your comments. Ready for review when you have some time. Thanks.

@markylaing markylaing force-pushed the bug-auth-storage-location branch from 878605c to b000906 Compare July 4, 2024 15:23
@tomponline
Copy link
Member

Please can you rebase this

@markylaing markylaing force-pushed the bug-auth-storage-location branch from b000906 to bc55e27 Compare July 9, 2024 09:27
@markylaing
Copy link
Contributor Author

Please can you rebase this

Yep done.

lxd/storage_volumes.go Outdated Show resolved Hide resolved
lxd/storage_volumes.go Outdated Show resolved Hide resolved
lxd/storage_volumes.go Outdated Show resolved Hide resolved
lxd/storage_volumes.go Outdated Show resolved Hide resolved
@markylaing markylaing force-pushed the bug-auth-storage-location branch from bc55e27 to 319d6b7 Compare July 25, 2024 16:25
Contents are copied and slightly modified from
`cluster.ConnectIfVolumeIsRemote`.

Signed-off-by: Mark Laing <[email protected]>
@markylaing markylaing force-pushed the bug-auth-storage-location branch from 319d6b7 to 992c1b7 Compare July 25, 2024 17:25
@markylaing markylaing requested a review from tomponline July 25, 2024 17:30
lxd/storage_volumes.go Outdated Show resolved Hide resolved
lxd/storage_volumes.go Outdated Show resolved Hide resolved
@markylaing markylaing force-pushed the bug-auth-storage-location branch from 992c1b7 to 51292f0 Compare July 26, 2024 12:32
This function will now only forward the request to another member if a
db.NodeInfo is found in the request context under
`ctxStorageVolumeRemoteNodeInfo`.

Signed-off-by: Mark Laing <[email protected]>
This is no longer used.

Signed-off-by: Mark Laing <[email protected]>
@markylaing markylaing force-pushed the bug-auth-storage-location branch from 51292f0 to f0ac51f Compare July 26, 2024 12:35
@markylaing markylaing requested a review from tomponline July 29, 2024 08:00
Copy link
Member

@tomponline tomponline left a comment

Choose a reason for hiding this comment

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

Thanks! This pattern of extracting fields common to several API endpoints and loading the DB resource and storing them into the context seems like a good way of avoiding additional DB queries when performing access checks as well as removing code duplication in the API endpoint handlers themselves.

@tomponline tomponline merged commit 8964692 into canonical:main Jul 29, 2024
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Confirmed to be a bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Auth: Use correct location of storage volume/bucket when performing access check
3 participants