|  | // 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; | 
|  | } |