Skip to content

Commit

Permalink
docs: clarify different types of API access (#535)
Browse files Browse the repository at this point in the history
The purpose of this PR is make it easier to understand details about API
security. (I'll create a separate PR to add a general security overview
doc)

Summary of changes:
* Specify which API endpoints have which access level
* Use terms more consistently:
    * "Authenticated" to mean a user with `read` or `admin` access level
    * "Unauthenticated" to mean a user with `untrusted` access level
* "Open-access" to mean an API endpoint that doesn't require
authentication (instead of calling them "untrusted")

Preview build:
https://canonical-pebble--535.com.readthedocs.build/en/535/
  • Loading branch information
dwilding authored Dec 17, 2024
1 parent 8b7b7a6 commit 6372a42
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 9 deletions.
21 changes: 16 additions & 5 deletions docs/explanation/api-and-clients.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The Pebble daemon exposes an API (HTTP over a unix socket) to allow remote clients to interact with the daemon. It can start and stop services, add configuration layers to the plan, and so on.

If `pebble run` is started with the `--http <address>` option, Pebble also allows access to "untrusted" HTTP endpoints using the given TCP address (see {ref}`api-access-levels` below).
If `pebble run` is started with the `--http <address>` option, Pebble also exposes open-access HTTP endpoints using the given TCP address (see {ref}`api-access-levels` below).

There is currently no official documentation for the API at the HTTP level (apart from the [code itself](https://github.com/canonical/pebble/blob/master/internals/daemon/api.go)!); most users will interact with it via the Pebble command line interface or by using the Go or Python clients.

Expand All @@ -18,13 +18,24 @@ In addition to the Go client, there's also a [Python client](https://github.com/

API endpoints fall into one of three access levels, from least restricted to most restricted:

* `untrusted`: these are allowed from any user, even unauthenticated users using the HTTP-over-TCP listener. The only untrusted endpoints are `/v1/system-info` and `/v1/health`.
* `read`: these are allowed from any authenticated user, regardless of access level. They are usually read operations that use the HTTP `GET` method, such as listing services or viewing notices.
* `admin`: these are only allowed from admin users. They are usually write or modify operations that use the HTTP `POST` method, such as adding a layer or starting a service.
* **Open-access** - Allowed from any user, even unauthenticated users using the HTTP-over-TCP listener.
* `GET /v1/system-info`, which returns the Pebble version and other information
* `GET /v1/health`, which returns a boolean to indicate whether Pebble's health checks are all healthy

* **Read-access** - Allowed from any authenticated user. For example, listing services or viewing notices.
* All `GET` endpoints except the admin-access `GET` endpoints
* `POST /v1/notices`, which records a custom notice

* **Admin-access** - Only allowed from admin users. For example, adding a layer or starting a service.
* `GET /v1/files`, which pulls a file from a remote system
* `GET /v1/tasks/{task-id}/websocket/{websocket-id}`
* All `POST` endpoints except `POST /v1/notices` (which is read-access)

Pebble authenticates clients that connect to the socket API using peer credentials ([`SO_PEERCRED`](https://man7.org/linux/man-pages/man7/socket.7.html)) to determine the user ID (UID) of the connecting process. If this UID is 0 (root) or the UID of the Pebble daemon, the user's access level is `admin`, otherwise the access level is `read`.

If Pebble can't authenticate the user at all, or if it's an unauthenticated user connecting over TCP, the user is considered `untrusted`.
If Pebble can't authenticate the user, the user's access level is `untrusted`. Unauthenticated users can only use open-access endpoints.

Pebble doesn't try to authenticate users that connect over TCP. So any user that connects over TCP is unauthenticated (access level `untrusted`) and can only use open-access endpoints.


## Controlling API access using identities
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -837,7 +837,7 @@ pebble run --args myservice --port 8080 \; --hold
--create-dirs Create Pebble directory on startup if it doesn't exist
--hold Do not start default services automatically
--http= Start HTTP API listening on this address (e.g.,
":4000")
":4000") and expose open-access endpoints
-v, --verbose Log all output from services to stdout
--args= Provide additional arguments to a service
--identities= Seed identities from file (like update-identities
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/identities.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ identities:
<name>:
# (Required) Access level of this identity. Possible values are:
#
# - untrusted: has access only to untrusted or "open" endpoints
# - read: has access to read or "user" endpoints
# - untrusted: has access to open-access endpoints only
# - read: has access to read-access endpoints
# - admin: has access to all endpoints
access: untrusted | read | admin

Expand Down
2 changes: 1 addition & 1 deletion internals/cli/cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ type sharedRunEnterOpts struct {
var sharedRunEnterArgsHelp = map[string]string{
"--create-dirs": "Create {{.DisplayName}} directory on startup if it doesn't exist",
"--hold": "Do not start default services automatically",
"--http": `Start HTTP API listening on this address (e.g., ":4000")`,
"--http": `Start HTTP API listening on this address (e.g., ":4000") and expose open-access endpoints`,
"--verbose": "Log all output from services to stdout",
"--args": "Provide additional arguments to a service",
"--identities": "Seed identities from file (like update-identities --replace)",
Expand Down

0 comments on commit 6372a42

Please sign in to comment.