Skip to content

Commit 98a748a

Browse files
committed
fix: ensure domain defined in acls is included in host rules
1 parent 3194f4b commit 98a748a

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

internal/service/kubernetes_service.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package service
33
import (
44
"context"
55
"fmt"
6+
"slices"
67
"strings"
78
"sync"
89
"time"
@@ -167,6 +168,68 @@ func (k *KubernetesService) getByAppName(appName string) *model.App {
167168
return nil
168169
}
169170

171+
func (k *KubernetesService) extractPaths(rule map[string]any) ([]string, error) {
172+
http, found, err := unstructured.NestedMap(rule, "http")
173+
if err != nil {
174+
return nil, fmt.Errorf("reading http from rule: %w", err)
175+
}
176+
if !found {
177+
return nil, nil
178+
}
179+
paths, found, err := unstructured.NestedSlice(http, "paths")
180+
if err != nil {
181+
return nil, fmt.Errorf("reading http.paths: %w", err)
182+
}
183+
if !found {
184+
return nil, nil
185+
}
186+
var result []string
187+
for _, p := range paths {
188+
path, ok := p.(map[string]any)
189+
if !ok {
190+
continue
191+
}
192+
if p, ok := path["path"].(string); ok && p != "" {
193+
result = append(result, p)
194+
}
195+
}
196+
return result, nil
197+
}
198+
199+
func (k *KubernetesService) extractHosts(item *unstructured.Unstructured) ([]string, error) {
200+
rules, found, err := unstructured.NestedSlice(item.Object, "spec", "rules")
201+
if err != nil {
202+
return nil, fmt.Errorf("reading spec.rules: %w", err)
203+
}
204+
if !found {
205+
return nil, nil
206+
}
207+
var hosts []string
208+
for _, r := range rules {
209+
rule, ok := r.(map[string]any)
210+
if !ok {
211+
continue
212+
}
213+
if host, ok := rule["host"].(string); ok && host != "" {
214+
hosts = append(hosts, host)
215+
}
216+
paths, err := k.extractPaths(rule)
217+
if err != nil {
218+
// This is purely to warn users, it doesn't affect our ability to extract hosts so we won't fail the whole operation
219+
k.log.App.Warn().Err(err).Str("namespace", item.GetNamespace()).Str("name", item.GetName()).Msg("Failed to extract paths from ingress rule")
220+
continue
221+
}
222+
if len(paths) == 0 {
223+
continue
224+
}
225+
if !slices.Contains(paths, "/") {
226+
k.log.App.Warn().Str("namespace", item.GetNamespace()).Str("name", item.GetName()).Strs("paths", paths).Msg("Ingress rule does not contain a catch-all path, another ingress may be able to bypass auth checks if it routes the same host with a different path. Consider adding a catch-all path to this rule to ensure auth checks are applied to all paths for this host.")
227+
}
228+
}
229+
k.log.App.Trace().Strs("hosts", hosts).Msg("Extracted hosts from ingress rules")
230+
return hosts, nil
231+
}
232+
170233
func (k *KubernetesService) updateFromItem(item *unstructured.Unstructured) {
171234
namespace := item.GetNamespace()
172235
name := item.GetName()
@@ -175,6 +238,11 @@ func (k *KubernetesService) updateFromItem(item *unstructured.Unstructured) {
175238
k.removeIngress(namespace, name)
176239
return
177240
}
241+
hosts, err := k.extractHosts(item)
242+
if err != nil {
243+
k.removeIngress(namespace, name)
244+
return
245+
}
178246
labels, err := decoders.DecodeLabels[model.Apps](annotations, "apps")
179247
if err != nil {
180248
k.log.App.Warn().Err(err).Str("namespace", namespace).Str("name", name).Msg("Failed to decode ingress labels, skipping")
@@ -186,6 +254,10 @@ func (k *KubernetesService) updateFromItem(item *unstructured.Unstructured) {
186254
if appLabels.Config.Domain == "" {
187255
continue
188256
}
257+
if len(hosts) > 0 && !slices.Contains(hosts, appLabels.Config.Domain) {
258+
k.log.App.Warn().Str("namespace", namespace).Str("name", name).Str("appName", appName).Str("domain", appLabels.Config.Domain).Msg("App domain does not match any hosts defined in ingress rules, skipping")
259+
continue
260+
}
189261
apps = append(apps, ingressApp{
190262
domain: appLabels.Config.Domain,
191263
appName: appName,

0 commit comments

Comments
 (0)