Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a policy for deny-default-service-account-bindings #1118

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
creationTimestamp: null
name: sample-test
spec:
steps:
- name: step-01
try:
- script:
content: kyverno test .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chainsaw tests must not wrap Kyverno CLI.

check:
($error != null): false
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: cli.kyverno.io/v1alpha1
kind: Test
metadata:
name: kyverno-test.yaml
policies:
- ../deny-default-service-account-bindings.yaml
resources:
- resources.yaml
results:
- kind: RoleBinding
policy: deny-default-service-account-bindings
resources:
- goodpod01
- goodpod02
result: pass
rule: deny-default-service-account-bindings
- kind: RoleBinding
policy: deny-default-service-account-bindings
resources:
- badpod01
- badpod02
result: fail
rule: deny-default-service-account-bindings
31 changes: 31 additions & 0 deletions other/deny-default-service-account-bindings/.tests/resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: goodpod01
subjects:
- kind: ServiceAccount
name: custom-service-account01
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: goodpod02
subjects:
- kind: ServiceAccount
name: custom-service-account02
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: badpod01
subjects:
- kind: ServiceAccount
name: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: badpod02
subjects:
- kind: ServiceAccount
name: default
22 changes: 22 additions & 0 deletions other/deny-default-service-account-bindings/artifacthub-pkg.yml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File needs to be updated accordingly including with changes to annotations in the policy.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: deny-force-delete
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name is not accurate here.

version: 1.0.0
displayName: Deny Force Deletion of Resources
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not accurate.

createdAt: "2024-08-05T10:30:02.000Z"
description: >-
The default service account is automatically mounted into all pods in a namespace unless explicitly overridden. If this account is bound to a Role or ClusterRole that grants extensive permissions, every pod in the namespace using the default service account will inherit these permissions. This setup can lead to unnecessary security risks if a pod is compromised, as an attacker could potentially gain access to other resources within the cluster.For an enhnaced security, using the default service account in RoleBindings is not recommended.
install: |-
```shell
kubectl apply -f https://raw.githubusercontent.com/kyverno/policies/main/other/deny-default-service-account-bindings/deny-default-service-account-bindings.yaml
```
keywords:
- kyverno
- Other
readme: |
Using the default service account in RoleBindings is not allowed.

Refer to the documentation for more details on Kyverno annotations: https://artifacthub.io/docs/topics/annotations/kyverno/
annotations:
kyverno/category: "Other"
kyverno/kubernetesVersion: "1.28"
kyverno/subject: "Pod"
digest: ca4094718f70c2bfbfad6051ce357a34c5dbb65512dcc118e0897786626aff37
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: deny-default-service-account-bindings
annotations:
policies.kyverno.io/title: Deny binding of default service accounts
policies.kyverno.io/category: Security
policies.kyverno.io/subject: RoleBinding, ClusterRoleBinding
kyverno.io/kyverno-version: 1.11.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test and certify on the latest Kyverno release.

policies.kyverno.io/minversion: 1.10.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

kyverno.io/kubernetes-version: "1.26"
policies.kyverno.io/description: >-
The default service account is automatically mounted into all pods in a namespace unless
explicitly overridden. If this account is bound to a Role or ClusterRole that grants extensive
permissions, every pod in the namespace using the default service account will inherit these
permissions. This setup can lead to unnecessary security risks if a pod is compromised, as an
attacker could potentially gain access to other resources within the cluster. For enhanced
security, using the default service account in RoleBindings is not recommended.
spec:
validationFailureAction: enforce
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
validationFailureAction: enforce
validationFailureAction: Audit

background: false
rules:
- name: deny-default-service-account-bindings
match:
resources:
kinds:
- RoleBinding
- ClusterRoleBinding
Comment on lines +24 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rules must use any or all under the match and exclude blocks to be conformant to the current schema.

validate:
message: "Using the default service account in RoleBindings is not allowed."
pattern:
subjects:
- kind: "ServiceAccount"
name: "!default"
Comment on lines +33 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested this, but my feeling is this may not work in all scenarios because subjects[] is an array of objects. If it isn't the first one in the list, it may bypass the policy. I suggest testing on your own to confirm. If confirmed, this would be better written as a deny rule.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @chipzoller,

With the change in policy, there's a new issue that the policy is excluding all the resources. Could you please point me to the issue here:

      validate:
        message: "Using the default service account in RoleBindings is not allowed."
        foreach:
          - list: "request.object.spec.subject[]"
            deny:
              conditions:
                all:
                  - key: "{{ element.kind }}"
                    operator: Equals
                    value: "ServiceAccount"
                  - key: "{{ element.name }}"
                    operator: Equals
                    value: "default"

Following is the result:

 krishna@Krishnas-MacBook-Pro .tests % kyverno test .                                
Loading test  ( kyverno-test.yaml ) ...
  Loading values/variables ...
  Loading policies ...
  Loading resources ...
  Loading exceptions ...
  Applying 1 policy to 4 resources ...
  Checking results ...

│────│───────────────────────────────────────│───────────────────────────────────────│───────────────────────│────────│──────────│
│ ID │ POLICY                                │ RULE                                  │ RESOURCE              │ RESULT │ REASON   │
│────│───────────────────────────────────────│───────────────────────────────────────│───────────────────────│────────│──────────│
│ 1  │ deny-default-service-account-bindings │ deny-default-service-account-bindings │ RoleBinding/goodpod01 │ Pass   │ Excluded │
│ 2  │ deny-default-service-account-bindings │ deny-default-service-account-bindings │ RoleBinding/goodpod02 │ Pass   │ Excluded │
│ 3  │ deny-default-service-account-bindings │ deny-default-service-account-bindings │ RoleBinding/badpod01  │ Pass   │ Excluded │
│ 4  │ deny-default-service-account-bindings │ deny-default-service-account-bindings │ RoleBinding/badpod02  │ Pass   │ Excluded │
│────│───────────────────────────────────────│───────────────────────────────────────│───────────────────────│────────│──────────│


Test Summary: 4 tests passed and 0 tests failed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the following policy, we see the goodpods start, but badpods get skipped.

     validate:
        message: "Using the default service account in RoleBindings is not allowed."
        deny:
          conditions:
            all: 
            - key: "{{request.object.subject[].kind}}"
              operator: Equals
              value: "ServiceAccount"
            - key: "{{request.object.subject[].name}}"
              operator: Equals
              value: "default"
krishna@Krishnas-MacBook-Pro .kyverno-test % kyverno test .                           
Loading test  ( kyverno-test.yaml ) ...
  Loading values/variables ...
  Loading policies ...
  Loading resources ...
  Loading exceptions ...
  Applying 1 policy to 4 resources ...
  Checking results ...

│────│───────────────────────────────│───────────────────────────────│───────────────│────────│─────────────────────│
│ ID │ POLICY                        │ RULE                          │ RESOURCE      │ RESULT │ REASON              │
│────│───────────────────────────────│───────────────────────────────│───────────────│────────│─────────────────────│
│ 1  │ deny-default-service-accounts │ deny-default-service-accounts │ Pod/goodpod01 │ Pass   │ Ok                  │
│ 2  │ deny-default-service-accounts │ deny-default-service-accounts │ Pod/goodpod02 │ Pass   │ Ok                  │
│ 3  │ deny-default-service-accounts │ deny-default-service-accounts │ Pod/badpod01  │ Pass   │ Want fail, got skip │
│ 4  │ deny-default-service-accounts │ deny-default-service-accounts │ Pod/badpod02  │ Pass   │ Want fail, got skip │
│────│───────────────────────────────│───────────────────────────────│───────────────│────────│─────────────────────│

Loading