<a id="projects-confine"></a>

# How to confine users to specific projects

You restrict users or clients to specific projects.
Projects can be configured with features, limits, and restrictions to prevent misuse.
See [Instances grouping with projects](https://canonical.com/lxd/docs/default/explanation/projects/index.html.md#exp-projects) for more information.

How to confine users to specific projects depends on whether LXD is accessible via the [HTTPS API](#projects-confine-https), or via the [Unix socket](#projects-confine-users).

<a id="projects-confine-https"></a>

## Confine users to specific projects on the HTTPS API

You can confine access to specific projects by restricting the TLS client certificate that is used to connect to the LXD server.
See [Restricted TLS certificates](https://canonical.com/lxd/docs/default/explanation/authorization/index.html.md#restricted-tls-certs) for more information.
Only certificates returned by `lxc config trust list` can be managed in this way.


            <p class="youtube_link">
              <a href="https://www.youtube.com/watch?v=4iNpiL-lrXU&t=525s" target="_blank">
                <span title="LXD token based remote authentication" class="play_icon">▶</span>
                <span title="LXD token based remote authentication">Watch on YouTube</span>
              </a>
            </p>
        
#### NOTE
The UI does not currently support configuring project confinement for certificates of this type.
Use the CLI or API to set up confinement.

To confine the access from the time the client certificate is added, you must either use token authentication or add the client certificate to the server directly.
If you use password authentication, you can restrict the client certificate only after it has been added.

You can also confine access to specific projects via group membership and [Fine-grained authorization](https://canonical.com/lxd/docs/default/explanation/authorization/index.html.md#fine-grained-authorization).
The permissions of OIDC clients and fine-grained TLS identities must be managed with `lxc auth` subcommands and the `/1.0/auth` API.

To create a TLS client and restrict the client to a single project, follow these instructions:

CLI

### Create a restricted trust store entry with access to a project

If you’re using token authentication:

```none
lxc config trust add --projects <project_name> --restricted
```

To add the client certificate directly:

```none
lxc config trust add <certificate_file> --projects <project_name> --restricted
```

The client can then add the server as a remote in the usual way ([`lxc remote add <server_name> <token>`](https://canonical.com/lxd/docs/default/reference/manpages/lxc/remote/add/index.html.md#lxc-remote-add-md) or [`lxc remote add <server_name> <server_address>`](https://canonical.com/lxd/docs/default/reference/manpages/lxc/remote/add/index.html.md#lxc-remote-add-md)) and can only access the project or projects that have been specified.

To confine access for an existing certificate (either because the access restrictions change or because the certificate was added with a trust password), use the following command:

```none
lxc config trust edit <fingerprint>
```

Make sure that `restricted` is set to `true` and specify the projects that the certificate should give access to under `projects`.

#### NOTE
You can specify the `--project` flag when adding a remote.
This configuration pre-selects the specified project.
However, it does not confine the client to this project.

### Create a fine-grained TLS identity with access to a project

First create a group and grant the group the `operator` entitlement on the project.

```none
lxc auth group create <group_name>
lxc auth group permission add <group_name> project <project_name> operator
```

The `operator` entitlement grants members of the group permission to create and edit resources belonging to that project, but does not grant permission to delete the project or edit its configuration.
See [Fine-grained authorization](https://canonical.com/lxd/docs/default/explanation/authorization/index.html.md#fine-grained-authorization) for more details.

Next create a TLS identity and add the identity to the group:

```none
lxc auth identity create tls/<client_name> [<certificate_file>] --group <group_name>
```

If `<certificate_file>` is provided the identity will be created directly.
Otherwise, a token will be returned that the client can use to add the LXD server as a remote:

```none
# Client machine
lxc remote add <remote_name> <token>
```

The client will be prompted with a list of projects to use as their default project.
Only the configured project will be presented to the client.

API

### Create a restricted trust store entry with access to a project

If you’re using token authentication, create the token first:

```none
lxc query --request POST /1.0/certificates --data '{
  "name": "<client_name>",
  "projects": ["<project_name>"]
  "restricted": true,
  "token": true,
  "type": "client"
}'
```

<!-- Include content from [/howto/server_expose.md](/howto/server_expose.md) -->

See [`POST /1.0/certificates`](/lxd/stable-5.21/api/#/certificates/certificates_post) for more information.

The return value of this query contains an operation that has the information that is required to generate the trust token:

```none
   {
    "class": "token",
    ...
    "metadata": {
       "addresses": [
          "<server_address>"
       ],
       "fingerprint": "<fingerprint>",
       ...
       "secret": "<secret>"
    },
    ...
   }
```

Use this information to generate the trust token:

```none
   echo -n '{"client_name":"<client_name>","fingerprint":"<fingerprint>",'\
   '"addresses":["<server_address>"],'\
   '"secret":"<secret>","expires_at":"0001-01-01T00:00:00Z"}' | base64 -w0
```

To instead add the client certificate directly, send the following request:

```none
lxc query --request POST /1.0/certificates --data '{
  "certificate": "<certificate>",
  "name": "<client_name>",
  "projects": ["<project_name>"]
  "restricted": true,
  "token": false,
  "type": "client"
}'
```

The client can then authenticate using this trust token or client certificate and can only access the project or projects that have been specified.

<!-- Include content from [/howto/server_expose.md](/howto/server_expose.md) -->

On the client, generate a certificate to use for the connection:

```none
   openssl req -x509 -newkey rsa:2048 -keyout "<keyfile_name>" -nodes \
   -out "<crtfile_name>" -subj "/CN=<client_name>"
```

<!-- Include content from [/howto/server_expose.md](/howto/server_expose.md) -->

Then send a POST request to the `/1.0/certificates?public` endpoint to authenticate:

```none
   curl -k -s --key "<keyfile_name>" --cert "<crtfile_name>" \
   -X POST https://<server_address>/1.0/certificates \
   --data '{ "password": "<trust_token>" }'
```

See [`POST /1.0/certificates?public`](/lxd/stable-5.21/api/#/certificates/certificates_post_untrusted) for more information.

**Create a fine-grained TLS identity with access to a project**

First create a group and grant the group the `operator` entitlement on the project.

```none
lxc query --request POST /1.0/auth/groups --data '{
  "name": "<group_name>",
}'

lxc query --request PUT /1.0/auth/groups/<group_name> --data '{
  "permissions": [
    {
      "entity_type": "project",
      "url": "/1.0/projects/<project_name>",
      "entitlement": "operator"
    }
  ]
}'
```

The `operator` entitlement grants members of the group permission to create and edit resources belonging to that project, but does not grant permission to delete the project or edit its configuration.
See [Fine-grained authorization](https://canonical.com/lxd/docs/default/explanation/authorization/index.html.md#fine-grained-authorization) for more details.

Next create a TLS identity and add the identity to the group:

```none
lxc query --request POST /1.0/auth/identities/tls --data '{
  "name": "<client_name>",
  "groups": ["<group_name>"],
  "token": true
}'
```

<!-- Include content from [/howto/server_expose.md](/howto/server_expose.md) -->

See [`POST /1.0/auth/identities/tls`](/lxd/stable-5.21/api/#/auth/identitites/identities_post_tls) for more information.

The return value of this query contains the information that is required to generate the trust token:

```none
   {
       "client_name": "<client_name>",
       "addresses": [
          "<server_address>"
       ],
       "expires_at": "<expiry_date>"
       "fingerprint": "<fingerprint>",
       "type": "<type>",
       "secret": "<secret>"
   }
```

Use this information to generate the trust token:

```none
   echo -n '{"client_name":"<client_name>","fingerprint":"<fingerprint>",'\
   '"addresses":["<server_address>"],'\
   '"secret":"<secret>","expires_at":"0001-01-01T00:00:00Z","type":"<type>"}' | base64 -w0
```

To instead add the client certificate directly, send the following request:

```none
lxc query --request POST /1.0/certificates --data '{
  "certificate": "<base64 encoded x509 certificate>",
  "name": "<client_name>",
  "groups": ["<group_name>"]
}'
```

If the certificate was added directly, the client is now authenticated with LXD.
If a token was used, the client must use it to add their certificate.

<!-- Include content from [/howto/server_expose.md](/howto/server_expose.md) -->

On the client, generate a certificate to use for the connection:

```none
   openssl req -x509 -newkey rsa:2048 -keyout "<keyfile_name>" -nodes \
   -out "<crtfile_name>" -subj "/CN=<client_name>"
```

<!-- Include content from [/howto/server_expose.md](/howto/server_expose.md) -->

Send a POST request to the `/1.0/auth/identities/tls?public` endpoint to authenticate:

```none
   curl --insecure --key "<keyfile_name>" --cert "<crtfile_name>" \
   -X POST https://<server_address>/1.0/auth/identities/tls \
   --data '{ "trust_token": "<trust_token>" }'
```

See [`POST /1.0/auth/identities/tls?public`](/lxd/stable-5.21/api/#/auth/identities/identities_post_tls_untrusted) for more information.

To confine access for an existing certificate:

CLI

**Trust store entry**

Use the following command:

```none
lxc config trust edit <fingerprint>
```

Make sure that `restricted` is set to `true` and specify the projects that the certificate should give access to under `projects`.

**Fine-grained TLS or OIDC identity**

Create a group with the `operator` entitlement on the project:

```none
lxc auth group create <group_name>
lxc auth group permission add <group_name> project <project_name> operator
```

Then add the group to the identity. For TLS identities run:

```none
lxc auth identity group add tls/<client_name> <group_name>
```

The `<client_name>` must be unique. If it is not, the certificate fingerprint of the client can be used.

For OIDC identities, run:

```none
lxc auth identity group add oidc/<client_name> <group_name>
```

The `<client_name>` must be unique. If it is not, the email address of the client can be used.

API

**Trust store entry**

Send the following request:

```none
lxc query --request PATCH /1.0/certificates/<fingerprint> --data '{
  "projects": ["<project_name>"],
  "restricted": true
}'
```

Make sure that `restricted` is set to `true` and specify the projects that the certificate should give access to under `projects`.

**Fine-grained TLS or OIDC identity**

Create a group with the `operator` entitlement on the project:

```none
lxc query --request POST /1.0/auth/groups --data '{
  "name": "<group_name>",
}'

lxc query --request PUT /1.0/auth/groups/<group_name> --data '{
  "permissions": [
    {
      "entity_type": "project",
      "url": "/1.0/projects/<project_name>",
      "entitlement": "operator"
    }
  ]
}'
```

Then add the group to the identity. For TLS identities run:

```none
lxc query --request PATCH /1.0/auth/identities/tls/<client_name> --data '{
  "groups": ["<group_name>"]
}'
```

The `<client_name>` must be unique. If it is not, the certificate fingerprint of the client can be used.

For OIDC identities, run:

```none
lxc query --request PATCH /1.0/auth/identities/oidc/<client_name> --data '{
  "groups": ["<group_name>"]
}'
```

The `<client_name>` must be unique. If it is not, the email address of the client can be used.

<a id="projects-confine-users"></a>

## Confine users to specific LXD projects via Unix socket


            <p class="youtube_link">
              <a href="https://www.youtube.com/watch?v=6O0q3rSWr8A" target="_blank">
                <span title="LXD for multi-user systems" class="play_icon">▶</span>
                <span title="LXD for multi-user systems">Watch on YouTube</span>
              </a>
            </p>
        
If you use the [LXD snap](https://snapcraft.io/lxd), you can configure the multi-user LXD daemon contained in the snap to dynamically create projects for all users in a specific user group.

To do so, set the `daemon.user.group` configuration option to the corresponding user group:

```none
sudo snap set lxd daemon.user.group=<user_group>
```

Make sure that all user accounts that you want to be able to use LXD are a member of this group.

Once a member of the group issues a LXD command, LXD creates a confined project for this user and switches to this project.
If LXD has not been [initialized](https://canonical.com/lxd/docs/default/howto/initialize/index.html.md#initialize) at this point, it is automatically initialized (with the default settings).

If you want to customize the project settings, for example, to impose limits or restrictions, you can do so after the project has been created.
To modify the project configuration, you must have full access to LXD, which means you must be part of the `lxd` group and not only the group that you configured as the LXD user group.
