diff --git a/rules/exposure-to-internet-via-istio-ingress/raw.rego b/rules/exposure-to-internet-via-istio-ingress/raw.rego index 9d010ae6..996ccc91 100644 --- a/rules/exposure-to-internet-via-istio-ingress/raw.rego +++ b/rules/exposure-to-internet-via-istio-ingress/raw.rego @@ -6,12 +6,18 @@ deny[msga] { virtualservice := input[_] virtualservice.kind == "VirtualService" + # Get the namescape of the VirtualService + vs_ns := get_namespace(virtualservice) + # Looping over the gateways of the VirtualService + vs_gw_name := virtualservice.spec.gateways[_] + # Get the namespace of the Gateway + vs_gw = get_vs_gw_ns(vs_ns, vs_gw_name) + # Check if the VirtualService is connected to a Gateway gateway := input[_] gateway.kind == "Gateway" - - is_same_namespace(gateway, virtualservice) - virtualservice.spec.gateways[_] == gateway.metadata.name + gateway.metadata.name == vs_gw.name + get_namespace(gateway) == vs_gw.namespace # Find the connected Istio Ingress Gateway that should be a LoadBalancer if it is exposed to the internet istioingressgateway := input[_] @@ -19,7 +25,6 @@ deny[msga] { istioingressgateway.metadata.namespace == "istio-system" gateway.spec.selector[_] == istioingressgateway.metadata.labels[_] - # Check if the Istio Ingress Gateway is exposed to the internet is_exposed_service(istioingressgateway) @@ -27,7 +32,7 @@ deny[msga] { # First, find the service that the VirtualService is connected to connected_service := input[_] connected_service.kind == "Service" - fqsn := get_fqsn(get_namespace(virtualservice), virtualservice.spec.http[_].route[_].destination.host) + fqsn := get_fqsn(get_namespace(virtualservice), virtualservice.spec.http[i].route[j].destination.host) target_ns := split(fqsn,".")[1] target_name := split(fqsn,".")[0] # Check if the service is in the same namespace as the VirtualService @@ -42,7 +47,7 @@ deny[msga] { spec_template_spec_patterns[wl.kind] wl_connected_to_service(wl, connected_service) - result := svc_connected_to_virtualservice(connected_service, virtualservice) + failedPaths := [sprintf("spec.http[%d].routes[%d].destination.host", [i,j])] msga := { "alertMessage": sprintf("workload '%v' is exposed through virtualservice '%v'", [wl.metadata.name, virtualservice.metadata.name]), @@ -54,14 +59,14 @@ deny[msga] { "k8sApiObjects": [wl] }, "relatedObjects": [ - { + { "object": virtualservice, - "reviewPaths": result, - "failedPaths": result, + "reviewPaths": failedPaths, + "failedPaths": failedPaths, }, - { - "object": connected_service, - } + { + "object": connected_service, + } ] } } @@ -79,6 +84,20 @@ get_namespace(obj) = namespace { namespace := "default" } +get_vs_gw_ns(vs_ns, vs_gw_name) = {"name": name, "namespace": ns} { + # Check if there is a / in the gateway name + count(split(vs_gw_name, "/")) == 2 + ns := split(vs_gw_name, "/")[0] + name := split(vs_gw_name, "/")[1] +} + +get_vs_gw_ns(vs_ns, vs_gw_name) = {"name": name, "namespace": ns} { + # Check if there is no / in the gateway name + count(split(vs_gw_name, "/")) == 1 + ns := vs_ns + name := vs_gw_name +} + is_same_namespace(obj1, obj2) { obj1.metadata.namespace == obj2.metadata.namespace } @@ -141,4 +160,3 @@ get_fqsn(ns, dest_host) = fqsn { } - diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/expected.json b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/expected.json new file mode 100644 index 00000000..df1b5fa1 --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/expected.json @@ -0,0 +1,193 @@ +[ + { + "alertMessage": "workload 'nginx' is exposed through virtualservice 'int-0721'", + "failedPaths": [], + "reviewPaths": null, + "deletePaths": null, + "fixPaths": [], + "ruleStatus": "", + "packagename": "armo_builtins", + "alertScore": 7, + "alertObject": { + "k8sApiObjects": [ + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "labels": { + "app": "int-0721", + "context": "default", + "name": "int-0721", + "role": "app" + }, + "name": "nginx" + } + } + ] + }, + "relatedObjects": [ + { + "object": { + "apiVersion": "networking.istio.io/v1beta1", + "kind": "VirtualService", + "metadata": { + "creationTimestamp": "2024-04-15T08:56:16Z", + "generation": 2, + "labels": { + "app": "int-0721", + "context": "default", + "name": "int-0721", + "owner": "int-0721", + "owner-namespace": "kt-itinternal", + "role": "app" + }, + "name": "int-0721", + "namespace": "kt-itinternal" + }, + "spec": { + "gateways": [ + "kt-connections/prod-lan-gateway", + "kt-connections/sdfsdfs-gateway", + "kt-connections/api-public", + "kt-connections/aaaaa-public", + "kt-connections/mydddd-public" + ], + "hosts": [ + "api.stg.prod.lan" + ], + "http": [ + { + "corsPolicy": { + "allowHeaders": [ + "authorization", + "Origin", + "Content-Type", + "Accept" + ], + "allowMethods": [ + "POST", + "GET", + "OPTIONS", + "PUT", + "PATCH", + "DELETE" + ], + "allowOrigins": [ + { + "regex": ".*" + } + ] + }, + "match": [ + { + "authority": { + "exact": "api.stg.prod.lan" + }, + "uri": { + "prefix": "/int/0698/" + } + } + ], + "name": "api-http-stgprodlan", + "rewrite": { + "uri": "/" + }, + "route": [ + { + "destination": { + "host": "int-0721.kt-itinternal.svc.cluster.local", + "port": { + "number": 8080 + } + }, + "headers": { + "request": { + "set": { + "X-Forwarded-Prefix": "/int/0698", + "X-Forwarded-Proto": "https" + } + } + } + } + ] + } + ] + } + }, + "failedPaths": [ + "spec.http[0].routes[0].destination.host" + ], + "reviewPaths": [ + "spec.http[0].routes[0].destination.host" + ], + "deletePaths": null, + "fixPaths": null + }, + { + "object": { + "apiVersion": "v1", + "kind": "Service", + "metadata": { + "creationTimestamp": "2024-04-15T09:00:11Z", + "labels": { + "app": "int-0721", + "context": "default", + "name": "int-0721", + "owner": "int-0721", + "owner-namespace": "kt-itinternal", + "role": "app" + }, + "name": "int-0721", + "namespace": "kt-itinternal", + "ownerReferences": [ + { + "apiVersion": "msss/v1alpha1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "Microservice", + "name": "int-0721", + "uid": "14a69d5b-249c-487d-9500-645bda6a4c56" + } + ], + "resourceVersion": "3779885629", + "uid": "0428cb70-5d8f-4345-8ef2-5b0a249e0793" + }, + "spec": { + "clusterIP": "10.81.208.49", + "clusterIPs": [ + "10.81.208.49" + ], + "internalTrafficPolicy": "Cluster", + "ipFamilies": [ + "IPv4" + ], + "ipFamilyPolicy": "SingleStack", + "ports": [ + { + "name": "http", + "port": 8080, + "protocol": "TCP", + "targetPort": 8080 + } + ], + "selector": { + "app": "int-0721", + "context": "default", + "name": "int-0721", + "role": "app" + }, + "sessionAffinity": "None", + "type": "ClusterIP" + }, + "status": { + "loadBalancer": {} + } + }, + "failedPaths": null, + "reviewPaths": null, + "deletePaths": null, + "fixPaths": null + } + ] + } +] \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/gateway.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/gateway.yaml new file mode 100644 index 00000000..6371f688 --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/gateway.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.istio.io/v1beta1 +kind: Gateway +metadata: + annotations: + meta.helm.sh/release-name: legacy-compatibility + meta.helm.sh/release-namespace: kt-itinternal + creationTimestamp: "2023-03-16T10:18:13Z" + generation: 1 + labels: + app.kubernetes.io/managed-by: Helm + name: prod-lan-gateway + namespace: kt-itinternal + resourceVersion: "713118464" + uid: 46cb8274-3569-4b4a-952a-52037a352715 +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - legacy.stg.prod.lan + port: + name: http + number: 80 + protocol: HTTP \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/deployment.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/deployment.yaml new file mode 100644 index 00000000..8586c613 --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/deployment.yaml @@ -0,0 +1,58 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: int-0721 + context: default + name: int-0721 + role: app + name: nginx + namespace: kt-itinternal +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: nginx + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx + imagePullPolicy: Always + name: nginx + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 +status: + availableReplicas: 1 + conditions: + - lastTransitionTime: "2024-11-19T19:33:45Z" + lastUpdateTime: "2024-11-19T19:33:45Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: "True" + type: Available + - lastTransitionTime: "2024-11-19T19:33:37Z" + lastUpdateTime: "2024-11-19T19:33:45Z" + message: ReplicaSet "nginx-7854ff8877" has successfully progressed. + reason: NewReplicaSetAvailable + status: "True" + type: Progressing + observedGeneration: 1 + readyReplicas: 1 + replicas: 1 + updatedReplicas: 1 diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/gateway.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/gateway.yaml new file mode 100644 index 00000000..61743f7c --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/gateway.yaml @@ -0,0 +1,15 @@ +apiVersion: networking.istio.io/v1beta1 +kind: Gateway +metadata: + name: prod-lan-gateway + namespace: kt-connections +spec: + selector: + istio: ingressgateway + servers: + - hosts: + - legacy.stg.prod.lan + port: + name: http + number: 80 + protocol: HTTP \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/istio-gw.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/istio-gw.yaml new file mode 100644 index 00000000..2c430ffd --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/istio-gw.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app: istio-ingressgateway + istio: ingressgateway + istio.io/rev: default + operator.istio.io/component: IngressGateways + operator.istio.io/managed: Reconcile + operator.istio.io/version: 1.18.7 + release: istio + name: istio-ingressgateway + namespace: istio-system +spec: + externalTrafficPolicy: Local + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: status-port + nodePort: 30432 + port: 15033 + protocol: TCP + targetPort: 15033 + selector: + app: istio-ingressgateway + istio: ingressgateway + sessionAffinity: None + type: NodePort +status: + loadBalancer: {} \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/service.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/service.yaml new file mode 100644 index 00000000..8b478e61 --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/service.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: "2024-04-15T09:00:11Z" + labels: + app: int-0721 + context: default + name: int-0721 + owner: int-0721 + owner-namespace: kt-itinternal + role: app + name: int-0721 + namespace: kt-itinternal + ownerReferences: + - apiVersion: msss/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: Microservice + name: int-0721 + uid: 14a69d5b-249c-487d-9500-645bda6a4c56 + resourceVersion: "3779885629" + uid: 0428cb70-5d8f-4345-8ef2-5b0a249e0793 +spec: + clusterIP: 10.81.208.49 + clusterIPs: + - 10.81.208.49 + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: int-0721 + context: default + name: int-0721 + role: app + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/vs.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/vs.yaml new file mode 100644 index 00000000..37f65359 --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/input/vs.yaml @@ -0,0 +1,57 @@ +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + creationTimestamp: "2024-04-15T08:56:16Z" + generation: 2 + labels: + app: int-0721 + context: default + name: int-0721 + owner: int-0721 + owner-namespace: kt-itinternal + role: app + name: int-0721 + namespace: kt-itinternal +spec: + gateways: + - kt-connections/prod-lan-gateway + - kt-connections/sdfsdfs-gateway + - kt-connections/api-public + - kt-connections/aaaaa-public + - kt-connections/mydddd-public + hosts: + - api.stg.prod.lan + http: + - corsPolicy: + allowHeaders: + - authorization + - Origin + - Content-Type + - Accept + allowMethods: + - POST + - GET + - OPTIONS + - PUT + - PATCH + - DELETE + allowOrigins: + - regex: .* + match: + - authority: + exact: api.stg.prod.lan + uri: + prefix: /int/0698/ + name: api-http-stgprodlan + rewrite: + uri: / + route: + - destination: + host: int-0721.kt-itinternal.svc.cluster.local + port: + number: 8080 + headers: + request: + set: + X-Forwarded-Prefix: /int/0698 + X-Forwarded-Proto: https \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/service.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/service.yaml new file mode 100644 index 00000000..07b2c3e1 --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/service.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + ctx.vrs.meeseeks.sre.monaco-telecom.mc/default: "3664777130" + ms.vrs.meeseeks.sre.monaco-telecom.mc/int-0721: "3779862107" + pe.vrs.meeseeks.sre.monaco-telecom.mc/int-0721: "2387894954" + creationTimestamp: "2024-04-15T09:00:11Z" + labels: + app: int-0721 + context: default + name: int-0721 + owner: int-0721 + owner-namespace: kt-itinternal + role: app + name: int-0721 + namespace: kt-itinternal + ownerReferences: + - apiVersion: msss/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: Microservice + name: int-0721 + uid: 14a69d5b-249c-487d-9500-645bda6a4c56 + resourceVersion: "3779885629" + uid: 0428cb70-5d8f-4345-8ef2-5b0a249e0793 +spec: + clusterIP: 10.81.208.49 + clusterIPs: + - 10.81.208.49 + internalTrafficPolicy: Cluster + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + ports: + - name: http + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: int-0721 + context: default + name: int-0721 + role: app + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} \ No newline at end of file diff --git a/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/vs.yaml b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/vs.yaml new file mode 100644 index 00000000..13e3c06a --- /dev/null +++ b/rules/exposure-to-internet-via-istio-ingress/test/failed_with_beta/vs.yaml @@ -0,0 +1,57 @@ +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + creationTimestamp: "2024-04-15T08:56:16Z" + generation: 2 + labels: + app: int-0721 + context: default + name: int-0721 + owner: int-0721 + owner-namespace: kt-itinternal + role: app + name: int-0721 + namespace: kt-itinternal +spec: + gateways: + - kt-connections/wildcard-stg-gateway + - kt-connections/sdfsdfs-gateway + - kt-connections/api-public + - kt-connections/aaaaa-public + - kt-connections/mydddd-public + hosts: + - api.stg.prod.lan + http: + - corsPolicy: + allowHeaders: + - authorization + - Origin + - Content-Type + - Accept + allowMethods: + - POST + - GET + - OPTIONS + - PUT + - PATCH + - DELETE + allowOrigins: + - regex: .* + match: + - authority: + exact: api.stg.prod.lan + uri: + prefix: /int/0698/ + name: api-http-stgprodlan + rewrite: + uri: / + route: + - destination: + host: int-0721.kt-itinternal.svc.cluster.local + port: + number: 8080 + headers: + request: + set: + X-Forwarded-Prefix: /int/0698 + X-Forwarded-Proto: https \ No newline at end of file