1616//
1717
1818use crate :: config:: core:: StringMatcher ;
19+ use compact_str:: CompactString ;
1920use ipnet:: IpNet ;
2021use serde:: { Deserialize , Serialize } ;
21- use std:: net:: SocketAddr ;
22+ use std:: { collections :: BTreeMap , net:: SocketAddr } ;
2223use tracing:: debug;
2324
2425#[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
2526pub struct NetworkRbac {
2627 pub action : Action ,
27- //fixme(hayley): replace vec with std::collections::BTreeMap
28- // and include the policy name as Envoy says to apply them
29- // in lexical order
30- pub policies : Vec < Policy > ,
28+ pub policies : BTreeMap < CompactString , Policy > ,
3129}
3230
3331#[ derive( Debug , Clone , Copy , Deserialize , Serialize , PartialEq , Eq ) ]
@@ -74,7 +72,7 @@ impl<'a> NetworkContext<'a> {
7472}
7573
7674impl Permission {
77- fn is_applicable ( & self , ctx : NetworkContext ) -> bool {
75+ fn is_applicable ( & self , ctx : & NetworkContext ) -> bool {
7876 match self {
7977 Self :: Any => true ,
8078 Self :: DestinationIp ( ip) => ip. contains ( & ctx. destination . ip ( ) ) ,
@@ -89,7 +87,7 @@ impl Permission {
8987}
9088
9189impl Principal {
92- fn has_principal ( & self , ctx : NetworkContext ) -> bool {
90+ fn has_principal ( & self , ctx : & NetworkContext ) -> bool {
9391 match self {
9492 Principal :: Any => true ,
9593 Principal :: DownstreamRemoteIp ( ip) => ip. contains ( & ctx. downstream . ip ( ) ) ,
@@ -98,7 +96,7 @@ impl Principal {
9896}
9997
10098impl Policy {
101- fn enforce ( & self , ctx : NetworkContext ) -> bool {
99+ fn enforce ( & self , ctx : & NetworkContext ) -> bool {
102100 let has_permission = self . permissions . iter ( ) . any ( |p| p. is_applicable ( ctx) ) ;
103101 let has_principal = self . principals . iter ( ) . any ( |p| p. has_principal ( ctx) ) ;
104102 debug ! ( "Enforcing policy permissions {has_permission} principals {has_principal}" ) ;
@@ -107,13 +105,18 @@ impl Policy {
107105}
108106
109107impl NetworkRbac {
110- pub fn is_permitted ( & self , ctx : NetworkContext ) -> bool {
111- let is_enforced = self . policies . iter ( ) . any ( |p| p. enforce ( ctx) ) ;
112- debug ! ( "Rule is enforced {is_enforced}" ) ;
113- match self . action {
114- Action :: Allow => is_enforced,
115- Action :: Deny => !is_enforced,
116- }
108+ pub fn is_permitted ( & self , ctx : & NetworkContext ) -> ( bool , Option < CompactString > ) {
109+ let enforced_policy = self . policies . iter ( ) . find ( |( _, p) | p. enforce ( ctx) ) . map ( |( id, _) | id. clone ( ) ) ;
110+ let permitted = match self . action {
111+ Action :: Allow => enforced_policy. is_some ( ) ,
112+ Action :: Deny => enforced_policy. is_none ( ) ,
113+ } ;
114+
115+ debug ! (
116+ "NetworkRbac: rule is enforced by {enforced_policy:?} with action: {:?} -> permitted {permitted}" ,
117+ self . action
118+ ) ;
119+ ( permitted, enforced_policy)
117120 }
118121}
119122
@@ -141,16 +144,24 @@ mod tests {
141144 let permission = Permission :: Any ;
142145 let principal = Principal :: Any ;
143146 let policy = Policy { permissions : vec ! [ permission] , principals : vec ! [ principal] } ;
144- let rbac_rule = NetworkRbac { action : Action :: Allow , policies : vec ! [ policy] } ;
145- assert ! ( rbac_rule. is_permitted( create_network_context( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ) ;
147+ let rbac_rule =
148+ NetworkRbac { action : Action :: Allow , policies : vec ! [ ( "my-id" . into( ) , policy) ] . into_iter ( ) . collect ( ) } ;
149+ let ( permitted, rule) =
150+ rbac_rule. is_permitted ( & create_network_context ( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ;
151+ assert ! ( permitted) ;
152+ assert_eq ! ( rule, Some ( "my-id" . into( ) ) ) ;
146153 }
147154 #[ test]
148155 fn rule_test_allow_dest_ip_permission_any_principal ( ) {
149156 let permission = Permission :: DestinationIp ( "127.0.0.0/24" . parse ( ) . unwrap ( ) ) ;
150157 let principal = Principal :: Any ;
151158 let policy = Policy { permissions : vec ! [ permission] , principals : vec ! [ principal] } ;
152- let rbac_rule = NetworkRbac { action : Action :: Allow , policies : vec ! [ policy] } ;
153- assert ! ( rbac_rule. is_permitted( create_network_context( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ) ;
159+ let rbac_rule =
160+ NetworkRbac { action : Action :: Allow , policies : vec ! [ ( "my-id" . into( ) , policy) ] . into_iter ( ) . collect ( ) } ;
161+ let ( permitted, rule) =
162+ rbac_rule. is_permitted ( & create_network_context ( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ;
163+ assert ! ( permitted) ;
164+ assert_eq ! ( rule, Some ( "my-id" . into( ) ) ) ;
154165 }
155166
156167 #[ test]
@@ -159,8 +170,12 @@ mod tests {
159170 let permission1 = Permission :: Any ;
160171 let principal = Principal :: Any ;
161172 let policy = Policy { permissions : vec ! [ permission1, permission2] , principals : vec ! [ principal] } ;
162- let rbac_rule = NetworkRbac { action : Action :: Allow , policies : vec ! [ policy] } ;
163- assert ! ( rbac_rule. is_permitted( create_network_context( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ) ;
173+ let rbac_rule =
174+ NetworkRbac { action : Action :: Allow , policies : vec ! [ ( "my-id" . into( ) , policy) ] . into_iter ( ) . collect ( ) } ;
175+ let ( permitted, rule) =
176+ rbac_rule. is_permitted ( & create_network_context ( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ;
177+ assert ! ( permitted) ;
178+ assert_eq ! ( rule, Some ( "my-id" . into( ) ) ) ;
164179 }
165180
166181 #[ test]
@@ -169,17 +184,25 @@ mod tests {
169184 let permission1 = Permission :: Any ;
170185 let principal = Principal :: Any ;
171186 let policy = Policy { permissions : vec ! [ permission1, permission2] , principals : vec ! [ principal] } ;
172- let rbac_rule = NetworkRbac { action : Action :: Allow , policies : vec ! [ policy] } ;
173- assert ! ( rbac_rule. is_permitted( create_network_context( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ) ;
187+ let rbac_rule =
188+ NetworkRbac { action : Action :: Allow , policies : vec ! [ ( "my-id" . into( ) , policy) ] . into_iter ( ) . collect ( ) } ;
189+ let ( permitted, rule) =
190+ rbac_rule. is_permitted ( & create_network_context ( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ;
191+ assert ! ( permitted) ;
192+ assert_eq ! ( rule, Some ( "my-id" . into( ) ) ) ;
174193 }
175194
176195 #[ test]
177196 fn rule_test_allow_dest_ip_permission_src_ip_principal ( ) {
178197 let permission = Permission :: DestinationIp ( "127.0.0.0/24" . parse ( ) . unwrap ( ) ) ;
179198 let principal = Principal :: DownstreamRemoteIp ( "127.0.0.0/24" . parse ( ) . unwrap ( ) ) ;
180199 let policy = Policy { permissions : vec ! [ permission] , principals : vec ! [ principal] } ;
181- let rbac_rule = NetworkRbac { action : Action :: Allow , policies : vec ! [ policy] } ;
182- assert ! ( rbac_rule. is_permitted( create_network_context( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ) ;
200+ let rbac_rule =
201+ NetworkRbac { action : Action :: Allow , policies : vec ! [ ( "my-id" . into( ) , policy) ] . into_iter ( ) . collect ( ) } ;
202+ let ( permitted, rule) =
203+ rbac_rule. is_permitted ( & create_network_context ( "127.0.0.1" , 8000 , "127.0.0.1" , 9000 , None ) ) ;
204+ assert ! ( permitted) ;
205+ assert_eq ! ( rule, Some ( "my-id" . into( ) ) ) ;
183206 }
184207}
185208
@@ -205,7 +228,10 @@ mod envoy_conversions {
205228 let EnvoyRbac { action, policies, audit_logging_options } = envoy;
206229 unsupported_field ! ( audit_logging_options) ?;
207230 let action = Action :: try_from ( action) . with_node ( "action" ) ?;
208- let policies = required ! ( policies) ?. into_values ( ) . map ( Policy :: try_from) . collect :: < Result < _ , _ > > ( ) ?;
231+ let policies = required ! ( policies) ?
232+ . into_iter ( )
233+ . map ( |( id, pol) | Policy :: try_from ( pol) . map ( |value| ( id. into ( ) , value) ) )
234+ . collect :: < Result < _ , _ > > ( ) ?;
209235 Ok ( NetworkRbac { action, policies } )
210236 }
211237 }
0 commit comments