From 49a39cd9416c8ef5e8bd162a0174714daa60ccd6 Mon Sep 17 00:00:00 2001 From: Sukumar Yethadka Date: Fri, 26 Jun 2026 08:22:48 +0000 Subject: [PATCH 1/3] Add OpenShift Route security check Add insecure-route-termination check that flags OpenShift Routes with InsecureEdgeTerminationPolicy: Allow, which permits plaintext HTTP on credential-bearing endpoints. --- .../yamls/insecure-route-termination.yaml | 17 +++++++ tests/checks/insecure-route-termination.yml | 45 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 pkg/builtinchecks/yamls/insecure-route-termination.yaml create mode 100644 tests/checks/insecure-route-termination.yml diff --git a/pkg/builtinchecks/yamls/insecure-route-termination.yaml b/pkg/builtinchecks/yamls/insecure-route-termination.yaml new file mode 100644 index 000000000..0f8c76eb3 --- /dev/null +++ b/pkg/builtinchecks/yamls/insecure-route-termination.yaml @@ -0,0 +1,17 @@ +name: insecure-route-termination +description: >- + OpenShift Route allows plaintext HTTP via InsecureEdgeTerminationPolicy: Allow. + Credential-bearing endpoints should enforce TLS by using Redirect or None. +remediation: >- + Set spec.tls.insecureEdgeTerminationPolicy to 'Redirect' or 'None'. +scope: + objectKinds: + - Any +template: cel-expression +params: + check: > + object.kind == 'Route' && + has(object.spec.tls) && + has(object.spec.tls.insecureEdgeTerminationPolicy) && + object.spec.tls.insecureEdgeTerminationPolicy == 'Allow' + ? 'Route allows plaintext HTTP — credential-bearing endpoints should use Redirect or None' : '' diff --git a/tests/checks/insecure-route-termination.yml b/tests/checks/insecure-route-termination.yml new file mode 100644 index 000000000..67fbfb160 --- /dev/null +++ b/tests/checks/insecure-route-termination.yml @@ -0,0 +1,45 @@ +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: dont-fire-redirect +spec: + to: + kind: Service + name: my-service + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: dont-fire-none +spec: + to: + kind: Service + name: my-service + tls: + termination: edge + insecureEdgeTerminationPolicy: None +--- +apiVersion: route.openshift.io/v1 +kind: Route +metadata: + name: fire-allow-insecure +spec: + to: + kind: Service + name: my-service + tls: + termination: edge + insecureEdgeTerminationPolicy: Allow +--- +apiVersion: v1 +kind: Service +metadata: + name: dont-fire-not-a-route +spec: + type: ClusterIP + ports: + - port: 80 From 40d93ed6efd6b2c1fd5c5cfdfe600e3e56965c82 Mon Sep 17 00:00:00 2001 From: Sukumar Yethadka Date: Fri, 26 Jun 2026 09:06:20 +0000 Subject: [PATCH 2/3] Add bats test and regenerate docs - Add bats test case for insecure-route-termination check - Regenerate docs/generated/checks.md and templates.md --- docs/generated/checks.md | 16 ++++++++++++++++ e2etests/bats-tests.sh | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/generated/checks.md b/docs/generated/checks.md index 772475bc0..9e1b2aad8 100644 --- a/docs/generated/checks.md +++ b/docs/generated/checks.md @@ -284,6 +284,22 @@ forbiddenServiceTypes: ```yaml minReplicas: 3 ``` +## insecure-route-termination + +**Enabled by default**: No + +**Description**: OpenShift Route allows plaintext HTTP via InsecureEdgeTerminationPolicy: Allow. Credential-bearing endpoints should enforce TLS by using Redirect or None. + +**Remediation**: Set spec.tls.insecureEdgeTerminationPolicy to 'Redirect' or 'None'. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.kind == 'Route' && has(object.spec.tls) && has(object.spec.tls.insecureEdgeTerminationPolicy) && object.spec.tls.insecureEdgeTerminationPolicy == 'Allow' ? 'Route allows plaintext HTTP — credential-bearing endpoints should use Redirect or None' : '' +``` ## invalid-target-ports **Enabled by default**: Yes diff --git a/e2etests/bats-tests.sh b/e2etests/bats-tests.sh index 56dbeb06a..d3bbd279a 100755 --- a/e2etests/bats-tests.sh +++ b/e2etests/bats-tests.sh @@ -1244,3 +1244,15 @@ get_value_from() { rm -f ${json_out} ${sarif_out} } +@test "insecure-route-termination" { + tmp="tests/checks/insecure-route-termination.yml" + cmd="${KUBE_LINTER_BIN} lint --include insecure-route-termination --do-not-auto-add-defaults --format json ${tmp}" + run ${cmd} + + print_info "${status}" "${output}" "${cmd}" "${tmp}" + [ "$status" -eq 1 ] + + count=$(get_value_from "${lines[0]}" '.Reports | length') + + [[ "${count}" == "1" ]] +} From cbeef3a1cc20af87da349e13faf23437dca4da0f Mon Sep 17 00:00:00 2001 From: Sukumar Yethadka Date: Fri, 26 Jun 2026 10:57:46 +0000 Subject: [PATCH 3/3] Fix bats test ordering for insecure-route-termination Move insecure-route-termination test to correct alphabetical position in bats-tests.sh to satisfy check-bats-tests.sh verification. --- e2etests/bats-tests.sh | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/e2etests/bats-tests.sh b/e2etests/bats-tests.sh index d3bbd279a..bf1f77fc8 100755 --- a/e2etests/bats-tests.sh +++ b/e2etests/bats-tests.sh @@ -435,6 +435,19 @@ get_value_from() { [[ "${count}" == "1" ]] } +@test "insecure-route-termination" { + tmp="tests/checks/insecure-route-termination.yml" + cmd="${KUBE_LINTER_BIN} lint --include insecure-route-termination --do-not-auto-add-defaults --format json ${tmp}" + run ${cmd} + + print_info "${status}" "${output}" "${cmd}" "${tmp}" + [ "$status" -eq 1 ] + + count=$(get_value_from "${lines[0]}" '.Reports | length') + + [[ "${count}" == "1" ]] +} + @test "invalid-target-ports" { tmp="tests/checks/invalid-target-ports.yaml" cmd="${KUBE_LINTER_BIN} lint --include invalid-target-ports --do-not-auto-add-defaults --format json ${tmp}" @@ -1243,16 +1256,3 @@ get_value_from() { # Cleanup rm -f ${json_out} ${sarif_out} } - -@test "insecure-route-termination" { - tmp="tests/checks/insecure-route-termination.yml" - cmd="${KUBE_LINTER_BIN} lint --include insecure-route-termination --do-not-auto-add-defaults --format json ${tmp}" - run ${cmd} - - print_info "${status}" "${output}" "${cmd}" "${tmp}" - [ "$status" -eq 1 ] - - count=$(get_value_from "${lines[0]}" '.Reports | length') - - [[ "${count}" == "1" ]] -}