blob: a4d685cf9dffc1bb3525a8db4d8f50b69a214ece [file] [log] [blame]
Serge Bazanski3379a5d2021-09-09 12:56:40 +02001package rpc
2
3import (
4 "context"
5 "fmt"
6
7 "google.golang.org/grpc"
8 "google.golang.org/grpc/codes"
9 "google.golang.org/grpc/status"
10
11 epb "source.monogon.dev/metropolis/proto/ext"
12)
13
14type Permissions map[epb.Permission]bool
15
16// PeerInfo represents the Metropolis-level information about the remote side
17// of a gRPC RPC, ie. about the calling client in server handlers and about the
18// handling server in client code.
19//
20// Exactly one of {Node, User, Unauthenticated} will be non-nil.
21type PeerInfo struct {
22 // Node is the information about a peer Node, and identifies that the other side
23 // of the connection is either a Node servicng gRPC requests for a cluster, or a
24 // Node connecting to a gRPC service.
25 Node *PeerInfoNode
26 // User is the information about a peer User, and identifies that the other side
27 // of the connection is a Metropolis user or manager (eg. owner). This will only
28 // be set in service handlers, as users cannot serve gRPC connections.
29 User *PeerInfoUser
30 // Unauthenticated is set for incoming gRPC connections which that have the
31 // Unauthenticated authorization extension set to true, and mark that the other
32 // side of the connection has not been verified at all.
33 Unauthenticated *PeerInfoUnauthenticated
34}
35
36// PeerInfoNode contains information about a Node on the other side of a gRPC
37// connection.
38type PeerInfoNode struct {
39 // PublicKey is the ED25519 public key bytes of the node.
40 PublicKey []byte
41
42 // Permissions are the set of permissions this node has.
43 Permissions Permissions
44}
45
46// PeerInfoUser contains information about a user on the other side of a gRPC
47// connection.
48type PeerInfoUser struct {
49 // Identity is an opaque identifier for the user. MVP: Currently this is always
50 // "manager".
51 Identity string
52}
53
54type PeerInfoUnauthenticated struct {
55 // SelfSignedPublicKey is the ED25519 public key bytes of the other side of the
56 // connection, if that side presented a self-signed certificate to prove control
57 // of a private key corresponding to this public key. If it did not present a
58 // self-signed certificate that can be parsed for such a key, this will be nil.
59 //
60 // This can be used by code with expects Unauthenticated RPCs but wants to
61 // authenticate the connection based on ownership of some keypair, for example
62 // in the AAA.Escrow method.
63 SelfSignedPublicKey []byte
64}
65
66// GetPeerInfo returns the PeerInfo of the peer of a gRPC connection, or nil if
67// this connection does not carry any PeerInfo.
68func GetPeerInfo(ctx context.Context) *PeerInfo {
69 if pi, ok := ctx.Value(peerInfoKey).(*PeerInfo); ok {
70 return pi
71 }
72 return nil
73}
74
75func (p *PeerInfo) CheckPermissions(need Permissions) error {
76 if p.Unauthenticated != nil {
77 // This generally shouldn't happen, as unauthenticated users shouldn't be
78 // allowed to reach this part of the code - methods with Need != nil will not be
79 // processed as unauthenticated for security, and will instead act as
80 // authenticated methods and reject unauthenticated connections.
81 for _, v := range need {
82 if v {
83 return status.Error(codes.Unauthenticated, "unauthenticated connection")
84 }
85 }
86 return nil
87 } else if p.User != nil {
88 // MVP: all permissions are granted to all users.
89 // TODO(q3k): check authz.Need once we have a user/identity system implemented.
90 return nil
91 } else if p.Node != nil {
92 for n, v := range need {
93 if v && !p.Node.Permissions[n] {
94 return status.Errorf(codes.PermissionDenied, "node missing %s permission", n.String())
95 }
96 }
97 return nil
98 }
99
100 return fmt.Errorf("invalid PeerInfo: neither Unauthenticated, User nor Node is set")
101}
102
103type peerInfoKeyType string
104
105// peerInfoKey is the context key for storing PeerInfo.
106const peerInfoKey = peerInfoKeyType("peerInfo")
107
108// apply returns the given context with itself stored under a unique key, that
109// can be later retrieved via GetPeerInfo.
110func (p *PeerInfo) apply(ctx context.Context) context.Context {
111 return context.WithValue(ctx, peerInfoKey, p)
112}
113
114// peerInfoServerStream is a grpc.ServerStream wrapper which contains some
115// PeerInfo, and returns it as part of the Context() of the ServerStream.
116type peerInfoServerStream struct {
117 grpc.ServerStream
118 pi *PeerInfo
119}
120
121func (p *peerInfoServerStream) Context() context.Context {
122 return p.pi.apply(p.ServerStream.Context())
123}
124
125// serverStream wraps a grpc.ServerStream with a structure that attaches this
126// PeerInfo in all contexts returned by Context().
127func (p *PeerInfo) serverStream(ss grpc.ServerStream) grpc.ServerStream {
128 return &peerInfoServerStream{ss, p}
129}