| // Copyright 2016 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. |
| |
| syntax = "proto3"; |
| |
| package tokenserver.minter; |
| |
| option go_package = "minter"; |
| |
| import "google/protobuf/timestamp.proto"; |
| |
| import "go.chromium.org/luci/server/auth/delegation/messages/delegation.proto"; |
| import "go.chromium.org/luci/tokenserver/api/machine_token.proto"; |
| |
| |
| // Supported ways of singing the request. |
| enum SignatureAlgorithm { |
| UNKNOWN_ALGO = 0; // used if the field is not initialized |
| SHA256_RSA_ALGO = 1; // matches x509's sha256WithRSAEncryption |
| } |
| |
| |
| // Possible kinds of fatal errors. |
| // |
| // Non fatal errors are returned as grpc.Internal errors instead. |
| enum ErrorCode { |
| SUCCESS = 0; |
| UNSUPPORTED_SIGNATURE = 1; // used signature_algorithm is not supported |
| UNSUPPORTED_TOKEN_TYPE = 2; // requested token_type is not supported |
| BAD_TIMESTAMP = 3; // issued_at field is wrong |
| BAD_CERTIFICATE_FORMAT = 4; // malformed or unsupported certificate |
| BAD_SIGNATURE = 5; // signature doesn't match or can't be verified |
| UNTRUSTED_CERTIFICATE = 6; // invalid certificate or can't verify it yet |
| BAD_TOKEN_ARGUMENTS = 7; // FQDN or Scopes are invalid or not whitelisted |
| MACHINE_TOKEN_MINTING_ERROR = 8; // unspecified fatal error when minting a machine token |
| } |
| |
| |
| // TokenMinter implements main API of the token server. |
| // |
| // It provides an interface for generating: |
| // |
| // * Machine tokens: short lived stateless tokens used in Swarming bot |
| // authentication protocol. They are derived from PKI keys deployed on bots, |
| // and consumed primarily by Swarming. See MintMachineToken. |
| // |
| // * Delegation tokens: these are involved whenever a service calls other |
| // service on behalf of a user. They are passed via 'X-Delegation-Token-V1' |
| // HTTP header along with a credentials of the impersonating user. |
| // See MintDelegationToken. |
| // |
| // * OAuth2 token grants: they are signed assertions that particular |
| // services are allowed to grab service account OAuth2 tokens on behalf |
| // of particular end users. They are used in Swarming service accounts |
| // implementation. See MintOAuthTokenGrant and MintOAuthTokenViaGrant. |
| // |
| // * OAuth2 access tokens: these are regular Google OAuth2 access tokens |
| // associated with various service accounts. See MintOAuthTokenGrant |
| // and MintOAuthTokenViaGrant. |
| service TokenMinter { |
| // MintMachineToken generates a new token for an authenticated machine. |
| // |
| // It checks that provided certificate was signed by some trusted CA, and it |
| // is still valid (non-expired and hasn't been revoked). It then checks that |
| // the request was signed by the corresponding private key. Finally it checks |
| // that the caller is authorized to generate requested kind of token. |
| // |
| // If everything checks out, it generates and returns a new machine token. |
| // |
| // On fatal error it returns detailed error response via same |
| // MintMachineTokenResponse. On transient errors it returns generic |
| // grpc.Internal error. |
| rpc MintMachineToken(MintMachineTokenRequest) returns (MintMachineTokenResponse); |
| |
| // MintDelegationToken generates a new bearer delegation token. |
| // |
| // Such token can be sent in 'X-Delegation-Token-V1' header (alongside regular |
| // credentials like OAuth2 access token) to convey that the caller should be |
| // authentication as 'delegated_identity' specified in the token. |
| // |
| // The delegation tokens are subject to multiple restrictions (embedded in |
| // the token): |
| // * They have expiration time. |
| // * They are usable only if presented with a credential of someone from |
| // the 'audience' list. |
| // * They are usable only on services specified in the 'services' list. |
| // |
| // The token server must be configured in advance with all expected |
| // combinations of (caller identity, delegated identity, audience, service) |
| // tuples. See DelegationRule in config.proto. |
| rpc MintDelegationToken(MintDelegationTokenRequest) returns (MintDelegationTokenResponse); |
| |
| // MintOAuthTokenGrant generates a new grant for getting an OAuth2 token. |
| // |
| // This is a special (opaque for clients) token that asserts that the caller |
| // at the time of the call was allowed to act as a particular service account |
| // to perform a task authorized by an end-user. |
| // |
| // The returned grant can be used later (when the end-user is no longer |
| // present) to get a real OAuth2 access token via MintOAuthTokenViaGrant call. |
| // |
| // This pair of RPCs is used to "delay" generation of service account OAuth |
| // token until some later time, when it is actually needed. This is used by |
| // Swarming: |
| // 1. When the task is posted, Swarming calls MintOAuthTokenGrant to verify |
| // that the end-user is allowed to act as the requested service account |
| // on Swarming. On success, Swarming stores the grant in the task |
| // metadata. |
| // 2. At a later time, when the task is executing and it needs an access |
| // token, Swarming calls MintOAuthTokenViaGrant to convert the grant into |
| // a real OAuth2 token. |
| // |
| // The returned grant can be used multiple times (as long as its validity |
| // duration and the token server policy allows). |
| // |
| // The token server must be configured in advance with all expected |
| // combinations of (caller identity, service account name, end users) tuples. |
| // See ServiceAccountRule in config.proto. |
| // |
| // MintOAuthTokenGrant will check that the requested usage is allowed by the |
| // rules. Later, MintOAuthTokenViaGrant will recheck this too. |
| rpc MintOAuthTokenGrant(MintOAuthTokenGrantRequest) returns (MintOAuthTokenGrantResponse); |
| |
| // MintOAuthTokenViaGrant converts an OAuth2 token grant into an access token. |
| // |
| // The grant must be previously generated by MintOAuthTokenGrant function, see |
| // its docs for more details. |
| rpc MintOAuthTokenViaGrant(MintOAuthTokenViaGrantRequest) returns (MintOAuthTokenViaGrantResponse); |
| |
| // MintProjectToken mints an OAuth2 identity token that represents an identity |
| // associated with a LUCI project. |
| // |
| // Project-scoped tokens prevent accidental cross-project identity confusion |
| // when LUCI services access project specific resources such as a source code |
| // repository. |
| rpc MintProjectToken(MintProjectTokenRequest) returns (MintProjectTokenResponse); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Machine tokens. |
| |
| |
| // MintMachineTokenRequest wraps a serialized and signed MachineTokenRequest |
| // message. |
| message MintMachineTokenRequest { |
| // The protobuf-serialized MachineTokenRequest message, signed by the private |
| // key that matches MachineTokenRequest.certificate. |
| // |
| // We have to send it as a byte blob to avoid dealing with possible protobuf |
| // serialization inconsistencies when checking the signature. |
| bytes serialized_token_request = 1; |
| |
| // The signature of 'serialized_token_parameters' blob. |
| // |
| // See MachineTokenRequest.signature_algorithm for exact meaning. |
| bytes signature = 2; |
| } |
| |
| |
| // MachineTokenRequest contains the actual request parameters. |
| message MachineTokenRequest { |
| reserved 5; |
| |
| // The certificate that identifies a caller (as ASN1-serialized blob). |
| // |
| // It will be used to extract machine FQDN (it's CN of the cert) and CA name |
| // to use to check the cert. |
| bytes certificate = 1; |
| |
| // The signature algorithm used to sign this request. |
| // |
| // Defines what's in MintMachineTokenRequest.signature field. |
| SignatureAlgorithm signature_algorithm = 2; |
| |
| // Timestamp when this request was created, by the issuer clock. |
| google.protobuf.Timestamp issued_at = 3; |
| |
| // The token type being requested. |
| // |
| // Defines what fields of the response are set. |
| MachineTokenType token_type = 4; |
| } |
| |
| |
| // MintMachineTokenResponse is returned by MintMachineToken if the server |
| // processed the request. |
| // |
| // It's returned even if server refuses to mint a token. It contains the error |
| // details in that case. |
| message MintMachineTokenResponse { |
| // Possible kinds of fatal errors. |
| // |
| // Non fatal errors are returned as grpc.Internal errors instead. |
| ErrorCode error_code = 1; |
| |
| // Optional detailed error message. |
| string error_message = 2; |
| |
| // On success (SUCCESS error code) contains the produced token. |
| MachineTokenResponse token_response = 3; |
| |
| // Identifier of the service and its version that produced the response. |
| // |
| // Set for both successful responses and errors. On success, it is identical |
| // to token_response.service_version. |
| string service_version = 4; |
| } |
| |
| |
| // MachineTokenResponse contains a token requested by MachineTokenRequest. |
| message MachineTokenResponse { |
| reserved 1, 20; |
| |
| // Identifier of the service and its version that produced the token. |
| // |
| // Has the form "<app-id>/<module-version>". Reported to the monitoring by |
| // the client. This is _not_ a part of the token. |
| string service_version = 2; |
| |
| // The generated token. |
| // |
| // The exact field set here depends on a requested type of the token, see |
| // MachineTokenRequest.token_type. |
| oneof token_type { |
| LuciMachineToken luci_machine_token = 21; |
| } |
| } |
| |
| |
| // LuciMachineToken is short lived machine token. |
| // |
| // It is understood only by LUCI backends. It is a bearer token, that embeds |
| // machine hostname and details about the machine certificate it was issued for. |
| // It has short lifetime (usually 1h). |
| // |
| // It is expected to be sent to backends in 'X-Luci-Machine-Token' HTTP header. |
| // |
| // The token here is supposed to be treated as an opaque base64-encoded blob, |
| // but in reality it is serialized MachineTokenEnvelope, see machine_token.proto |
| // and read the comment there for more info about the token format. |
| message LuciMachineToken { |
| string machine_token = 1; // the actual token |
| google.protobuf.Timestamp expiry = 2; // when the token expires |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Delegation tokens. |
| |
| |
| // MintDelegationTokenRequest is passed to MintDelegationToken. |
| message MintDelegationTokenRequest { |
| // Identity whose authority is delegated. |
| // |
| // A string of the form "user:<email>" or a special token "REQUESTOR" that |
| // means to delegate caller's own identity. The token server will check its |
| // ACLs to make sure the caller is authorized to impersonate this identity. |
| // |
| // Required. |
| string delegated_identity = 1; |
| |
| // How long the token should be considered valid (in seconds). |
| // |
| // Default is 3600 sec. |
| int64 validity_duration = 2; |
| |
| // Who will be able to use the new token. |
| // |
| // Each item can be an identity string (e.g. "user:<email>"), a "group:<name>" |
| // string, special "*" string which means "Any bearer can use the token", or |
| // "REQUESTOR" string which means "Whoever is making this call can use the |
| // token". |
| // |
| // This is semantically is a set, the order of elements doesn't matter. |
| // |
| // Required. |
| repeated string audience = 3; |
| |
| // What services should accept the new token. |
| // |
| // List of LUCI services (specified as service identities, e.g. |
| // "service:app-id" or as https:// root URLs e.g. "https://<host>") that |
| // should accept this token. May also contain special "*" string, which |
| // means "All LUCI services". |
| // |
| // This is semantically is a set, the order of elements doesn't matter. |
| // |
| // Required. |
| repeated string services = 4; |
| |
| // Optional reason why the token is created. |
| // |
| // Used only for logging and auditing purposes. Doesn't become part of the |
| // token. |
| string intent = 5; |
| |
| // Arbitrary key:value pairs embedded into the token by whoever requested it. |
| // Convey circumstance of why the token is created. |
| // |
| // Services that accept the token may use them for additional authorization |
| // decisions. Please use extremely carefully, only when you control both sides |
| // of the delegation link and can guarantee that services involved understand |
| // the tags. |
| repeated string tags = 6; |
| } |
| |
| |
| // MintDelegationTokenResponse is returned by MintDelegationToken on success. |
| // |
| // Errors are returned via standard gRPC codes. |
| message MintDelegationTokenResponse { |
| // The actual base64-encoded signed token. |
| string token = 1; |
| |
| // Same data as in 'token' in deserialized form, just for convenience. |
| // |
| // Mostly for JSON encoding users, since they may not understand proto-encoded |
| // tokens. |
| messages.Subtoken delegation_subtoken = 2; |
| |
| // Identifier of the service and its version that produced the token. |
| // |
| // Has the form "<app-id>/<module-version>". This is _not_ part of the token. |
| // Used only for logging and monitoring. |
| string service_version = 3; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // OAuth2 access token grants and OAuth2 service account access tokens. |
| |
| |
| // MintOAuthTokenGrantRequest is passed to MintOAuthTokenGrant. |
| // |
| // Additional implicit field is the identity of whoever makes this call. It |
| // becomes 'wielder_identity' of the generated token. |
| message MintOAuthTokenGrantRequest { |
| // Service account identity the end user wants to act as. |
| // |
| // A string of the form "user:<email>". |
| // |
| // Required. |
| string service_account = 1; |
| |
| // How long the generated grant should be considered valid (in seconds). |
| // |
| // Default is 3600 sec. |
| int64 validity_duration = 2; |
| |
| // An end user that wants to act as the service account (perhaps indirectly). |
| // |
| // A string of the form "user:<email>". On Swarming, this is an identity of |
| // a user that posted the task. |
| // |
| // TODO(vadimsh): Verify that this user is present during MintOAuthTokenGrant |
| // RPC by requiring the end user's credentials, e.g make Swarming forward |
| // user's OAuth token to the token server, where it can be validated. |
| // |
| // Required. |
| string end_user = 3; |
| |
| // Arbitrary key:value pairs describing circumstances of this call. |
| // |
| // Used only for logging and auditing purposes. Not involved in authorization |
| // and don't become part of the grant. |
| repeated string audit_tags = 4; |
| } |
| |
| |
| // MintOAuthTokenGrantResponse is returned by MintOAuthTokenGrant. |
| message MintOAuthTokenGrantResponse { |
| string grant_token = 1; // an opaque urlsafe token |
| google.protobuf.Timestamp expiry = 2; // when this token expires |
| |
| // Identifier of the service and its version that produced the token. |
| // |
| // Has the form "<app-id>/<module-version>". This is _not_ part of the token. |
| // Used only for logging and monitoring. |
| string service_version = 3; |
| } |
| |
| |
| // MintOAuthTokenViaGrantRequest is passed to MintOAuthTokenViaGrant. |
| // |
| // Additional implicit field is the identity of whoever makes this call. It is |
| // compared against 'wielder_identity' inside the token. |
| message MintOAuthTokenViaGrantRequest { |
| // A previously generated grant, as returned by MintOAuthTokenGrant. |
| string grant_token = 1; |
| |
| // The list of OAuth scopes the access token should have. |
| // |
| // The server may reject the request if some scopes are not allowed. |
| repeated string oauth_scope = 2; |
| |
| // Minimally accepted validity duration of the returned OAuth token (seconds). |
| // |
| // The server may return a token that lives longer than this. The maximum is |
| // 1h. An attempt to get a token that lives longer than 1h will result in |
| // an error. |
| // |
| // The returned token validity duration doesn't depend on the lifetime of |
| // the grant: it's possible to use a grant that expires in 1 sec to get an |
| // access token that lives for 1h. |
| // |
| // Default is 300 sec. |
| int64 min_validity_duration = 3; |
| |
| // Arbitrary key:value pairs describing circumstances of this call. |
| // |
| // Used only for logging and auditing purposes. Not involved in authorization. |
| repeated string audit_tags = 4; |
| } |
| |
| |
| // MintOAuthTokenViaGrantResponse is returned by MintOAuthTokenViaGrant. |
| message MintOAuthTokenViaGrantResponse { |
| string access_token = 1; // service account OAuth2 access token |
| google.protobuf.Timestamp expiry = 2; // when this token expires |
| |
| // Identifier of the service and its version that produced the token. |
| // |
| // Has the form "<app-id>/<module-version>". Used only for logging and |
| // monitoring. |
| string service_version = 3; |
| } |
| |
| |
| // MintProjectTokenRequest is passed to MintProjectToken. |
| message MintProjectTokenRequest { |
| // Luci project to which this token will be bound. |
| string luci_project = 1; |
| |
| // Requested OAuth scopes for the token. |
| repeated string oauth_scope = 2; |
| |
| // Minimum token validity duration in seconds. |
| int64 min_validity_duration = 3; |
| |
| // Arbitrary key:value pairs describing circumstances of this call. |
| // |
| // Used only for logging and auditing purposes. Not involved in authorization. |
| repeated string audit_tags = 4; |
| } |
| |
| |
| // MintProjectTokenResponse is returned by MintProjectToken. |
| message MintProjectTokenResponse { |
| // Full service account email. |
| string service_account_email = 1; |
| |
| // OAuth access token. |
| string access_token = 2; |
| |
| // Token expiration timestamp. |
| google.protobuf.Timestamp expiry = 3; |
| |
| // Identifier of the service and its version that produced the token. |
| // |
| // Has the form "<app-id>/<module-version>". Used only for logging and |
| // monitoring. |
| string service_version = 4; |
| } |
| |