@@ -17,6 +17,9 @@ defmodule SentinelCp.Services.KdlGenerator do
1717 InternalCa
1818 }
1919
20+ alias SentinelCp.Waf
21+ alias SentinelCp.Waf.WafPolicy
22+
2023 @ doc """
2124 Generates KDL configuration for a project from its services and config.
2225
@@ -38,6 +41,7 @@ defmodule SentinelCp.Services.KdlGenerator do
3841 upstream_groups = Services . list_upstream_groups ( project_id )
3942 certificates = Services . list_certificates ( project_id )
4043 auth_policies = Services . list_auth_policies ( project_id )
44+ waf_policies = Waf . list_policies ( project_id )
4145 trust_stores = Services . list_trust_stores ( project_id )
4246 internal_ca = Services . get_internal_ca ( project_id )
4347
@@ -68,7 +72,8 @@ defmodule SentinelCp.Services.KdlGenerator do
6872 middleware_chains ,
6973 trust_stores ,
7074 internal_ca ,
71- plugin_chains
75+ plugin_chains ,
76+ waf_policies
7277 )
7378
7479 { :ok , kdl }
@@ -146,7 +151,8 @@ defmodule SentinelCp.Services.KdlGenerator do
146151 middleware_chains \\ % { } ,
147152 trust_stores \\ [ ] ,
148153 internal_ca \\ nil ,
149- plugin_chains \\ % { }
154+ plugin_chains \\ % { } ,
155+ waf_policies \\ [ ]
150156 ) do
151157 # Build lookup maps
152158 group_map =
@@ -161,6 +167,10 @@ defmodule SentinelCp.Services.KdlGenerator do
161167 auth_policies
162168 |> Enum . into ( % { } , fn a -> { a . id , a } end )
163169
170+ waf_policy_map =
171+ waf_policies
172+ |> Enum . into ( % { } , fn w -> { w . id , w } end )
173+
164174 trust_store_map =
165175 trust_stores
166176 |> Enum . into ( % { } , fn t -> { t . id , t } end )
@@ -201,7 +211,8 @@ defmodule SentinelCp.Services.KdlGenerator do
201211 auth_policy_map ,
202212 middleware_chains ,
203213 internal_ca ,
204- plugin_chains
214+ plugin_chains ,
215+ waf_policy_map
205216 ) ,
206217 build_rate_limits ( services )
207218 ]
@@ -344,14 +355,25 @@ defmodule SentinelCp.Services.KdlGenerator do
344355 auth_policy_map ,
345356 middleware_chains ,
346357 internal_ca ,
347- plugin_chains
358+ plugin_chains ,
359+ waf_policy_map
348360 ) do
349361 route_blocks =
350362 services
351363 |> Enum . map ( fn service ->
352364 chain = Map . get ( middleware_chains , service . id , [ ] )
353365 plugins = Map . get ( plugin_chains , service . id , [ ] )
354- build_route ( service , group_map , cert_map , auth_policy_map , chain , internal_ca , plugins )
366+
367+ build_route (
368+ service ,
369+ group_map ,
370+ cert_map ,
371+ auth_policy_map ,
372+ chain ,
373+ internal_ca ,
374+ plugins ,
375+ waf_policy_map
376+ )
355377 end )
356378 |> Enum . intersperse ( [ "" ] )
357379
@@ -365,7 +387,8 @@ defmodule SentinelCp.Services.KdlGenerator do
365387 auth_policy_map ,
366388 middleware_chain ,
367389 internal_ca ,
368- plugin_chain
390+ plugin_chain ,
391+ waf_policy_map
369392 ) do
370393 lines = [ " route #{ inspect ( service . route_path ) } {" ]
371394
@@ -411,7 +434,15 @@ defmodule SentinelCp.Services.KdlGenerator do
411434 lines = lines ++ build_path_rewrite_block ( service . path_rewrite )
412435 lines = lines ++ build_tls_ref ( service . certificate_id , cert_map )
413436 lines = lines ++ build_auth_block ( service . auth_policy_id , auth_policy_map , internal_ca )
414- lines = lines ++ build_security_block ( service . security )
437+
438+ lines =
439+ lines ++
440+ build_waf_block (
441+ Map . get ( service , :waf_policy_id ) ,
442+ waf_policy_map ,
443+ service . security
444+ )
445+
415446 lines = lines ++ build_request_transform_block ( service . request_transform )
416447 lines = lines ++ build_response_transform_block ( service . response_transform )
417448 lines = lines ++ build_traffic_split_block ( service . traffic_split , group_map )
@@ -543,6 +574,59 @@ defmodule SentinelCp.Services.KdlGenerator do
543574 build_nested_map_block ( sec , "security" , " " )
544575 end
545576
577+ # WAF block: when a policy is bound, emit structured waf {} block.
578+ # When no policy but legacy security map exists, fall back to build_security_block.
579+ defp build_waf_block ( nil , _waf_policy_map , security_map ) do
580+ build_security_block ( security_map )
581+ end
582+
583+ defp build_waf_block ( waf_policy_id , waf_policy_map , _security_map ) do
584+ case Map . get ( waf_policy_map , waf_policy_id ) do
585+ nil ->
586+ [ ]
587+
588+ % WafPolicy { } = policy ->
589+ effective_rules = Waf . get_effective_rules ( policy )
590+
591+ lines = [ " waf {" ]
592+ lines = lines ++ [ " mode #{ inspect ( policy . mode ) } " ]
593+ lines = lines ++ [ " sensitivity #{ inspect ( policy . sensitivity ) } " ]
594+
595+ lines =
596+ if policy . max_body_size ,
597+ do: lines ++ [ " max_body_size #{ policy . max_body_size } " ] ,
598+ else: lines
599+
600+ lines =
601+ if policy . max_header_size ,
602+ do: lines ++ [ " max_header_size #{ policy . max_header_size } " ] ,
603+ else: lines
604+
605+ lines =
606+ if policy . max_uri_length ,
607+ do: lines ++ [ " max_uri_length #{ policy . max_uri_length } " ] ,
608+ else: lines
609+
610+ # Group effective rules by category
611+ by_category =
612+ effective_rules
613+ |> Enum . group_by ( fn { rule , _action } -> rule . category end )
614+ |> Enum . sort_by ( fn { cat , _ } -> cat end )
615+
616+ category_lines =
617+ Enum . flat_map ( by_category , fn { category , rules_with_actions } ->
618+ rule_lines =
619+ Enum . map ( rules_with_actions , fn { rule , action } ->
620+ " rule #{ inspect ( rule . rule_id ) } action=#{ inspect ( action ) } "
621+ end )
622+
623+ [ " category #{ inspect ( category ) } {" ] ++ rule_lines ++ [ " }" ]
624+ end )
625+
626+ lines ++ category_lines ++ [ " }" ]
627+ end
628+ end
629+
546630 defp build_request_transform_block ( rt ) when rt == % { } or rt == nil , do: [ ]
547631
548632 defp build_request_transform_block ( rt ) do
0 commit comments