canonical / lxd

Powerful system container and virtual machine manager
https://canonical.com/lxd
GNU Affero General Public License v3.0
4.33k stars 929 forks source link

Fix image not being transfered from the host when security.devlxd.images is enabled #13678

Closed MusicDin closed 2 months ago

MusicDin commented 3 months ago

This is just a demo showcasing the issue with security.devlxd.images which is blocked due to the missing request context fields (trusted, protocol, username) and to open discussion regarding image access over devlxd socket.


Enabling security.devlxd.images allows LXD server running within a container to fetch the already cached image from the host (if the image with a given fingerprint exists on the host).

If request fails, for example because the image is not found, the LXD on container will proceed to download an image from the actual server.

However, the requests are blocked because fields in request context are not populated. This PR simply sets trusted=true and protocol=unix. The username field can be anything just not empty, to prevent failure when parsing request details (function requestDetails()).

The request will pass if protocol is unix, as communication over unix is considered trusted with admin privilege. This brings us to another question, whether devlxd is allowed to access all images from all projects in the first place (as discussed on the meeting).

cc @tomponline @markylaing

MusicDin commented 3 months ago

Nice observation. Yes, I've tested this and when the instance is in non-default project, it always requests images from default project.

markylaing commented 3 months ago

Some initial thoughts on this:

I think a good approach to this would be to add the following to the hoist function:

  1. Always set the request address to @devlxd.
  2. Always set request.CtxTrusted to true in the request context.
  3. Always set request.CtxProtocol to a new authentication method "devlxd" in the request context.
  4. Always set request.CtxUsername to the URL of the instance (e.g. /1.0/instances/c1?project=default).
  5. Before the handler is called, add an entry to the identity cache for the container. This can be restricted or can only allow access in a specific project.
  6. After the handler is called, remove the entry from the identity cache.
tomponline commented 3 months ago

Some initial thoughts on this:

* The request address is set to `@devlxd` for "security checks". In reality this just enforces that the request uses the exact fingerprint.

* All requests to the devlxd API are going through a hoist function to find the instance name.

* The authorizer doesn't know what project the instance is in or what project it has access to.

I think a good approach to this would be to add the following to the hoist function:

1. Always set the request address to `@devlxd`.

2. Always set `request.CtxTrusted` to `true` in the request context.

3. Always set `request.CtxProtocol` to a new authentication method `"devlxd"` in the request context.

4. Always set `request.CtxUsername` to the URL of the instance (e.g. `/1.0/instances/c1?project=default`).

5. Before the handler is called, add an entry to the identity cache for the container. This can be restricted or can only allow access in a specific project.

6. After the handler is called, remove the entry from the identity cache.

Before we go down that route, do we understand why this request needs to go through the authoriser at all?

Assuming we fix the issue that is allowing instances to access images outside of their effective project, is there any reason why the authorizer needs to get involved here?

Because

Before the handler is called, add an entry to the identity cache for the container. This can be restricted or can only allow access in a specific project.

That sounds like a bit of a kludge to me - the identity cache isn't for instances.