diff --git a/.github/scripts/config/helm/values-vap.yaml b/.github/scripts/config/helm/values-vap.yaml new file mode 100644 index 00000000..64f28aba --- /dev/null +++ b/.github/scripts/config/helm/values-vap.yaml @@ -0,0 +1,18 @@ +features: + generateValidatingAdmissionPolicy: + enabled: true + +admissionController: + rbac: + clusterRole: + extraResources: + - apiGroups: + - admissionregistration.k8s.io + resources: + - validatingadmissionpolicies + - validatingadmissionpolicybindings + verbs: + - create + - update + - delete + - list \ No newline at end of file diff --git a/.github/scripts/config/kind/vap-v1alpha1.yaml b/.github/scripts/config/kind/vap-v1alpha1.yaml new file mode 100644 index 00000000..7ab36c3f --- /dev/null +++ b/.github/scripts/config/kind/vap-v1alpha1.yaml @@ -0,0 +1,9 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +featureGates: + ValidatingAdmissionPolicy: true +runtimeConfig: + admissionregistration.k8s.io/v1alpha1: true +nodes: + - role: control-plane + - role: worker \ No newline at end of file diff --git a/.github/scripts/config/kind/vap-v1beta1.yaml b/.github/scripts/config/kind/vap-v1beta1.yaml new file mode 100644 index 00000000..36609acf --- /dev/null +++ b/.github/scripts/config/kind/vap-v1beta1.yaml @@ -0,0 +1,10 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +featureGates: + ValidatingAdmissionPolicy: true +runtimeConfig: + admissionregistration.k8s.io/v1beta1: true + admissionregistration.k8s.io/v1alpha1: true +nodes: + - role: control-plane + - role: worker \ No newline at end of file diff --git a/.github/workflows/chainsaw-e2e.yaml b/.github/workflows/chainsaw-e2e.yaml index df25e49c..5b14425c 100644 --- a/.github/workflows/chainsaw-e2e.yaml +++ b/.github/workflows/chainsaw-e2e.yaml @@ -45,7 +45,7 @@ jobs: run: chainsaw version - name: Test with Chainsaw - run: make test-chainsaw + run: make test-chainsaw-exclude-cel run-e2etest-2: runs-on: ubuntu-latest @@ -84,3 +84,69 @@ jobs: - name: Test with Chainsaw run: make test-chainsaw + + run-e2etest-vap-alpha: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + k8s-version: [v1.27.3, v1.26.3] + n4k-chart-version: [3.1.14] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Prepare environment + run: | + K8S_VERSION=${{ matrix.k8s-version }} make kind-create-cluster-vap-alpha + + - name: Install kyverno + run: | + N4K_VERSION=${{ matrix.n4k-chart-version }} make kind-deploy-kyverno-vap + + - name: Check Kyverno status + run: make wait-for-kyverno + + - name: Install chainsaw + uses: kyverno/action-install-chainsaw@v0.1.6 + + - name: Verify Chainsaw Installation + run: chainsaw version + + - name: Test with Chainsaw + run: make test-chainsaw-vap + + run-e2etest-vap-beta: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + k8s-version: [v1.29.2, v1.28.0] + n4k-chart-version: [3.1.14] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Prepare environment + run: | + K8S_VERSION=${{ matrix.k8s-version }} make kind-create-cluster-vap-beta + + - name: Install kyverno + run: | + N4K_VERSION=${{ matrix.n4k-chart-version }} make kind-deploy-kyverno-vap + + - name: Check Kyverno status + run: make wait-for-kyverno + + - name: Install chainsaw + uses: kyverno/action-install-chainsaw@v0.1.6 + + - name: Verify Chainsaw Installation + run: chainsaw version + + - name: Test with Chainsaw + run: make test-chainsaw-vap diff --git a/Makefile b/Makefile index 2dea7295..68522dea 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,9 @@ USE_CONFIG ?= standard TOOLS_DIR := $(PWD)/.tools KIND := $(TOOLS_DIR)/kind KIND_VERSION := v0.22.0 +KIND_VAP_ALPHA_CONFIG := $(PWD)/.github/scripts/config/kind/vap-v1alpha1.yaml +KIND_VAP_BETA_CONFIG := $(PWD)/.github/scripts/config/kind/vap-v1beta1.yaml +HELM_VALUES_VAP := $(PWD)/.github/scripts/config/helm/values-vap.yaml HELM := $(TOOLS_DIR)/helm HELM_VERSION := v3.10.1 TOOLS := $(KIND) $(HELM) @@ -37,12 +40,34 @@ test-chainsaw: @echo Running chainsaw tests... >&2 @chainsaw test --config .chainsaw-config.yaml +.PHONY: test-chainsaw-exclude-cel +test-chainsaw-exclude-cel: + @echo Running chainsaw tests by excluding CEL folders... >&2 + @chainsaw test --config .chainsaw-config.yaml --exclude-test-regex 'chainsaw/.*-cel' + +.PHONY: test-chainsaw-vap +test-chainsaw-vap: + @echo Running chainsaw tests for VAPs... >&2 + @chainsaw test --config .chainsaw-config.yaml --test-file chainsaw-test-vap.yaml + ## Create kind cluster .PHONY: kind-create-cluster kind-create-cluster: $(KIND) @echo Create kind cluster... >&2 @$(KIND) create cluster --name $(KIND_NAME) --image $(KIND_IMAGE) +## Create kind cluster with alpha VAP enabled +.PHONY: kind-create-cluster-vap-alpha +kind-create-cluster-vap-alpha: $(KIND) + @echo Create kind cluster... >&2 + @$(KIND) create cluster --name $(KIND_NAME) --image $(KIND_IMAGE) --config $(KIND_VAP_ALPHA_CONFIG) + +## Create kind cluster with beta VAP enabled +.PHONY: kind-create-cluster-vap-beta +kind-create-cluster-vap-beta: $(KIND) + @echo Create kind cluster... >&2 + @$(KIND) create cluster --name $(KIND_NAME) --image $(KIND_IMAGE) --config $(KIND_VAP_BETA_CONFIG) + ## Delete kind cluster .PHONY: kind-delete-cluster kind-delete-cluster: $(KIND) @@ -57,6 +82,14 @@ kind-deploy-kyverno: $(HELM) @$(HELM) repo update @$(HELM) install kyverno nirmata/kyverno -n kyverno --create-namespace --version=$(N4K_VERSION) +## Deploy Enterprise Kyverno with VAP generation enabled +.PHONY: kind-deploy-kyverno-vap +kind-deploy-kyverno-vap: $(HELM) + @echo Install kyverno chart... >&2 + @$(HELM) repo add nirmata https://nirmata.github.io/kyverno-charts + @$(HELM) repo update + @$(HELM) install kyverno nirmata/kyverno -n kyverno --create-namespace --version=$(N4K_VERSION) --values=$(HELM_VALUES_VAP) + ## Check Kyverno status .PHONY: wait-for-kyverno wait-for-kyverno: diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/bad-resource.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/bad-resource.yaml new file mode 100644 index 00000000..4e7d48ee --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/bad-resource.yaml @@ -0,0 +1,67 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: badcrb01 +subjects: +- kind: Group + name: bar + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: "system:masters" + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: badcrb02 +subjects: +- kind: Group + namespace: foo + name: bar + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: "system:masters" + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: badrb01 +subjects: +- kind: Group + name: bar + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: "system:masters" + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: badrb02 +subjects: +- kind: Group + name: bar + namespace: foo + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: "system:masters" + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: badrb03 +subjects: +- kind: Group + name: bar + namespace: foo + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: "system:masters" + apiGroup: rbac.authorization.k8s.io diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/chainsaw-test-vap.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/chainsaw-test-vap.yaml new file mode 100644 index 00000000..c583bd9a --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/chainsaw-test-vap.yaml @@ -0,0 +1,28 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-binding-system-groups-policy +spec: + steps: + - name: test-restrict-binding-system-groups + try: + - apply: + file: ../restrict-binding-system-groups.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-binding-system-groups.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - assert: + file: vap-assert.yaml + - assert: + file: vap-binding-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/chainsaw-test.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/chainsaw-test.yaml new file mode 100644 index 00000000..a48d4aa0 --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/chainsaw-test.yaml @@ -0,0 +1,24 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-binding-system-groups-policy +spec: + steps: + - name: test-restrict-binding-system-groups + try: + - apply: + file: ../restrict-binding-system-groups.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-binding-system-groups.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/enforce-policy-assert.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/enforce-policy-assert.yaml new file mode 100644 index 00000000..d5768e9d --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/enforce-policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-binding-system-groups +spec: + validationFailureAction: Enforce +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/good-resource.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/good-resource.yaml new file mode 100644 index 00000000..7e958419 --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/good-resource.yaml @@ -0,0 +1,77 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: goodcrb01 +subjects: +- kind: Group + name: secret-reader + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: ClusterRole + name: manager + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: goodcrb02 +subjects: +- kind: ServiceAccount + namespace: foo + name: foo-reader +roleRef: + kind: ClusterRole + name: manager + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: goodcrb03 +subjects: +- kind: ServiceAccount + namespace: foo + name: "system.foo" +roleRef: + kind: ClusterRole + name: manager + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: goodrb01 +subjects: +- kind: User + name: foo + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: foo-bar + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: goodrb02 +subjects: +- kind: ServiceAccount + name: foo + namespace: foo +roleRef: + kind: Role + name: foo-bar + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: goodrb03 +subjects: +- kind: Group + name: "system:foo" + apiGroup: rbac.authorization.k8s.io +roleRef: + kind: Role + name: foo + apiGroup: rbac.authorization.k8s.io diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/policy-assert.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/policy-assert.yaml new file mode 100644 index 00000000..35d048f1 --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-binding-system-groups +spec: + validationFailureAction: Audit +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/vap-assert.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/vap-assert.yaml new file mode 100644 index 00000000..0d03c480 --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/vap-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-binding-system-groups + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-binding-system-groups +spec: + failurePolicy: Fail \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/e2e/vap-binding-assert.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/vap-binding-assert.yaml new file mode 100644 index 00000000..c44d8ea6 --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/e2e/vap-binding-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-binding-system-groups-binding + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-binding-system-groups +spec: + policyName: restrict-binding-system-groups \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-binding-system-groups/restrict-binding-system-groups.yaml b/rbac-best-practices-cel/restrict-binding-system-groups/restrict-binding-system-groups.yaml new file mode 100644 index 00000000..b73bc50d --- /dev/null +++ b/rbac-best-practices-cel/restrict-binding-system-groups/restrict-binding-system-groups.yaml @@ -0,0 +1,32 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-binding-system-groups + annotations: + policies.kyverno.io/title: Restrict Binding System Groups in CEL expressions + policies.kyverno.io/category: RBAC Best Practices in CEL + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: RoleBinding, ClusterRoleBinding, RBAC + policies.kyverno.io/minversion: 1.11.0 + kyverno.io/kubernetes-version: "1.26" + policies.kyverno.io/description: >- + Certain system groups exist in Kubernetes which grant permissions that + are used for certain system-level functions yet typically never appropriate + for other users. This policy prevents creating bindings for system:masters group. +spec: + validationFailureAction: Audit + background: true + rules: + - name: restrict-masters + match: + any: + - resources: + kinds: + - RoleBinding + - ClusterRoleBinding + validate: + cel: + expressions: + - expression: "object.roleRef.name != 'system:masters'" + message: "Binding to system:masters is not allowed." + diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/bad-resource.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/bad-resource.yaml new file mode 100644 index 00000000..65063c9c --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/bad-resource.yaml @@ -0,0 +1,20 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr01 +rules: +- apiGroups: [""] + resources: ["nodes/proxy", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr02 +rules: +- apiGroups: [""] + resources: ["pods", "nodes/proxy"] + verbs: ["get", "watch", "list"] diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/chainsaw-test-vap.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/chainsaw-test-vap.yaml new file mode 100644 index 00000000..002fb48d --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/chainsaw-test-vap.yaml @@ -0,0 +1,28 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-clusterrole-nodesproxy-policy +spec: + steps: + - name: test-restrict-clusterrole-nodesproxy + try: + - apply: + file: ../restrict-clusterrole-nodesproxy.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-clusterrole-nodesproxy.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - assert: + file: vap-assert.yaml + - assert: + file: vap-binding-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/chainsaw-test.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/chainsaw-test.yaml new file mode 100644 index 00000000..5d36c2a9 --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/chainsaw-test.yaml @@ -0,0 +1,24 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-clusterrole-nodesproxy-policy +spec: + steps: + - name: test-restrict-clusterrole-nodesproxy + try: + - apply: + file: ../restrict-clusterrole-nodesproxy.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-clusterrole-nodesproxy.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/enforce-policy-assert.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/enforce-policy-assert.yaml new file mode 100644 index 00000000..0b7e800e --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/enforce-policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-clusterrole-nodesproxy +spec: + validationFailureAction: Enforce +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/good-resource.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/good-resource.yaml new file mode 100644 index 00000000..a84a62b8 --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/good-resource.yaml @@ -0,0 +1,41 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr02 +rules: +- apiGroups: [""] + resources: ["nodes"] + verbs: ["get", "watch", "list"] +--- +# If 'rules' is specified without a value, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-empty-rules +rules: +--- +# If the 'rules' field is omitted from the manifest, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-omitted-rules +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-null-rules + rules: null diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/policy-assert.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/policy-assert.yaml new file mode 100644 index 00000000..7220658d --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-clusterrole-nodesproxy +spec: + validationFailureAction: Audit +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/vap-assert.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/vap-assert.yaml new file mode 100644 index 00000000..d5a4acf1 --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/vap-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-clusterrole-nodesproxy + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-clusterrole-nodesproxy +spec: + failurePolicy: Fail \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/vap-binding-assert.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/vap-binding-assert.yaml new file mode 100644 index 00000000..94306751 --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/e2e/vap-binding-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-clusterrole-nodesproxy-binding + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-clusterrole-nodesproxy +spec: + policyName: restrict-clusterrole-nodesproxy \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/restrict-clusterrole-nodesproxy.yaml b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/restrict-clusterrole-nodesproxy.yaml new file mode 100644 index 00000000..169bade9 --- /dev/null +++ b/rbac-best-practices-cel/restrict-clusterrole-nodesproxy/restrict-clusterrole-nodesproxy.yaml @@ -0,0 +1,38 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-clusterrole-nodesproxy + annotations: + policies.kyverno.io/title: Restrict ClusterRole with Nodes Proxy in CEL expressions + policies.kyverno.io/category: RBAC Best Practices in CEL + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: ClusterRole, RBAC + policies.kyverno.io/minversion: 1.11.0 + kyverno.io/kubernetes-version: "1.26" + policies.kyverno.io/description: >- + A ClusterRole with nodes/proxy resource access allows a user to + perform anything the kubelet API allows. It also allows users to bypass + the API server and talk directly to the kubelet potentially circumventing + audits and admission controllers. See https://blog.aquasec.com/privilege-escalation-kubernetes-rbac + for more info. This policy prevents the creation + of a ClusterRole if it contains the nodes/proxy resource. +spec: + validationFailureAction: Audit + background: true + rules: + - name: clusterrole-nodesproxy + match: + any: + - resources: + kinds: + - ClusterRole + validate: + cel: + expressions: + - expression: >- + object.rules == null || + !object.rules.exists(rule, + rule.resources.exists(resource, resource == 'nodes/proxy') && + rule.apiGroups.exists(apiGroup, apiGroup == '')) + message: "A ClusterRole containing the nodes/proxy resource is not allowed." + diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/bad-resource.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/bad-resource.yaml new file mode 100644 index 00000000..a4a57855 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/bad-resource.yaml @@ -0,0 +1,107 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["bind", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["update", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr02 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["get", "watch", "list"] +- apiGroups: ["batches", "rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["update", "escalate", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr03 +rules: +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["get", "watch", "bind"] +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["batches", "rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr04 +rules: +- apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["bind", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["update", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole02 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["get", "watch", "list"] +- apiGroups: ["batches", "rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["update", "escalate", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole03 +rules: +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["get", "watch", "bind"] +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["batches"] + resources: ["jobs"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole04 +rules: +- apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/chainsaw-test-vap.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/chainsaw-test-vap.yaml new file mode 100644 index 00000000..8e0062f4 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/chainsaw-test-vap.yaml @@ -0,0 +1,28 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-escalation-verbs-roles-policy +spec: + steps: + - name: test-restrict-escalation-verbs-roles + try: + - apply: + file: ../restrict-escalation-verbs-roles.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-escalation-verbs-roles.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - assert: + file: vap-assert.yaml + - assert: + file: vap-binding-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/chainsaw-test.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/chainsaw-test.yaml new file mode 100644 index 00000000..b2cecb30 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/chainsaw-test.yaml @@ -0,0 +1,24 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-escalation-verbs-roles-policy +spec: + steps: + - name: test-restrict-escalation-verbs-roles + try: + - apply: + file: ../restrict-escalation-verbs-roles.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-escalation-verbs-roles.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/enforce-policy-assert.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/enforce-policy-assert.yaml new file mode 100644 index 00000000..467bc1a6 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/enforce-policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-escalation-verbs-roles +spec: + validationFailureAction: Enforce +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/good-resource.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/good-resource.yaml new file mode 100644 index 00000000..e0a6adac --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/good-resource.yaml @@ -0,0 +1,90 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["update", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr02 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +--- +# If 'rules' is specified without a value, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-empty-rules +rules: +--- +# If the 'rules' field is omitted from the manifest, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-omitted-rules +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-null-rules + rules: null +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io", "apps"] + resources: ["deployments", "roles"] + verbs: ["get", "watch", "list"] +- apiGroups: ["rbac.authorization.k8s.io"] + resources: ["clusterroles"] + verbs: ["update", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole02 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +--- +# If 'rules' is specified without a value, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole-empty-rules +rules: +--- +# If the 'rules' field is omitted from the manifest, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole-omitted-rules +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole-null-rules + rules: null +--- diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/policy-assert.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/policy-assert.yaml new file mode 100644 index 00000000..56f39264 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-escalation-verbs-roles +spec: + validationFailureAction: Audit +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/vap-assert.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/vap-assert.yaml new file mode 100644 index 00000000..bff40bbc --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/vap-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-escalation-verbs-roles + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-escalation-verbs-roles +spec: + failurePolicy: Fail \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/vap-binding-assert.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/vap-binding-assert.yaml new file mode 100644 index 00000000..f3d4f552 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/e2e/vap-binding-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-escalation-verbs-roles-binding + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-escalation-verbs-roles +spec: + policyName: restrict-escalation-verbs-roles \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-escalation-verbs-roles/restrict-escalation-verbs-roles.yaml b/rbac-best-practices-cel/restrict-escalation-verbs-roles/restrict-escalation-verbs-roles.yaml new file mode 100644 index 00000000..af1ca304 --- /dev/null +++ b/rbac-best-practices-cel/restrict-escalation-verbs-roles/restrict-escalation-verbs-roles.yaml @@ -0,0 +1,37 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-escalation-verbs-roles + annotations: + policies.kyverno.io/title: Restrict Escalation Verbs in Roles in CEL expressions + policies.kyverno.io/category: RBAC Best Practices in CEL + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: Role, ClusterRole, RBAC + policies.kyverno.io/minversion: 1.11.0 + kyverno.io/kubernetes-version: "1.26" + policies.kyverno.io/description: >- + The verbs `impersonate`, `bind`, and `escalate` may all potentially lead to + privilege escalation and should be tightly controlled. This policy prevents + use of these verbs in Role or ClusterRole resources. +spec: + validationFailureAction: Audit + background: true + rules: + - name: escalate + match: + any: + - resources: + kinds: + - Role + - ClusterRole + validate: + cel: + expressions: + - expression: >- + object.rules == null || + !object.rules.exists(rule, + rule.apiGroups.exists(apiGroup, apiGroup in ['*', 'rbac.authorization.k8s.io']) && + rule.resources.exists(resource, resource in ['*', 'clusterroles', 'roles']) && + rule.verbs.exists(verb, verb in ['*', 'bind', 'escalate', 'impersonate'])) + message: "Use of verbs `escalate`, `bind`, and `impersonate` are forbidden." + diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/bad-resource.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/bad-resource.yaml new file mode 100644 index 00000000..7180d7c2 --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/bad-resource.yaml @@ -0,0 +1,65 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr01 +rules: +- apiGroups: [""] + resources: ["namespaces", "*", "pods"] + verbs: ["get", "create"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr02 +rules: +- apiGroups: ["apps"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: [""] + resources: ["namespaces", "secrets", "pods"] + verbs: ["create", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: badcr03 +rules: +- apiGroups: [""] + resources: ["*"] + verbs: ["update", "list", "create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole01 +rules: +- apiGroups: [""] + resources: ["namespaces", "*", "pods"] + verbs: ["get", "create"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole02 +rules: +- apiGroups: ["apps"] + resources: ["*"] + verbs: ["get", "watch", "list"] +- apiGroups: [""] + resources: ["namespaces", "secrets", "pods"] + verbs: ["create", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: badrole03 +rules: +- apiGroups: [""] + resources: ["*"] + verbs: ["update", "list", "create"] diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/chainsaw-test-vap.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/chainsaw-test-vap.yaml new file mode 100644 index 00000000..bacdb83a --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/chainsaw-test-vap.yaml @@ -0,0 +1,28 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-wildcard-resources-policy +spec: + steps: + - name: test-restrict-wildcard-resources + try: + - apply: + file: ../restrict-wildcard-resources.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-wildcard-resources.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - assert: + file: vap-assert.yaml + - assert: + file: vap-binding-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/chainsaw-test.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/chainsaw-test.yaml new file mode 100644 index 00000000..188244b5 --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/chainsaw-test.yaml @@ -0,0 +1,24 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: restrict-wildcard-resources-policy +spec: + steps: + - name: test-restrict-wildcard-resources + try: + - apply: + file: ../restrict-wildcard-resources.yaml + - assert: + file: policy-assert.yaml + - script: + content: | + sed 's/validationFailureAction: Audit/validationFailureAction: Enforce/' ../restrict-wildcard-resources.yaml | kubectl apply -f - + - assert: + file: enforce-policy-assert.yaml + - apply: + file: good-resource.yaml + - apply: + expect: + - check: + ($error != null): true + file: bad-resource.yaml diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/enforce-policy-assert.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/enforce-policy-assert.yaml new file mode 100644 index 00000000..6054e24e --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/enforce-policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-wildcard-resources +spec: + validationFailureAction: Enforce +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/good-resource.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/good-resource.yaml new file mode 100644 index 00000000..fad3036f --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/good-resource.yaml @@ -0,0 +1,137 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr02 +rules: +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "create", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr03 +rules: +- apiGroups: ["batch"] + resources: ["secrets"] + verbs: ["create", "update", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr04 +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr05 +rules: +- apiGroups: ["*"] + resources: ["secrets"] + verbs: ["create", "update", "patch"] +--- +# If 'rules' is specified without a value, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-empty-rules +rules: +--- +# If the 'rules' field is omitted from the manifest, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-omitted-rules +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: goodcr-null-rules + rules: null +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole01 +rules: +- apiGroups: [""] + resources: ["pods", "namespaces"] + verbs: ["get", "watch", "list"] +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "watch", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole02 +rules: +- apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["get", "create", "update"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole03 +rules: +- apiGroups: ["batch"] + resources: ["secrets"] + verbs: ["create", "update", "patch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole04 +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole05 +rules: +- apiGroups: ["*"] + resources: ["secrets"] + verbs: ["create", "update", "patch"] +--- +# If 'rules' is specified without a value, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole-empty-rules +rules: +--- +# If the 'rules' field is omitted from the manifest, +# the field will be set to 'rules: null' by default when the resource is created in the cluster. +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole-omitted-rules +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: goodrole-null-rules + rules: null diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/policy-assert.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/policy-assert.yaml new file mode 100644 index 00000000..28a0f36f --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/policy-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-wildcard-resources +spec: + validationFailureAction: Audit +status: + conditions: + - reason: Succeeded + status: "True" + type: Ready diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/vap-assert.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/vap-assert.yaml new file mode 100644 index 00000000..17cbc1b0 --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/vap-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicy +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-wildcard-resources + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-wildcard-resources +spec: + failurePolicy: Fail \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/e2e/vap-binding-assert.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/vap-binding-assert.yaml new file mode 100644 index 00000000..e01957af --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/e2e/vap-binding-assert.yaml @@ -0,0 +1,12 @@ +apiVersion: admissionregistration.k8s.io/v1alpha1 +kind: ValidatingAdmissionPolicyBinding +metadata: + labels: + app.kubernetes.io/managed-by: kyverno + name: restrict-wildcard-resources-binding + ownerReferences: + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + name: restrict-wildcard-resources +spec: + policyName: restrict-wildcard-resources \ No newline at end of file diff --git a/rbac-best-practices-cel/restrict-wildcard-resources/restrict-wildcard-resources.yaml b/rbac-best-practices-cel/restrict-wildcard-resources/restrict-wildcard-resources.yaml new file mode 100644 index 00000000..b22943a4 --- /dev/null +++ b/rbac-best-practices-cel/restrict-wildcard-resources/restrict-wildcard-resources.yaml @@ -0,0 +1,34 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: restrict-wildcard-resources + annotations: + policies.kyverno.io/title: Restrict Wildcards in Resources in CEL expressions + policies.kyverno.io/category: RBAC Best Practices in CEL + policies.kyverno.io/severity: medium + policies.kyverno.io/subject: ClusterRole, Role, RBAC + policies.kyverno.io/minversion: 1.11.0 + kyverno.io/kubernetes-version: "1.26" + policies.kyverno.io/description: >- + Wildcards ('*') in resources grants access to all of the resources referenced by + the given API group and does not follow the principal of least privilege. As much as possible, + avoid such open resources unless scoped to perhaps a custom API group. + This policy blocks any Role or ClusterRole that contains a wildcard entry in + the resources list found in any rule. +spec: + validationFailureAction: Audit + background: true + rules: + - name: wildcard-resources + match: + any: + - resources: + kinds: + - Role + - ClusterRole + validate: + cel: + expressions: + - expression: "object.rules == null || !object.rules.exists(rule, '*' in rule.resources)" + message: "Use of a wildcard ('*') in any resources is forbidden." +