diff --git a/docs/generated/checks.md b/docs/generated/checks.md index 772475bc0..c82e27381 100644 --- a/docs/generated/checks.md +++ b/docs/generated/checks.md @@ -49,6 +49,75 @@ verbs: - ^watch$ - ^*$ ``` +## aggregate-to-admin-escalation + +**Enabled by default**: No + +**Description**: ClusterRole with an aggregate-to-admin, aggregate-to-edit, or aggregate-to-view label grants escalation-capable verbs on privileged resources. Kubernetes automatically merges these rules into the admin, edit, or view ClusterRole, meaning every namespace admin inherits them. + +**Remediation**: Review whether the aggregated permissions are necessary. Remove escalation verbs (create, delete, patch, *) on privileged resources (secrets, roles, clusterroles, clusterrolebindings) from aggregate-labeled ClusterRoles. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + has(object.metadata.labels) && ( + (has(object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-admin']) && + object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-admin'] == 'true') || + (has(object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-edit']) && + object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-edit'] == 'true') || + (has(object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-view']) && + object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-view'] == 'true') + ) && object.rules.exists(r, + r.apiGroups.exists(g, g == '' || g == 'rbac.authorization.k8s.io' || g == '*') && + r.verbs.exists(v, v == '*' || v == 'create' || v == 'delete' || v == 'patch') && + r.resources.exists(res, res == '*' || res == 'secrets' || res == 'roles' || + res == 'clusterroles' || res == 'clusterrolebindings') + ) ? 'aggregate-labeled ClusterRole grants escalation verbs on privileged resources — inherited by every namespace admin/editor' : '' +``` +## approve-signers-without-resource-names + +**Enabled by default**: No + +**Description**: Roles granting the 'approve' verb on certificate signers without resourceNames restriction allow approval of certificates from any signer, including cluster-scoped signers. + +**Remediation**: Add resourceNames to restrict which certificate signers can be approved. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.rules.exists(r, + r.apiGroups.exists(g, g == 'certificates.k8s.io' || g == '*') && + r.resources.exists(res, res == 'signers' || res == '*') && + r.verbs.exists(v, v == 'approve' || v == '*') && + (!has(r.resourceNames) || r.resourceNames.size() == 0) + ) ? 'approve verb on signers without resourceNames restriction' : '' +``` +## bind-verb-in-role + +**Enabled by default**: No + +**Description**: Roles granting the 'bind' verb on roles, clusterroles, rolebindings, or clusterrolebindings allow the holder to create bindings to any role, including roles with more permissions than they currently have. + +**Remediation**: Remove the 'bind' verb unless the workload is a controller that legitimately manages RBAC bindings. If required, scope with resourceNames to limit which roles can be bound. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.rules.exists(r, + r.apiGroups.exists(g, g == 'rbac.authorization.k8s.io' || g == '*') && + r.resources.exists(res, res == 'roles' || res == 'clusterroles' || res == '*') && + r.verbs.exists(v, v == 'bind' || v == '*') + ) ? 'bind verb on RBAC resources allows privilege escalation via arbitrary bindings' : '' +``` ## cluster-admin-role-binding **Enabled by default**: No @@ -127,6 +196,26 @@ verbs: ```yaml serviceAccount: ^(|default)$ ``` +## deletecollection-verb-in-role + +**Enabled by default**: No + +**Description**: Role grants deletecollection verb, which allows bulk deletion of all resources of a type in a single API call. Unlike delete (per-resource), deletecollection enables rapid, complete resource destruction. + +**Remediation**: Remove deletecollection unless the workload legitimately needs to bulk-delete resources. Use delete instead for per-resource deletion. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.rules.exists(r, + r.verbs.exists(v, v == 'deletecollection' || v == '*') && + r.resources.exists(res, res == '*' || res == 'secrets' || res == 'pods' || + res == 'deployments' || res == 'configmaps' || res == 'namespaces') + ) ? 'deletecollection verb allows bulk resource destruction in a single API call' : '' +``` ## deprecated-service-account-field **Enabled by default**: Yes @@ -225,6 +314,26 @@ IgnoredSecrets: [] name: (?i).*secret.* value: .+ ``` +## escalate-verb-in-role + +**Enabled by default**: No + +**Description**: Roles granting the 'escalate' verb on roles or clusterroles allow the holder to create or modify roles with permissions exceeding their own, bypassing Kubernetes RBAC escalation protection. + +**Remediation**: Remove the 'escalate' verb unless the workload is a controller that legitimately manages RBAC resources. If required, scope with resourceNames to limit which roles can be escalated. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.rules.exists(r, + r.apiGroups.exists(g, g == 'rbac.authorization.k8s.io' || g == '*') && + r.resources.exists(res, res == 'roles' || res == 'clusterroles' || res == '*') && + r.verbs.exists(v, v == 'escalate' || v == '*') + ) ? 'escalate verb on roles/clusterroles allows privilege escalation' : '' +``` ## exposed-services **Enabled by default**: No @@ -284,6 +393,26 @@ forbiddenServiceTypes: ```yaml minReplicas: 3 ``` +## impersonate-without-resource-names + +**Enabled by default**: No + +**Description**: Roles granting the 'impersonate' verb on users, groups, or serviceaccounts without a resourceNames restriction allow any bearer of the bound SA token to impersonate system:masters and gain cluster-admin equivalent access. + +**Remediation**: Add a resourceNames list to restrict which identities can be impersonated, or remove the impersonate verb if it is not needed. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.rules.exists(r, + r.resources.exists(res, res == 'users' || res == 'groups' || res == 'serviceaccounts' || res == '*') && + r.verbs.exists(v, v == 'impersonate' || v == '*') && + (!has(r.resourceNames) || r.resourceNames.size() == 0) + ) ? 'impersonate verb granted without resourceNames restriction — allows system:masters impersonation' : '' +``` ## invalid-target-ports **Enabled by default**: Yes @@ -757,6 +886,26 @@ upperBoundMB: 0 **Remediation**: Create namespaces for objects in your deployment. **Template**: [use-namespace](templates.md#use-namespaces-for-administrative-boundaries-between-resources) +## webhook-failure-policy-ignore + +**Enabled by default**: No + +**Description**: Admission webhook with failurePolicy: Ignore silently allows all requests when the webhook is unavailable — attackers can bypass validation by DoSing the webhook endpoint. + +**Remediation**: Set failurePolicy to Fail. Ensure webhook availability with proper health checks, replicas, and PodDisruptionBudgets. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + (object.kind == 'ValidatingWebhookConfiguration' || + object.kind == 'MutatingWebhookConfiguration') && + has(object.webhooks) && object.webhooks.exists(w, + has(w.failurePolicy) && w.failurePolicy == 'Ignore' + ) ? 'admission webhook with failurePolicy: Ignore fails open — bypass via webhook DoS' : '' +``` ## wildcard-in-rules **Enabled by default**: No @@ -766,6 +915,26 @@ upperBoundMB: 0 **Remediation**: Where possible replace any use of wildcards in clusterroles and roles with specific objects or actions. **Template**: [wildcard-in-rules](templates.md#wildcard-use-in-role-and-clusterrole-rules) +## wildcard-resource-verb-combo + +**Enabled by default**: No + +**Description**: ClusterRole rule with wildcard verbs on wildcard resources is functionally equivalent to cluster-admin. Unlike a named cluster-admin binding, this pattern is not caught by the cluster-admin-role-binding check. + +**Remediation**: Replace wildcard grants with explicit resource and verb lists scoped to what the workload actually needs. + +**Template**: [cel-expression](templates.md#cel) + +**Parameters**: + +```yaml +check: | + object.rules.exists(r, + r.apiGroups.exists(g, g == '*') && + r.resources.exists(res, res == '*') && + r.verbs.exists(v, v == '*') + ) ? 'rule grants wildcard verbs on wildcard resources — functionally cluster-admin' : '' +``` ## writable-host-mount **Enabled by default**: No diff --git a/e2etests/bats-tests.sh b/e2etests/bats-tests.sh index 56dbeb06a..0f4a9490e 100755 --- a/e2etests/bats-tests.sh +++ b/e2etests/bats-tests.sh @@ -98,6 +98,42 @@ get_value_from() { [[ "${count}" == "1" ]] } +@test "aggregate-to-admin-escalation" { + tmp="tests/checks/aggregate-to-admin-escalation.yml" + cmd="${KUBE_LINTER_BIN} lint --include aggregate-to-admin-escalation --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}" == "2" ]] +} + +@test "approve-signers-without-resource-names" { + tmp="tests/checks/approve-signers-without-resource-names.yml" + cmd="${KUBE_LINTER_BIN} lint --include approve-signers-without-resource-names --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}" == "2" ]] +} + +@test "bind-verb-in-role" { + tmp="tests/checks/bind-verb-in-role.yml" + cmd="${KUBE_LINTER_BIN} lint --include bind-verb-in-role --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}" == "2" ]] +} + @test "cluster-admin-role-binding" { tmp="tests/checks/cluster-admin-role-binding.yml" cmd="${KUBE_LINTER_BIN} lint --include cluster-admin-role-binding --do-not-auto-add-defaults --format json ${tmp}" @@ -231,6 +267,18 @@ get_value_from() { [[ "${count}" == "2" ]] } +@test "deletecollection-verb-in-role" { + tmp="tests/checks/deletecollection-verb-in-role.yml" + cmd="${KUBE_LINTER_BIN} lint --include deletecollection-verb-in-role --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}" == "2" ]] +} + @test "deprecated-service-account-field" { tmp="tests/checks/deprecated-service-account-field.yml" cmd="${KUBE_LINTER_BIN} lint --include deprecated-service-account-field --do-not-auto-add-defaults --format json ${tmp}" @@ -354,6 +402,18 @@ get_value_from() { [[ "${count}" == "2" ]] } +@test "escalate-verb-in-role" { + tmp="tests/checks/escalate-verb-in-role.yml" + cmd="${KUBE_LINTER_BIN} lint --include escalate-verb-in-role --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}" == "3" ]] +} + @test "exposed-services" { tmp="tests/checks/exposed-services.yml" cmd="${KUBE_LINTER_BIN} lint --include exposed-services --do-not-auto-add-defaults --format json ${tmp}" @@ -435,6 +495,18 @@ get_value_from() { [[ "${count}" == "1" ]] } +@test "impersonate-without-resource-names" { + tmp="tests/checks/impersonate-without-resource-names.yml" + cmd="${KUBE_LINTER_BIN} lint --include impersonate-without-resource-names --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}" == "4" ]] +} + @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}" @@ -1120,6 +1192,18 @@ get_value_from() { [[ "${count}" == "1" ]] } +@test "webhook-failure-policy-ignore" { + tmp="tests/checks/webhook-failure-policy-ignore.yml" + cmd="${KUBE_LINTER_BIN} lint --include webhook-failure-policy-ignore --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}" == "2" ]] +} + @test "wildcard-in-rules" { tmp="tests/checks/wildcard-in-rules.yml" cmd="${KUBE_LINTER_BIN} lint --include wildcard-in-rules --do-not-auto-add-defaults --format json ${tmp}" @@ -1135,6 +1219,18 @@ get_value_from() { [[ "${count}" == "1" ]] } +@test "wildcard-resource-verb-combo" { + tmp="tests/checks/wildcard-resource-verb-combo.yml" + cmd="${KUBE_LINTER_BIN} lint --include wildcard-resource-verb-combo --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}" == "2" ]] +} + @test "writable-host-mount" { tmp="tests/checks/writable-host-mount.yml" cmd="${KUBE_LINTER_BIN} lint --include writable-host-mount --do-not-auto-add-defaults --format json ${tmp}" diff --git a/pkg/builtinchecks/yamls/aggregate-to-admin-escalation.yaml b/pkg/builtinchecks/yamls/aggregate-to-admin-escalation.yaml new file mode 100644 index 000000000..e99b8f520 --- /dev/null +++ b/pkg/builtinchecks/yamls/aggregate-to-admin-escalation.yaml @@ -0,0 +1,31 @@ +name: aggregate-to-admin-escalation +description: >- + ClusterRole with an aggregate-to-admin, aggregate-to-edit, or + aggregate-to-view label grants escalation-capable verbs on privileged + resources. Kubernetes automatically merges these rules into the admin, + edit, or view ClusterRole, meaning every namespace admin inherits them. +remediation: >- + Review whether the aggregated permissions are necessary. Remove escalation + verbs (create, delete, patch, *) on privileged resources (secrets, roles, + clusterroles, clusterrolebindings) from aggregate-labeled ClusterRoles. +scope: + objectKinds: + - ClusterRole +template: cel-expression +params: + check: > + has(object.metadata.labels) && + ( + (has(object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-admin']) && + object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-admin'] == 'true') || + (has(object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-edit']) && + object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-edit'] == 'true') || + (has(object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-view']) && + object.metadata.labels['rbac.authorization.k8s.io/aggregate-to-view'] == 'true') + ) && + object.rules.exists(r, + r.apiGroups.exists(g, g == '' || g == 'rbac.authorization.k8s.io' || g == '*') && + r.verbs.exists(v, v == '*' || v == 'create' || v == 'delete' || v == 'patch') && + r.resources.exists(res, res == '*' || res == 'secrets' || res == 'roles' || + res == 'clusterroles' || res == 'clusterrolebindings') + ) ? 'aggregate-labeled ClusterRole grants escalation verbs on privileged resources — inherited by every namespace admin/editor' : '' diff --git a/pkg/builtinchecks/yamls/approve-signers-without-resource-names.yaml b/pkg/builtinchecks/yamls/approve-signers-without-resource-names.yaml new file mode 100644 index 000000000..c26102e28 --- /dev/null +++ b/pkg/builtinchecks/yamls/approve-signers-without-resource-names.yaml @@ -0,0 +1,20 @@ +name: approve-signers-without-resource-names +description: >- + Roles granting the 'approve' verb on certificate signers without + resourceNames restriction allow approval of certificates from any + signer, including cluster-scoped signers. +remediation: >- + Add resourceNames to restrict which certificate signers can be approved. +scope: + objectKinds: + - Role + - ClusterRole +template: cel-expression +params: + check: > + object.rules.exists(r, + r.apiGroups.exists(g, g == 'certificates.k8s.io' || g == '*') && + r.resources.exists(res, res == 'signers' || res == '*') && + r.verbs.exists(v, v == 'approve' || v == '*') && + (!has(r.resourceNames) || r.resourceNames.size() == 0) + ) ? 'approve verb on signers without resourceNames restriction' : '' diff --git a/pkg/builtinchecks/yamls/bind-verb-in-role.yaml b/pkg/builtinchecks/yamls/bind-verb-in-role.yaml new file mode 100644 index 000000000..bcfd26016 --- /dev/null +++ b/pkg/builtinchecks/yamls/bind-verb-in-role.yaml @@ -0,0 +1,21 @@ +name: bind-verb-in-role +description: >- + Roles granting the 'bind' verb on roles, clusterroles, rolebindings, + or clusterrolebindings allow the holder to create bindings to any role, + including roles with more permissions than they currently have. +remediation: >- + Remove the 'bind' verb unless the workload is a controller that + legitimately manages RBAC bindings. If required, scope with + resourceNames to limit which roles can be bound. +scope: + objectKinds: + - Role + - ClusterRole +template: cel-expression +params: + check: > + object.rules.exists(r, + r.apiGroups.exists(g, g == 'rbac.authorization.k8s.io' || g == '*') && + r.resources.exists(res, res == 'roles' || res == 'clusterroles' || res == '*') && + r.verbs.exists(v, v == 'bind' || v == '*') + ) ? 'bind verb on RBAC resources allows privilege escalation via arbitrary bindings' : '' diff --git a/pkg/builtinchecks/yamls/deletecollection-verb-in-role.yaml b/pkg/builtinchecks/yamls/deletecollection-verb-in-role.yaml new file mode 100644 index 000000000..67f17ccc9 --- /dev/null +++ b/pkg/builtinchecks/yamls/deletecollection-verb-in-role.yaml @@ -0,0 +1,20 @@ +name: deletecollection-verb-in-role +description: >- + Role grants deletecollection verb, which allows bulk deletion of all + resources of a type in a single API call. Unlike delete (per-resource), + deletecollection enables rapid, complete resource destruction. +remediation: >- + Remove deletecollection unless the workload legitimately needs to bulk-delete + resources. Use delete instead for per-resource deletion. +scope: + objectKinds: + - Role + - ClusterRole +template: cel-expression +params: + check: > + object.rules.exists(r, + r.verbs.exists(v, v == 'deletecollection' || v == '*') && + r.resources.exists(res, res == '*' || res == 'secrets' || res == 'pods' || + res == 'deployments' || res == 'configmaps' || res == 'namespaces') + ) ? 'deletecollection verb allows bulk resource destruction in a single API call' : '' diff --git a/pkg/builtinchecks/yamls/escalate-verb-in-role.yaml b/pkg/builtinchecks/yamls/escalate-verb-in-role.yaml new file mode 100644 index 000000000..1932158b8 --- /dev/null +++ b/pkg/builtinchecks/yamls/escalate-verb-in-role.yaml @@ -0,0 +1,21 @@ +name: escalate-verb-in-role +description: >- + Roles granting the 'escalate' verb on roles or clusterroles allow the + holder to create or modify roles with permissions exceeding their own, + bypassing Kubernetes RBAC escalation protection. +remediation: >- + Remove the 'escalate' verb unless the workload is a controller that + legitimately manages RBAC resources. If required, scope with + resourceNames to limit which roles can be escalated. +scope: + objectKinds: + - Role + - ClusterRole +template: cel-expression +params: + check: > + object.rules.exists(r, + r.apiGroups.exists(g, g == 'rbac.authorization.k8s.io' || g == '*') && + r.resources.exists(res, res == 'roles' || res == 'clusterroles' || res == '*') && + r.verbs.exists(v, v == 'escalate' || v == '*') + ) ? 'escalate verb on roles/clusterroles allows privilege escalation' : '' diff --git a/pkg/builtinchecks/yamls/impersonate-without-resource-names.yaml b/pkg/builtinchecks/yamls/impersonate-without-resource-names.yaml new file mode 100644 index 000000000..283430469 --- /dev/null +++ b/pkg/builtinchecks/yamls/impersonate-without-resource-names.yaml @@ -0,0 +1,20 @@ +name: impersonate-without-resource-names +description: >- + Roles granting the 'impersonate' verb on users, groups, or serviceaccounts + without a resourceNames restriction allow any bearer of the bound SA token + to impersonate system:masters and gain cluster-admin equivalent access. +remediation: >- + Add a resourceNames list to restrict which identities can be impersonated, + or remove the impersonate verb if it is not needed. +scope: + objectKinds: + - Role + - ClusterRole +template: cel-expression +params: + check: > + object.rules.exists(r, + r.resources.exists(res, res == 'users' || res == 'groups' || res == 'serviceaccounts' || res == '*') && + r.verbs.exists(v, v == 'impersonate' || v == '*') && + (!has(r.resourceNames) || r.resourceNames.size() == 0) + ) ? 'impersonate verb granted without resourceNames restriction — allows system:masters impersonation' : '' diff --git a/pkg/builtinchecks/yamls/webhook-failure-policy-ignore.yaml b/pkg/builtinchecks/yamls/webhook-failure-policy-ignore.yaml new file mode 100644 index 000000000..62ca9512d --- /dev/null +++ b/pkg/builtinchecks/yamls/webhook-failure-policy-ignore.yaml @@ -0,0 +1,20 @@ +name: webhook-failure-policy-ignore +description: >- + Admission webhook with failurePolicy: Ignore silently allows all requests + when the webhook is unavailable — attackers can bypass validation by DoSing + the webhook endpoint. +remediation: >- + Set failurePolicy to Fail. Ensure webhook availability with proper + health checks, replicas, and PodDisruptionBudgets. +scope: + objectKinds: + - Any +template: cel-expression +params: + check: > + (object.kind == 'ValidatingWebhookConfiguration' || + object.kind == 'MutatingWebhookConfiguration') && + has(object.webhooks) && + object.webhooks.exists(w, + has(w.failurePolicy) && w.failurePolicy == 'Ignore' + ) ? 'admission webhook with failurePolicy: Ignore fails open — bypass via webhook DoS' : '' diff --git a/pkg/builtinchecks/yamls/wildcard-resource-verb-combo.yaml b/pkg/builtinchecks/yamls/wildcard-resource-verb-combo.yaml new file mode 100644 index 000000000..b9c0aeda4 --- /dev/null +++ b/pkg/builtinchecks/yamls/wildcard-resource-verb-combo.yaml @@ -0,0 +1,19 @@ +name: wildcard-resource-verb-combo +description: >- + ClusterRole rule with wildcard verbs on wildcard resources is functionally + equivalent to cluster-admin. Unlike a named cluster-admin binding, this + pattern is not caught by the cluster-admin-role-binding check. +remediation: >- + Replace wildcard grants with explicit resource and verb lists scoped to + what the workload actually needs. +scope: + objectKinds: + - ClusterRole +template: cel-expression +params: + check: > + object.rules.exists(r, + r.apiGroups.exists(g, g == '*') && + r.resources.exists(res, res == '*') && + r.verbs.exists(v, v == '*') + ) ? 'rule grants wildcard verbs on wildcard resources — functionally cluster-admin' : '' diff --git a/tests/checks/aggregate-to-admin-escalation.yml b/tests/checks/aggregate-to-admin-escalation.yml new file mode 100644 index 000000000..92cf37a40 --- /dev/null +++ b/tests/checks/aggregate-to-admin-escalation.yml @@ -0,0 +1,22 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: ["example.com"] + resources: ["widgets"] + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-aggregate-admin-secrets + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["create", "delete"] diff --git a/tests/checks/approve-signers-without-resource-names.yml b/tests/checks/approve-signers-without-resource-names.yml new file mode 100644 index 000000000..065ea4cab --- /dev/null +++ b/tests/checks/approve-signers-without-resource-names.yml @@ -0,0 +1,19 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire +rules: + - apiGroups: ["certificates.k8s.io"] + resources: ["signers"] + verbs: ["approve"] + resourceNames: ["example.com/my-signer"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-approve-no-restriction +rules: + - apiGroups: ["certificates.k8s.io"] + resources: ["signers"] + verbs: ["approve"] diff --git a/tests/checks/bind-verb-in-role.yml b/tests/checks/bind-verb-in-role.yml new file mode 100644 index 000000000..90a8708ce --- /dev/null +++ b/tests/checks/bind-verb-in-role.yml @@ -0,0 +1,18 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire +rules: + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles"] + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-bind +rules: + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["bind"] diff --git a/tests/checks/deletecollection-verb-in-role.yml b/tests/checks/deletecollection-verb-in-role.yml new file mode 100644 index 000000000..cb62a5a41 --- /dev/null +++ b/tests/checks/deletecollection-verb-in-role.yml @@ -0,0 +1,18 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-deletecollection +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["deletecollection"] diff --git a/tests/checks/escalate-verb-in-role.yml b/tests/checks/escalate-verb-in-role.yml new file mode 100644 index 000000000..2b9c56df6 --- /dev/null +++ b/tests/checks/escalate-verb-in-role.yml @@ -0,0 +1,28 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire +rules: + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles"] + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-escalate +rules: + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["roles"] + verbs: ["escalate"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: fire-wildcard-verb-on-clusterroles + namespace: default +rules: + - apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["*"] diff --git a/tests/checks/impersonate-without-resource-names.yml b/tests/checks/impersonate-without-resource-names.yml new file mode 100644 index 000000000..726efccdf --- /dev/null +++ b/tests/checks/impersonate-without-resource-names.yml @@ -0,0 +1,37 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire +rules: + - apiGroups: [""] + resources: ["users"] + verbs: ["impersonate"] + resourceNames: ["jane"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire-no-impersonate +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-impersonate-no-restriction +rules: + - apiGroups: [""] + resources: ["users", "groups", "serviceaccounts"] + verbs: ["impersonate"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-wildcard-verb +rules: + - apiGroups: [""] + resources: ["users"] + verbs: ["*"] diff --git a/tests/checks/webhook-failure-policy-ignore.yml b/tests/checks/webhook-failure-policy-ignore.yml new file mode 100644 index 000000000..570df272f --- /dev/null +++ b/tests/checks/webhook-failure-policy-ignore.yml @@ -0,0 +1,28 @@ +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: dont-fire +webhooks: + - name: validate.example.com + failurePolicy: Fail + clientConfig: + service: + name: webhook-service + namespace: default + admissionReviewVersions: ["v1"] + sideEffects: None +--- +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: fire-ignore-policy +webhooks: + - name: validate.example.com + failurePolicy: Ignore + clientConfig: + service: + name: webhook-service + namespace: default + admissionReviewVersions: ["v1"] + sideEffects: None diff --git a/tests/checks/wildcard-resource-verb-combo.yml b/tests/checks/wildcard-resource-verb-combo.yml new file mode 100644 index 000000000..e2ca1fad1 --- /dev/null +++ b/tests/checks/wildcard-resource-verb-combo.yml @@ -0,0 +1,18 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dont-fire +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: fire-triple-wildcard +rules: + - apiGroups: ["*"] + resources: ["*"] + verbs: ["*"]