diff --git a/README.md b/README.md index 4568cf9..3cfee99 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ It is possible to add global IP allow and block lists, the helm chart will have * allowing IP addresses via `/lists/allowedips` file which is a single line per entry of ip address to allow * blocking IP addresses via `/lists/blockedips` file which is a single line per entry of ip address to block -There are also annotations that can be added to specific `Kind: Ingress` objects that allow for ip allow or blocking. +There are also annotations that can be added to the namespace, or individual `Kind: Ingress` objects that allow for ip allow or blocking. * `idling.amazee.io/ip-allow-list` - a comma separated list of ip addresses to allow, will be checked against x-forward-for, but if true-client-ip is provided it will prefer this. * `idling.amazee.io/ip-block-list` - a comma separated list of ip addresses to allow, will be checked against x-forward-for, but if true-client-ip is provided it will prefer this. @@ -40,7 +40,7 @@ It is possible to add global UserAgent allow and block lists, the helm chart wil * allowing user agents via a `/lists/allowedagents` file which is a single line per entry of useragents or regex patterns to match against. These must be `go` based regular expressions. * blocking user agents via a `/lists/blockedagents` file which is a single line per entry of useragents or regex patterns to match against. These must be `go` based regular expressions. -There are also annotations that can be added to specific `Kind: Ingress` objects that allow for user agent allow or blocking. +There are also annotations that can be added to the namespace, or individual `Kind: Ingress` objects that allow for user agent allow or blocking. * `idling.amazee.io/allowed-agents` - a comma separated list of user agents or regex patterns to allow. * `idling.amazee.io/blocked-agents` - a comma separated list of user agents or regex patterns to block. diff --git a/handlers/unidler/handler.go b/handlers/unidler/handler.go index e37d7aa..2853c23 100644 --- a/handlers/unidler/handler.go +++ b/handlers/unidler/handler.go @@ -12,6 +12,7 @@ import ( "time" "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" networkv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/types" ) @@ -66,6 +67,13 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re // @TODO: check for code 503 specifically, or just any request that has the namespace in it will be "unidled" if a request comes in for // that ingress and the if ns != "" { + namespace := &corev1.Namespace{} + if err := h.Client.Get(ctx, types.NamespacedName{ + Name: ns, + }, namespace); err != nil { + opLog.Info(fmt.Sprintf("unable to get any namespaces: %v", err)) + return + } ingress := &networkv1.Ingress{} if err := h.Client.Get(ctx, types.NamespacedName{ Namespace: ns, @@ -81,7 +89,7 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re trueClientIP := r.Header.Get("True-Client-IP") requestUserAgent := r.Header.Get("User-Agent") - allowUnidle := h.checkAccess(ingress.ObjectMeta.Annotations, requestUserAgent, trueClientIP, xForwardedFor) + allowUnidle := h.checkAccess(namespace.ObjectMeta.Annotations, ingress.ObjectMeta.Annotations, requestUserAgent, trueClientIP, xForwardedFor) // then run checks to start to unidle the environment if allowUnidle { // if a namespace exists, it means that the custom-http-errors code is defined in the ingress object diff --git a/handlers/unidler/restrictions.go b/handlers/unidler/restrictions.go index 45e7977..41ac4d4 100644 --- a/handlers/unidler/restrictions.go +++ b/handlers/unidler/restrictions.go @@ -34,7 +34,7 @@ func checkIPList(allowList []string, xForwardedFor []string, trueClientIP string return false } -func (h *Unidler) checkAccess(annotations map[string]string, userAgent, trueClientIP string, xForwardedFor []string) bool { +func (h *Unidler) checkAccess(nsannotations map[string]string, annotations map[string]string, userAgent, trueClientIP string, xForwardedFor []string) bool { allowedIP := false allowedAgent := false blockedIP := false @@ -51,9 +51,14 @@ func (h *Unidler) checkAccess(annotations map[string]string, userAgent, trueClie hasIPAllowList = true allowedIP = checkIPList(strings.Split(alist, ","), xForwardedFor, trueClientIP) } else { - if h.AllowedIPs != nil { + if alist, ok := nsannotations["idling.amazee.io/ip-allow-list"]; ok { hasIPAllowList = true - allowedIP = checkIPList(h.AllowedIPs, xForwardedFor, trueClientIP) + allowedIP = checkIPList(strings.Split(alist, ","), xForwardedFor, trueClientIP) + } else { + if h.AllowedIPs != nil { + hasIPAllowList = true + allowedIP = checkIPList(h.AllowedIPs, xForwardedFor, trueClientIP) + } } } @@ -63,9 +68,14 @@ func (h *Unidler) checkAccess(annotations map[string]string, userAgent, trueClie hasIPBlockList = true blockedIP = checkIPList(strings.Split(blist, ","), xForwardedFor, trueClientIP) } else { - if h.BlockedIPs != nil { + if blist, ok := nsannotations["idling.amazee.io/ip-block-list"]; ok { hasIPBlockList = true - blockedIP = checkIPList(h.BlockedIPs, xForwardedFor, trueClientIP) + blockedIP = checkIPList(strings.Split(blist, ","), xForwardedFor, trueClientIP) + } else { + if h.BlockedIPs != nil { + hasIPBlockList = true + blockedIP = checkIPList(h.BlockedIPs, xForwardedFor, trueClientIP) + } } } @@ -81,9 +91,14 @@ func (h *Unidler) checkAccess(annotations map[string]string, userAgent, trueClie hasAllowedAgentList = true allowedAgent = checkAgents(strings.Split(agents, ","), userAgent) } else { - if h.AllowedUserAgents != nil { + if agents, ok := annotations["idling.amazee.io/allowed-agents"]; ok { hasAllowedAgentList = true - allowedAgent = checkAgents(h.AllowedUserAgents, userAgent) + allowedAgent = checkAgents(strings.Split(agents, ","), userAgent) + } else { + if h.AllowedUserAgents != nil { + hasAllowedAgentList = true + allowedAgent = checkAgents(h.AllowedUserAgents, userAgent) + } } } @@ -91,9 +106,14 @@ func (h *Unidler) checkAccess(annotations map[string]string, userAgent, trueClie hasBlockedAgentList = true blockedAgent = checkAgents(strings.Split(agents, ","), userAgent) } else { - if h.BlockedUserAgents != nil { + if agents, ok := annotations["idling.amazee.io/blocked-agents"]; ok { hasBlockedAgentList = true - blockedAgent = checkAgents(h.BlockedUserAgents, userAgent) + blockedAgent = checkAgents(strings.Split(agents, ","), userAgent) + } else { + if h.BlockedUserAgents != nil { + hasBlockedAgentList = true + blockedAgent = checkAgents(h.BlockedUserAgents, userAgent) + } } } diff --git a/handlers/unidler/restrictions_test.go b/handlers/unidler/restrictions_test.go index 44916a0..a8cc841 100644 --- a/handlers/unidler/restrictions_test.go +++ b/handlers/unidler/restrictions_test.go @@ -116,6 +116,7 @@ func TestUnidler_checkAccess(t *testing.T) { BlockedIPs []string } type args struct { + nsannotations map[string]string annotations map[string]string userAgent string trueClientIP string @@ -362,6 +363,25 @@ func TestUnidler_checkAccess(t *testing.T) { }, want: true, }, + { + name: "test15 - allowed ip blocked agent namespace annotation", + args: args{ + nsannotations: map[string]string{ + "idling.amazee.io/blocked-agents": "@(example).test.?$,@(internal).test.?$", + "idling.amazee.io/ip-allow-list": "1.2.3.4", + }, + userAgent: "This is not a bot, don't complaint to: complain@example.test.", + trueClientIP: "1.2.3.4", + xForwardedFor: nil, + }, + fields: fields{ + AllowedUserAgents: nil, + BlockedUserAgents: nil, + BlockedIPs: nil, + AllowedIPs: nil, + }, + want: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -371,7 +391,7 @@ func TestUnidler_checkAccess(t *testing.T) { AllowedIPs: tt.fields.AllowedIPs, BlockedIPs: tt.fields.BlockedIPs, } - if got := h.checkAccess(tt.args.annotations, tt.args.userAgent, tt.args.trueClientIP, tt.args.xForwardedFor); got != tt.want { + if got := h.checkAccess(tt.args.nsannotations, tt.args.annotations, tt.args.userAgent, tt.args.trueClientIP, tt.args.xForwardedFor); got != tt.want { t.Errorf("Unidler.checkAccess() = %v, want %v", got, tt.want) } })