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

docs: add Identities documentation #479

Merged
merged 3 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion docs/explanation/api-and-clients.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# API and clients

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 the plan, and so on.
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).

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 @@ -9,3 +11,36 @@ The Go client is used primarily by the CLI, but is importable and can be used by
We try to never change the underlying HTTP API in a backwards-incompatible way, however, in rare cases we may change the Go client in a backwards-incompatible way.

In addition to the Go client, there's also a [Python client](https://github.com/canonical/operator/blob/master/ops/pebble.py) for the Pebble API that's part of the [`ops` library](https://github.com/canonical/operator) used by Juju charms ([documentation here](https://juju.is/docs/sdk/interact-with-pebble)).


benhoyt marked this conversation as resolved.
Show resolved Hide resolved
(api-access-levels)=
## API access levels

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.

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`.


## Controlling API access using identities

In addition to the default access control, Pebble admins can also set up named [identities](../reference/identities.md) with specific access levels using the identities CLI commands.

Each identity has a name, an access level, and an authentication type with type-specific configuration.

Currently the only authentication type is `local`, that is, a local user ID determined using peer credentials. An example admin identity named "bob" is shown below:

```yaml
identities:
bob:
access: admin
local:
user-id: 42
```

Read [how to manage identities](../how-to/manage-identities.md) for more information.
16 changes: 15 additions & 1 deletion docs/how-to/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

These guides will walk you through every step of using Pebble through its complete operations lifecycle.


## Installation

Installation follows a broadly similar pattern on all architectures, and you can choose to install the pre-built binary or build it from the source by yourself.
Expand All @@ -13,7 +14,8 @@ Installation follows a broadly similar pattern on all architectures, and you can
Install Pebble <install-pebble>
```

## Service Orchestration

## Service orchestration
benhoyt marked this conversation as resolved.
Show resolved Hide resolved

As your needs grow, you may want to orchestrate multiple services.

Expand All @@ -23,3 +25,15 @@ As your needs grow, you may want to orchestrate multiple services.

Manage service dependencies <service-dependencies>
```


## Identities

Use named identities to allow additional users to access the API.

```{toctree}
:titlesonly:
:maxdepth: 1

Manage identities <manage-identities>
```
145 changes: 145 additions & 0 deletions docs/how-to/manage-identities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@

# How to manage identities

Pebble uses named [identities](../reference/identities.md) to extend access to its [API](../explanation/api-and-clients.md).

For example, let's say you're building a container-based system with one container running Pebble and the workload, and another container in the same user namespace talking to Pebble over the API. You may want to give API access to a non-root user -- that's where identities come in.

By default any UID (user ID) connected to the API socket is a `read` user; UID 0 (root) or the UID of the Pebble server process gives `admin` access.


## Add new identities

To extend this to additional users, add named identities using the [`add-identities`](../reference/cli-commands/add-identities.md) command with a YAML file configuring the details. For example, to add a new admin "bob" with UID 42 and a new read user "alice" with UID 2000, prepare this file:
benhoyt marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest a slight change since the flow is broken a little after sectioning out the content:
To extend access to Pebble's API to additional users, add...

Thanks.


```yaml
# idents-add.yaml
identities:
bob:
access: admin
local:
user-id: 42
alice:
access: read
local:
user-id: 2000
```

and run the following command:

```{terminal}
:input: pebble add-identities --from idents-add.yaml
Added 2 new identities.
```


## Remove identities

To remove existing identities, use [`remove-identities`](../reference/cli-commands/remove-identities.md)with a YAML file that has a `null` value for each identity you want to remove. For example, to remove "alice", prepare this file:

```yaml
# idents-remove.yaml
identities:
alice: null
```

and run the following command:

```{terminal}
:input: pebble remove-identities --from idents-remove.yaml
Removed 1 identity.
```


## Update or replace identities

To update existing identities, use [`update-identities`](../reference/cli-commands/update-identities.md). For example, prepare this file:

```yaml
# idents-update.yaml
identities:
bob:
access: admin
local:
user-id: 1042
```

and run the following command:

```{terminal}
:input: pebble update-identities --from idents-update.yaml
Updated 1 identity.
```

You can use the `--replace` flag to idempotently add or update (or even remove) identities, whether or not they exist. The replace option is useful in automated scripts. For example, to update "bob", add "alice", and remove "mallory" (if it exists), prepare this file:

```yaml
# idents-replace.yaml
identities:
bob:
access: admin
local:
user-id: 1042
alice:
access: read
local:
user-id: 3000
mallory: null
```

and run the following command:

```{terminal}
:input: pebble update-identities --from idents-replace.yaml --replace
Replaced 3 identities.
```


## List identities

You can list identities with the [`identities`](../reference/cli-commands/identities.md) command:

```{terminal}
:input: pebble identities
Name Access Types
alice read local
bob admin local
```

Use `--format yaml` (or `--format json`) to show all non-secret fields in the YAML (or JSON) format:

```{terminal}
:input: pebble identities --format=yaml
identities:
alice:
access: read
local:
user-id: 3000
bob:
access: admin
local:
user-id: 1042
```


## View a single identity

To show a single identity in YAML format, use the `identity` command:

```{terminal}
:input: pebble identity alice
access: read
local:
user-id: 2000
```


## Seed initial identities

To seed a Pebble server with one or more initial identities, use [`pebble run`](../reference/cli-commands/run.md) with the `--identities` option. This has the effect of running `update-identities --replace` with the content of the given identities file before running the server:

```{terminal}
:input: pebble run --identities idents-add.yaml
2024-08-12T03:04:51.785Z [pebble] Started daemon.
...
```
37 changes: 37 additions & 0 deletions docs/reference/identities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Identities

Pebble has the concept of named "identities", which lets administrators manage users' access to the [API](../explanation/api-and-clients.md).

Each identity has a name, an access level, and an authentication type with type-specific configuration. Admins use the identities CLI commands to [manage identities](../how-to/manage-identities.md), and the identity configuration is persisted to disk.

The identity configuration must be provided to Pebble, and is read from Pebble, in the following YAML format:

```yaml
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
# - admin: has access to all endpoints
access: untrusted | read | admin

# Configure local, peer credential-based authentication.
#
# Currently the only suported authentication type is "local". Other
# types may be added in future, at which point you may configure an
# identity with one or more authentication types.
local:
# (Required) Peer credential UID.
user-id: <uid>
```

For example, a local identity named "bob" with UID 42 that is granted `admin` access would be defined as follows:

```yaml
identities:
bob:
access: admin
local:
user-id: 42
```
1 change: 1 addition & 0 deletions docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Changes and tasks <changes-and-tasks>
CLI Commands <cli-commands/cli-commands>
Health checks <health-checks>
Identities <identities>
Layers <layers>
Layer specification <layer-specification>
Log forwarding <log-forwarding>
Expand Down
Loading