From bebbf79d962654c30b62175b448d2febb19f04b8 Mon Sep 17 00:00:00 2001 From: "data-plane-api(CircleCI)" Date: Wed, 8 Apr 2020 02:39:37 +0000 Subject: [PATCH] rbac: add remote_ip for matching downstream remote IP. (#10460) Signed-off-by: Yangmin Zhu Mirrored from https://github.com/envoyproxy/envoy @ 4b6e81c112e204ef04445318d2cbfa168cf22ca7 --- envoy/config/rbac/v2/rbac.proto | 18 +- envoy/config/rbac/v3/rbac.proto | 18 +- envoy/config/rbac/v4alpha/BUILD | 16 ++ envoy/config/rbac/v4alpha/rbac.proto | 258 ++++++++++++++++++ .../filters/http/rbac/v4alpha/BUILD | 13 + .../filters/http/rbac/v4alpha/rbac.proto | 44 +++ .../filters/network/rbac/v4alpha/BUILD | 13 + .../filters/network/rbac/v4alpha/rbac.proto | 57 ++++ 8 files changed, 433 insertions(+), 4 deletions(-) create mode 100644 envoy/config/rbac/v4alpha/BUILD create mode 100644 envoy/config/rbac/v4alpha/rbac.proto create mode 100644 envoy/extensions/filters/http/rbac/v4alpha/BUILD create mode 100644 envoy/extensions/filters/http/rbac/v4alpha/rbac.proto create mode 100644 envoy/extensions/filters/network/rbac/v4alpha/BUILD create mode 100644 envoy/extensions/filters/network/rbac/v4alpha/rbac.proto diff --git a/envoy/config/rbac/v2/rbac.proto b/envoy/config/rbac/v2/rbac.proto index 8f8323e5..943ac33e 100644 --- a/envoy/config/rbac/v2/rbac.proto +++ b/envoy/config/rbac/v2/rbac.proto @@ -170,7 +170,7 @@ message Permission { } // Principal defines an identity or a group of identities for a downstream subject. -// [#next-free-field: 10] +// [#next-free-field: 12] message Principal { // Used in the `and_ids` and `or_ids` fields in the `identifier` oneof. Depending on the context, // each are applied with the associated behavior. @@ -204,7 +204,21 @@ message Principal { Authenticated authenticated = 4; // A CIDR block that describes the downstream IP. - api.v2.core.CidrRange source_ip = 5; + // This address will honor proxy protocol, but will not honor XFF. + api.v2.core.CidrRange source_ip = 5 [deprecated = true]; + + // A CIDR block that describes the downstream remote/origin address. + // Note: This is always the physical peer even if the + // :ref:`remote_ip ` is inferred + // from for example the x-forwarder-for header, proxy protocol, etc. + api.v2.core.CidrRange direct_remote_ip = 10; + + // A CIDR block that describes the downstream remote/origin address. + // Note: This may not be the physical peer and could be different from the + // :ref:`direct_remote_ip `. + // E.g, if the remote ip is inferred from for example the x-forwarder-for header, + // proxy protocol, etc. + api.v2.core.CidrRange remote_ip = 11; // A header (or pseudo-header such as :path or :method) on the incoming HTTP request. Only // available for HTTP request. diff --git a/envoy/config/rbac/v3/rbac.proto b/envoy/config/rbac/v3/rbac.proto index 055e1425..040f537d 100644 --- a/envoy/config/rbac/v3/rbac.proto +++ b/envoy/config/rbac/v3/rbac.proto @@ -180,7 +180,7 @@ message Permission { } // Principal defines an identity or a group of identities for a downstream subject. -// [#next-free-field: 10] +// [#next-free-field: 12] message Principal { option (udpa.annotations.versioning).previous_message_type = "envoy.config.rbac.v2.Principal"; @@ -222,7 +222,21 @@ message Principal { Authenticated authenticated = 4; // A CIDR block that describes the downstream IP. - core.v3.CidrRange source_ip = 5; + // This address will honor proxy protocol, but will not honor XFF. + core.v3.CidrRange source_ip = 5 [deprecated = true]; + + // A CIDR block that describes the downstream remote/origin address. + // Note: This is always the physical peer even if the + // :ref:`remote_ip ` is inferred + // from for example the x-forwarder-for header, proxy protocol, etc. + core.v3.CidrRange direct_remote_ip = 10; + + // A CIDR block that describes the downstream remote/origin address. + // Note: This may not be the physical peer and could be different from the + // :ref:`direct_remote_ip `. + // E.g, if the remote ip is inferred from for example the x-forwarder-for header, + // proxy protocol, etc. + core.v3.CidrRange remote_ip = 11; // A header (or pseudo-header such as :path or :method) on the incoming HTTP request. Only // available for HTTP request. diff --git a/envoy/config/rbac/v4alpha/BUILD b/envoy/config/rbac/v4alpha/BUILD new file mode 100644 index 00000000..dbfa8be4 --- /dev/null +++ b/envoy/config/rbac/v4alpha/BUILD @@ -0,0 +1,16 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/core/v4alpha:pkg", + "//envoy/config/rbac/v3:pkg", + "//envoy/config/route/v4alpha:pkg", + "//envoy/type/matcher/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + "@com_google_googleapis//google/api/expr/v1alpha1:syntax_proto", + ], +) diff --git a/envoy/config/rbac/v4alpha/rbac.proto b/envoy/config/rbac/v4alpha/rbac.proto new file mode 100644 index 00000000..09723128 --- /dev/null +++ b/envoy/config/rbac/v4alpha/rbac.proto @@ -0,0 +1,258 @@ +syntax = "proto3"; + +package envoy.config.rbac.v4alpha; + +import "envoy/config/core/v4alpha/address.proto"; +import "envoy/config/route/v4alpha/route_components.proto"; +import "envoy/type/matcher/v3/metadata.proto"; +import "envoy/type/matcher/v3/path.proto"; +import "envoy/type/matcher/v3/string.proto"; + +import "google/api/expr/v1alpha1/syntax.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.config.rbac.v4alpha"; +option java_outer_classname = "RbacProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: Role Based Access Control (RBAC)] + +// Role Based Access Control (RBAC) provides service-level and method-level access control for a +// service. RBAC policies are additive. The policies are examined in order. A request is allowed +// once a matching policy is found (suppose the `action` is ALLOW). +// +// Here is an example of RBAC configuration. It has two policies: +// +// * Service account "cluster.local/ns/default/sa/admin" has full access to the service, and so +// does "cluster.local/ns/default/sa/superuser". +// +// * Any user can read ("GET") the service at paths with prefix "/products", so long as the +// destination port is either 80 or 443. +// +// .. code-block:: yaml +// +// action: ALLOW +// policies: +// "service-admin": +// permissions: +// - any: true +// principals: +// - authenticated: +// principal_name: +// exact: "cluster.local/ns/default/sa/admin" +// - authenticated: +// principal_name: +// exact: "cluster.local/ns/default/sa/superuser" +// "product-viewer": +// permissions: +// - and_rules: +// rules: +// - header: { name: ":method", exact_match: "GET" } +// - url_path: +// path: { prefix: "/products" } +// - or_rules: +// rules: +// - destination_port: 80 +// - destination_port: 443 +// principals: +// - any: true +// +message RBAC { + option (udpa.annotations.versioning).previous_message_type = "envoy.config.rbac.v3.RBAC"; + + // Should we do safe-list or block-list style access control? + enum Action { + // The policies grant access to principals. The rest is denied. This is safe-list style + // access control. This is the default type. + ALLOW = 0; + + // The policies deny access to principals. The rest is allowed. This is block-list style + // access control. + DENY = 1; + } + + // The action to take if a policy matches. The request is allowed if and only if: + // + // * `action` is "ALLOWED" and at least one policy matches + // * `action` is "DENY" and none of the policies match + Action action = 1; + + // Maps from policy name to policy. A match occurs when at least one policy matches the request. + map policies = 2; +} + +// Policy specifies a role and the principals that are assigned/denied the role. A policy matches if +// and only if at least one of its permissions match the action taking place AND at least one of its +// principals match the downstream AND the condition is true if specified. +message Policy { + option (udpa.annotations.versioning).previous_message_type = "envoy.config.rbac.v3.Policy"; + + // Required. The set of permissions that define a role. Each permission is matched with OR + // semantics. To match all actions for this policy, a single Permission with the `any` field set + // to true should be used. + repeated Permission permissions = 1 [(validate.rules).repeated = {min_items: 1}]; + + // Required. The set of principals that are assigned/denied the role based on “action”. Each + // principal is matched with OR semantics. To match all downstreams for this policy, a single + // Principal with the `any` field set to true should be used. + repeated Principal principals = 2 [(validate.rules).repeated = {min_items: 1}]; + + // An optional symbolic expression specifying an access control + // :ref:`condition `. The condition is combined + // with the permissions and the principals as a clause with AND semantics. + google.api.expr.v1alpha1.Expr condition = 3; +} + +// Permission defines an action (or actions) that a principal can take. +// [#next-free-field: 11] +message Permission { + option (udpa.annotations.versioning).previous_message_type = "envoy.config.rbac.v3.Permission"; + + // Used in the `and_rules` and `or_rules` fields in the `rule` oneof. Depending on the context, + // each are applied with the associated behavior. + message Set { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.rbac.v3.Permission.Set"; + + repeated Permission rules = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + oneof rule { + option (validate.required) = true; + + // A set of rules that all must match in order to define the action. + Set and_rules = 1; + + // A set of rules where at least one must match in order to define the action. + Set or_rules = 2; + + // When any is set, it matches any action. + bool any = 3 [(validate.rules).bool = {const: true}]; + + // A header (or pseudo-header such as :path or :method) on the incoming HTTP request. Only + // available for HTTP request. + // Note: the pseudo-header :path includes the query and fragment string. Use the `url_path` + // field if you want to match the URL path without the query and fragment string. + route.v4alpha.HeaderMatcher header = 4; + + // A URL path on the incoming HTTP request. Only available for HTTP. + type.matcher.v3.PathMatcher url_path = 10; + + // A CIDR block that describes the destination IP. + core.v4alpha.CidrRange destination_ip = 5; + + // A port number that describes the destination port connecting to. + uint32 destination_port = 6 [(validate.rules).uint32 = {lte: 65535}]; + + // Metadata that describes additional information about the action. + type.matcher.v3.MetadataMatcher metadata = 7; + + // Negates matching the provided permission. For instance, if the value of `not_rule` would + // match, this permission would not match. Conversely, if the value of `not_rule` would not + // match, this permission would match. + Permission not_rule = 8; + + // The request server from the client's connection request. This is + // typically TLS SNI. + // + // .. attention:: + // + // The behavior of this field may be affected by how Envoy is configured + // as explained below. + // + // * If the :ref:`TLS Inspector ` + // filter is not added, and if a `FilterChainMatch` is not defined for + // the :ref:`server name `, + // a TLS connection's requested SNI server name will be treated as if it + // wasn't present. + // + // * A :ref:`listener filter ` may + // overwrite a connection's requested server name within Envoy. + // + // Please refer to :ref:`this FAQ entry ` to learn to + // setup SNI. + type.matcher.v3.StringMatcher requested_server_name = 9; + } +} + +// Principal defines an identity or a group of identities for a downstream subject. +// [#next-free-field: 12] +message Principal { + option (udpa.annotations.versioning).previous_message_type = "envoy.config.rbac.v3.Principal"; + + // Used in the `and_ids` and `or_ids` fields in the `identifier` oneof. Depending on the context, + // each are applied with the associated behavior. + message Set { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.rbac.v3.Principal.Set"; + + repeated Principal ids = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + // Authentication attributes for a downstream. + message Authenticated { + option (udpa.annotations.versioning).previous_message_type = + "envoy.config.rbac.v3.Principal.Authenticated"; + + reserved 1; + + // The name of the principal. If set, The URI SAN or DNS SAN in that order is used from the + // certificate, otherwise the subject field is used. If unset, it applies to any user that is + // authenticated. + type.matcher.v3.StringMatcher principal_name = 2; + } + + reserved 5; + + reserved "source_ip"; + + oneof identifier { + option (validate.required) = true; + + // A set of identifiers that all must match in order to define the downstream. + Set and_ids = 1; + + // A set of identifiers at least one must match in order to define the downstream. + Set or_ids = 2; + + // When any is set, it matches any downstream. + bool any = 3 [(validate.rules).bool = {const: true}]; + + // Authenticated attributes that identify the downstream. + Authenticated authenticated = 4; + + // A CIDR block that describes the downstream remote/origin address. + // Note: This is always the physical peer even if the + // :ref:`remote_ip ` is inferred + // from for example the x-forwarder-for header, proxy protocol, etc. + core.v4alpha.CidrRange direct_remote_ip = 10; + + // A CIDR block that describes the downstream remote/origin address. + // Note: This may not be the physical peer and could be different from the + // :ref:`direct_remote_ip `. + // E.g, if the remote ip is inferred from for example the x-forwarder-for header, + // proxy protocol, etc. + core.v4alpha.CidrRange remote_ip = 11; + + // A header (or pseudo-header such as :path or :method) on the incoming HTTP request. Only + // available for HTTP request. + // Note: the pseudo-header :path includes the query and fragment string. Use the `url_path` + // field if you want to match the URL path without the query and fragment string. + route.v4alpha.HeaderMatcher header = 6; + + // A URL path on the incoming HTTP request. Only available for HTTP. + type.matcher.v3.PathMatcher url_path = 9; + + // Metadata that describes additional information about the principal. + type.matcher.v3.MetadataMatcher metadata = 7; + + // Negates matching the provided principal. For instance, if the value of `not_id` would match, + // this principal would not match. Conversely, if the value of `not_id` would not match, this + // principal would match. + Principal not_id = 8; + } +} diff --git a/envoy/extensions/filters/http/rbac/v4alpha/BUILD b/envoy/extensions/filters/http/rbac/v4alpha/BUILD new file mode 100644 index 00000000..bd16c3f2 --- /dev/null +++ b/envoy/extensions/filters/http/rbac/v4alpha/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/rbac/v4alpha:pkg", + "//envoy/extensions/filters/http/rbac/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/envoy/extensions/filters/http/rbac/v4alpha/rbac.proto b/envoy/extensions/filters/http/rbac/v4alpha/rbac.proto new file mode 100644 index 00000000..ec65f5d7 --- /dev/null +++ b/envoy/extensions/filters/http/rbac/v4alpha/rbac.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package envoy.extensions.filters.http.rbac.v4alpha; + +import "envoy/config/rbac/v4alpha/rbac.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.http.rbac.v4alpha"; +option java_outer_classname = "RbacProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: RBAC] +// Role-Based Access Control :ref:`configuration overview `. +// [#extension: envoy.filters.http.rbac] + +// RBAC filter config. +message RBAC { + option (udpa.annotations.versioning).previous_message_type = + "envoy.extensions.filters.http.rbac.v3.RBAC"; + + // Specify the RBAC rules to be applied globally. + // If absent, no enforcing RBAC policy will be applied. + config.rbac.v4alpha.RBAC rules = 1; + + // Shadow rules are not enforced by the filter (i.e., returning a 403) + // but will emit stats and logs and can be used for rule testing. + // If absent, no shadow RBAC policy will be applied. + config.rbac.v4alpha.RBAC shadow_rules = 2; +} + +message RBACPerRoute { + option (udpa.annotations.versioning).previous_message_type = + "envoy.extensions.filters.http.rbac.v3.RBACPerRoute"; + + reserved 1; + + // Override the global configuration of the filter with this new config. + // If absent, the global RBAC policy will be disabled for this route. + RBAC rbac = 2; +} diff --git a/envoy/extensions/filters/network/rbac/v4alpha/BUILD b/envoy/extensions/filters/network/rbac/v4alpha/BUILD new file mode 100644 index 00000000..25620c85 --- /dev/null +++ b/envoy/extensions/filters/network/rbac/v4alpha/BUILD @@ -0,0 +1,13 @@ +# DO NOT EDIT. This file is generated by tools/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = [ + "//envoy/config/rbac/v4alpha:pkg", + "//envoy/extensions/filters/network/rbac/v3:pkg", + "@com_github_cncf_udpa//udpa/annotations:pkg", + ], +) diff --git a/envoy/extensions/filters/network/rbac/v4alpha/rbac.proto b/envoy/extensions/filters/network/rbac/v4alpha/rbac.proto new file mode 100644 index 00000000..8452a898 --- /dev/null +++ b/envoy/extensions/filters/network/rbac/v4alpha/rbac.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; + +package envoy.extensions.filters.network.rbac.v4alpha; + +import "envoy/config/rbac/v4alpha/rbac.proto"; + +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.filters.network.rbac.v4alpha"; +option java_outer_classname = "RbacProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE; + +// [#protodoc-title: RBAC] +// Role-Based Access Control :ref:`configuration overview `. +// [#extension: envoy.filters.network.rbac] + +// RBAC network filter config. +// +// Header should not be used in rules/shadow_rules in RBAC network filter as +// this information is only available in :ref:`RBAC http filter `. +message RBAC { + option (udpa.annotations.versioning).previous_message_type = + "envoy.extensions.filters.network.rbac.v3.RBAC"; + + enum EnforcementType { + // Apply RBAC policies when the first byte of data arrives on the connection. + ONE_TIME_ON_FIRST_BYTE = 0; + + // Continuously apply RBAC policies as data arrives. Use this mode when + // using RBAC with message oriented protocols such as Mongo, MySQL, Kafka, + // etc. when the protocol decoders emit dynamic metadata such as the + // resources being accessed and the operations on the resources. + CONTINUOUS = 1; + } + + // Specify the RBAC rules to be applied globally. + // If absent, no enforcing RBAC policy will be applied. + config.rbac.v4alpha.RBAC rules = 1; + + // Shadow rules are not enforced by the filter but will emit stats and logs + // and can be used for rule testing. + // If absent, no shadow RBAC policy will be applied. + config.rbac.v4alpha.RBAC shadow_rules = 2; + + // The prefix to use when emitting statistics. + string stat_prefix = 3 [(validate.rules).string = {min_bytes: 1}]; + + // RBAC enforcement strategy. By default RBAC will be enforced only once + // when the first byte of data arrives from the downstream. When used in + // conjunction with filters that emit dynamic metadata after decoding + // every payload (e.g., Mongo, MySQL, Kafka) set the enforcement type to + // CONTINUOUS to enforce RBAC policies on every message boundary. + EnforcementType enforcement_type = 4; +}