From 727fe1bed28951689a7e11437aaf25331f45e2e2 Mon Sep 17 00:00:00 2001 From: Julian Katz Date: Fri, 27 Dec 2024 12:50:09 -0800 Subject: [PATCH 1/3] chore: Bump GATOR_VERSION to 1.17.0 from 1.16.3 (#586) * chore: Bump GATOR_VERSION to 1.17.0 from 1.16.3 In the 1.17.0 version of gator (which I've been using on my machine), the `--experimental-enable-k8s-native-validation` flag has been renamed to `--enable-k8s-native-validation`. This was preventing me from using the `make verify-gator` target. This PR fixes updates the GATOR_VERSION and changes the flag. Signed-off-by: juliankatz * bump gatekeeper Signed-off-by: Andrew Peabody --------- Signed-off-by: juliankatz Signed-off-by: Andrew Peabody Co-authored-by: Rita Zhang Co-authored-by: Andrew Peabody --- .github/workflows/workflow.yaml | 12 ++---------- Makefile | 10 +++++----- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index fcc48a9d3..a50fac89e 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -65,22 +65,19 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - gatekeeper: [ "3.15.1", "3.16.3" ] + gatekeeper: [ "3.17.1", "3.18.1" ] engine: [ "cel", "rego" ] name: "Integration test on Gatekeeper ${{ matrix.gatekeeper }} for ${{ matrix.engine }} policies" steps: - name: Harden Runner - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} # remove this condition once 3.17 is out uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - name: Check out code into the Go module directory - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Bootstrap integration test - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} run: | mkdir -p $GITHUB_WORKSPACE/bin echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH @@ -88,12 +85,10 @@ jobs: make deploy GATEKEEPER_VERSION=${{ matrix.gatekeeper }} POLICY_ENGINE=${{ matrix.engine }} - name: Run integration test - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} run: | make test-integration - name: Save logs - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} run: | kubectl logs -n gatekeeper-system -l control-plane=controller-manager --tail=-1 > logs-controller.json kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=-1 > logs-audit.json @@ -136,18 +131,15 @@ jobs: strategy: matrix: engine: [ "cel", "rego" ] - gatekeeper: [ "3.15.1", "3.16.3" ] + gatekeeper: [ "3.17.1", "3.18.1" ] name: "Verify assertions in suite.yaml files for ${{ matrix.engine }} policies" steps: - name: Harden Runner - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} # remove this condition once 3.17 is out uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} - run: | make verify-gator-dockerized POLICY_ENGINE=${{ matrix.engine }} GATOR_VERSION=${{ matrix.gatekeeper }} - if: ${{ !(matrix.gatekeeper == '3.15.1' && matrix.engine == 'cel') }} diff --git a/Makefile b/Makefile index bc7908f22..064e6ec94 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ KUBERNETES_VERSION ?= 1.30.0 KUSTOMIZE_VERSION ?= 4.5.5 GATEKEEPER_VERSION ?= 3.16.3 BATS_VERSION ?= 1.8.2 -GATOR_VERSION ?= 3.16.3 +GATOR_VERSION ?= 3.17.0 GOMPLATE_VERSION ?= 3.11.6 POLICY_ENGINE ?= rego @@ -50,17 +50,17 @@ test-integration: .PHONY: verify-gator verify-gator: ifeq ($(POLICY_ENGINE), rego) - gator verify ./... --experimental-enable-k8s-native-validation=false + gator verify ./... --enable-k8s-native-validation=false else ifeq ($(POLICY_ENGINE), cel) - gator verify ./... --experimental-enable-k8s-native-validation=true + gator verify ./... --enable-k8s-native-validation=true endif .PHONY: verify-gator-dockerized verify-gator-dockerized: __build-gator ifeq ($(POLICY_ENGINE), rego) - $(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./... --experimental-enable-k8s-native-validation=false + $(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./... --enable-k8s-native-validation=false else ifeq ($(POLICY_ENGINE), cel) - $(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./... --experimental-enable-k8s-native-validation=true + $(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./... --enable-k8s-native-validation=true endif .PHONY: build-gator From 8d0ab8d208c5c5be53c0aa1f97b5392d0102886d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:39:55 -0800 Subject: [PATCH 2/3] chore: bump the all group across 1 directory with 3 updates (#617) Bumps the all group with 3 updates in the / directory: [github/codeql-action](https://github.com/github/codeql-action), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/setup-go](https://github.com/actions/setup-go). Updates `github/codeql-action` from 3.27.6 to 3.28.0 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/aa578102511db1f4524ed59b8cc2bae4f6e88195...48ab28a6f5dbc2a99bf1e0131198dd8f1df78169) Updates `actions/upload-artifact` from 4.4.3 to 4.5.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882...6f51ac03b9356f520e9adb1b1b7802705f340c2b) Updates `actions/setup-go` from 5.1.0 to 5.2.0 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed...3041bf56c941b39c61721a86cd11f3bb1338122a) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecards.yml | 4 ++-- .github/workflows/scripts.yaml | 2 +- .github/workflows/workflow.yaml | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b71c31b9c..dcb2abe2e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -50,7 +50,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/init@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -60,7 +60,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/autobuild@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 # ℹī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -73,6 +73,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/analyze@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 316a0a5de..abdd33847 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -63,7 +63,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 with: name: SARIF file path: results.sarif @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 + uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0 with: sarif_file: results.sarif diff --git a/.github/workflows/scripts.yaml b/.github/workflows/scripts.yaml index 7a56c683f..402593708 100644 --- a/.github/workflows/scripts.yaml +++ b/.github/workflows/scripts.yaml @@ -22,7 +22,7 @@ jobs: matrix: folder: [artifacthub, require-sync, validate, website] steps: - - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: go-version: '1.20' cache: false diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index a50fac89e..16986dbd0 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -94,7 +94,7 @@ jobs: kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=-1 > logs-audit.json - name: Upload artifacts - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 if: ${{ always() }} with: name: logs-int-test-${{ matrix.gatekeeper }}-${{ matrix.engine }} From a55ade4e938d75688d235dd1769e208369514189 Mon Sep 17 00:00:00 2001 From: Rita Zhang Date: Mon, 30 Dec 2024 11:00:03 -0800 Subject: [PATCH 3/3] fsgroup cel (#523) * Add cel for fsgroup Signed-off-by: Rita Zhang * add tests and address comments Signed-off-by: Rita Zhang --------- Signed-off-by: Rita Zhang --- .../samples/psp-fsgroup/constraint2.yaml | 13 + .../fsgroup/1.1.0/README.md | 7 + .../fsgroup/1.1.0/artifacthub-pkg.yml | 22 ++ .../fsgroup/1.1.0/kustomization.yaml | 2 + .../1.1.0/samples/psp-fsgroup/constraint.yaml | 14 + .../samples/psp-fsgroup/constraint2.yaml | 13 + .../samples/psp-fsgroup/constraint3.yaml | 12 + .../samples/psp-fsgroup/example_allowed.yaml | 17 + .../psp-fsgroup/example_disallowed.yaml | 17 + .../1.1.0/samples/psp-fsgroup/update.yaml | 22 ++ .../fsgroup/1.1.0/suite.yaml | 53 +++ .../fsgroup/1.1.0/template.yaml | 127 +++++++ .../samples/psp-fsgroup/constraint2.yaml | 13 + .../samples/psp-fsgroup/constraint3.yaml | 12 + .../samples/psp-fsgroup/example_allowed.yaml | 2 +- .../pod-security-policy/fsgroup/suite.yaml | 32 ++ .../pod-security-policy/fsgroup/template.yaml | 134 ++++--- .../fsgroup/constraint.tmpl | 18 +- src/pod-security-policy/fsgroup/src.cel | 17 + src/pod-security-policy/fsgroup/src.rego | 2 +- website/docs/validation/fsgroup.md | 331 ++++++++++++++---- 21 files changed, 756 insertions(+), 124 deletions(-) create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint2.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/README.md create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/artifacthub-pkg.yml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint2.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint3.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_allowed.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_disallowed.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/update.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/suite.yaml create mode 100644 artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml create mode 100644 library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml create mode 100644 library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml create mode 100644 src/pod-security-policy/fsgroup/src.cel diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint2.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint2.yaml new file mode 100644 index 000000000..64739ab94 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.0.2/samples/psp-fsgroup/constraint2.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ranges: + - min: 1 + max: 1000 diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/README.md b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/README.md new file mode 100644 index 000000000..b70d94d45 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/README.md @@ -0,0 +1,7 @@ +# Deprecated + +**This Policy is deprecated** + +Please use the FSGroup settings on the users policy to enforce FSGroup Settings. + +[Users Policy](../users) diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/artifacthub-pkg.yml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/artifacthub-pkg.yml new file mode 100644 index 000000000..a63262243 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/artifacthub-pkg.yml @@ -0,0 +1,22 @@ +version: 1.1.0 +name: k8spspfsgroup +displayName: FS Group +createdAt: "2024-07-08T22:14:40Z" +description: Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +digest: b0c1dada1dd06b897676e480a7a1439cc339cd9d1703dc0dbb4329e0b89ba4bd +license: Apache-2.0 +homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/fsgroup +keywords: + - gatekeeper + - open-policy-agent + - policies +readme: |- + # FS Group + Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +install: |- + ### Usage + ```shell + kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml + ``` +provider: + name: Gatekeeper Library diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml new file mode 100644 index 000000000..7d70d11b7 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - template.yaml diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint.yaml new file mode 100644 index 000000000..4eb14fe3c --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MayRunAs" #"MustRunAs" #"MayRunAs", "RunAsAny" + ranges: + - min: 1 + max: 1000 diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint2.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint2.yaml new file mode 100644 index 000000000..64739ab94 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint2.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ranges: + - min: 1 + max: 1000 diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint3.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint3.yaml new file mode 100644 index 000000000..b0176f832 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/constraint3.yaml @@ -0,0 +1,12 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MustRunAs" #"MayRunAs", "RunAsAny" + ranges: [] # empty ranges should result in violation diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_allowed.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_allowed.yaml new file mode 100644 index 000000000..c5f697269 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_allowed.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-allowed +spec: + securityContext: + fsGroup: 500 # directory will have group ID 500 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: ["sh", "-c", "sleep 1h"] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_disallowed.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_disallowed.yaml new file mode 100644 index 000000000..9caf7c0a3 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/example_disallowed.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-disallowed +spec: + securityContext: + fsGroup: 2000 # directory will have group ID 2000 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: [ "sh", "-c", "sleep 1h" ] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/update.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/update.yaml new file mode 100644 index 000000000..c0de7258a --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/samples/psp-fsgroup/update.yaml @@ -0,0 +1,22 @@ +kind: AdmissionReview +apiVersion: admission.k8s.io/v1beta1 +request: + operation: "UPDATE" + object: + apiVersion: v1 + kind: Pod + metadata: + name: fsgroup-disallowed + spec: + securityContext: + fsGroup: 2000 # directory will have group ID 2000 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: [ "sh", "-c", "sleep 1h" ] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/suite.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/suite.yaml new file mode 100644 index 000000000..9f75c7138 --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/suite.yaml @@ -0,0 +1,53 @@ +kind: Suite +apiVersion: test.gatekeeper.sh/v1alpha1 +metadata: + name: fsgroup +tests: + - name: fsgroup + template: template.yaml + constraint: samples/psp-fsgroup/constraint.yaml + cases: + - name: example-disallowed + object: samples/psp-fsgroup/example_disallowed.yaml + assertions: + - violations: yes + - name: example-allowed + object: samples/psp-fsgroup/example_allowed.yaml + assertions: + - violations: no + - name: update + object: samples/psp-fsgroup/update.yaml + assertions: + - violations: no + - name: fsgroup-no-rules + template: template.yaml + constraint: samples/psp-fsgroup/constraint2.yaml + cases: + - name: example-allowed + object: samples/psp-fsgroup/example_disallowed.yaml + assertions: + - violations: no + - name: example-allowed + object: samples/psp-fsgroup/example_allowed.yaml + assertions: + - violations: no + - name: update + object: samples/psp-fsgroup/update.yaml + assertions: + - violations: no + - name: fsgroup-empty-ranges + template: template.yaml + constraint: samples/psp-fsgroup/constraint3.yaml + cases: + - name: example-disallowed-2000 + object: samples/psp-fsgroup/example_disallowed.yaml + assertions: + - violations: yes + - name: example-disallowed-500 + object: samples/psp-fsgroup/example_allowed.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-fsgroup/update.yaml + assertions: + - violations: no diff --git a/artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml new file mode 100644 index 000000000..48d58644a --- /dev/null +++ b/artifacthub/library/pod-security-policy/fsgroup/1.1.0/template.yaml @@ -0,0 +1,127 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8spspfsgroup + annotations: + metadata.gatekeeper.sh/title: "FS Group" + metadata.gatekeeper.sh/version: 1.1.0 + description: >- + Controls allocating an FSGroup that owns the Pod's volumes. Corresponds + to the `fsGroup` field in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems +spec: + crd: + spec: + names: + kind: K8sPSPFSGroup + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + description: >- + Controls allocating an FSGroup that owns the Pod's volumes. Corresponds + to the `fsGroup` field in a PodSecurityPolicy. For more information, see + https://kubernetes.io/docs/concepts/policy/pod-security-policy/#volumes-and-file-systems + properties: + rule: + description: "An FSGroup rule name." + enum: + - MayRunAs + - MustRunAs + - RunAsAny + type: string + ranges: + type: array + description: "GID ranges affected by the rule." + items: + type: object + properties: + min: + description: "The minimum GID in the range, inclusive." + type: integer + max: + description: "The maximum GID in the range, inclusive." + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + code: + - engine: K8sNativeValidation + source: + variables: + - name: isUpdate + expression: has(request.operation) && request.operation == "UPDATE" + - name: fsGroup + expression: '!has(variables.anyObject.spec.securityContext) ? "" : !has(variables.anyObject.spec.securityContext.fsGroup) ? "" : variables.anyObject.spec.securityContext.fsGroup' + - name: ruleString + expression: | + !has(variables.params.rule) ? "unspecified" : string(variables.params.rule) + - name: rangesString + expression: | + !has(variables.params.ranges) ? "unspecified" : size(variables.params.ranges) == 0 ? "empty" : variables.params.ranges.map(r, string(r)).join(", ") + - name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.exists(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false + validations: + - expression: 'variables.isUpdate || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed fsGroup rule: " + variables.ruleString + ", allowed fsGroup ranges: " + variables.rangesString' + - engine: Rego + source: + rego: | + package k8spspfsgroup + + import data.lib.exclude_update.is_update + + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.fsGroup field is immutable. + not is_update(input.review) + has_field(input.parameters, "rule") + spec := input.review.object.spec + not input_fsGroup_allowed(spec) + msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) + } + + input_fsGroup_allowed(_) { + # RunAsAny - No range is required. Allows any fsGroup ID to be specified. + input.parameters.rule == "RunAsAny" + } + input_fsGroup_allowed(spec) { + # MustRunAs - Validates pod spec fsgroup against all ranges + input.parameters.rule == "MustRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not has_field(spec, "securityContext") + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not spec.securityContext.fsGroup + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + value_within_range(range, value) { + range.min <= value + range.max >= value + } + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } diff --git a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml new file mode 100644 index 000000000..64739ab94 --- /dev/null +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ranges: + - min: 1 + max: 1000 diff --git a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml new file mode 100644 index 000000000..b0176f832 --- /dev/null +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml @@ -0,0 +1,12 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MustRunAs" #"MayRunAs", "RunAsAny" + ranges: [] # empty ranges should result in violation diff --git a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml index 17d3274c3..c5f697269 100644 --- a/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml +++ b/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: Pod metadata: - name: fsgroup-disallowed + name: fsgroup-allowed spec: securityContext: fsGroup: 500 # directory will have group ID 500 diff --git a/library/pod-security-policy/fsgroup/suite.yaml b/library/pod-security-policy/fsgroup/suite.yaml index cb102e785..9f75c7138 100644 --- a/library/pod-security-policy/fsgroup/suite.yaml +++ b/library/pod-security-policy/fsgroup/suite.yaml @@ -19,3 +19,35 @@ tests: object: samples/psp-fsgroup/update.yaml assertions: - violations: no + - name: fsgroup-no-rules + template: template.yaml + constraint: samples/psp-fsgroup/constraint2.yaml + cases: + - name: example-allowed + object: samples/psp-fsgroup/example_disallowed.yaml + assertions: + - violations: no + - name: example-allowed + object: samples/psp-fsgroup/example_allowed.yaml + assertions: + - violations: no + - name: update + object: samples/psp-fsgroup/update.yaml + assertions: + - violations: no + - name: fsgroup-empty-ranges + template: template.yaml + constraint: samples/psp-fsgroup/constraint3.yaml + cases: + - name: example-disallowed-2000 + object: samples/psp-fsgroup/example_disallowed.yaml + assertions: + - violations: yes + - name: example-disallowed-500 + object: samples/psp-fsgroup/example_allowed.yaml + assertions: + - violations: yes + - name: update + object: samples/psp-fsgroup/update.yaml + assertions: + - violations: no diff --git a/library/pod-security-policy/fsgroup/template.yaml b/library/pod-security-policy/fsgroup/template.yaml index 4e1b9449a..48d58644a 100644 --- a/library/pod-security-policy/fsgroup/template.yaml +++ b/library/pod-security-policy/fsgroup/template.yaml @@ -4,7 +4,7 @@ metadata: name: k8spspfsgroup annotations: metadata.gatekeeper.sh/title: "FS Group" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -44,62 +44,84 @@ spec: type: integer targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspfsgroup + code: + - engine: K8sNativeValidation + source: + variables: + - name: isUpdate + expression: has(request.operation) && request.operation == "UPDATE" + - name: fsGroup + expression: '!has(variables.anyObject.spec.securityContext) ? "" : !has(variables.anyObject.spec.securityContext.fsGroup) ? "" : variables.anyObject.spec.securityContext.fsGroup' + - name: ruleString + expression: | + !has(variables.params.rule) ? "unspecified" : string(variables.params.rule) + - name: rangesString + expression: | + !has(variables.params.ranges) ? "unspecified" : size(variables.params.ranges) == 0 ? "empty" : variables.params.ranges.map(r, string(r)).join(", ") + - name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.exists(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false + validations: + - expression: 'variables.isUpdate || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed fsGroup rule: " + variables.ruleString + ", allowed fsGroup ranges: " + variables.rangesString' + - engine: Rego + source: + rego: | + package k8spspfsgroup - import data.lib.exclude_update.is_update + import data.lib.exclude_update.is_update - violation[{"msg": msg, "details": {}}] { - # spec.securityContext.fsGroup field is immutable. - not is_update(input.review) + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.fsGroup field is immutable. + not is_update(input.review) + has_field(input.parameters, "rule") + spec := input.review.object.spec + not input_fsGroup_allowed(spec) + msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) + } - spec := input.review.object.spec - not input_fsGroup_allowed(spec) - msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) - } + input_fsGroup_allowed(_) { + # RunAsAny - No range is required. Allows any fsGroup ID to be specified. + input.parameters.rule == "RunAsAny" + } + input_fsGroup_allowed(spec) { + # MustRunAs - Validates pod spec fsgroup against all ranges + input.parameters.rule == "MustRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not has_field(spec, "securityContext") + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not spec.securityContext.fsGroup + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + value_within_range(range, value) { + range.min <= value + range.max >= value + } + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + libs: + - | + package lib.exclude_update - input_fsGroup_allowed(_) { - # RunAsAny - No range is required. Allows any fsGroup ID to be specified. - input.parameters.rule == "RunAsAny" - } - input_fsGroup_allowed(spec) { - # MustRunAs - Validates pod spec fsgroup against all ranges - input.parameters.rule == "MustRunAs" - fg := spec.securityContext.fsGroup - count(input.parameters.ranges) > 0 - range := input.parameters.ranges[_] - value_within_range(range, fg) - } - input_fsGroup_allowed(spec) { - # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset - input.parameters.rule == "MayRunAs" - not has_field(spec, "securityContext") - } - input_fsGroup_allowed(spec) { - # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset - input.parameters.rule == "MayRunAs" - not spec.securityContext.fsGroup - } - input_fsGroup_allowed(spec) { - # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset - input.parameters.rule == "MayRunAs" - fg := spec.securityContext.fsGroup - count(input.parameters.ranges) > 0 - range := input.parameters.ranges[_] - value_within_range(range, fg) - } - value_within_range(range, value) { - range.min <= value - range.max >= value - } - # has_field returns whether an object has a field - has_field(object, field) = true { - object[field] - } - libs: - - | - package lib.exclude_update - - is_update(review) { - review.operation == "UPDATE" - } + is_update(review) { + review.operation == "UPDATE" + } diff --git a/src/pod-security-policy/fsgroup/constraint.tmpl b/src/pod-security-policy/fsgroup/constraint.tmpl index 01e9f415d..783cb8efc 100644 --- a/src/pod-security-policy/fsgroup/constraint.tmpl +++ b/src/pod-security-policy/fsgroup/constraint.tmpl @@ -4,7 +4,7 @@ metadata: name: k8spspfsgroup annotations: metadata.gatekeeper.sh/title: "FS Group" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -44,8 +44,14 @@ spec: type: integer targets: - target: admission.k8s.gatekeeper.sh - rego: | -{{ file.Read "src/pod-security-policy/fsgroup/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }} - libs: - - | -{{ file.Read "src/pod-security-policy/fsgroup/lib_exclude_update.rego" | strings.Indent 10 | strings.TrimSuffix "\n" }} + code: + - engine: K8sNativeValidation + source: +{{ file.Read "src/pod-security-policy/fsgroup/src.cel" | strings.Indent 10 | strings.TrimSuffix "\n" }} + - engine: Rego + source: + rego: | +{{ file.Read "src/pod-security-policy/fsgroup/src.rego" | strings.Indent 12 | strings.TrimSuffix "\n" }} + libs: + - | +{{ file.Read "src/pod-security-policy/fsgroup/lib_exclude_update.rego" | strings.Indent 14 | strings.TrimSuffix "\n" }} diff --git a/src/pod-security-policy/fsgroup/src.cel b/src/pod-security-policy/fsgroup/src.cel new file mode 100644 index 000000000..e2ed2e620 --- /dev/null +++ b/src/pod-security-policy/fsgroup/src.cel @@ -0,0 +1,17 @@ +variables: +- name: isUpdate + expression: has(request.operation) && request.operation == "UPDATE" +- name: fsGroup + expression: '!has(variables.anyObject.spec.securityContext) ? "" : !has(variables.anyObject.spec.securityContext.fsGroup) ? "" : variables.anyObject.spec.securityContext.fsGroup' +- name: ruleString + expression: | + !has(variables.params.rule) ? "unspecified" : string(variables.params.rule) +- name: rangesString + expression: | + !has(variables.params.ranges) ? "unspecified" : size(variables.params.ranges) == 0 ? "empty" : variables.params.ranges.map(r, string(r)).join(", ") +- name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.exists(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false +validations: +- expression: 'variables.isUpdate || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed fsGroup rule: " + variables.ruleString + ", allowed fsGroup ranges: " + variables.rangesString' diff --git a/src/pod-security-policy/fsgroup/src.rego b/src/pod-security-policy/fsgroup/src.rego index 2eb95cab7..fcb19f10a 100644 --- a/src/pod-security-policy/fsgroup/src.rego +++ b/src/pod-security-policy/fsgroup/src.rego @@ -5,7 +5,7 @@ import data.lib.exclude_update.is_update violation[{"msg": msg, "details": {}}] { # spec.securityContext.fsGroup field is immutable. not is_update(input.review) - + has_field(input.parameters, "rule") spec := input.review.object.spec not input_fsGroup_allowed(spec) msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) diff --git a/website/docs/validation/fsgroup.md b/website/docs/validation/fsgroup.md index 35e1b035e..bad66fb81 100644 --- a/website/docs/validation/fsgroup.md +++ b/website/docs/validation/fsgroup.md @@ -16,7 +16,7 @@ metadata: name: k8spspfsgroup annotations: metadata.gatekeeper.sh/title: "FS Group" - metadata.gatekeeper.sh/version: 1.0.2 + metadata.gatekeeper.sh/version: 1.1.0 description: >- Controls allocating an FSGroup that owns the Pod's volumes. Corresponds to the `fsGroup` field in a PodSecurityPolicy. For more information, see @@ -56,65 +56,87 @@ spec: type: integer targets: - target: admission.k8s.gatekeeper.sh - rego: | - package k8spspfsgroup - - import data.lib.exclude_update.is_update - - violation[{"msg": msg, "details": {}}] { - # spec.securityContext.fsGroup field is immutable. - not is_update(input.review) - - spec := input.review.object.spec - not input_fsGroup_allowed(spec) - msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) - } - - input_fsGroup_allowed(_) { - # RunAsAny - No range is required. Allows any fsGroup ID to be specified. - input.parameters.rule == "RunAsAny" - } - input_fsGroup_allowed(spec) { - # MustRunAs - Validates pod spec fsgroup against all ranges - input.parameters.rule == "MustRunAs" - fg := spec.securityContext.fsGroup - count(input.parameters.ranges) > 0 - range := input.parameters.ranges[_] - value_within_range(range, fg) - } - input_fsGroup_allowed(spec) { - # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset - input.parameters.rule == "MayRunAs" - not has_field(spec, "securityContext") - } - input_fsGroup_allowed(spec) { - # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset - input.parameters.rule == "MayRunAs" - not spec.securityContext.fsGroup - } - input_fsGroup_allowed(spec) { - # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset - input.parameters.rule == "MayRunAs" - fg := spec.securityContext.fsGroup - count(input.parameters.ranges) > 0 - range := input.parameters.ranges[_] - value_within_range(range, fg) - } - value_within_range(range, value) { - range.min <= value - range.max >= value - } - # has_field returns whether an object has a field - has_field(object, field) = true { - object[field] - } - libs: - - | - package lib.exclude_update - - is_update(review) { - review.operation == "UPDATE" - } + code: + - engine: K8sNativeValidation + source: + variables: + - name: isUpdate + expression: has(request.operation) && request.operation == "UPDATE" + - name: fsGroup + expression: '!has(variables.anyObject.spec.securityContext) ? "" : !has(variables.anyObject.spec.securityContext.fsGroup) ? "" : variables.anyObject.spec.securityContext.fsGroup' + - name: ruleString + expression: | + !has(variables.params.rule) ? "unspecified" : string(variables.params.rule) + - name: rangesString + expression: | + !has(variables.params.ranges) ? "unspecified" : size(variables.params.ranges) == 0 ? "empty" : variables.params.ranges.map(r, string(r)).join(", ") + - name: input_fsGroup_allowed + expression: | + !has(variables.params.rule) ? true : variables.params.rule == "RunAsAny" ? true : variables.params.rule == "MayRunAs" && variables.fsGroup == "" ? true : (variables.params.rule == "MayRunAs" || variables.params.rule == "MustRunAs") && has(variables.params.ranges) && size(variables.params.ranges) > 0 ? variables.params.ranges.exists(range, range.min <= variables.fsGroup && range.max >= variables.fsGroup) : false + validations: + - expression: 'variables.isUpdate || variables.input_fsGroup_allowed' + messageExpression: '"The provided pod spec fsGroup is not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed fsGroup rule: " + variables.ruleString + ", allowed fsGroup ranges: " + variables.rangesString' + - engine: Rego + source: + rego: | + package k8spspfsgroup + + import data.lib.exclude_update.is_update + + violation[{"msg": msg, "details": {}}] { + # spec.securityContext.fsGroup field is immutable. + not is_update(input.review) + has_field(input.parameters, "rule") + spec := input.review.object.spec + not input_fsGroup_allowed(spec) + msg := sprintf("The provided pod spec fsGroup is not allowed, pod: %v. Allowed fsGroup: %v", [input.review.object.metadata.name, input.parameters]) + } + + input_fsGroup_allowed(_) { + # RunAsAny - No range is required. Allows any fsGroup ID to be specified. + input.parameters.rule == "RunAsAny" + } + input_fsGroup_allowed(spec) { + # MustRunAs - Validates pod spec fsgroup against all ranges + input.parameters.rule == "MustRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not has_field(spec, "securityContext") + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + not spec.securityContext.fsGroup + } + input_fsGroup_allowed(spec) { + # MayRunAs - Validates pod spec fsgroup against all ranges or allow pod spec fsgroup to be left unset + input.parameters.rule == "MayRunAs" + fg := spec.securityContext.fsGroup + count(input.parameters.ranges) > 0 + range := input.parameters.ranges[_] + value_within_range(range, fg) + } + value_within_range(range, value) { + range.min <= value + range.max >= value + } + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + libs: + - | + package lib.exclude_update + + is_update(review) { + review.operation == "UPDATE" + } ``` @@ -189,11 +211,200 @@ kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-
example-allowed +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-allowed +spec: + securityContext: + fsGroup: 500 # directory will have group ID 500 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: ["sh", "-c", "sleep 1h"] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml +``` + +
+ + +
+fsgroup-no-rules + +
+constraint + +```yaml +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + ranges: + - min: 1 + max: 1000 + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint2.yaml +``` + +
+ +
+example-allowed + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-disallowed +spec: + securityContext: + fsGroup: 2000 # directory will have group ID 2000 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: [ "sh", "-c", "sleep 1h" ] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_disallowed.yaml +``` + +
+
+example-allowed + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-allowed +spec: + securityContext: + fsGroup: 500 # directory will have group ID 500 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: ["sh", "-c", "sleep 1h"] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_allowed.yaml +``` + +
+ + +
+fsgroup-empty-ranges + +
+constraint + +```yaml +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPFSGroup +metadata: + name: psp-fsgroup +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Pod"] + parameters: + rule: "MustRunAs" #"MayRunAs", "RunAsAny" + ranges: [] # empty ranges should result in violation + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/fsgroup/samples/psp-fsgroup/constraint3.yaml +``` + +
+ +
+example-disallowed-2000 + ```yaml apiVersion: v1 kind: Pod metadata: name: fsgroup-disallowed +spec: + securityContext: + fsGroup: 2000 # directory will have group ID 2000 + volumes: + - name: fsgroup-demo-vol + emptyDir: {} + containers: + - name: fsgroup-demo + image: busybox + command: [ "sh", "-c", "sleep 1h" ] + volumeMounts: + - name: fsgroup-demo-vol + mountPath: /data/demo + +``` + +Usage + +```shell +kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/pod-security-policy/fsgroup/samples/psp-fsgroup/example_disallowed.yaml +``` + +
+
+example-disallowed-500 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: fsgroup-allowed spec: securityContext: fsGroup: 500 # directory will have group ID 500