Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 syntax = "proto3"; | 5 syntax = "proto3"; |
| 6 | 6 |
| 7 package tokenserver.minter; | 7 package tokenserver.minter; |
| 8 | 8 |
| 9 import "google/protobuf/timestamp.proto"; | 9 import "google/protobuf/timestamp.proto"; |
| 10 | 10 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 30 BAD_CERTIFICATE_FORMAT = 4; // malformed or unsupported certificate | 30 BAD_CERTIFICATE_FORMAT = 4; // malformed or unsupported certificate |
| 31 BAD_SIGNATURE = 5; // signature doesn't match or can't be verifi ed | 31 BAD_SIGNATURE = 5; // signature doesn't match or can't be verifi ed |
| 32 UNTRUSTED_CERTIFICATE = 6; // invalid certificate or can't verify it yet | 32 UNTRUSTED_CERTIFICATE = 6; // invalid certificate or can't verify it yet |
| 33 BAD_TOKEN_ARGUMENTS = 7; // FQDN or Scopes are invalid or not whitelis ted | 33 BAD_TOKEN_ARGUMENTS = 7; // FQDN or Scopes are invalid or not whitelis ted |
| 34 MACHINE_TOKEN_MINTING_ERROR = 8; // unspecified fatal error when minting a mac hine token | 34 MACHINE_TOKEN_MINTING_ERROR = 8; // unspecified fatal error when minting a mac hine token |
| 35 } | 35 } |
| 36 | 36 |
| 37 | 37 |
| 38 // TokenMinter implements main API of the token server. | 38 // TokenMinter implements main API of the token server. |
| 39 // | 39 // |
| 40 // It provides an interface for generating and inspecting of: | 40 // It provides an interface for generating: |
| 41 // | 41 // |
| 42 // * Machine tokens: short lived stateless tokens used in Swarming bot | 42 // * Machine tokens: short lived stateless tokens used in Swarming bot |
| 43 // authentication protocol. They are derived from PKI keys deployed on bots, | 43 // authentication protocol. They are derived from PKI keys deployed on bots, |
| 44 // and consumed primarily by Swarming. | 44 // and consumed primarily by Swarming. See MintMachineToken. |
| 45 // | 45 // |
| 46 // * Delegation tokens: these are involved whenever something wants to act on | 46 // * Delegation tokens: these are involved whenever something wants to act on |
| 47 // behalf of something else. In particular, whenever a service calls other | 47 // behalf of something else. In particular, whenever a service calls other |
| 48 // service on behalf of a user, or when a user posts a Swarming task that | 48 // service on behalf of a user, or when a user posts a Swarming task that |
| 49 // runs in a context of some service account. There are multiple kinds of | 49 // runs in a context of some service account. They passed via |
| 50 // delegation tokens: | 50 // 'X-Delegation-Token-V1' HTTP header and can be used to "impersonate" |
| 51 // - Bearer delegation tokens: they passed via 'X-Delegation-Token-V1' | 51 // a caller. See MintDelegationToken. |
| 52 // HTTP header and can be used to "impersonate" the identity of a caller. | |
| 53 // - OAuth2 token grants: they are signed assertions that particular | |
|
Vadim Sh.
2017/03/30 06:04:48
After long consideration I decided to make "oauth2
| |
| 54 // services are allowed to grab service account OAuth2 tokens. They are | |
| 55 // used in Swarming service accounts implementation. This is TODO. | |
| 56 // | 52 // |
| 57 // * OAuth2 tokens: these are regular Google OAuth2 access tokens associated | 53 // * OAuth2 token grants: they are signed assertions that particular |
| 58 // with various service accounts (that the token server has | 54 // services are allowed to grab service account OAuth2 tokens on behalf |
| 59 // serviceAccountActor role in). This is TODO. | 55 // of particular end users. They are used in Swarming service accounts |
| 56 // implementation. See MintOAuthTokenGrant and MintOAuthTokenViaGrant. | |
| 57 // | |
| 58 // * OAuth2 access tokens: these are regular Google OAuth2 access tokens | |
| 59 // associated with various service accounts. See MintOAuthTokenGrant | |
| 60 // and MintOAuthTokenViaGrant. | |
| 60 service TokenMinter { | 61 service TokenMinter { |
| 61 // MintMachineToken generates a new token for an authenticated machine. | 62 // MintMachineToken generates a new token for an authenticated machine. |
| 62 // | 63 // |
| 63 // It checks that provided certificate was signed by some trusted CA, and it | 64 // It checks that provided certificate was signed by some trusted CA, and it |
| 64 // is still valid (non-expired and hasn't been revoked). It then checks that | 65 // is still valid (non-expired and hasn't been revoked). It then checks that |
| 65 // the request was signed by the corresponding private key. Finally it checks | 66 // the request was signed by the corresponding private key. Finally it checks |
| 66 // that the caller is authorized to generate requested kind of token. | 67 // that the caller is authorized to generate requested kind of token. |
| 67 // | 68 // |
| 68 // If everything checks out, it generates and returns a new machine token. | 69 // If everything checks out, it generates and returns a new machine token. |
| 69 // | 70 // |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 82 // the token): | 83 // the token): |
| 83 // * They have expiration time. | 84 // * They have expiration time. |
| 84 // * They are usable only if presented with a credential of someone from | 85 // * They are usable only if presented with a credential of someone from |
| 85 // the 'audience' list. | 86 // the 'audience' list. |
| 86 // * They are usable only on services specified in the 'services' list. | 87 // * They are usable only on services specified in the 'services' list. |
| 87 // | 88 // |
| 88 // The token server must be configured in advance with all expected | 89 // The token server must be configured in advance with all expected |
| 89 // combinations of (caller identity, delegated identity, audience, service) | 90 // combinations of (caller identity, delegated identity, audience, service) |
| 90 // tuples. See DelegationRule in config.proto. | 91 // tuples. See DelegationRule in config.proto. |
| 91 rpc MintDelegationToken(MintDelegationTokenRequest) returns (MintDelegationTok enResponse); | 92 rpc MintDelegationToken(MintDelegationTokenRequest) returns (MintDelegationTok enResponse); |
| 93 | |
| 94 // MintOAuthTokenGrant generates a new grant for getting an OAuth2 token. | |
|
Vadim Sh.
2017/03/30 06:04:48
This is the most important comment in this CL. It
| |
| 95 // | |
| 96 // This is a special (opaque for clients) token that asserts that the caller | |
| 97 // at the time of the call was allowed to act as a particular service account | |
| 98 // to perform a task authorized by an end-user. | |
| 99 // | |
| 100 // The returned grant can be used later (when the end-user is no longer | |
| 101 // present) to get a real OAuth2 access token via MintOAuthTokenViaGrant call. | |
| 102 // | |
| 103 // This pair of RPCs is used to "delay" generation of service account OAuth | |
| 104 // token until some later time, when it is actually needed. This is used by | |
| 105 // Swarming: | |
| 106 // 1. When the task is posted, Swarming calls MintOAuthTokenGrant to verify | |
| 107 // that the end-user is allowed to act as the requested service account | |
| 108 // on Swarming. On success, Swarming stores the grant in the task | |
| 109 // metadata. | |
| 110 // 2. At a later time, when the task is executing and it needs an access | |
| 111 // token, Swarming calls MintOAuthTokenViaGrant to convert the grant into | |
| 112 // a real OAuth2 token. | |
| 113 // | |
| 114 // The returned grant can be used multiple times (as long as its validity | |
| 115 // duration and the token server policy allows). | |
| 116 // | |
| 117 // The token server must be configured in advance with all expected | |
| 118 // combinations of (caller identity, service account name, end users) tuples. | |
| 119 // See ServiceAccountRule in config.proto. | |
| 120 // | |
| 121 // MintOAuthTokenGrant will check that the requested usage is allowed by the | |
| 122 // rules. Later, MintOAuthTokenViaGrant will recheck this too. | |
| 123 rpc MintOAuthTokenGrant(MintOAuthTokenGrantRequest) returns (MintOAuthTokenGra ntResponse); | |
| 124 | |
| 125 // MintOAuthTokenViaGrant converts an OAuth2 token grant into an access token. | |
| 126 // | |
| 127 // The grant must be previously generated by MintOAuthTokenGrant function, see | |
| 128 // its docs for more details. | |
| 129 rpc MintOAuthTokenViaGrant(MintOAuthTokenViaGrantRequest) returns (MintOAuthTo kenViaGrantResponse); | |
| 92 } | 130 } |
| 93 | 131 |
| 94 | 132 |
| 95 //////////////////////////////////////////////////////////////////////////////// | 133 //////////////////////////////////////////////////////////////////////////////// |
| 96 // Machine Tokens messages | 134 // Machine tokens. |
| 97 | 135 |
| 98 | 136 |
| 99 // MintMachineTokenRequest wraps a serialized and signed MachineTokenRequest | 137 // MintMachineTokenRequest wraps a serialized and signed MachineTokenRequest |
| 100 // message. | 138 // message. |
| 101 message MintMachineTokenRequest { | 139 message MintMachineTokenRequest { |
| 102 // The protobuf-serialized MachineTokenRequest message, signed by the private | 140 // The protobuf-serialized MachineTokenRequest message, signed by the private |
| 103 // key that matches MachineTokenRequest.certificate. | 141 // key that matches MachineTokenRequest.certificate. |
| 104 // | 142 // |
| 105 // We have to send it as a byte blob to avoid dealing with possible protobuf | 143 // We have to send it as a byte blob to avoid dealing with possible protobuf |
| 106 // serialization inconsistencies when checking the signature. | 144 // serialization inconsistencies when checking the signature. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 131 // Timestamp when this request was created, by the issuer clock. | 169 // Timestamp when this request was created, by the issuer clock. |
| 132 google.protobuf.Timestamp issued_at = 3; | 170 google.protobuf.Timestamp issued_at = 3; |
| 133 | 171 |
| 134 // The token type being requested. | 172 // The token type being requested. |
| 135 // | 173 // |
| 136 // Defines what fields of the response are set. | 174 // Defines what fields of the response are set. |
| 137 MachineTokenType token_type = 4; | 175 MachineTokenType token_type = 4; |
| 138 } | 176 } |
| 139 | 177 |
| 140 | 178 |
| 141 // MintMachineTokenResponse is returned by 'MintMachineToken' if the server | 179 // MintMachineTokenResponse is returned by MintMachineToken if the server |
| 142 // processed the request. | 180 // processed the request. |
| 143 // | 181 // |
| 144 // It's returned even if server refuses to mint a token. It contains the error | 182 // It's returned even if server refuses to mint a token. It contains the error |
| 145 // details in that case. | 183 // details in that case. |
| 146 message MintMachineTokenResponse { | 184 message MintMachineTokenResponse { |
| 147 // Possible kinds of fatal errors. | 185 // Possible kinds of fatal errors. |
| 148 // | 186 // |
| 149 // Non fatal errors are returned as grpc.Internal errors instead. | 187 // Non fatal errors are returned as grpc.Internal errors instead. |
| 150 ErrorCode error_code = 1; | 188 ErrorCode error_code = 1; |
| 151 | 189 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 194 // The token here is supposed to be treated as an opaque base64-encoded blob, | 232 // The token here is supposed to be treated as an opaque base64-encoded blob, |
| 195 // but in reality it is serialized MachineTokenEnvelope, see machine_token.proto | 233 // but in reality it is serialized MachineTokenEnvelope, see machine_token.proto |
| 196 // and read the comment there for more info about the token format. | 234 // and read the comment there for more info about the token format. |
| 197 message LuciMachineToken { | 235 message LuciMachineToken { |
| 198 string machine_token = 1; // the actual token | 236 string machine_token = 1; // the actual token |
| 199 google.protobuf.Timestamp expiry = 2; // when the token expires | 237 google.protobuf.Timestamp expiry = 2; // when the token expires |
| 200 } | 238 } |
| 201 | 239 |
| 202 | 240 |
| 203 //////////////////////////////////////////////////////////////////////////////// | 241 //////////////////////////////////////////////////////////////////////////////// |
| 204 // Delegation Tokens messages | 242 // Delegation tokens. |
| 205 | 243 |
| 206 | 244 |
| 207 // MintDelegationTokenRequest is passed to MintDelegationToken. | 245 // MintDelegationTokenRequest is passed to MintDelegationToken. |
| 208 message MintDelegationTokenRequest { | 246 message MintDelegationTokenRequest { |
| 209 // Identity whose authority is delegated. | 247 // Identity whose authority is delegated. |
| 210 // | 248 // |
| 211 // A string of the form "user:<email>" or a special token "REQUESTOR" that | 249 // A string of the form "user:<email>" or a special token "REQUESTOR" that |
| 212 // means to delegate caller's own identity. The token server will check its | 250 // means to delegate caller's own identity. The token server will check its |
| 213 // ACLs to make sure the caller is authorized to impersonate this identity. | 251 // ACLs to make sure the caller is authorized to impersonate this identity. |
| 214 // | 252 // |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 245 repeated string services = 4; | 283 repeated string services = 4; |
| 246 | 284 |
| 247 // Optional reason why the token is created. | 285 // Optional reason why the token is created. |
| 248 // | 286 // |
| 249 // Used only for logging and auditing purposes. Doesn't become part of the | 287 // Used only for logging and auditing purposes. Doesn't become part of the |
| 250 // token. | 288 // token. |
| 251 string intent = 5; | 289 string intent = 5; |
| 252 } | 290 } |
| 253 | 291 |
| 254 | 292 |
| 255 // MintDelegationTokenResponse is returned by 'MintDelegationToken' on success. | 293 // MintDelegationTokenResponse is returned by MintDelegationToken on success. |
| 256 // | 294 // |
| 257 // Errors are returned via standard gRPC codes. | 295 // Errors are returned via standard gRPC codes. |
| 258 message MintDelegationTokenResponse { | 296 message MintDelegationTokenResponse { |
| 259 // The actual base64-encoded signed token. | 297 // The actual base64-encoded signed token. |
| 260 string token = 1; | 298 string token = 1; |
| 261 | 299 |
| 262 // Same data as in 'token' in deserialized form, just for convenience. | 300 // Same data as in 'token' in deserialized form, just for convenience. |
| 263 // | 301 // |
| 264 // Mostly for JSON encoding users, since they may not understand proto-encoded | 302 // Mostly for JSON encoding users, since they may not understand proto-encoded |
| 265 // tokens. | 303 // tokens. |
| 266 messages.Subtoken delegation_subtoken = 2; | 304 messages.Subtoken delegation_subtoken = 2; |
| 267 | 305 |
| 268 // Identifier of the service and its version that produced the token. | 306 // Identifier of the service and its version that produced the token. |
| 269 // | 307 // |
| 270 // Has the form "<app-id>/<module-version>". This is _not_ part of the token. | 308 // Has the form "<app-id>/<module-version>". This is _not_ part of the token. |
| 309 // Used only for logging and monitoring. | |
| 271 string service_version = 3; | 310 string service_version = 3; |
| 272 } | 311 } |
| 312 | |
| 313 | |
| 314 //////////////////////////////////////////////////////////////////////////////// | |
| 315 // OAuth2 access token grants and OAuth2 service account access tokens. | |
| 316 | |
| 317 | |
| 318 // MintOAuthTokenGrantRequest is passed to MintOAuthTokenGrant. | |
| 319 // | |
| 320 // Additional implicit field is the identity of whoever makes this call. It | |
| 321 // becomes 'wielder_identity' of the generated token. | |
| 322 message MintOAuthTokenGrantRequest { | |
| 323 // Service account identity the end user wants to act as. | |
| 324 // | |
| 325 // A string of the form "user:<email>". | |
| 326 // | |
| 327 // Required. | |
| 328 string service_account = 1; | |
| 329 | |
| 330 // How long the generated grant should be considered valid (in seconds). | |
| 331 // | |
| 332 // Default is 3600 sec. | |
| 333 int64 validity_duration = 2; | |
| 334 | |
| 335 // An end user that wants to act as the service account (perhaps indirectly). | |
| 336 // | |
| 337 // A string of the form "user:<email>". On Swarming, this is an identity of | |
| 338 // a user that posted the task. | |
| 339 // | |
| 340 // TODO(vadimsh): Verify that this user is present during MintOAuthTokenGrant | |
| 341 // RPC by requiring the end user's credentials, e.g make Swarming forward | |
| 342 // user's OAuth token to the token server, where it can be validated. | |
| 343 // | |
| 344 // Required. | |
| 345 string end_user_identity = 3; | |
| 346 | |
| 347 // Optional reason why the grant is created. | |
| 348 // | |
| 349 // Used only for logging and auditing purposes. Doesn't become part of the | |
| 350 // grant. | |
| 351 string intent = 4; | |
| 352 } | |
| 353 | |
| 354 | |
| 355 // MintOAuthTokenGrantResponse is returned by MintOAuthTokenGrant. | |
| 356 message MintOAuthTokenGrantResponse { | |
| 357 string grant_token = 1; // base64-encoded token with the grant | |
| 358 google.protobuf.Timestamp expiry = 2; // when this token expires | |
| 359 | |
| 360 // Identifier of the service and its version that produced the token. | |
| 361 // | |
| 362 // Has the form "<app-id>/<module-version>". This is _not_ part of the token. | |
| 363 // Used only for logging and monitoring. | |
| 364 string service_version = 3; | |
| 365 } | |
| 366 | |
| 367 | |
| 368 // MintOAuthTokenViaGrantRequest is passed to MintOAuthTokenViaGrant. | |
| 369 // | |
| 370 // Additional implicit field is the identity of whoever makes this call. It is | |
| 371 // compared against 'wielder_identity' inside the token. | |
| 372 message MintOAuthTokenViaGrantRequest { | |
| 373 // A previously generated grant, as returned by MintOAuthTokenGrant. | |
| 374 string grant_token = 1; | |
| 375 | |
| 376 // The list of OAuth scopes the access token should have. | |
| 377 // | |
| 378 // The server may reject the request if some scopes are not allowed. | |
| 379 repeated string oauth_scopes = 2; | |
| 380 | |
| 381 // Minimally accepted validity duration of the returned OAuth token (seconds). | |
| 382 // | |
| 383 // The server may return a token that lives longer than this. The maximum is | |
| 384 // 1h. An attempt to get a token that lives longer will result in a error. | |
| 385 // | |
| 386 // The returned token validity duration doesn't not depend on the lifetime of | |
| 387 // the grant: it's possible to use a grant that expires in 1 sec to get an | |
| 388 // access token that lives for 1h. | |
| 389 // | |
| 390 // Default is 3600 sec. | |
| 391 int64 min_validity_duration = 3; | |
| 392 } | |
| 393 | |
| 394 | |
| 395 // MintOAuthTokenViaGrantResponse is returned by MintOAuthTokenViaGrant. | |
| 396 message MintOAuthTokenViaGrantResponse { | |
| 397 string access_token = 1; // service account OAuth2 access token | |
| 398 google.protobuf.Timestamp expiry = 2; // when this token expires | |
| 399 | |
| 400 // Identifier of the service and its version that produced the token. | |
| 401 // | |
| 402 // Has the form "<app-id>/<module-version>". Used only for logging and | |
| 403 // monitoring. | |
| 404 string service_version = 3; | |
| 405 } | |
| OLD | NEW |