Skip to content
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
1 change: 0 additions & 1 deletion public/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Phase's RBAC system allows you to define permissions for Create, Read, Update, a
| **Secrets** | Manage access to app secrets |
| **Lockbox** | Control access to Lockbox secret sharing |
| **Logs** | Manage access to app and secret audit logs |
| **Tokens** | Control creation and management of access tokens |
| **Members** | Manage user access within the app |
| **Integrations** | Control setup and management of app integrations |
| **Encryption Mode** | Manage encryption settings for the app |
Expand Down
2 changes: 1 addition & 1 deletion public/access-control/authentication/account.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ To confirm deletion, type your email address into the confirmation dialog.
Organisation audit logs are preserved for compliance. Events you performed remain in your organisations' logs, with the actor shown as *"Deleted account"*. Your account and its personal data are removed. Audit records can still contain identifying fields captured at the time of each event.
</Note>

Any active dynamic secret leases you hold are revoked at the provider before your account is removed. Existing service account tokens and organisation resources you created (network policies, service tokens) are unaffected: they belong to the organisation, not to you.
Any active dynamic secret leases you hold are revoked at the provider before your account is removed. Existing service account tokens and organisation resources you created, such as network policies, are unaffected: they belong to the organisation, not to you.
8 changes: 0 additions & 8 deletions public/access-control/roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ The organization owner. This role is automatically assigned when a user creates
| **RotatingSecrets** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Tokens (Legacy)** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Members** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Service Accounts** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -106,7 +105,6 @@ Admin users have access to most resources and permissions, and have global acces
| **RotatingSecrets** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Tokens (Legacy)** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Members** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Service Accounts** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -150,7 +148,6 @@ Management users with broad access to environments, secrets, and service account
| **RotatingSecrets** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Tokens (Legacy)** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Members** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Service Accounts** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -192,7 +189,6 @@ Default role for Service Accounts, providing programmatic access to secrets with
| **RotatingSecrets** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Lockbox** | No access | ❌ | ❌ | ❌ | ❌ |
| **Logs** | No access | ❌ | ❌ | ❌ | ❌ |
| **Tokens (Legacy)** | No access | ❌ | ❌ | ❌ | ❌ |
| **Members** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Service Accounts** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Integrations** | Read access | ✅ | ❌ | ❌ | ❌ |
Expand Down Expand Up @@ -234,7 +230,6 @@ Developers have limited permissions at the organization level and must be given
| **RotatingSecrets** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Tokens (Legacy)** | Custom access | ✅ | ✅ | ❌ | ❌ |
| **Members** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Service Accounts** | Custom access | ❌ | ✅ | ❌ | ❌ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -293,9 +288,6 @@ Some actions require a combination of permissions across multiple resources. Bel
- Creating a new third party integration inside of an App
- `Integrations:create`
- `Environments:read`
- Creating a new Service Token:
- `Tokens:create`
- `Environments:read`
- Enable or disable SSE (Server-side Encryption):
- `EncryptionMode:update`
- `Environments:read`
Expand Down
2 changes: 1 addition & 1 deletion public/console/apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,6 @@ Once enabled, the settings page will show you the updated Encryption mode:
To delete an App, click the "Delete" button in the Settings tab.

<Warning>
Deleting an App will permanently delete all Environments, Secrets, and Tokens
Deleting an App will permanently delete all Environments and Secrets
associated with it.
</Warning>
2 changes: 1 addition & 1 deletion public/console/logstreams.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Log Streams continuously ship organisation audit logs and secret events from Pha

## Exported events

Every event is a structured JSON envelope (`schema_version: 1`) aligned with OpenTelemetry semantic conventions. `event.category` is `secrets` or `org_audit`; `event.type` is one of `create`, `read`, `update`, `delete` or `access`. The `actor` block identifies who acted (a `user`, `service_account` with its token, `service_token`, or `phase` for system actions), and `phase.description` carries a human-readable summary of every event.
Every event is a structured JSON envelope (`schema_version: 1`) aligned with OpenTelemetry semantic conventions. `event.category` is `secrets` or `org_audit`; `event.type` is one of `create`, `read`, `update`, `delete` or `access`. The `actor` block identifies who acted (a `user`, `service_account` with its token, `service_token` for historical events from a legacy service token, or `phase` for system actions), and `phase.description` carries a human-readable summary of every event.

Secret events carry a `phase.secret` block (id, path, version, type — never the name or value). Organisation audit events instead carry a `phase.resource` block with a readable `type` slug (e.g. `app`, `environment`, `member`, `invite`, `role`, `service_account_token`, `rotating_secret`, `network_access_policy`, `log_stream`), the resource `id` and `metadata`, plus `old_values` / `new_values` for changes.

Expand Down
2 changes: 1 addition & 1 deletion public/integrations/platforms/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ CMD ["sh", "-c", "phase run \"python manage.py migrate && python manage.py runse
Ensure the `PHASE_SERVICE_TOKEN` is securely provided to your container for authentication with Phase services.

```fish
export PHASE_SERVICE_TOKEN=[pss_env:...]
export PHASE_SERVICE_TOKEN=pss_service:v2:...
```

```fish
Expand Down
4 changes: 2 additions & 2 deletions public/integrations/platforms/hashicorp-terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ To configure the provider, you need to provide your Phase API credentials. We re

```hcl
provider "phase" {
phase_token = "pss_service:v1:..." # or "pss_user:v1:..." // A Phase Service Token or a Phase User Token (PAT)
phase_token = "pss_service:v2:..." # or "pss_user:v1:..." // A Phase Service Account Token or a Phase User Token (PAT)
// Alternatively supply a PHASE_TOKEN environment variable
}
```
Expand All @@ -66,7 +66,7 @@ If you are using a self-hosted instance of Phase, you can specify the API host u
provider "phase" {
host = "https://phase.example.io"
skip_tls_verification = true # Optional, if your Phase instance is using a self-signed certificate, you can set this to true to skip TLS verification.
phase_token = "pss_service:v1:..." # or "pss_user:v1:..." // A Phase Service Token or a Phase User Token (PAT)
phase_token = "pss_service:v2:..." # or "pss_user:v1:..." // A Phase Service Account Token or a Phase User Token (PAT)
}
```

Expand Down
1 change: 0 additions & 1 deletion public/public-api/roles.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ Responses use camelCase keys (`appPermissions`, `globalAccess`). On POST and PUT
"appPermissions": {
"Environments": ["read", "create", "update"],
"Secrets": ["create", "read", "update", "delete"],
"Tokens": ["read", "create"],
"Members": ["read"]
},
"globalAccess": false
Expand Down
4 changes: 2 additions & 2 deletions public/sdks/go.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Before interacting with the Phase service, initialize the SDK with your service

Parameters:

- `token` type `string`: Your Phase Service Token (`pss_service:v1:...` or `pss_service:v2:...`) or User Token (`pss_user:v1:...`)
- `token` type `string`: Your Phase Service Token (`pss_service:v2:...`) or User Token (`pss_user:v1:...`)
- `host` type `string`: The URL of the Phase Console instance. Defaults to `https://console.phase.dev` if empty.
- `debug` type `bool`: Setting to true will result in a higher level of log verbosity useful when debugging

Expand All @@ -93,7 +93,7 @@ import (
)

func main() {
token := "pss_service:v1:....."
token := "pss_service:v2:....."
host := "https://console.phase.dev" // Adjust this for a self-hosted instance of Phase
debug := false // For logging verbosity, disable in production

Expand Down
30 changes: 15 additions & 15 deletions public/security/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,28 +211,28 @@ Once reconstructed, the user's private key can be used to unwrap the *Wrapped Se



### Service Tokens
### Service Account Tokens

Service tokens are used to programmatically access secrets stored in Phase. They can be scoped to one or more environments of an application. Service tokens work analogously to User tokens, but instead of using a pre-existing asymmetric keypair, a new random key pair is generated.
Service account tokens are used to programmatically access secrets stored in Phase as a [Service Account](/access-control/service-accounts). The scope of the token depends on the Apps and Environments the service account has access to, and the role associated with the account.

- A random public/private Curve25519 keypair (<MathSymbol>K<sub>token</sub></MathSymbol>, <MathSymbol>k<sub>token</sub></MathSymbol>) is generated
- Additionally, a 32-byte *Token ID* and a random *Wrapping Key* <MathSymbol>K<sub>wrapping</sub></MathSymbol> are generated
- The token private key <MathSymbol>k<sub>token</sub></MathSymbol> is split into 2 shares: <MathSymbol>s<sub>0</sub></MathSymbol> and <MathSymbol>s<sub>1</sub></MathSymbol>
- The token string is assembled using <MathSymbol>s<sub>0</sub></MathSymbol>, <MathSymbol>K<sub>wrapping</sub></MathSymbol>, the token's public key <MathSymbol>K<sub>token</sub></MathSymbol>, and the *Token ID*
- <MathSymbol>s<sub>1</sub></MathSymbol> is encrypted with <MathSymbol>K<sub>wrapping</sub></MathSymbol> to compute a wrapped share <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol> and stored on the backend
- The token string has the format: <MathSymbol>K<sub>token</sub></MathSymbol>||<MathSymbol>s<sub>0</sub></MathSymbol>||<MathSymbol>K<sub>wrapping</sub></MathSymbol>||<MathSymbol>TokenId</MathSymbol>
Each service account has its own set of keys. When a service account is created in the Console, its keys are generated client-side: a random 24-word mnemonic is used to derive an *Account Seed* and an Ed25519 signing key pair, from which an X25519 key-exchange keypair (<MathSymbol>K<sub>sa</sub><sup>kx</sup></MathSymbol>, <MathSymbol>k<sub>sa</sub><sup>kx</sup></MathSymbol>) is derived, exactly as described in [user keys](#user-keys). The account keyring and mnemonic are encrypted asymmetrically (wrapped) with the public key <MathSymbol>K<sub>user</sub><sup>kx</sup></MathSymbol> of each organization member whose role has access to Service Accounts, and stored on the backend. If server-side key management is enabled for the account, the keyring and mnemonic are additionally wrapped with the server's public key. Service accounts created via the [API](/public-api/service-accounts) always use server-side key management: the server generates a random Ed25519 key pair and wraps the keyring with its own public key.

![service token construction](/assets/images/security/service-token-construction.png)
Service account tokens work analogously to User tokens: they are generated by securely splitting the service account's private key and distributing these shares between the server and client token string:

For each environment that the service token is scoped to, the respective *Environment Salt* and *Environment Seed* are encrypted asymmetrically (wrapped) with the service token publicKey <MathSymbol>K<sub>token</sub></MathSymbol> and stored on the backend.
- A random 32-byte *Token ID* and a random 32-byte *Wrapping key* <MathSymbol>K<sub>wrapping</sub></MathSymbol> are generated
- The service account's private key <MathSymbol>k<sub>sa</sub><sup>kx</sup></MathSymbol> is split into 2 shares: <MathSymbol>s<sub>0</sub></MathSymbol> and <MathSymbol>s<sub>1</sub></MathSymbol>
- The token string is assembled using the *Token ID*, the service account's public key <MathSymbol>K<sub>sa</sub><sup>kx</sup></MathSymbol>, <MathSymbol>s<sub>0</sub></MathSymbol> and <MathSymbol>K<sub>wrapping</sub></MathSymbol>
- <MathSymbol>s<sub>1</sub></MathSymbol> is encrypted with <MathSymbol>K<sub>wrapping</sub></MathSymbol> to compute a wrapped share <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol> and stored on the backend along with the *Token ID*
- The token string has the format: `pss_service:v2:`<MathSymbol>TokenId</MathSymbol>:<MathSymbol>K<sub>sa</sub><sup>kx</sup></MathSymbol>:<MathSymbol>s<sub>0</sub></MathSymbol>:<MathSymbol>K<sub>wrapping</sub></MathSymbol>

When a service token is invoked, the token private key is re-assembled client-side:
- Fetch <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol> from the server
- Decrypt <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol> with <MathSymbol>K<sub>wrapping</sub></MathSymbol> to retrieve <MathSymbol>s<sub>1</sub></MathSymbol>
- Reconstruct the token private key <MathSymbol>k<sub>token</sub></MathSymbol> from <MathSymbol>s<sub>0</sub></MathSymbol> and <MathSymbol>s<sub>1</sub></MathSymbol>.
These steps are performed in the browser by a user who can unwrap the service account keyring with their own private key. If server-side key management is enabled, the server can instead unwrap the keyring with its own private key, perform the same steps and return the token string once. In both cases the server stores the *Token ID*, the public key <MathSymbol>K<sub>sa</sub><sup>kx</sup></MathSymbol> and <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol>; <MathSymbol>s<sub>0</sub></MathSymbol> and <MathSymbol>K<sub>wrapping</sub></MathSymbol> exist only in the token string.

A service account is granted access to an environment in the same way as a user: the *Environment Seed* and *Environment Salt* are wrapped with the service account's public key <MathSymbol>K<sub>sa</sub><sup>kx</sup></MathSymbol> and stored on the backend as an EnvironmentKey object. Access is provisioned to the account and not to individual tokens, so every token of a service account can access the same environments across any number of Apps, and creating or deleting a token does not require environment keys to be re-wrapped.

![service token usage](/assets/images/security/service-token-use.png)
When a service account token is invoked, the service account's private key is re-assembled client-side:
- Fetch <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol> from the server
- Decrypt <MathSymbol>s<sub>1</sub><sup>wrapped</sup></MathSymbol> with <MathSymbol>K<sub>wrapping</sub></MathSymbol> to retrieve <MathSymbol>s<sub>1</sub></MathSymbol>
- Reconstruct the service account's private key <MathSymbol>k<sub>sa</sub><sup>kx</sup></MathSymbol> from <MathSymbol>s<sub>0</sub></MathSymbol> and <MathSymbol>s<sub>1</sub></MathSymbol>

The private key is used to unwrap the *Environment Seed*, which in turn can be used to derive the Environment keys and decrypt secrets. See [environment access provisioning](#environment-access-provisioning) for details.

Expand Down
2 changes: 1 addition & 1 deletion src/pages/access-control/authentication/account.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ To confirm deletion, type your email address into the confirmation dialog.
Organisation audit logs are preserved for compliance. Events you performed remain in your organisations' logs, with the actor shown as *"Deleted account"*. Your account and its personal data are removed. Audit records can still contain identifying fields captured at the time of each event.
</Note>

Any active dynamic secret leases you hold are revoked at the provider before your account is removed. Existing service account tokens and organisation resources you created (network policies, service tokens) are unaffected: they belong to the organisation, not to you.
Any active dynamic secret leases you hold are revoked at the provider before your account is removed. Existing service account tokens and organisation resources you created, such as network policies, are unaffected: they belong to the organisation, not to you.
1 change: 0 additions & 1 deletion src/pages/access-control/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ Phase's RBAC system allows you to define permissions for Create, Read, Update, a
| **Secrets** | Manage access to app secrets |
| **Lockbox** | Control access to Lockbox secret sharing |
| **Logs** | Manage access to app and secret audit logs |
| **Tokens** | Control creation and management of access tokens |
| **Members** | Manage user access within the app |
| **Integrations** | Control setup and management of app integrations |
| **Encryption Mode** | Manage encryption settings for the app |
Expand Down
8 changes: 0 additions & 8 deletions src/pages/access-control/roles.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ The organization owner. This role is automatically assigned when a user creates
| **RotatingSecrets** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Tokens (Legacy)** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Members** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Service Accounts** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -106,7 +105,6 @@ Admin users have access to most resources and permissions, and have global acces
| **RotatingSecrets** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Tokens (Legacy)** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Members** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Service Accounts** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -150,7 +148,6 @@ Management users with broad access to environments, secrets, and service account
| **RotatingSecrets** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Tokens (Legacy)** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Members** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Service Accounts** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -192,7 +189,6 @@ Default role for Service Accounts, providing programmatic access to secrets with
| **RotatingSecrets** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Lockbox** | No access | ❌ | ❌ | ❌ | ❌ |
| **Logs** | No access | ❌ | ❌ | ❌ | ❌ |
| **Tokens (Legacy)** | No access | ❌ | ❌ | ❌ | ❌ |
| **Members** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Service Accounts** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Integrations** | Read access | ✅ | ❌ | ❌ | ❌ |
Expand Down Expand Up @@ -234,7 +230,6 @@ Developers have limited permissions at the organization level and must be given
| **RotatingSecrets** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Lockbox** | Full access | ✅ | ✅ | ✅ | ✅ |
| **Logs** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Tokens (Legacy)** | Custom access | ✅ | ✅ | ❌ | ❌ |
| **Members** | Read access | ✅ | ❌ | ❌ | ❌ |
| **Service Accounts** | Custom access | ❌ | ✅ | ❌ | ❌ |
| **Integrations** | Full access | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -293,9 +288,6 @@ Some actions require a combination of permissions across multiple resources. Bel
- Creating a new third party integration inside of an App
- `Integrations:create`
- `Environments:read`
- Creating a new Service Token:
- `Tokens:create`
- `Environments:read`
- Enable or disable SSE (Server-side Encryption):
- `EncryptionMode:update`
- `Environments:read`
Expand Down
Loading