m/n/core/curator: authenticated RPC
This adds authentication middleware (server interceptors) for gRPC
services running on the public curator listener.
Most of this code is testing harnesses to start up just the curator
listener with enough of a PKI infrastructure copy from a real Metropolis
cluster to be able to start running tests against GetRegisterTicket.
Change-Id: I429ff29e3c1233d74e8da619ddb543d56bc051b9
Reviewed-on: https://review.monogon.dev/c/monogon/+/311
Reviewed-by: Lorenz Brun <lorenz@monogon.tech>
diff --git a/metropolis/proto/api/BUILD.bazel b/metropolis/proto/api/BUILD.bazel
index 61d14fb..ef8885d 100644
--- a/metropolis/proto/api/BUILD.bazel
+++ b/metropolis/proto/api/BUILD.bazel
@@ -11,6 +11,7 @@
"management.proto",
],
visibility = ["//visibility:public"],
+ deps = ["//metropolis/proto/ext:ext_proto"],
)
go_proto_library(
@@ -19,6 +20,7 @@
importpath = "source.monogon.dev/metropolis/proto/api",
proto = ":api_proto",
visibility = ["//visibility:public"],
+ deps = ["//metropolis/proto/ext:go_default_library"],
)
go_library(
diff --git a/metropolis/proto/api/aaa.proto b/metropolis/proto/api/aaa.proto
index e469d0d..faf6dda 100644
--- a/metropolis/proto/api/aaa.proto
+++ b/metropolis/proto/api/aaa.proto
@@ -18,6 +18,8 @@
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
@@ -144,7 +146,13 @@
// will lead to retrieving identities from with the same namespace of
// entities.
//
- rpc Escrow(stream EscrowFromClient) returns (stream EscrowFromServer);
+ 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 {
diff --git a/metropolis/proto/api/management.proto b/metropolis/proto/api/management.proto
index c0b8332..ae7dd8d 100644
--- a/metropolis/proto/api/management.proto
+++ b/metropolis/proto/api/management.proto
@@ -2,6 +2,8 @@
package metropolis.proto.api;
option go_package = "source.monogon.dev/metropolis/proto/api";
+import "metropolis/proto/ext/authorization.proto";
+
// Management service available to Cluster Managers.
service Management {
// GetRegisterTicket retrieves the current RegisterTicket which is required
@@ -10,7 +12,11 @@
// registration. Instead, it is used to guard the API surface of the
// Register RPC from potential denial of service attacks, and can be
// regenerated at any time in case it leaks.
- rpc GetRegisterTicket(GetRegisterTicketRequest) returns (GetRegisterTicketResponse);
+ rpc GetRegisterTicket(GetRegisterTicketRequest) returns (GetRegisterTicketResponse) {
+ option (metropolis.proto.ext.authorization) = {
+ need: PERMISSION_GET_REGISTER_TICKET
+ };
+ }
}
message GetRegisterTicketRequest {
diff --git a/metropolis/proto/ext/BUILD.bazel b/metropolis/proto/ext/BUILD.bazel
new file mode 100644
index 0000000..c93882e
--- /dev/null
+++ b/metropolis/proto/ext/BUILD.bazel
@@ -0,0 +1,24 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+
+proto_library(
+ name = "ext_proto",
+ srcs = ["authorization.proto"],
+ visibility = ["//visibility:public"],
+ deps = ["@com_google_protobuf//:descriptor_proto"],
+)
+
+go_proto_library(
+ name = "ext_go_proto",
+ importpath = "source.monogon.dev/metropolis/proto/ext",
+ proto = ":ext_proto",
+ visibility = ["//visibility:public"],
+)
+
+go_library(
+ name = "go_default_library",
+ embed = [":ext_go_proto"],
+ importpath = "source.monogon.dev/metropolis/proto/ext",
+ visibility = ["//visibility:public"],
+)
diff --git a/metropolis/proto/ext/authorization.proto b/metropolis/proto/ext/authorization.proto
new file mode 100644
index 0000000..cc9082f
--- /dev/null
+++ b/metropolis/proto/ext/authorization.proto
@@ -0,0 +1,36 @@
+syntax = "proto3";
+package metropolis.proto.ext;
+option go_package = "source.monogon.dev/metropolis/proto/ext";
+
+import "google/protobuf/descriptor.proto";
+
+extend google.protobuf.MethodOptions {
+ // Set authorization policy for this RPC. If not set but the service is
+ // configured to use authorization, the default/zero value of the
+ // Authorization message will be used (effectively allowing all
+ // authenticated users).
+ Authorization authorization = 1000;
+}
+
+
+// Permission is a combined activity/object that an identity can perform in the
+// cluster.
+//
+// MVP: this might get replaced with a full activity/object split later on.
+enum Permission {
+ PERMISSION_UNSPECIFIED = 0;
+ PERMISSION_GET_REGISTER_TICKET = 1;
+}
+
+// Authorization policy for an RPC method. This message/API does not have the
+// same stability guarantees as the rest of Metropolis APIs - it is internal,
+// might change in wire and text incompatible ways and should not be used by
+// consumers of the API.
+message Authorization {
+ // Set of permissions required from the caller.
+ repeated Permission need = 1;
+ // If set, this API can be called unauthorized and unauthenticated, thereby
+ // allowing full access to anyone, including public access by anyone with
+ // network connectivity to the cluster.. Ignored if `need` is non-empty.
+ bool allow_unauthenticated = 2;
+}