diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/artifacthub-pkg.yml b/artifacthub/library/general/disallowanonymous/1.1.0/artifacthub-pkg.yml new file mode 100644 index 0000000000..efd550cc00 --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.1.0 +name: k8sdisallowanonymous +displayName: Disallow Anonymous Access +createdAt: "2024-08-21T21:13:49Z" +description: Disallows associating ClusterRole and Role resources to the system:anonymous user and system:unauthenticated group. +digest: f81216454c4b87d71f680ea0a548e1c6981b678bf1befe0a3c6f6ededde8b3e0 +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/disallowanonymous +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # Disallow Anonymous Access + Disallows associating ClusterRole and Role resources to the system:anonymous user and system:unauthenticated group. +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/disallowanonymous/1.1.0/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/kustomization.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/kustomization.yaml new file mode 100644 index 0000000000..7d70d11b71 --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/constraint.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/constraint.yaml new file mode 100644 index 0000000000..1d14ae1333 --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sDisallowAnonymous +metadata: + name: no-anonymous +spec: + match: + kinds: + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["ClusterRoleBinding"] + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["RoleBinding"] + parameters: + allowedRoles: + - cluster-role-1 diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/example_allowed.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/example_allowed.yaml new file mode 100644 index 0000000000..f8889d941d --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/example_allowed.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-1 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-1 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:unauthenticated diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/example_disallowed.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/example_disallowed.yaml new file mode 100644 index 0000000000..1f34ffd642 --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-anonymous-bindings/example_disallowed.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-2 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:unauthenticated diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-authenticated/constraint.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-authenticated/constraint.yaml new file mode 100644 index 0000000000..f4a74f4fbb --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-authenticated/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sDisallowAnonymous +metadata: + name: no-anonymous +spec: + match: + kinds: + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["ClusterRoleBinding"] + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["RoleBinding"] + parameters: + disallowAuthenticated: true diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-authenticated/example_disallowed.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-authenticated/example_disallowed.yaml new file mode 100644 index 0000000000..804798e2c2 --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/samples/no-authenticated/example_disallowed.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-2 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/suite.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/suite.yaml new file mode 100644 index 0000000000..50d33faeaf --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/suite.yaml @@ -0,0 +1,29 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: disallowanonymous +tests: +- name: disallow-anonymous + template: template.yaml + constraint: samples/no-anonymous-bindings/constraint.yaml + cases: + - name: example-allowed + object: samples/no-anonymous-bindings/example_allowed.yaml + assertions: + - violations: no + - name: example-disallowed + object: samples/no-anonymous-bindings/example_disallowed.yaml + assertions: + - violations: yes + - name: authenticated-allowed-with-parameter-undefined + object: samples/no-authenticated/example_disallowed.yaml + assertions: + - violations: no +- name: disallow-authenticated + template: template.yaml + constraint: samples/no-authenticated/constraint.yaml + cases: + - name: authenticated-disallowed-with-parameter-specified + object: samples/no-authenticated/example_disallowed.yaml + assertions: + - violations: yes diff --git a/artifacthub/library/general/disallowanonymous/1.1.0/template.yaml b/artifacthub/library/general/disallowanonymous/1.1.0/template.yaml new file mode 100644 index 0000000000..4e522127d6 --- /dev/null +++ b/artifacthub/library/general/disallowanonymous/1.1.0/template.yaml @@ -0,0 +1,69 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8sdisallowanonymous + annotations: + metadata.gatekeeper.sh/title: "Disallow Anonymous Access" + metadata.gatekeeper.sh/version: 1.1.0 + description: Disallows associating ClusterRole and Role resources to the system:anonymous user and system:unauthenticated group. +spec: + crd: + spec: + names: + kind: K8sDisallowAnonymous + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedRoles: + description: >- + The list of ClusterRoles and Roles that may be associated + with the `system:unauthenticated` group and `system:anonymous` + user. + type: array + items: + type: string + disallowAuthenticated: + description: >- + A boolean indicating whether `system:authenticated` should be + disallowed by this policy. + type: boolean + default: false + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8sdisallowanonymous + + + violation[{"msg": msg}] { + not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) + + group := ["system:unauthenticated", "system:anonymous"][_] + subject_is(input.review.object.subjects[_], group) + + msg := message(group) + } + + violation[{"msg": msg}] { + not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) + + object.get(input, ["parameters", "disallowAuthenticated"], false) + + group := "system:authenticated" + subject_is(input.review.object.subjects[_], group) + + msg := message(group) + } + + is_allowed(role, allowedRoles) { + role.name == allowedRoles[_] + } + + subject_is(subject, expected) { + subject.name == expected + } + + message(group) := val { + val := sprintf("%v is not allowed as a subject name in %v %v", [group, input.review.object.kind, input.review.object.metadata.name]) + } diff --git a/library/general/disallowanonymous/samples/no-authenticated/constraint.yaml b/library/general/disallowanonymous/samples/no-authenticated/constraint.yaml new file mode 100644 index 0000000000..f4a74f4fbb --- /dev/null +++ b/library/general/disallowanonymous/samples/no-authenticated/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sDisallowAnonymous +metadata: + name: no-anonymous +spec: + match: + kinds: + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["ClusterRoleBinding"] + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["RoleBinding"] + parameters: + disallowAuthenticated: true diff --git a/library/general/disallowanonymous/samples/no-authenticated/example_disallowed.yaml b/library/general/disallowanonymous/samples/no-authenticated/example_disallowed.yaml new file mode 100644 index 0000000000..804798e2c2 --- /dev/null +++ b/library/general/disallowanonymous/samples/no-authenticated/example_disallowed.yaml @@ -0,0 +1,12 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-2 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated diff --git a/library/general/disallowanonymous/suite.yaml b/library/general/disallowanonymous/suite.yaml index 46daa7f2fb..50d33faeaf 100644 --- a/library/general/disallowanonymous/suite.yaml +++ b/library/general/disallowanonymous/suite.yaml @@ -14,4 +14,16 @@ tests: - name: example-disallowed object: samples/no-anonymous-bindings/example_disallowed.yaml assertions: - - violations: yes \ No newline at end of file + - violations: yes + - name: authenticated-allowed-with-parameter-undefined + object: samples/no-authenticated/example_disallowed.yaml + assertions: + - violations: no +- name: disallow-authenticated + template: template.yaml + constraint: samples/no-authenticated/constraint.yaml + cases: + - name: authenticated-disallowed-with-parameter-specified + object: samples/no-authenticated/example_disallowed.yaml + assertions: + - violations: yes diff --git a/library/general/disallowanonymous/template.yaml b/library/general/disallowanonymous/template.yaml index 1f090f3521..4e522127d6 100644 --- a/library/general/disallowanonymous/template.yaml +++ b/library/general/disallowanonymous/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8sdisallowanonymous annotations: metadata.gatekeeper.sh/title: "Disallow Anonymous Access" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.1.0 description: Disallows associating ClusterRole and Role resources to the system:anonymous user and system:unauthenticated group. spec: crd: @@ -24,25 +24,46 @@ spec: type: array items: type: string + disallowAuthenticated: + description: >- + A boolean indicating whether `system:authenticated` should be + disallowed by this policy. + type: boolean + default: false targets: - target: admission.k8s.gatekeeper.sh rego: | package k8sdisallowanonymous + violation[{"msg": msg}] { not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) - review(input.review.object.subjects[_]) - msg := sprintf("Unauthenticated user reference is not allowed in %v %v ", [input.review.object.kind, input.review.object.metadata.name]) + + group := ["system:unauthenticated", "system:anonymous"][_] + subject_is(input.review.object.subjects[_], group) + + msg := message(group) + } + + violation[{"msg": msg}] { + not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) + + object.get(input, ["parameters", "disallowAuthenticated"], false) + + group := "system:authenticated" + subject_is(input.review.object.subjects[_], group) + + msg := message(group) } is_allowed(role, allowedRoles) { role.name == allowedRoles[_] } - review(subject) = true { - subject.name == "system:unauthenticated" + subject_is(subject, expected) { + subject.name == expected } - review(subject) = true { - subject.name == "system:anonymous" + message(group) := val { + val := sprintf("%v is not allowed as a subject name in %v %v", [group, input.review.object.kind, input.review.object.metadata.name]) } diff --git a/src/general/disallowanonymous/constraint.tmpl b/src/general/disallowanonymous/constraint.tmpl index ff7caf000e..19559944b6 100644 --- a/src/general/disallowanonymous/constraint.tmpl +++ b/src/general/disallowanonymous/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8sdisallowanonymous annotations: metadata.gatekeeper.sh/title: "Disallow Anonymous Access" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.1.0 description: Disallows associating ClusterRole and Role resources to the system:anonymous user and system:unauthenticated group. spec: crd: @@ -24,6 +24,12 @@ spec: type: array items: type: string + disallowAuthenticated: + description: >- + A boolean indicating whether `system:authenticated` should be + disallowed by this policy. + type: boolean + default: false targets: - target: admission.k8s.gatekeeper.sh rego: | diff --git a/src/general/disallowanonymous/src.rego b/src/general/disallowanonymous/src.rego index fee795a3dc..8fa1761f05 100644 --- a/src/general/disallowanonymous/src.rego +++ b/src/general/disallowanonymous/src.rego @@ -1,19 +1,34 @@ package k8sdisallowanonymous + +violation[{"msg": msg}] { + not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) + + group := ["system:unauthenticated", "system:anonymous"][_] + subject_is(input.review.object.subjects[_], group) + + msg := message(group) +} + violation[{"msg": msg}] { not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) - review(input.review.object.subjects[_]) - msg := sprintf("Unauthenticated user reference is not allowed in %v %v ", [input.review.object.kind, input.review.object.metadata.name]) + + object.get(input, ["parameters", "disallowAuthenticated"], false) + + group := "system:authenticated" + subject_is(input.review.object.subjects[_], group) + + msg := message(group) } is_allowed(role, allowedRoles) { role.name == allowedRoles[_] } -review(subject) = true { - subject.name == "system:unauthenticated" +subject_is(subject, expected) { + subject.name == expected } -review(subject) = true { - subject.name == "system:anonymous" +message(group) := val { + val := sprintf("%v is not allowed as a subject name in %v %v", [group, input.review.object.kind, input.review.object.metadata.name]) } diff --git a/src/general/disallowanonymous/src_test.rego b/src/general/disallowanonymous/src_test.rego index ff951c9b35..fbc8e87a94 100644 --- a/src/general/disallowanonymous/src_test.rego +++ b/src/general/disallowanonymous/src_test.rego @@ -6,12 +6,6 @@ test_blank_subject_clusterrolebinding { count(results) == 0 } -test_authenticated_group_clusterrolebinding { - inp := {"review": clusterrolebinding([{"name": "system:authenticated", "kind": "Group"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} - results := violation with input as inp - count(results) == 0 -} - test_non_anonymous_user_clusterrolebinding { inp := {"review": clusterrolebinding([{"name": "user-1", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} results := violation with input as inp @@ -105,7 +99,7 @@ test_allowed_multiple_role_multiple_subjects_unauthenticated_group_clusterrolebi test_multiple_subjects_mix_clusterrolebinding { inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} results := violation with input as inp - count(results) == 1 + count(results) == 2 } test_allowed_role_multiple_subjects_mix_clusterrolebinding { @@ -117,7 +111,7 @@ test_allowed_role_multiple_subjects_mix_clusterrolebinding { test_multiple_role_multiple_subjects_mix_clusterrolebinding { inp := {"review": clusterrolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} results := violation with input as inp - count(results) == 1 + count(results) == 2 } test_allowed_multiple_role_multiple_subjects_mix_clusterrolebinding { @@ -225,7 +219,7 @@ test_allowed_multiple_role_multiple_subjects_unauthenticated_group_rolebinding { test_multiple_subjects_mix_rolebinding { inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1"]}} results := violation with input as inp - count(results) == 1 + count(results) == 2 } test_allowed_role_multiple_subjects_mix_rolebinding { @@ -237,7 +231,7 @@ test_allowed_role_multiple_subjects_mix_rolebinding { test_multiple_role_multiple_subjects_mix_rolebinding { inp := {"review": rolebinding([{"name": "system:unauthenticated", "kind": "Group"}, {"name": "system:anonymous", "kind": "User"}], "role-2"), "parameters": {"allowedRoles": ["role-1", "role-3"]}} results := violation with input as inp - count(results) == 1 + count(results) == 2 } test_allowed_multiple_role_multiple_subjects_mix_rolebinding { @@ -246,6 +240,26 @@ test_allowed_multiple_role_multiple_subjects_mix_rolebinding { count(results) == 0 } +authenticated_rolebinding := rolebinding([{"name": "system:authenticated", "kind": "Group"}], "role-2") + +test_authenticated_with_disallow_authenticated_true { + inp := {"review": authenticated_rolebinding, "parameters": { "allowedRoles": [], "disallowAuthenticated": true }} + results := violation with input as inp + count(results) == 1 +} + +test_authenticated_with_disallow_authenticated_false { + inp := {"review": authenticated_rolebinding, "parameters": { "allowedRoles": [], "disallowAuthenticated": false }} + results := violation with input as inp + count(results) == 0 +} + +test_authenticated_with_disallow_authenticated_undefined { + inp := {"review": authenticated_rolebinding, "parameters": { "allowedRoles": [] }} + results := violation with input as inp + count(results) == 0 +} + clusterrolebinding(subjects, roleref_name) = { "object": { "kind": "ClusterRoleBinding", diff --git a/website/docs/validation/disallowanonymous.md b/website/docs/validation/disallowanonymous.md index 12526a9a0d..1f950a42b2 100644 --- a/website/docs/validation/disallowanonymous.md +++ b/website/docs/validation/disallowanonymous.md @@ -16,7 +16,7 @@ metadata: name: k8sdisallowanonymous annotations: metadata.gatekeeper.sh/title: "Disallow Anonymous Access" - metadata.gatekeeper.sh/version: 1.0.1 + metadata.gatekeeper.sh/version: 1.1.0 description: Disallows associating ClusterRole and Role resources to the system:anonymous user and system:unauthenticated group. spec: crd: @@ -36,27 +36,48 @@ spec: type: array items: type: string + disallowAuthenticated: + description: >- + A boolean indicating whether `system:authenticated` should be + disallowed by this policy. + type: boolean + default: false targets: - target: admission.k8s.gatekeeper.sh rego: | package k8sdisallowanonymous + violation[{"msg": msg}] { not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) - review(input.review.object.subjects[_]) - msg := sprintf("Unauthenticated user reference is not allowed in %v %v ", [input.review.object.kind, input.review.object.metadata.name]) + + group := ["system:unauthenticated", "system:anonymous"][_] + subject_is(input.review.object.subjects[_], group) + + msg := message(group) + } + + violation[{"msg": msg}] { + not is_allowed(input.review.object.roleRef, object.get(input, ["parameters", "allowedRoles"], [])) + + object.get(input, ["parameters", "disallowAuthenticated"], false) + + group := "system:authenticated" + subject_is(input.review.object.subjects[_], group) + + msg := message(group) } is_allowed(role, allowedRoles) { role.name == allowedRoles[_] } - review(subject) = true { - subject.name == "system:unauthenticated" + subject_is(subject, expected) { + subject.name == expected } - review(subject) = true { - subject.name == "system:anonymous" + message(group) := val { + val := sprintf("%v is not allowed as a subject name in %v %v", [group, input.review.object.kind, input.review.object.metadata.name]) } ``` @@ -155,6 +176,91 @@ Usage kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/disallowanonymous/samples/no-anonymous-bindings/example_disallowed.yaml ``` + +
+authenticated-allowed-with-parameter-undefined + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-2 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/disallowanonymous/samples/no-authenticated/example_disallowed.yaml +``` + +
+ + +
+disallow-authenticated + +
+constraint + +```yaml +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sDisallowAnonymous +metadata: + name: no-anonymous +spec: + match: + kinds: + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["ClusterRoleBinding"] + - apiGroups: ["rbac.authorization.k8s.io"] + kinds: ["RoleBinding"] + parameters: + disallowAuthenticated: true + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/disallowanonymous/samples/no-authenticated/constraint.yaml +``` + +
+ +
+authenticated-disallowed-with-parameter-specified + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: cluster-role-binding-2 +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-role-2 +subjects: +- apiGroup: rbac.authorization.k8s.io + kind: Group + name: system:authenticated + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/disallowanonymous/samples/no-authenticated/example_disallowed.yaml +``` +