Skip to content

Commit

Permalink
feat(k8sdisallowanonymous): allow preventing system:authenticated
Browse files Browse the repository at this point in the history
Previously, the k8sdisallowanonymous would prevent bindings to the
system:anonymous and system:unauthenticated groups.

For Google Kubernetes Engine, the system:authenticated group is a
potential security threat.  This was described by Orca Security in this
blog post:

https://orca.security/resources/blog/sys-all-google-kubernetes-engine-risk/

This PR updates the k8sdisallowanonymous to prevent bindings to
`system:authenticated` if the parameters.disallowAuthenticated toggle is
set to true.  This will not break existing customers as the default
boolean value is false, leaving this functionality disabled.

Signed-off-by: juliankatz <[email protected]>
  • Loading branch information
julianKatz committed Aug 21, 2024
1 parent ee2e26e commit 7809cea
Show file tree
Hide file tree
Showing 17 changed files with 422 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
resources:
- template.yaml
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
29 changes: 29 additions & 0 deletions artifacthub/library/general/disallowanonymous/1.1.0/suite.yaml
Original file line number Diff line number Diff line change
@@ -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
69 changes: 69 additions & 0 deletions artifacthub/library/general/disallowanonymous/1.1.0/template.yaml
Original file line number Diff line number Diff line change
@@ -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])
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
14 changes: 13 additions & 1 deletion library/general/disallowanonymous/suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,16 @@ tests:
- name: example-disallowed
object: samples/no-anonymous-bindings/example_disallowed.yaml
assertions:
- violations: yes
- 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
35 changes: 28 additions & 7 deletions library/general/disallowanonymous/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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])
}
8 changes: 7 additions & 1 deletion src/general/disallowanonymous/constraint.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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: |
Expand Down
27 changes: 21 additions & 6 deletions src/general/disallowanonymous/src.rego
Original file line number Diff line number Diff line change
@@ -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])
}
Loading

0 comments on commit 7809cea

Please sign in to comment.