| // Copyright 2020 The Monogon Project Authors. | 
 | // | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | syntax = "proto3"; | 
 | package metropolis.proto.api; | 
 | option go_package = "source.monogon.dev/metropolis/proto/api"; | 
 |  | 
 | import "metropolis/proto/ext/authorization.proto"; | 
 |  | 
 | // Authentication, authorization and accounting. | 
 | service AAA { | 
 |     // Escrow is an endpoint used to retrieve short-lived access credentials to | 
 |     // the cluster. These short-lived access credentials are x509 certificates | 
 |     // that can then be used to directly authenticate to other RPC methods | 
 |     // exposed by Metropolis. This short-lived certificate may or may not be | 
 |     // fully self-standing cryptographically - this depends on the policy and | 
 |     // other configuration of the system. The returned short-lived certificate | 
 |     // may even be used as proofs within next Escrow calls in the case of more | 
 |     // complex flows. | 
 |     // | 
 |     // The client in this RPC is an end-user of the cluster, be it a human or | 
 |     // automated process that runs outside of a Metropolis cluster. | 
 |     // | 
 |     // To retrieve this short-lived certificate, the client must provide | 
 |     // different kind of proofs to the server. Upon connecting and receiving | 
 |     // the initial message from the client, the server will send a list of | 
 |     // proof requests, detailing proofs that the client must need to fulfill to | 
 |     // retrieve the requested credentials. Which proofs are requested depends | 
 |     // on the configuration of the client. The way to fulfill these proofs | 
 |     // depend on their kind, with some being provided in-band (eg.  access | 
 |     // credentials, U2F codes), some being provided out of band (eg. an RPC | 
 |     // channel opened from a given IP address or with a given existing TLS | 
 |     // certificate), and some dependent on external systems (eg. SSO). | 
 |     // | 
 |     // If the requested identity within the first EscrowFromClient is not | 
 |     // defined, the server may: | 
 |     // | 
 |     //  - Abort the connection immediately with an error about an unknown | 
 |     //    identity being requested. | 
 |     //  - Continue processing the Escrow RPC as if the identity existed, and | 
 |     //    either gather enough other proofs to be able to trust the client | 
 |     //    enough to abort it saying that the identity is unknown; or continue | 
 |     //    and pretend that the other proofs submitted by the client are | 
 |     //    invalid. | 
 |     // | 
 |     // Once the proofs are fulfilled by the client, the server will send an | 
 |     // x509 PEM-encoded certificate that the client can use in subsequent | 
 |     // calls to other Metropolis services. | 
 |     // | 
 |     // TODO(q3k): SPIFFE compatibility for short-lived certificates? | 
 |     // | 
 |     // This escrow flow can thus be used to implement several typical flows | 
 |     // used for 'logging in' cluster users: | 
 |     // | 
 |     // Example: Username and password login | 
 |     // | 
 |     // This shows the simplest possible message flow for a simple interactive | 
 |     // password authentication. | 
 |     // | 
 |     //   Client                                             Server | 
 |     //     |                                                  | | 
 |     //     |          .---------------------------.           | | 
 |     //     |----------| parameters <              |-------->>>| | 
 |     //     |          |  requested_identity_name: |           | | 
 |     //     |          |    "janedoe"              |           | | 
 |     //     |          |  public_key:              |           | | 
 |     //     |          |    "DEADBEEF..."          |           | | 
 |     //     |          | >                         |           | | 
 |     //     |          '---------------------------'           | | 
 |     //     |                                                  | | 
 |     //     |          .---------------------------.           | | 
 |     //     |<<<-------| needed <                  |-----------| | 
 |     //     |          |  kind: PLAINTEXT_PASSWORD |           | | 
 |     //     |          | >                         |           | | 
 |     //     |          '---------------------------'           | | 
 |     //     |                                                  | | 
 |     //     |          .---------------------------.           | | 
 |     //     |----------| proofs <                  |-------->>>| | 
 |     //     |          |  plaintext_password: ".." |           | | 
 |     //     |          | >                         |           | | 
 |     //     |          '---------------------------'           | | 
 |     //     |                                                  | | 
 |     //     |          .---------------------------.           | | 
 |     //     |<<<-------| fulfilled <               |-----------| | 
 |     //     |          |  kind: PLAINTEXT_PASSWORD |           | | 
 |     //     |          | >                         |           | | 
 |     //     |          | emitted_certificate:      |           | | 
 |     //     |          |   "DEADFOOD..."           |           | | 
 |     //     |          '---------------------------'           | | 
 |     //     |                                                  | | 
 |     //     |<<<---------------- close ----------------------- | | 
 |     //     |                                                  | | 
 |     // | 
 |     // Example: multi-phase OIDC with hardware assessment (simplified): | 
 |     // | 
 |     // This first requests a certificate that's valid for one day, and requires | 
 |     // the interactive use of a browser. Then, shorter-term certificates | 
 |     // (actually used to perform RPCs) are requested on demand, their lifetime | 
 |     // corresponding to the access tokens emitted by the IdP, but requiring | 
 |     // no interactive browser access or reconfirmations by the user. | 
 |     // | 
 |     //   Client                                             Server | 
 |     //     |                                                  | | 
 |     //     |     .--------------------------------------.     | | 
 |     //     |<<<--| Exchange OIDC login proof and TPM    |-->>>| | 
 |     //     |     | assessment for week-long certificate,|     |<--> IdP | 
 |     //     |     | retrieve 1-day long certificate      |     |<--> User | 
 |     //     |     | binding user to a refresh token on   |     |     Browser | 
 |     //     |     | the server.                          |     | | 
 |     //     |     '--------------------------------------'     | | 
 |     //     |                                                  | | 
 |     //     |     .--------------------------------------.     | -. | 
 |     //     |<<<--| Exchange earlier certificate and TPM |-->>>|<--> IdP | 
 |     //     |     | hardware assessment for 10-minute    |     | | | 
 |     //     |     | long self-standing cryptographic     |     |  > Repeats as | 
 |     //     |     | certificate used to access other     |     | |  long as | 
 |     //     |     | services                             |     | \  possible. | 
 |     //     |     '--------------------------------------'     | -' | 
 |     // | 
 |     // FAQ: How does this relate to access via web browsers? | 
 |     // | 
 |     // This flow is explicitly designed to be non dependent on web browers for | 
 |     // security reasons. Due to these requirements, we cannot port this flow to | 
 |     // always also work on browsers. Instead, we focus on the best that a | 
 |     // standalone application on the client side can give us, eg. being able to | 
 |     // use TLS client certificates, perform hardware attestation, and even talk | 
 |     // to HSMs. | 
 |     // | 
 |     // In addition to this gRPC Escrow flow, an alternative flow geared | 
 |     // especially towards web browser access (and eg. bearer token | 
 |     // authentication and OAuth/OpenIDC integration) will be developed for | 
 |     // users whose cluster policy allows for browser access. Both, however, | 
 |     // will lead to retrieving identities from with the same namespace of | 
 |     // entities. | 
 |     // | 
 |     rpc Escrow(stream EscrowFromClient) returns (stream EscrowFromServer) { | 
 |         option (metropolis.proto.ext.authorization) = { | 
 |             // The AAA implementation performs its own checks as needed, so the | 
 |             // RPC middleware should allow everything through. | 
 |             allow_unauthenticated: true | 
 |         }; | 
 |     } | 
 | } | 
 |  | 
 | message EscrowFromClient { | 
 |     // Parameters used for the entirety of the escrow flow. These must be set | 
 |     // only during the first EscrowFromClient message, and are ignored in | 
 |     // further messages. | 
 |     message Parameters { | 
 |         // The requested identity name. This is currently opaque and not defined, | 
 |         // but corresponds to the future 'Entity' system that Metropolis will | 
 |         // implement. Required. | 
 |         string requested_identity_name = 1; | 
 |  | 
 |         // Public key for which the short-lived certificate will be issued. | 
 |         // Currently, this must be an ed25519 public key's raw bytes (32 | 
 |         // bytes). In the future, other x509 signature algorithms might be | 
 |         // supported. | 
 |         // This key does not have to be the same key as the one that is part of | 
 |         // the presented certificate during the Escrow RPC (if any). However, | 
 |         // some proofs might have stricter requirements. | 
 |         bytes public_key = 2; | 
 |     } | 
 |     Parameters parameters = 1; | 
 |  | 
 |     // Proofs. These should only be submitted by the client after the server | 
 |     // requests them, but if they are submitted within the first | 
 |     // EscrowFromClientMessage they will be interpreted too. The problem with | 
 |     // ahead of time proofs is that different a proof request from the server | 
 |     // might parametrize the request in a way that would elicit a different | 
 |     // answer from the client, so care must be taken to ensure that the | 
 |     // requests from the server are verified against the assumption that the | 
 |     // client makes (if any). Ideally, the client should be fully reactive to | 
 |     // requested proofs, and not hardcode any behaviour. | 
 |     message Proofs { | 
 |         // Plaintext password in response to KIND_PLAINTEXT_PASSWORD proof | 
 |         // request. | 
 |         string plaintext_password = 1; | 
 |     } | 
 |     Proofs proofs = 2; | 
 | } | 
 |  | 
 | message EscrowFromServer { | 
 |     // A proof requested from the server. Within an Escrow RPC, proofs can be | 
 |     // either 'needed' or 'fulfilled'. Each proof has a kind, and kinds within | 
 |     // all proof requests (either needed or fulfilled) are unique. | 
 |     message ProofRequest { | 
 |         enum Kind { | 
 |             KIND_INVALID = 0; | 
 |             // The client needs to present a long-lived 'refresh' certificate. | 
 |             // If this is in `needed`, it means the client did not present a | 
 |             // certificate and will need to abort this RPC and connect with one | 
 |             // presented. | 
 |             // If the client presents an invalid certificate, the Escrow RPC | 
 |             // will fail. | 
 |             KIND_REFRESH_CERTIFICATE = 1; | 
 |             // The client needs to present a static, plaintext password/token. | 
 |             // This can be fulfilled by setting | 
 |             // EscrowFromClient.proofs.plaintext_password. | 
 |             // If the client presents an invalid password, the Escrow RPC will | 
 |             // fail. | 
 |             KIND_PLAINTEXT_PASSWORD = 2; | 
 |  | 
 |             // Future possibilities: | 
 |             // // One-or-two-sided hardware assessment via TPM. | 
 |             // KIND_HARDWARE_ASSESMENT_EXCHANGE = ... | 
 |             // // Making the client proove that the certificate is stored on | 
 |             // // some secure element. | 
 |             // KIND_PRIVATE_KEY_IN_SECURE_ELEMENT = ... | 
 |             // // Making the client go through an OIDC login flow, with the | 
 |             // // server possibly storing the resulting refresh/access tokens. | 
 |             // KIND_OIDC_FLOW_COMPLETION = ... | 
 |         }; | 
 |         Kind kind = 1; | 
 |     } | 
 |     // Proofs that the server requests from the client which the client has not | 
 |     // yet fulfilled. Within the lifecycle of the Escrow RPC, the needed proofs | 
 |     // will only move from needed to fulfilled as the client submits more | 
 |     // proofs. | 
 |     repeated ProofRequest needed = 1; | 
 |     // Proofs that the server accepted from the client. | 
 |     repeated ProofRequest fulfilled = 2; | 
 |  | 
 |     // If all proof requests are fulfilled, the bytes of the emitted PEM | 
 |     // certificate. | 
 |     bytes emitted_certificate = 3; | 
 | } | 
 |  | 
 | // Protobuf-encoded data that is part of certificates emitted by the | 
 | // Metropolis CA. Encoded as protobuf and inserted into a Subject Alternative | 
 | // Name of type otherName with type-id: | 
 | // | 
 | //     2.25.205720787499610521842135044124912906832.1.1 | 
 | // | 
 | // TODO(q3k): register something under 1.3.6.1.4.1 and alloacte some OID within | 
 | // that instead of relying on UUIDs within 2.25? | 
 | message CertificateSAN { | 
 |     // Validity descrises how consumers of this certificate should treat the | 
 |     // information contained within it. Currently there's two kinds of | 
 |     // validities, the difference between them being whether or not the | 
 |     // certificate needs to actively be checked for revocation or not. | 
 |     enum Validity { | 
 |         VALIDITY_INVALID = 0; | 
 |         // Certificate must only be used by components that can verify with | 
 |         // Metropolis that it hasn't been revoked. The method (OCSP, CRL) | 
 |         // intentionally left blank for now. | 
 |         VALIDITY_ONLINE = 1; | 
 |         // Certificate can be trusted on cryptographic basis alone as long as | 
 |         // it hasn't expired, without consulting revocation system. | 
 |         VALIDITY_OFFLINE = 2; | 
 |     } | 
 |     Validity validity = 1; | 
 |  | 
 |     // Assertions are facts stated about the bearer of this certificate by the | 
 |     // CA that emitted it - in this case, the Metropolis cluster that emitted | 
 |     // it. Each assertion details exactly one fact of one kind, and there can | 
 |     // be multiple assertions of any given kind. | 
 |     message Assertion { | 
 |         // IdentityConfirmed asserts that the emitter of this certificate has | 
 |         // received all the required proofs at the time of issuance to confirm | 
 |         // that the bearer of this certificate is the entity described by the | 
 |         // identity name. | 
 |         message IdentityConfirmed { | 
 |             string name = 1; | 
 |         }; | 
 |         // MetropolisRPCAllowed means that that connections established to | 
 |         // Metropolis RPC endpoints will proceed. If given, IdentityConfirmed | 
 |         // must also be given. | 
 |         message MetropolisRPCAllowed { | 
 |             // Future possibilities: scoping to only some (low privilege) RPC | 
 |             // methods, ... | 
 |         }; | 
 |         oneof kind { | 
 |             IdentityConfirmed identity_confirmed = 1; | 
 |             MetropolisRPCAllowed metropolis_rpc_allowed = 2; | 
 |             // Future possibilties: | 
 |             // OIDCIdentityConfirmed ... | 
 |             // TPMColocationConfirmed ... | 
 |             // SourceAddressConfirmed ... | 
 |             // ReportedClientConfiguration ... | 
 |         }; | 
 |     } | 
 |     repeated Assertion assertions = 2; | 
 | } |