@@ -6,7 +6,7 @@ defmodule SentinelCp.Services.KdlGenerator do
66 """
77
88 alias SentinelCp.Services
9- alias SentinelCp.Services . { Service , ProjectConfig , UpstreamGroup , Certificate , AuthPolicy }
9+ alias SentinelCp.Services . { Service , ProjectConfig , UpstreamGroup , Certificate , TrustStore , AuthPolicy }
1010
1111 @ doc """
1212 Generates KDL configuration for a project from its services and config.
@@ -29,6 +29,7 @@ defmodule SentinelCp.Services.KdlGenerator do
2929 upstream_groups = Services . list_upstream_groups ( project_id )
3030 certificates = Services . list_certificates ( project_id )
3131 auth_policies = Services . list_auth_policies ( project_id )
32+ trust_stores = Services . list_trust_stores ( project_id )
3233
3334 # Build middleware chain map: service_id -> [service_middlewares]
3435 middleware_chains =
@@ -40,7 +41,7 @@ defmodule SentinelCp.Services.KdlGenerator do
4041 # Resolve secret references if requested
4142 case maybe_resolve_secrets ( services , opts ) do
4243 { :ok , resolved_services } ->
43- kdl = build_kdl ( resolved_services , config , upstream_groups , certificates , auth_policies , middleware_chains )
44+ kdl = build_kdl ( resolved_services , config , upstream_groups , certificates , auth_policies , middleware_chains , trust_stores )
4445 { :ok , kdl }
4546
4647 { :error , _ } = error ->
@@ -92,7 +93,7 @@ defmodule SentinelCp.Services.KdlGenerator do
9293 Generates KDL from provided services, config, and upstream groups (no DB access).
9394 Useful for testing.
9495 """
95- def build_kdl ( services , % ProjectConfig { } = config , upstream_groups \\ [ ] , certificates \\ [ ] , auth_policies \\ [ ] , middleware_chains \\ % { } ) do
96+ def build_kdl ( services , % ProjectConfig { } = config , upstream_groups \\ [ ] , certificates \\ [ ] , auth_policies \\ [ ] , middleware_chains \\ % { } , trust_stores \\ [ ] ) do
9697 # Build lookup maps
9798 group_map =
9899 upstream_groups
@@ -106,6 +107,10 @@ defmodule SentinelCp.Services.KdlGenerator do
106107 auth_policies
107108 |> Enum . into ( % { } , fn a -> { a . id , a } end )
108109
110+ trust_store_map =
111+ trust_stores
112+ |> Enum . into ( % { } , fn t -> { t . id , t } end )
113+
109114 # Determine which certificates are used by services
110115 used_cert_ids =
111116 services
@@ -115,14 +120,24 @@ defmodule SentinelCp.Services.KdlGenerator do
115120
116121 used_certs = Enum . filter ( certificates , fn c -> MapSet . member? ( used_cert_ids , c . id ) end )
117122
123+ # Determine which trust stores are used by upstream groups
124+ used_trust_store_ids =
125+ upstream_groups
126+ |> Enum . map ( & & 1 . trust_store_id )
127+ |> Enum . reject ( & is_nil / 1 )
128+ |> MapSet . new ( )
129+
130+ used_trust_stores = Enum . filter ( trust_stores , fn t -> MapSet . member? ( used_trust_store_ids , t . id ) end )
131+
118132 parts = [
119133 "// Generated by Sentinel Control Plane" ,
120134 "// Do not edit manually — managed via Services UI" ,
121135 "" ,
122136 build_settings ( config ) ,
123137 "" ,
124138 build_tls_certificates ( used_certs ) ,
125- build_upstream_groups ( upstream_groups ) ,
139+ build_trust_stores ( used_trust_stores ) ,
140+ build_upstream_groups ( upstream_groups , trust_store_map ) ,
126141 build_routes ( services , group_map , cert_map , auth_policy_map , middleware_chains ) ,
127142 build_rate_limits ( services )
128143 ]
@@ -167,18 +182,38 @@ defmodule SentinelCp.Services.KdlGenerator do
167182 build_nested_map_block ( config . default_security , "security" , " " )
168183 end
169184
170- defp build_upstream_groups ( [ ] ) , do: [ ]
185+ defp build_trust_stores ( [ ] ) , do: [ ]
171186
172- defp build_upstream_groups ( groups ) do
187+ defp build_trust_stores ( trust_stores ) do
188+ blocks =
189+ trust_stores
190+ |> Enum . map ( & build_trust_store_block / 1 )
191+ |> Enum . intersperse ( [ "" ] )
192+
193+ [ "trust_stores {" ] ++ List . flatten ( blocks ) ++ [ "}" , "" ]
194+ end
195+
196+ defp build_trust_store_block ( % TrustStore { } = ts ) do
197+ [
198+ " store #{ inspect ( ts . slug ) } {" ,
199+ " ca_file \" /etc/sentinel/trust-stores/#{ ts . slug } .pem\" " ,
200+ " }"
201+ ]
202+ end
203+
204+ defp build_upstream_groups ( groups , trust_store_map )
205+ defp build_upstream_groups ( [ ] , _trust_store_map ) , do: [ ]
206+
207+ defp build_upstream_groups ( groups , trust_store_map ) do
173208 blocks =
174209 groups
175- |> Enum . map ( & build_upstream_group_block / 1 )
210+ |> Enum . map ( & build_upstream_group_block ( & 1 , trust_store_map ) )
176211 |> Enum . intersperse ( [ "" ] )
177212
178213 [ "upstream_groups {" ] ++ List . flatten ( blocks ) ++ [ "}" , "" ]
179214 end
180215
181- defp build_upstream_group_block ( % UpstreamGroup { } = group ) do
216+ defp build_upstream_group_block ( % UpstreamGroup { } = group , trust_store_map ) do
182217 lines = [ " group #{ inspect ( group . slug ) } {" ]
183218 lines = lines ++ [ " algorithm #{ inspect ( group . algorithm ) } " ]
184219
@@ -203,9 +238,29 @@ defmodule SentinelCp.Services.KdlGenerator do
203238 # Add sticky sessions
204239 lines = lines ++ build_nested_map_block ( group . sticky_sessions , "sticky_sessions" , " " )
205240
241+ # Add TLS verify block if trust store is linked
242+ lines = lines ++ build_upstream_tls_block ( group . trust_store_id , trust_store_map )
243+
206244 lines ++ [ " }" ]
207245 end
208246
247+ defp build_upstream_tls_block ( nil , _trust_store_map ) , do: [ ]
248+
249+ defp build_upstream_tls_block ( trust_store_id , trust_store_map ) do
250+ case Map . get ( trust_store_map , trust_store_id ) do
251+ nil ->
252+ [ ]
253+
254+ ts ->
255+ [
256+ " tls {" ,
257+ " verify true" ,
258+ " ca_file \" /etc/sentinel/trust-stores/#{ ts . slug } .pem\" " ,
259+ " }"
260+ ]
261+ end
262+ end
263+
209264 defp build_routes ( services , group_map , cert_map , auth_policy_map , middleware_chains ) do
210265 route_blocks =
211266 services
0 commit comments