blob: cdd17fbb6a039401d9d5d7e5531bb9845dd59404 [file] [log] [blame]
// 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;
}