# Built-in User Management

> The overview of GreptimeDB User and Permission mechanism.

# Built-in User Management

GreptimeDB Enterprise provides a built-in user and permission system backed by
metadata storage. In cluster mode, the Metasrv manages this storage; in standalone
mode, users are stored in the standalone metadata backend. The system supports
Role-Based Access Control (RBAC) and fine-grained
Access Control Lists (ACLs) to ensure data security and isolation.

For programmatic account management, see the
[User Management API](/enterprise/user/api.md).

## Key Features

- **Built-in User Management**: User accounts and permissions are persisted in
  metadata storage and shared across frontend nodes in a cluster.
- **Role-Based Access Control (RBAC)**: Assign global privileges to users,
  controlling operations like `SELECT`, `INSERT`, `CREATE TABLE`, and more.
- **Fine-grained ACLs**: Select databases and tables using exact names or regular
  expressions.
- **Dynamic Management**: Manage users dynamically via HTTP APIs without
  restarting the server.
- **Initial Seeding**: Support for seeding initial accounts from a password
  file at startup.

## Configuration and Explanation

This section walks through how to enable the enterprise user provider and
perform basic user management.

### 1. Enable User Provider

To use the enterprise user and permission system, enable the
`greptime_ee_user_provider` in the component that receives client requests.
Configure it on the standalone server in standalone mode, or on each frontend
node in cluster mode.

The user provider value is:

```text
greptime_ee_user_provider:<path-to-password-file>
```

The password file is optional and is used only for initial account seeding. To
enable the provider without seeding users, use `greptime_ee_user_provider:`.
The trailing colon `:` is required by the configuration parser.

**Standalone command line:**

```shell
./greptime standalone start \
  --user-provider=greptime_ee_user_provider:/path/to/passwords.txt
```

**Standalone configuration file:**

```toml
user_provider = "greptime_ee_user_provider:/path/to/passwords.txt"
```

```shell
./greptime standalone start \
  -c /path/to/standalone.toml
```

**Frontend command line:**

```shell
./greptime frontend start \
  --metasrv-addrs=127.0.0.1:3002 \
  --user-provider=greptime_ee_user_provider:/path/to/passwords.txt
```

**Frontend configuration file:**

```toml
user_provider = "greptime_ee_user_provider:/path/to/passwords.txt"

[meta_client]
metasrv_addrs = ["127.0.0.1:3002"]
```

Then start frontend with the configuration file:

```shell
./greptime frontend start \
  -c /path/to/frontend.toml
```

### 2. Initial Account Seeding (Optional)

The password file uses the following format:
`[<catalog>/]<username>[:<role>]=<password>`

The catalog prefix is optional. Entries without it belong to the default
catalog, `greptime`.

Available roles:

- `admin`: Full privileges, including user management.
- `readonly` (or `ro`): Read-only access (`SqlSelect`).
- `writeonly` (or `wo`): Write-only access (e.g., `SqlInsert`, `TableCreate`).
- `readwrite` (or `rw`): Both read and write access (default).

Example `passwords.txt`:

```text
# [catalog/]username[:role]=password
superuser:admin=strong_password
alice:ro=alice_pwd
bob:rw=bob_pwd
tenant_a/carol:ro=carol_pwd
```

The username `admin` is reserved and skipped during seeding. Use another name,
such as `superuser`, for a seeded administrator.

Seeded users are granted full access (`AclType::All`) to the `public` database
in their catalog, subject to their global privileges.

Seed accounts are created only once. Existing users are skipped, and deleting a
seeded user does not cause it to be recreated on later startups. You can modify
seeded users later through the UI or HTTP API.

## Catalog Scope

Usernames are unique within a catalog. The HTTP user-management APIs at
`/v1/users` list and manage users in the request's current catalog, which defaults
to `greptime`. To select another catalog, use the `db` query parameter or
`x-greptime-db-name` header with a value such as `tenant_a-public`. The `catalog`
field in a create-user request body does not select the target catalog.

HTTP, gRPC, and PostgreSQL authentication look up users in the selected catalog.
MySQL password authentication and the admin-password CLI still look up users in
the default catalog.

## Privileges and ACLs

### Global Privileges

Privileges include the following operations:

| Privilege | Description |
| :--- | :--- |
| `TableCreate` | Create new tables |
| `TableAlter` | Alter existing tables |
| `TableDrop` | Drop tables |
| `SqlSelect` | Execute `SELECT` queries |
| `SqlInsert` | Execute `INSERT` operations |
| `SqlDelete` | Execute `DELETE` operations |
| `FlowCreate` | Create flows |
| `FlowDrop` | Drop flows |
| `DatabaseCreate` | Create databases |
| `DatabaseAlter` | Alter databases |
| `DatabaseDrop` | Drop databases |
| `Admin` | Full administrative privileges |
| `TriggerCreate` | Create triggers |
| `TriggerDrop` | Drop triggers |
| `TriggerAlter` | Alter triggers |

#### Predefined Role Privileges

When using the password file for seeding, the predefined roles map to the
following privilege combinations:

| Role | Privileges |
| :--- | :--- |
| `admin` | All privileges |
| `readonly` / `ro` | `SqlSelect` |
| `writeonly` / `wo` | `SqlInsert`, `SqlDelete`, `TableCreate`, `TableAlter`, `TableDrop`, `FlowCreate`, `FlowDrop`, `TriggerCreate`, `TriggerDrop`, `TriggerAlter`, `DatabaseCreate`, `DatabaseAlter`, `DatabaseDrop` |
| `readwrite` / `rw` | `readonly` + `writeonly` privileges |

### Access Control Lists (ACLs)

ACLs control access to databases and their tables. In the HTTP API, `acl_map`
maps database selectors to lists of table ACL entries.

#### Table ACLs

The `all` ACL grants access to every table in the database. Use it when a user
should be able to read or write all current and future tables in that database,
subject to the user's global privileges.

The `match` ACL grants access to one table by exact name. Use it when a user
should only access a specific table and should not automatically gain access to
other tables with similar names.

The `regex` ACL grants access to tables whose names match a regular expression.
Use it when tables follow a naming convention and should be managed as a group.
Table regexes match substrings unless explicitly anchored. For example,
`mem_.*` also matches `old_mem_usage`, and `.*_metrics` also matches
`cpu_metrics_backup`. Use `^mem_.*$` for names that start with `mem_`,
`^.*_metrics$` for names that end with `_metrics`, and `^sensor_[0-9]+$` for
complete names such as `sensor_1` and `sensor_2024`.

#### Database Selectors

A normal `acl_map` key, such as `public`, selects one database by exact name.
A key with the reserved `~regex:` prefix selects databases by regular expression:

```json
{
  "acl_map": {
    "~regex:tenant_[0-9]+": [{"type": "all"}]
  }
}
```

Database regexes always match the entire name. This example grants access to all
tables in `tenant_42`, but not `archive_tenant_42` or `tenant_42_backup`. It applies
to current and future matching databases, regardless of who created them.

If exact and regex selectors match the same database, their table ACL entries
are combined. An `all` entry in any matching selector grants access to every
table in that database. Invalid database or table regexes, and empty database
regexes, are rejected when users are created or updated.

#### Database Operations and System Tables

A non-admin user with `DatabaseCreate` can create a database in their catalog
without an existing ACL for that database. Creation atomically grants the creator
effective `all` access to the new database and refreshes the submitting session's
permissions. Database selectors do not restrict which names the user can create.
`CREATE DATABASE IF NOT EXISTS` does not grant access to an existing database.

`DROP DATABASE` and `COPY DATABASE` require effective `all` access to the target
database, in addition to the relevant global privilege. For ordinary databases,
`SHOW DATABASES`, `SHOW TABLES`, `SHOW TABLE STATUS`, and `SHOW VIEWS` filter their
results according to the user's ACLs.

Some system tables have separate rules. Reading the following
`information_schema` tables requires `SqlSelect` but bypasses table ACLs:
`alerts`, `columns`, `flows`, `key_column_usage`, `partitions`, `region_peers`,
`schemata`, `table_constraints`, `tables`, `triggers`, and `views`.
Other `information_schema` tables require `Admin`.

## Validation Rules

### Username

Usernames must:

- Start with a letter (`a-z` or `A-Z`)
- Contain only letters, digits, and underscores
- Match the pattern `[a-zA-Z][a-zA-Z0-9_]*`

### Password

Password validation depends on how the user is created or updated:

- Seeded account passwords must not be empty.
- Passwords created or updated through the UI or HTTP API must be 6 to 64
  characters long.

## External Authentication

The built-in user provider supports optional authentication plugins on the
standalone server or frontend nodes that receive client requests:

- **JWT (`jwt_auth`)**: Configure a trusted verification key or JWKS endpoint.
  The token's username claim (default: `sub`) must identify an existing user in
  the selected catalog; the stored privileges and ACLs still apply. For HTTP,
  send `Authorization: Bearer <token>`. For MySQL and PostgreSQL, use `*` as the
  username and the JWT as the password.

## User Management in the Enterprise Dashboard

After you enable `greptime_ee_user_provider`, both GreptimeDB and the
Enterprise Dashboard require users to log in with an account.
The following screenshot shows the Enterprise Dashboard login page:

    

You can log in with an account defined in the seeding file, or with the fallback
`admin` account if one was created.

Only accounts with the `Admin` privilege can see the database management menu.
Non-admin accounts can only access the query page, similar to the open-source
dashboard.

After logging in as an admin user, click `User Management` in the lower-left
corner to open the user management page:

    

This page lists users in the current catalog. From here, you can:

1. Create users
2. Update existing users
3. Delete users

The following screenshot shows the form for creating a user:

    

In this form, you can configure:

1. The username
2. The password
3. Whether the account has the `Admin` privilege. Non-admin users are granted
   the `readwrite` privilege.
4. The account ACL list

The ACL form has two tabs. You can select an exact table, select an entire
database to grant full-database access, or use a regular expression to grant
access to a range of tables. The following screenshot shows the regular
expression form:

    

## Reference

- **Admin Account**: After account seeding, GreptimeDB Enterprise creates a
  fallback `admin` account in the default catalog, `greptime`, only if that
  catalog has no user with the `Admin` privilege and the username `admin` is
  unused. Existing accounts are never overwritten. For example, the
  `superuser:admin` entry above suppresses fallback account creation.
  - If the environment variable `GREPTIME_ENTERPRISE_ADMIN_PASSWORD` is set,
    it uses that value as the fallback account's password. Set it on the Metasrv
    in cluster mode or on the standalone process in standalone mode.
  - If the environment variable is not set, it generates a random UUID as the
    password.
- **Checking Auto-generated Password**: If a random password was generated,
  you can find it in the GreptimeDB log files. Search for a message like:
  ```text
  Created admin user with auto-generated password <UUID>
  ```
- **Resetting the Admin Password**: You can reset the existing `admin`
  account's password in the default catalog using the CLI. The command reads
  backend storage settings from a Metasrv config file and supports the standard
  `GREPTIMEDB_METASRV__...` environment variable overrides.
  ```shell
  ./greptime-ee cli user admin-password \
    --new-password <new-password> \
    --config-file /path/to/metasrv.toml
  ```
  The command connects directly to etcd, MySQL, or PostgreSQL and can run on any
  host with access to the backend. Use the deployment's Metasrv configuration,
  including its storage endpoints, metadata table, schema where applicable, and
  key prefix.
  The command does not support standalone's default Raft Engine backend. For
  standalone deployments using MySQL or PostgreSQL metadata storage, prepare a
  separate Metasrv-format configuration pointing to the same storage; do not
  pass the standalone configuration file directly. The command does not create
  a missing `admin` account.
- **Persistence**: In cluster mode, user information is persisted in the
  Metasrv's KV store and shared across frontend nodes. In standalone mode, it is
  persisted in the standalone metadata backend, which defaults to Raft Engine.
- **Admin Protection**: The built-in `admin` user cannot be deleted via the API.
