Skip to content

Commit 150e8d9

Browse files
touilleManFirelightFlagboy
authored andcommitted
Add RFC docs/rfcs/1021-sso-openbao-device-storage.md
1 parent 6cddbc5 commit 150e8d9

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

.cspell/custom-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Dorg
1616
Déselect
1717
Editics
1818
FRFX
19+
Hexagone
1920
HKCR
2021
LATEXMKOPTS
2122
Ljava
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
<!-- Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -->
2+
3+
# SSO OpenBao Device Storage
4+
5+
## 1 - Goals
6+
7+
This RFC introduces SSO-based authentication with OpenBao for secure device keys storage. The main objectives are:
8+
9+
1. Enable SSO-based authentication for Parsec devices (i.e. device keys file) using external identity providers.
10+
2. Leverage OpenBao as a secure storage backend for device encryption keys (opaque keys).
11+
3. Provide a seamless user experience where device authentication is tied to organizational SSO credentials.
12+
4. Maintain end-to-end encryption security by separating device files from their encryption keys.
13+
14+
## 2 - Overview
15+
16+
The SSO OpenBao approach implements a two-layer security model:
17+
18+
1. **Device Keys File**: Stored locally on the user's machine, encrypted with an opaque key
19+
2. **Opaque Key**: Stored in OpenBao, accessible only after SSO authentication
20+
21+
This separation ensures that compromise of either component alone doesn't expose device private keys. An attacker would need both:
22+
23+
- Access to the encrypted device file on the user's machine
24+
- Valid SSO credentials to retrieve the opaque key from OpenBao
25+
26+
> [!Note]
27+
> Obviously the level of security is lower than traditional approaches (e.g.
28+
> storing the opaque key on the OS Keyring or derive it from a strong password).
29+
>
30+
> Typically a system administrator in a company managing both the OpenBao server
31+
> and the fleet of computers used by the employees could silently get access to
32+
> the employees' device private keys!
33+
>
34+
> However this is a trade-of to increase user-friendliness, the decision whether
35+
> or not to use this is to be made by the server administrator according to its
36+
> own threat model.
37+
38+
### 2.1 - Device File Workflow
39+
40+
#### 2.1.1 - Device Creation
41+
42+
1. User authenticates via SSO to OpenBao through his Parsec client
43+
2. Parsec client generates a new opaque key
44+
3. Parsec client uploads opaque key to OpenBao
45+
4. Parsec client encrypts `LocalDevice` with the opaque key
46+
5. Parsec client saves `DeviceFileOpenBao` to local storage
47+
48+
#### 2.1.2 - Device Access
49+
50+
1. Client reads `DeviceFileOpenBao` from local storage
51+
2. User authenticates via SSO to OpenBao (if not already authenticated)
52+
3. Client fetches the opaque key from OpenBao
53+
4. Client decrypts `LocalDevice` using the retrieved opaque key
54+
55+
### 2.2 - OpenBao info storage strategy
56+
57+
To fetch/upload an OpenBao secret we need multiple things:
58+
59+
1. The address of the OpenBao server.
60+
2. The authentication to use (e.g. "OIDC SSO with Github as identity provider").
61+
3. The mount path of the authentication method (e.g. `auth/oidc/github`).
62+
4. The mount path of the secret store (e.g. `secrets/parsec-keys`).
63+
5. The path of the secret within the secret store.
64+
65+
However all those info are not stored in (and hence obtained from) the device
66+
keys file since it would make them complex to change in the future.
67+
68+
So instead the OpenBao server configuration (i.e. server address, list of
69+
supported authentication methods, mount paths) is to be obtained from the
70+
Parsec server each time we need to load this device keys file.
71+
72+
## 3 - Data model
73+
74+
### 3.1 - New `DeviceFileOpenBao` schema
75+
76+
```json5
77+
{
78+
// ⚠️ Note the device file (i.e. the stuff defined by this schema!) is not
79+
// stored on OpenBao.
80+
// Instead it is encrypted by the ciphertext key that is itself stored on
81+
// OpenBao.
82+
// This way getting access to the device private keys require both exfiltrating
83+
// the secret stored on OpenBao AND the device file stored on the end user's machine.
84+
"label": "DeviceFileOpenBao",
85+
"type": "openbao",
86+
"other_fields": [
87+
... // Common device file fields: created_on/organization_id/human_handle/etc.
88+
{
89+
// `LocalDevice` encrypted with a secret key which is itself stored
90+
// on the OpenBao server.
91+
"name": "ciphertext",
92+
"type": "Bytes"
93+
},
94+
{
95+
// Arbitrary field only used by the GUI.
96+
//
97+
// In practice, it is expected to contain a `OpenBaoAuthType`
98+
// corresponding to the authentication method that have been used
99+
// to authenticate to OpenBao during the creation of this device keys file.
100+
//
101+
// The idea here is to allow the GUI to use this again during subsequent
102+
// access of this device keys file in order to pre-select the
103+
// authentication method that should be used.
104+
//
105+
// Note we use a string instead of directly a `OpenBaoAuthType` for backward
106+
// compatibility (given, even if the auth ID is unknown, we could still
107+
// be able to decrypt this device file if the user can authenticate to
108+
// OpenBao using a different SSO auth).
109+
"name": "openbao_preferred_auth_id",
110+
"type": "String"
111+
},
112+
{
113+
// Entity ID basically correspond to an account ID in OpenBao.
114+
// So the GUI should authenticate as this entity in OpenBao in order
115+
// to be able to fetch the secret containing the ciphertext key.
116+
"name": "openbao_entity_id",
117+
"type": "String"
118+
},
119+
{
120+
// The ciphertext key is stored in OpenBao as a secret that is has
121+
// for path `<entity_id>/<ciphertext key UUID>`.
122+
//
123+
// Note we don't just use the ciphertext key UUID as path since OpenBao
124+
// is expected to be configured with path-based access policy (i.e.
125+
// a given entity is only allowed to access the secrets starting with
126+
// its entity ID).
127+
"name": "openbao_ciphertext_key_path",
128+
"type": "String"
129+
}
130+
]
131+
}
132+
```
133+
134+
### 3.2 - OpenBao Secret Format
135+
136+
The opaque key is stored in OpenBao as [a KV v2 secret](https://openbao.org/api-docs/secret/kv/kv-v2/)
137+
with the following structure:
138+
139+
```json
140+
{
141+
"data": {
142+
"opaque_key": "<secret key as base64>"
143+
}
144+
}
145+
```
146+
147+
## 4 - Protocol
148+
149+
### 4.1 - Server Configuration API
150+
151+
See [RFC 1022](1022-server-config-api.md)
152+
153+
## 5 - Security Considerations
154+
155+
### 5.1 - Threat Model
156+
157+
**Protected Against:**
158+
159+
- Compromise of user's local machine (device file alone is useless)
160+
- Compromise of OpenBao server (opaque keys alone don't reveal device private keys)
161+
- Loss of user credentials (device file remains on machine)
162+
163+
**Requires Additional Protection:**
164+
165+
- Simultaneous compromise of both user machine and SSO credentials
166+
- Admin-level access to both Parsec server and OpenBao server
167+
168+
### 5.2 - Access Control
169+
170+
- OpenBao policies enforce entity-based path restrictions
171+
- Each user can only access secrets under their entity ID
172+
- Authentication requires valid SSO credentials
173+
- Opaque keys are generated per-device and cannot be reused
174+
175+
### 5.3 - Audit & Monitoring
176+
177+
Organizations can leverage OpenBao's audit capabilities to:
178+
179+
- Monitor access to device encryption keys
180+
- Detect unusual access patterns
181+
- Maintain compliance with security policies

0 commit comments

Comments
 (0)