mirrored from https://chromium.googlesource.com/infra/luci/luci-py
-
Notifications
You must be signed in to change notification settings - Fork 35
/
replication.proto
317 lines (266 loc) · 11 KB
/
replication.proto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
// Copyright 2014 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
// Messages for Primary <-> Replica auth DB replication protocol.
// Used from both Primary side (i.e. auth_service) and Replica side (any service
// that uses auth component).
syntax = "proto3";
package components.auth;
import "components/auth/proto/realms.proto";
option go_package = "go.chromium.org/luci/server/auth/service/protocol;protocol";
////////////////////////////////////////////////////////////////////////////////
// Linking protocol, used to associate Replicas with Primary.
//
// Overall protocol flow:
// 1. Primary generates and serializes ServiceLinkTicket message (via
// /auth_service/api/v1/services/<app id>/linking_url call).
// 2. ServiceLinkTicket is passed to Replica as GET parameter in /auth/link
// endpoint accessible only to GAE-level administrators of Replica instance.
// 3. Replica sends ServiceLinkRequest to Primary via direct service <-> service
// URLFetch HTTP POST to /auth_service/api/v1/internal/link_replica.
// 4. Primary registers the replica, and replies with ServiceLinkResponse.
// 5. Replica registers the primary.
//
// Implementations:
// * Replica side: components/auth/ui/ui.py
// * Primary side: services/auth_service/frontend/handlers.py
// Generated by Primary, passed to Replica to initiate linking process.
message ServiceLinkTicket {
// GAE application ID of Primary that generated this ticket. Replica will send
// ServiceLinkRequest to this service when it processes the ticket.
string primary_id = 1;
// URL to the root page of a primary service, i.e. https://<...>.appspot.com.
// Useful when testing on dev appserver and on non-default version.
string primary_url = 2;
// Identity of a user that generated this ticket.
string generated_by = 3;
// Opaque blob passed back to Primary in ServiceLinkRequest. Its exact
// structure is an implementation detail of Primary. It contains app_id of
// a replica this ticket is intended for, timestamp and HMAC tag.
bytes ticket = 4;
}
// Sent from Replica to Primary via direct service <-> service HTTP call,
// replicas app_id would be available via X-Appengine-Inbound-Appid header.
message ServiceLinkRequest {
// Same ticket that was passed to Replica via ServiceLinkTicket.
bytes ticket = 1;
// URL to use when making requests to Replica from Primary.
string replica_url = 2;
// Identity of a user that accepted the ticket and initiated this request.
string initiated_by = 3;
}
// Primary's response to ServiceLinkRequest. Always returned with HTTP code 200.
message ServiceLinkResponse {
// Status codes.
enum Status {
// The service is now linked and primary will be pushing updates to it.
SUCCESS = 0;
// Primary do not replies.
TRANSPORT_ERROR = 1;
// Linking ticket is invalid or expired.
BAD_TICKET = 2;
// Linking ticket was generated for another app, not the calling one.
AUTH_ERROR = 3;
}
Status status = 1;
}
////////////////////////////////////////////////////////////////////////////////
// Main replication protocol. Used to push AuthDB from Primary to Replicas.
// Some user group. Corresponds to AuthGroup entity in model.py.
message AuthGroup {
// Name of the group.
string name = 1;
// List of members that are explicitly in this group.
repeated string members = 2;
// List of identity-glob expressions (like 'user:*@example.com').
repeated string globs = 3;
// List of nested group names.
repeated string nested = 4;
// Human readable description.
string description = 5;
// When the group was created. Microseconds since epoch.
int64 created_ts = 6;
// Who created the group.
string created_by = 7;
// When the group was modified last time. Microseconds since epoch.
int64 modified_ts = 8;
// Who modified the group last time.
string modified_by = 9;
// A name of the group that can modify or delete this group.
string owners = 10;
}
// A named set of whitelisted IP addresses. Corresponds to AuthIPWhitelist
// entity in model.py.
message AuthIPWhitelist {
// Name of the IP whitelist.
string name = 1;
// The list of IP subnets.
repeated string subnets = 2;
// Human readable description.
string description = 3;
// When the list was created. Microseconds since epoch.
int64 created_ts = 4;
// Who created the list.
string created_by = 5;
// When the list was modified. Microseconds since epoch.
int64 modified_ts = 6;
// Who modified the list the last time.
string modified_by = 7;
}
// A pair (identity, IP whitelist name) plus some metadata. Corresponds to
// AuthIPWhitelistAssignments.Assignment model in model.py.
message AuthIPWhitelistAssignment {
// Identity name to limit by IP whitelist.
string identity = 1;
// Name of IP whitelist to use (see AuthIPWhitelist).
string ip_whitelist = 2;
// Why the assignment was created.
string comment = 3;
// When the assignment was created. Microseconds since epoch.
int64 created_ts = 4;
// Who created the assignment.
string created_by = 5;
}
// An entire database of auth configuration that is being replicated.
message AuthDB {
// Next use: 12
reserved 5; // used to be 'secrets', no longer used
reserved 10; // used to be 'buckets', was never used
// OAuth2 client_id to use to mint new OAuth2 tokens.
string oauth_client_id = 1;
// OAuth2 client secret. Not so secret really, since it's passed to clients.
string oauth_client_secret = 2;
// Additional OAuth2 client_ids allowed to access the services.
repeated string oauth_additional_client_ids = 3;
// All groups.
repeated AuthGroup groups = 4;
// All IP whitelists.
repeated AuthIPWhitelist ip_whitelists = 6;
// Mapping 'account -> IP whitlist to use for that account'.
repeated AuthIPWhitelistAssignment ip_whitelist_assignments = 7;
// URL of a token server to use to generate delegation tokens.
string token_server_url = 8;
// Serialized security_config.SecurityConfig proto with security-related
// configuration to distribute across all services.
//
// It is distributed in a serialized form to make sure old services ingest it
// fully, even if they don't understand some SecurityConfig proto fields
// (yet). As soon as their code is updated, they SHOULD start using all
// SecurityConfig fields, without waiting for another push from Auth Service.
//
// If we use SecurityConfig directly here, old services would just drop fields
// they don't understand when accepting an AuthDB push.
bytes security_config = 9;
// Definition of all known permissions and realms in a LUCI deployment.
//
// It is ultimately used by LUCI services for authorizing access to resources.
// See realms.proto for more details.
realms.Realms realms = 11;
}
// Information about some particular revision of auth DB.
message AuthDBRevision {
// GAE App ID of a service holding primary copy of Auth DB.
string primary_id = 1;
// Revision of Auth DB being pushed.
int64 auth_db_rev = 2;
// Timestamp of that revision by Primary's clock, microseconds since epoch.
int64 modified_ts = 3;
}
// SignedAuthDB contains serialized and signed AuthDB proto.
//
// It is used to store AuthDB snapshots in Google Storage. Signing is used as
// a defense against unauthorized writes to the storage bucket.
message SignedAuthDB {
// Serialized ReplicationPushRequest message with actual data.
//
// Contains revision information and AuthDB itself.
bytes auth_db_blob = 1;
// Service account name whose key was used to sign the AuthDB blob.
string signer_id = 2;
// ID of the signing key.
string signing_key_id = 3;
// The signature of auth_db_blob field.
//
// It is RS256(SHA512(auth_db_blob)).
//
// Where:
// * RS256 is RSASSA-PKCS1-v1_5 using SHA-256, see RS256 algo in RFC7518.
// * SHA512 is a byte string (64 bytes) with SHA-512 digest of its input.
//
// Such peculiar structure is due to limitations of GAE signing infrastructure
// (RS256 function can accept at most 8KB of input).
//
// Consumers of SignedAuthDB are expected to do the following:
// 1. Check 'signer_id' is what they expect.
// 2. Use https://www.googleapis.com/service_accounts/v1/metadata/x509/...
// endpoint to get the signer's public key with ID 'signing_key_id'.
// 3. Construct to-be-signed string as SHA512(auth_db_blob).
// 4. Verify 'signature' matches to-be-signed string using the public key
// from step 2.
bytes signature = 4;
}
// Published by Primary into 'auth-db-changed' PubSub topic. The body of the
// message is base64 encoded serialized ChangeNotification. Additional
// attributes are:
// X-AuthDB-SigKey-v1: <id of a public key>
// X-AuthDB-SigVal-v1: <base64 encoded RSA-SHA256(blob) signature>
message ChangeNotification {
// New revision of the AuthDB.
AuthDBRevision revision = 1;
}
// Sent from Primary to Replica to update Replica's AuthDB.
//
// Primary signs the entire serialized message with its private key and appends
// two headers to HTTP request that carries the blob:
// X-AuthDB-SigKey-v1: <id of a public key>
// X-AuthDB-SigVal-v1: <base64 encoded RSA-SHA256(SHA512(blob)) signature>
//
// Binary serialization of ReplicationPushRequest is sometimes misleadingly
// called "AuthDB blob". It is stored in Datastore (as is) and in Google Storage
// (as serialized SignedAuthDB) for consumers that do not use Primary -> Replica
// protocol.
message ReplicationPushRequest {
// Revision that is being pushed.
AuthDBRevision revision = 1;
// An entire database of auth configuration for specific revision.
AuthDB auth_db = 2;
// Version of 'auth' component on Primary, see components/auth/version.py.
string auth_code_version = 3;
}
// Replica's response to ReplicationPushRequest.
message ReplicationPushResponse {
// Overall status of the operation.
enum Status {
// Replica accepted the push request and updated its copy of auth db.
APPLIED = 0;
// Replica has a newer version of AuthDB, the push request is skipped.
SKIPPED = 1;
// Non fatal error happened, the push request may be retried.
TRANSIENT_ERROR = 2;
// Fatal error happened, the push request must not be retried.
FATAL_ERROR = 3;
}
// Error codes, for TRANSIENT_ERROR and FATAL_ERROR statuses.
enum ErrorCode {
// Some unrecognized error.
ERROR_UNKNOWN = 0;
// Trying to push an update to service that is not a replica.
NOT_A_REPLICA = 1;
// Replica doesn't know about the service that pushing the update.
FORBIDDEN = 2;
// Signature headers are missing.
MISSING_SIGNATURE = 3;
// Signature is not valid.
BAD_SIGNATURE = 4;
// Format of the request is not valid.
BAD_REQUEST = 5;
}
// Overall status of the operation.
Status status = 1;
// Revision known by Replica (set for APPLIED and SKIPPED statuses).
AuthDBRevision current_revision = 2;
// Present for TRANSIENT_ERROR and FATAL_ERROR statuses.
ErrorCode error_code = 3;
// Version of 'auth' component on Replica, see components/auth/version.py.
string auth_code_version = 4;
}