├── .assets ├── kyverno-envoy-proxy-logo.pptx ├── logo-1.png ├── logo-2.png ├── logo-3.png ├── logo-4.png ├── logo-5.png └── logo-6.jpg ├── .chainsaw.yaml ├── .crds └── envoy.kyverno.io_authorizationpolicies.yaml ├── .docs └── RELEASE.md ├── .github ├── ISSUE_TEMPLATE │ ├── bug.yaml │ ├── config.yml │ ├── feature-request.yaml │ └── general-question.yaml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── check-actions.yaml │ ├── codegen.yaml │ ├── codeql.yaml │ ├── docs-main.yaml │ ├── docs-release.yaml │ ├── helm-release.yaml │ ├── ko-publish.yaml │ ├── lint.yaml │ ├── release.yaml │ ├── semantics-pr.yaml │ └── tests.yaml ├── .gitignore ├── .goreleaser.yaml ├── .hack └── boilerplate.go.txt ├── .manifests ├── cert-manager │ └── cluster-issuer.yaml └── policies │ └── demo-policy.example.com.yaml ├── .schemas └── json │ └── authorizationpolicy-envoy-v1alpha1.json ├── .vscode └── launch.json ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Makefile ├── README.md ├── ROADMAP.md ├── adopters.md ├── apis └── v1alpha1 │ ├── doc.go │ ├── types.go │ ├── types_test.go │ ├── zz_generated.deepcopy.go │ └── zz_generated.register.go ├── charts ├── kyverno-authz-server │ ├── .helmignore │ ├── Chart.lock │ ├── Chart.yaml │ ├── README.md │ ├── README.md.gotmpl │ ├── templates │ │ ├── NOTES.txt │ │ ├── _helpers.tpl │ │ ├── cluster-role-binding.yaml │ │ ├── cluster-role.yaml │ │ ├── crds.yaml │ │ ├── deployment.yaml │ │ ├── service-account.yaml │ │ ├── service.yaml │ │ └── validation-webhook │ │ │ ├── _helpers.tpl │ │ │ ├── certificates │ │ │ ├── cert-manager │ │ │ │ └── certificate.yaml │ │ │ └── static │ │ │ │ └── secret.yaml │ │ │ ├── deployment.yaml │ │ │ ├── service-account.yaml │ │ │ ├── service.yaml │ │ │ └── validating-webhook-configuration.yaml │ └── values.yaml ├── kyverno-lib │ ├── .helmignore │ ├── Chart.yaml │ └── templates │ │ ├── _chart.tpl │ │ ├── _labels.tpl │ │ └── _names.tpl └── kyverno-sidecar-injector │ ├── .helmignore │ ├── Chart.lock │ ├── Chart.yaml │ ├── README.md │ ├── README.md.gotmpl │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── certificates │ │ ├── cert-manager │ │ │ └── certificate.yaml │ │ └── static │ │ │ └── secret.yaml │ ├── crds.yaml │ ├── deployment.yaml │ ├── service-account.yaml │ ├── service.yaml │ └── webhook.yaml │ └── values.yaml ├── codecov.yml ├── docs ├── DocsArchitecture.md ├── demo │ ├── istio-mtls │ │ ├── README.md │ │ ├── arch-istio-mtls.png │ │ ├── bootstrap.sh │ │ └── manifests │ │ │ ├── authorizationpolicy.yaml │ │ │ ├── ext-auth-server.yaml │ │ │ ├── namespace.yaml │ │ │ ├── peerAuthentication.yaml │ │ │ ├── policy-config.yaml │ │ │ ├── test-application-1.yaml │ │ │ ├── test-application-2.yaml │ │ │ ├── test-client.yaml │ │ │ └── test-peerauth.yaml │ ├── istio │ │ └── architecture-istio.png │ └── standalone-envoy │ │ ├── README.md │ │ ├── bootstarp.sh │ │ ├── envoy_iptables │ │ ├── Dockerfile │ │ ├── README.md │ │ └── proxy_init.sh │ │ └── manifests │ │ ├── application.yaml │ │ ├── envoy-config.yaml │ │ ├── envoy.yaml │ │ ├── policy-config.yaml │ │ └── service.yaml └── sidecar-injector │ └── README.md ├── go.mod ├── go.sum ├── main.go ├── pkg ├── authz │ ├── cel │ │ ├── env.go │ │ ├── libs │ │ │ ├── envoy │ │ │ │ ├── impl.go │ │ │ │ ├── lib.go │ │ │ │ ├── lib_test.go │ │ │ │ └── response.go │ │ │ ├── jwk │ │ │ │ ├── impl.go │ │ │ │ ├── lib.go │ │ │ │ ├── lib_test.go │ │ │ │ └── types.go │ │ │ └── jwt │ │ │ │ ├── impl.go │ │ │ │ ├── lib.go │ │ │ │ ├── lib_test.go │ │ │ │ └── token.go │ │ ├── utils │ │ │ └── convert.go │ │ └── variables.go │ ├── server.go │ └── service.go ├── commands │ ├── root │ │ └── command.go │ └── serve │ │ ├── authz-server │ │ └── command.go │ │ ├── command.go │ │ ├── sidecar-injector │ │ └── command.go │ │ └── validation-webhook │ │ └── command.go ├── policy │ ├── compiler.go │ ├── compiler_test.go │ └── provider.go ├── probes │ ├── server.go │ └── true.go ├── server │ ├── grpc.go │ ├── handlers │ │ ├── admission.go │ │ ├── error.go │ │ ├── healthy.go │ │ └── ready.go │ ├── http.go │ ├── server.go │ └── server_test.go ├── sidecar │ ├── sidecar.go │ └── sidecar_test.go ├── signals │ ├── context.go │ └── context_test.go └── webhook │ ├── mutation │ └── sidecar-injector.go │ └── validation │ └── validator.go ├── requirements.txt ├── tests ├── e2e │ ├── authz-server │ │ ├── allow │ │ │ ├── chainsaw-test.yaml │ │ │ ├── istio-policy.yaml │ │ │ ├── policy.yaml │ │ │ └── shell.yaml │ │ ├── default │ │ │ ├── chainsaw-test.yaml │ │ │ ├── istio-policy.yaml │ │ │ ├── policy.yaml │ │ │ └── shell.yaml │ │ ├── deny │ │ │ ├── chainsaw-test.yaml │ │ │ ├── istio-policy.yaml │ │ │ ├── policy.yaml │ │ │ └── shell.yaml │ │ ├── match-conditions │ │ │ ├── failure-policy-fail │ │ │ │ ├── error-with-false │ │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ │ ├── istio-policy.yaml │ │ │ │ │ ├── policy.yaml │ │ │ │ │ └── shell.yaml │ │ │ │ └── error-with-true │ │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ │ ├── istio-policy.yaml │ │ │ │ │ ├── policy.yaml │ │ │ │ │ └── shell.yaml │ │ │ └── failure-policy-ignore │ │ │ │ ├── error-with-false │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ ├── istio-policy.yaml │ │ │ │ ├── policy.yaml │ │ │ │ └── shell.yaml │ │ │ │ └── error-with-true │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ ├── istio-policy.yaml │ │ │ │ ├── policy.yaml │ │ │ │ └── shell.yaml │ │ └── policy-ordering │ │ │ ├── chainsaw-test.yaml │ │ │ ├── istio-policy.yaml │ │ │ ├── policy-a.yaml │ │ │ ├── policy-b.yaml │ │ │ └── shell.yaml │ ├── sidecar-injector │ │ ├── injected │ │ │ ├── chainsaw-test.yaml │ │ │ ├── pod-assert.yaml │ │ │ └── pod.yaml │ │ └── not-injected │ │ │ ├── chainsaw-test.yaml │ │ │ ├── pod-assert.yaml │ │ │ └── pod.yaml │ └── validation-webhook │ │ ├── allow │ │ ├── match │ │ │ ├── compilation-failure │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ └── policy.yaml │ │ │ ├── invalid-output-type │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ └── policy.yaml │ │ │ └── valid │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ └── policy.yaml │ │ └── response │ │ │ ├── compilation-failure │ │ │ ├── chainsaw-test.yaml │ │ │ └── policy.yaml │ │ │ ├── invalid-output-type │ │ │ ├── chainsaw-test.yaml │ │ │ └── policy.yaml │ │ │ └── valid │ │ │ ├── chainsaw-test.yaml │ │ │ └── policy.yaml │ │ ├── deny │ │ ├── match │ │ │ ├── compilation-failure │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ └── policy.yaml │ │ │ ├── invalid-output-type │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ └── policy.yaml │ │ │ └── valid │ │ │ │ ├── chainsaw-test.yaml │ │ │ │ └── policy.yaml │ │ └── response │ │ │ ├── compilation-failure │ │ │ ├── chainsaw-test.yaml │ │ │ └── policy.yaml │ │ │ ├── invalid-output-type │ │ │ ├── chainsaw-test.yaml │ │ │ └── policy.yaml │ │ │ └── valid │ │ │ ├── chainsaw-test.yaml │ │ │ └── policy.yaml │ │ └── match-conditions │ │ ├── compilation-failure │ │ ├── chainsaw-test.yaml │ │ └── policy.yaml │ │ ├── invalid-output-type │ │ ├── chainsaw-test.yaml │ │ └── policy.yaml │ │ ├── no-variables │ │ ├── chainsaw-test.yaml │ │ └── policy.yaml │ │ └── valid │ │ ├── chainsaw-test.yaml │ │ └── policy.yaml └── performance-test │ ├── README.md │ ├── k6-script.js │ └── manifest │ ├── app-envoy-plugin.yaml │ ├── app-envoy.yaml │ └── app.yaml └── website ├── apis ├── config.yaml └── markdown │ ├── members.tpl │ ├── pkg.tpl │ └── type.tpl ├── docs ├── cel-extensions │ ├── envoy.md │ ├── index.md │ └── jwt.md ├── community │ ├── contribute.md │ ├── index.md │ ├── making-a-pull-request.md │ ├── reporting-a-bug.md │ ├── reporting-a-docs-issue.md │ └── requesting-a-change.md ├── index.md ├── install │ └── certificates.md ├── overrides │ ├── home.html │ └── main.html ├── performance │ └── index.md ├── policies │ ├── authorization-rules.md │ ├── failure-policy.md │ ├── index.md │ ├── match-conditions.md │ └── variables.md ├── quick-start │ ├── authz-server.md │ ├── index.md │ ├── next-steps.md │ └── sidecar-injector.md ├── reference │ ├── apis │ │ └── policy.v1alpha1.md │ ├── index.md │ └── json-schemas.md ├── schemas │ ├── dynamic-metadata.png │ ├── filters-chain.png │ ├── overview.png │ └── overview.svg ├── static │ ├── extra.css │ ├── favicon.ico │ ├── logo.png │ └── repo-card.js └── tutorials │ ├── envoy-gateway │ └── index.md │ ├── index.md │ └── istio │ └── index.md ├── mkdocs.base.yaml └── mkdocs.yaml /.assets/kyverno-envoy-proxy-logo.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/kyverno-envoy-proxy-logo.pptx -------------------------------------------------------------------------------- /.assets/logo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/logo-1.png -------------------------------------------------------------------------------- /.assets/logo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/logo-2.png -------------------------------------------------------------------------------- /.assets/logo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/logo-3.png -------------------------------------------------------------------------------- /.assets/logo-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/logo-4.png -------------------------------------------------------------------------------- /.assets/logo-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/logo-5.png -------------------------------------------------------------------------------- /.assets/logo-6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/.assets/logo-6.jpg -------------------------------------------------------------------------------- /.chainsaw.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/chainsaw/main/.schemas/json/configuration-chainsaw-v1alpha2.json 2 | apiVersion: chainsaw.kyverno.io/v1alpha2 3 | kind: Configuration 4 | metadata: 5 | name: configuration 6 | spec: 7 | cleanup: 8 | delayBeforeCleanup: 3s 9 | discovery: 10 | fullName: true 11 | execution: 12 | failFast: true 13 | forceTerminationGracePeriod: 5s 14 | parallel: 1 15 | -------------------------------------------------------------------------------- /.docs/RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release docs 2 | 3 | This doc contains information for releasing a new version. 4 | 5 | ## Create a release 6 | 7 | Creating a release can be done by pushing a tag to the GitHub repository (beginning with `v`). 8 | 9 | The [release workflow](../../.github/workflows/release.yaml) will take care of creating the GitHub release and will publish artifacts. 10 | 11 | ```shell 12 | VERSION="v0.0.1" 13 | TAG=$VERSION 14 | 15 | git tag $TAG -m "tag $TAG" -a 16 | git push origin $TAG 17 | ``` 18 | 19 | ## Publish chart 20 | 21 | Publishing the chart for a release is decoupled from cutting a release. 22 | 23 | To publish the chart push a tag to the GitHub repository (beginning with `charts-v`). 24 | 25 | ```shell 26 | VERSION="v0.0.1" 27 | TAG=charts-$VERSION 28 | 29 | git tag $TAG -m "tag $TAG" -a 30 | git push origin $TAG 31 | ``` 32 | 33 | ## Publish documentation 34 | 35 | Publishing the documentation for a release is decoupled from cutting a release. 36 | 37 | To publish the documentation push a tag to the GitHub repository (beginning with `docs-v`). 38 | 39 | ```shell 40 | VERSION="v0.0.1" 41 | TAG=docs-$VERSION 42 | 43 | git tag $TAG -m "tag $TAG" -a 44 | git push origin $TAG 45 | ``` 46 | 47 | ## Misc 48 | 49 | - Add to the drop-down list in the bug template 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-issue-forms.json 2 | 3 | name: Bug Report 4 | description: Report a bug 5 | title: '[Bug] ' 6 | labels: 7 | - bug 8 | - triage 9 | body: 10 | - type: markdown 11 | attributes: 12 | value: Please tell us about the bug. 13 | - type: dropdown 14 | id: version 15 | attributes: 16 | label: Version 17 | description: What version are you running? 18 | options: 19 | - v0.2.0 20 | - v0.1.0 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: bug-description 25 | attributes: 26 | label: Description 27 | description: Describe what happened. 28 | validations: 29 | required: true 30 | - type: textarea 31 | id: bug-reproduce-steps 32 | attributes: 33 | label: Steps to reproduce 34 | description: What are the exact steps needed to reproduce the bug you experienced? 35 | value: |- 36 | 1. 37 | validations: 38 | required: true 39 | - type: textarea 40 | id: bug-expectations 41 | attributes: 42 | label: Expected behavior 43 | description: What did you expect to happen? 44 | validations: 45 | required: true 46 | - type: textarea 47 | id: bug-screenshots 48 | attributes: 49 | label: Screenshots 50 | description: >- 51 | If you have any screenshots that would help, please paste them below. 52 | GitHub allows you to copy-and-paste directly from the clipboard into the text area. 53 | **Please avoid taking screenshots of either log or terminal output**; paste any textual output in the logs section below. 54 | validations: 55 | required: false 56 | - type: textarea 57 | id: logs 58 | attributes: 59 | label: Logs 60 | description: Please copy and paste any relevant log output. 61 | render: Shell 62 | - type: checkboxes 63 | id: troubleshooting 64 | attributes: 65 | label: Troubleshooting 66 | description: By submitting this issue, you agree that you have performed some basic attempts at researching and solving your problem. 67 | options: 68 | - label: I have searched other issues in this repository and mine is not recorded. 69 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-issue-config.json 2 | 3 | blank_issues_enabled: true 4 | 5 | contact_links: 6 | - name: Discussions 7 | url: https://github.com/kyverno/kyverno-envoy-plugin/discussions 8 | about: Please ask and answer questions here. 9 | - name: Documentation 10 | url: https://kyverno.github.io/kyverno-envoy-plugin 11 | about: Browse documentation here. 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-issue-forms.json 2 | 3 | name: Feature Request 4 | description: Suggest a new feature 5 | title: '[Feature] ' 6 | labels: 7 | - enhancement 8 | - triage 9 | body: 10 | - type: markdown 11 | attributes: 12 | value: Please explain the new feature. 13 | - type: textarea 14 | id: problem 15 | attributes: 16 | label: Problem Statement 17 | description: Describe the problem. 18 | placeholder: A clear and concise description of the problem statement. 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: solution 23 | attributes: 24 | label: Solution Description 25 | description: Describe the solution you'd like. 26 | placeholder: A clear and concise description of what you want to happen. 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: alternatives 31 | attributes: 32 | label: Alternatives 33 | description: Describe alternatives you've considered. 34 | placeholder: A clear and concise description of any alternative solutions or features you've considered. 35 | validations: 36 | required: false 37 | - type: textarea 38 | id: context 39 | attributes: 40 | label: Additional Context 41 | description: Any additional context to this enhancement request. 42 | placeholder: Add any other context or screenshots about the feature request here. 43 | validations: 44 | required: false 45 | - type: checkboxes 46 | id: research 47 | attributes: 48 | label: Research 49 | description: By submitting this issue, you agree that you have performed some basic attempts at researching your problem and solution. 50 | options: 51 | - label: I have searched other issues in this repository and mine is not recorded. 52 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general-question.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-issue-forms.json 2 | 3 | name: General Question 4 | description: Ask a question or need support 5 | title: '[Question] ' 6 | labels: 7 | - question 8 | body: 9 | - type: markdown 10 | attributes: 11 | value: Please answer these questions before submitting your issue. Thanks! 12 | - type: textarea 13 | id: describe-your-question 14 | attributes: 15 | label: Describe your question 16 | description: Provide details about your question or the support needed. 17 | placeholder: Type your question here... 18 | validations: 19 | required: true 20 | - type: dropdown 21 | id: version 22 | attributes: 23 | label: Version 24 | description: What version are you running? 25 | options: 26 | - v0.2.0 27 | - v0.1.0 28 | validations: 29 | required: true 30 | - type: textarea 31 | id: additional-context 32 | attributes: 33 | label: Additional context 34 | description: Add any other context or screenshots about the question here. 35 | placeholder: Additional details... 36 | validations: 37 | required: false 38 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Explanation 2 | 3 | 8 | 9 | ## Related issue 10 | 11 | 18 | 19 | ## Proposed Changes 20 | 21 | 26 | 27 | ## Checklist 28 | 29 | 33 | 34 | - [ ] I have read the [contributing guidelines](https://github.com/kyverno/kyverno/blob/main/CONTRIBUTING.md). 35 | - [ ] I have read the [PR documentation guide](https://github.com/kyverno/kyverno/blob/main/.github/pr_documentation.md) and followed the process including adding proof manifests to this PR. 36 | - [ ] This is a bug fix and I have added unit tests that prove my fix is effective. 37 | 38 | ## Further Comments 39 | 40 | 44 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: gomod 4 | directory: / 5 | schedule: 6 | interval: daily 7 | labels: 8 | - bot 9 | - package-ecosystem: github-actions 10 | directory: / 11 | schedule: 12 | interval: daily 13 | labels: 14 | - bot 15 | -------------------------------------------------------------------------------- /.github/workflows/check-actions.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: Check actions 4 | 5 | permissions: {} 6 | 7 | on: 8 | pull_request: 9 | branches: 10 | - main 11 | push: 12 | branches: 13 | - main 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | check-actions: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | - name: Ensure SHA pinned actions 26 | uses: zgosalvez/github-actions-ensure-sha-pinned-actions@fc87bb5b5a97953d987372e74478de634726b3e5 # v3.0.25 27 | with: 28 | # slsa-github-generator requires using a semver tag for reusable workflows. 29 | # See: https://github.com/slsa-framework/slsa-github-generator#referencing-slsa-builders-and-generators 30 | allowlist: | 31 | slsa-framework/slsa-github-generator 32 | -------------------------------------------------------------------------------- /.github/workflows/codegen.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: Verify codegen 4 | 5 | permissions: {} 6 | 7 | on: 8 | pull_request: 9 | branches: 10 | - 'main' 11 | - 'release*' 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | verify-codegen: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 24 | with: 25 | go-version-file: go.mod 26 | cache-dependency-path: go.sum 27 | - name: Verify codegen 28 | run: | 29 | set -e 30 | make verify-codegen 31 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: CodeQL 4 | 5 | permissions: {} 6 | 7 | on: 8 | pull_request: 9 | branches: 10 | - main 11 | push: 12 | branches: 13 | - main 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | scan-trivy: 21 | runs-on: ubuntu-latest 22 | permissions: 23 | security-events: write 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | with: 28 | fetch-depth: 0 29 | - name: Run trivy vulnerability scanner in repo mode 30 | uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0.31.0 31 | with: 32 | scan-type: fs 33 | ignore-unfixed: false 34 | format: sarif 35 | output: trivy-results.sarif 36 | severity: CRITICAL,HIGH,MEDIUM 37 | scanners: vuln,secret 38 | exit-code: "0" 39 | vuln-type: os,library 40 | env: 41 | TRIVY_DB_REPOSITORY: "public.ecr.aws/aquasecurity/trivy-db:2" 42 | - name: Upload trivy scan results 43 | uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19 44 | with: 45 | sarif_file: trivy-results.sarif 46 | category: code 47 | -------------------------------------------------------------------------------- /.github/workflows/docs-main.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: Dev docs 4 | 5 | permissions: {} 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.ref }} 14 | cancel-in-progress: true 15 | 16 | jobs: 17 | docs: 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: write 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 24 | - name: Build site 25 | run: | 26 | set -e 27 | make codegen-mkdocs 28 | - name: Deploy site 29 | run: | 30 | set -e 31 | git fetch origin gh-pages --depth=1 32 | git config user.name ci-bot 33 | git config user.email ci-bot@example.com 34 | mike deploy -F ./website/mkdocs.yaml --push --update-aliases main dev 35 | -------------------------------------------------------------------------------- /.github/workflows/docs-release.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: Release docs 4 | 5 | permissions: {} 6 | 7 | on: 8 | push: 9 | tags: 10 | - docs-v* 11 | 12 | jobs: 13 | docs: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | steps: 18 | - name: Parse semver string 19 | id: semver 20 | uses: booxmedialtd/ws-action-parse-semver@7784200024d6b3fc01253e617ec0168daf603de3 # v1.4.7 21 | with: 22 | input_string: ${{ github.ref_name }} 23 | version_extractor_regex: ^docs-v(.*)$ 24 | - name: Checkout 25 | if: ${{ steps.semver.outputs.prerelease == '' }} 26 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | - name: Build site 28 | if: ${{ steps.semver.outputs.prerelease == '' }} 29 | run: | 30 | set -e 31 | make codegen-mkdocs 32 | - name: Deploy site 33 | if: ${{ steps.semver.outputs.prerelease == '' }} 34 | run: | 35 | set -e 36 | git fetch origin gh-pages --depth=1 37 | git config user.name ci-bot 38 | git config user.email ci-bot@example.com 39 | mike deploy -F ./website/mkdocs.yaml --push --update-aliases ${{ steps.semver.outputs.fullversion }} latest 40 | -------------------------------------------------------------------------------- /.github/workflows/helm-release.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: Helm Release 4 | 5 | permissions: {} 6 | 7 | on: 8 | push: 9 | tags: 10 | - 'charts-v*' 11 | 12 | jobs: 13 | charts-releaser: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | pages: write 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | with: 22 | fetch-depth: 0 23 | - name: Install Helm 24 | uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4.3.0 25 | - name: Set version 26 | run: | 27 | set -e 28 | TAG=${{ github.ref_name }} 29 | echo "CHART_VERSION=${TAG#charts-}" >> $GITHUB_ENV 30 | VERSION=$(git describe --tags --match "v*" --abbrev=0) 31 | echo "APP_VERSION=$VERSION" >> $GITHUB_ENV 32 | - name: Run charts releaser 33 | uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 #v1.7.0 34 | with: 35 | token: ${{ secrets.GITHUB_TOKEN }} 36 | linting: off 37 | charts_dir: charts 38 | app_version: ${{ env.APP_VERSION }} 39 | chart_version: ${{ env.CHART_VERSION }} 40 | -------------------------------------------------------------------------------- /.github/workflows/ko-publish.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: KO publish 4 | 5 | permissions: {} 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | ko-publish: 14 | permissions: 15 | id-token: write 16 | packages: write 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | - name: Setup go 22 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 23 | with: 24 | go-version-file: go.mod 25 | cache-dependency-path: go.sum 26 | - name: Run ko 27 | run: | 28 | set -e 29 | REGISTRY=ghcr.io \ 30 | REGISTRY_USERNAME=${{ github.actor }} \ 31 | REGISTRY_PASSWORD=${{ secrets.GITHUB_TOKEN }} \ 32 | make ko-publish 33 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: Lint 4 | 5 | permissions: {} 6 | 7 | on: 8 | pull_request: 9 | branches: 10 | - main 11 | push: 12 | branches: 13 | - main 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }} 17 | cancel-in-progress: true 18 | 19 | jobs: 20 | required: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 25 | - name: Setup go 26 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 27 | with: 28 | go-version-file: go.mod 29 | cache-dependency-path: go.sum 30 | - name: golangci-lint 31 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 32 | with: 33 | skip-cache: true 34 | args: --timeout 5m 35 | -------------------------------------------------------------------------------- /.github/workflows/semantics-pr.yaml: -------------------------------------------------------------------------------- 1 | name: Semantic PR Validation 2 | 3 | # feat: (new feature for the user, not a new feature for build script) 4 | # fix: (bug fix for the user, not a fix to a build script) 5 | # build: (changes that affect the build system or external dependencies) 6 | # chore: (updating grunt tasks etc; no production code change) 7 | # ci: (updates to CI configuration files and scripts; no production code change) 8 | # docs: (changes to the documentation) 9 | # perf: (a code change that improves performance) 10 | # refactor: (refactoring production code, eg. renaming a variable) 11 | # style: (formatting, missing semi colons, etc; no production code change) 12 | # test: (adding missing tests, refactoring tests; no production code change) 13 | # revert: (reverting a previous commit) 14 | # release: (release a new version of the project) 15 | 16 | # Example: 17 | # test(runner): Add test for the runner 18 | # ^ ^ ^ 19 | # | | |__ Subject 20 | # | |_______ Scope 21 | # |____________ Type 22 | 23 | on: 24 | pull_request_target: 25 | types: 26 | - opened 27 | - edited 28 | - synchronize 29 | 30 | defaults: 31 | run: 32 | shell: bash 33 | 34 | jobs: 35 | semantics-pr: 36 | runs-on: ubuntu-latest 37 | steps: 38 | - name: Validate pull request 39 | uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 40 | env: 41 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | with: 43 | # Configure which types are allowed. 44 | # Default: https://github.com/commitizen/conventional-commit-types 45 | types: | 46 | feat 47 | fix 48 | build 49 | chore 50 | ci 51 | docs 52 | perf 53 | refactor 54 | revert 55 | style 56 | test 57 | revert 58 | release 59 | # Configure which scopes are allowed. 60 | scopes: | 61 | api 62 | client 63 | commands 64 | config 65 | data 66 | deps 67 | discovery 68 | internal 69 | report 70 | resource 71 | runner 72 | operations 73 | processors 74 | test 75 | utils 76 | validation 77 | version 78 | docs 79 | release 80 | testdata 81 | ignoreLabels: | 82 | bot 83 | ignore-semantic-pull-request 84 | # Configure that a scope must always be provided. 85 | requireScope: false 86 | # When using "Squash and merge" on a PR with only one commit, GitHub 87 | # will suggest using that commit message instead of the PR title for the 88 | # merge commit, and it's easy to commit this by mistake. Enable this option 89 | # to also validate the commit message for one commit PRs. 90 | validateSingleCommit: true 91 | # Related to `validateSingleCommit` you can opt-in to validate that the PR 92 | # title matches a single commit to avoid confusion. 93 | validateSingleCommitMatchesPrTitle: true 94 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.cache/ 2 | /.certs/ 3 | /.temp/ 4 | /.tools/ 5 | /.venv/ 6 | /charts/*/charts 7 | /kyverno-envoy-plugin 8 | /website/site/ 9 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | before: 4 | hooks: 5 | - go mod tidy 6 | 7 | builds: 8 | - id: kyverno-envoy-plugin 9 | env: 10 | - CGO_ENABLED=0 11 | goos: 12 | - linux 13 | - windows 14 | - darwin 15 | binary: kyverno-envoy-plugin 16 | flags: 17 | - -trimpath 18 | ldflags: 19 | - -s -w 20 | 21 | kos: 22 | - build: kyverno-envoy-plugin 23 | repositories: 24 | - ghcr.io/kyverno/kyverno-envoy-plugin 25 | tags: 26 | - '{{ .Tag }}' 27 | - '{{ if not .Prerelease }}latest{{ end }}' 28 | bare: true 29 | preserve_import_paths: false 30 | sbom: none 31 | platforms: 32 | - all 33 | labels: 34 | org.opencontainers.image.source: https://github.com/kyverno/kyverno-envoy-plugin 35 | org.opencontainers.image.description: Kyverno policies based authorization plugin for Envoy ❤️ 36 | 37 | signs: 38 | - cmd: cosign 39 | certificate: '${artifact}.pem' 40 | args: 41 | - sign-blob 42 | - --output-certificate=${certificate} 43 | - --output-signature=${signature} 44 | - ${artifact} 45 | - --yes 46 | artifacts: all 47 | output: true 48 | 49 | docker_signs: 50 | - cmd: cosign 51 | artifacts: all 52 | output: true 53 | args: 54 | - sign 55 | - ${artifact} 56 | - --yes 57 | 58 | archives: 59 | - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}' 60 | 61 | checksum: 62 | name_template: checksums.txt 63 | 64 | source: 65 | enabled: true 66 | 67 | sboms: 68 | - artifacts: archive 69 | - id: source 70 | artifacts: source 71 | 72 | snapshot: 73 | version_template: '{{ incpatch .Version }}-next' 74 | 75 | release: 76 | prerelease: auto 77 | 78 | changelog: 79 | sort: asc 80 | filters: 81 | exclude: 82 | - '^docs:' 83 | - '^test:' 84 | -------------------------------------------------------------------------------- /.hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright The Kubernetes Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | -------------------------------------------------------------------------------- /.manifests/cert-manager/cluster-issuer.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cert-manager.io/v1 2 | kind: ClusterIssuer 3 | metadata: 4 | name: selfsigned-issuer 5 | spec: 6 | selfSigned: {} 7 | -------------------------------------------------------------------------------- /.manifests/policies/demo-policy.example.com.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: demo-policy.example.com 6 | spec: 7 | variables: 8 | - name: force_authorized 9 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 10 | - name: force_unauthenticated 11 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 12 | - name: metadata 13 | expression: '{"my-new-metadata": "my-new-value"}' 14 | deny: 15 | # if force_unauthenticated -> 401 16 | - match: > 17 | variables.force_unauthenticated 18 | response: > 19 | envoy 20 | .Denied(401) 21 | .WithBody("Authentication Failed") 22 | .Response() 23 | # if not force_authorized -> 403 24 | - match: > 25 | !variables.force_authorized 26 | response: > 27 | envoy 28 | .Denied(403) 29 | .WithBody("Unauthorized Request") 30 | .Response() 31 | allow: 32 | # else -> 200 33 | - response: > 34 | envoy 35 | .Allowed() 36 | .WithHeader("x-validated-by", "my-security-checkpoint") 37 | .WithoutHeader("x-force-authorized") 38 | .WithResponseHeader("x-add-custom-response-header", "added") 39 | .Response() 40 | .WithMetadata(variables.metadata) 41 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Serve", 6 | "type": "go", 7 | "request": "launch", 8 | "mode": "auto", 9 | "program": "${workspaceFolder}", 10 | "args": [ 11 | "serve", 12 | "authz-server" 13 | ], 14 | }, 15 | { 16 | "name": "Inject", 17 | "type": "go", 18 | "request": "launch", 19 | "mode": "auto", 20 | "program": "${workspaceFolder}", 21 | "args": [ 22 | "serve", 23 | "sidecar-injector", 24 | ], 25 | } 26 | ] 27 | } -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @kyverno/kyverno-envoy-plugin-maintainers 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment include: 15 | 16 | * Using welcoming and inclusive language 17 | * Being respectful of differing viewpoints and experiences 18 | * Gracefully accepting constructive criticism 19 | * Focusing on what is best for our community 20 | * Showing empathy towards other community members 21 | 22 | Examples of unacceptable behavior by participants include: 23 | 24 | * The use of sexualized language or imagery and unwelcome sexual attention or 25 | advances 26 | * Trolling, insulting/derogatory comments, and personal or political attacks 27 | * Public or private harassment 28 | * Publishing others' private information, such as a physical or electronic 29 | address, without explicit permission 30 | * Other conduct which could reasonably be considered inappropriate in a 31 | professional setting 32 | 33 | ## Our Responsibilities 34 | 35 | Project maintainers are responsible for clarifying the standards of acceptable 36 | behavior and are expected to take appropriate and fair corrective action in 37 | response to any instances of unacceptable behavior. 38 | 39 | Project maintainers have the right and responsibility to remove, edit, or reject 40 | comments, commits, code, wiki edits, issues, and other contributions that are 41 | not aligned to this Code of Conduct, or to ban temporarily or permanently any 42 | contributor for other behaviors that they deem inappropriate, threatening, 43 | offensive, or harmful. 44 | 45 | ## Scope 46 | 47 | This Code of Conduct applies both within project spaces and in public spaces 48 | when an individual is representing the project or its community. Examples of 49 | representing a project or community include using an official project e-mail 50 | address, posting via an official social media account, or acting as an appointed 51 | representative at an online or offline event. Representation of a project may be 52 | further defined and clarified by project maintainers. 53 | 54 | ## Enforcement 55 | 56 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 57 | reported by contacting the project team privately at hello@squidfunk.com. The 58 | project team will review and investigate all complaints, and will respond in a 59 | way that it deems appropriate to the circumstances. The project team is 60 | obligated to maintain confidentiality with regard to the reporter of an 61 | incident. Further details of specific enforcement policies may be posted 62 | separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 71 | version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kyverno-envoy-plugin 2 | 3 | A plugin to enforce kyverno policies with Envoy. This plugin allows applying Kyverno policies to APIs managed by Envoy. 4 | 5 | ## Overview 6 | 7 | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/intro/what_is_envoy) is a L7 proxy and communication bus designed for large modern service oriented architectures . Envoy (v1.7.0+) supports an External Authorization filter which calls an authorization service to check if the incoming request is authorized or not. [External Authorization filter](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html) feature will help us to make a decision based on Kyverno policies . 8 | 9 | **WARNING: ⚠️ Kyverno-envoy-plugin is in development stage.** 10 | 11 | 12 | ## 📙 Documentation 13 | 14 | Kyverno Envoy plugin installation and reference documents are available [here](https://kyverno.github.io/kyverno-envoy-plugin) 15 | 16 | 👉 **[Quick Start](https://kyverno.github.io/kyverno-envoy-plugin/latest/quick-start/)** 17 | 18 | 👉 **[Installation](https://kyverno.github.io/kyverno-envoy-plugin/latest/quick-start/authz-server/)** 19 | 20 | ## RoadMap 21 | 22 | For detailed information on our planned features and upcoming updates, please [view our Roadmap](./ROADMAP.md). 23 | 24 | ## 🙋‍♂️ Getting Help 25 | 26 | We are here to help! 27 | 28 | 👉 For feature requests and bugs, file an [issue](https://github.com/kyverno/kyverno-envoy-plugin/issues). 29 | 30 | 👉 For discussions or questions, join the [Kyverno Slack channel](https://slack.k8s.io/#kyverno). 31 | 32 | 👉 To get notified on updates ⭐️ [star this repository](https://github.com/kyverno/kyverno-envoy-plugin/stargazers). 33 | 34 | ## ➕ Contributing 35 | 36 | Thanks for your interest in contributing to Kyverno! Here are some steps to help get you started: 37 | 38 | ✔ Look through the [good first issues](https://github.com/kyverno/kyverno-envoy-plugin/labels/good%20first%20issue) list. Add a comment with `/assign` to request the assignment of the issue. 39 | 40 | ✔ Check out the Kyverno [Community page](https://kyverno.io/community/) for other ways to get involved. 41 | 42 | ## License 43 | 44 | Copyright 2023, the Kyverno project. All rights reserved. kyverno-envoy-plugin is licensed under the [Apache License 2.0](LICENSE). 45 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # 🗺️ RoadMap 2 | 3 | ## 🚀 Version 0.1.0 4 | 5 | - **Achieve a Stable API:** 6 | - Focus on developing and finalizing a stable API, ensuring robustness, maintainability and reliability. 7 | 8 | ## 🌟 Version 0.2.0 9 | 10 | - **Validation WebHook:** 11 | - Support policy validation with a validation webhook to detect semantic errors at admission time. 12 | 13 | - **Match conditions:** 14 | - Add match conditions support to policies. 15 | 16 | ## 👀 Version 0.3.0 17 | 18 | - **Improve observability:** 19 | - Add better logs, metrics and traces in the code base. 20 | 21 | - **Performance testing:** 22 | - Thorough perfomance testing and reporting. 23 | -------------------------------------------------------------------------------- /adopters.md: -------------------------------------------------------------------------------- 1 | # Adopters 2 | 3 | This document lists organizations that are adopting the kyverno-envoy-plugin. 4 | 5 | ## Organizations 6 | 7 | 8 | | Organization | Contact | 9 | | ------------------------------- | ---------------------------------------------------------------------------------- | 10 | | [Nirmata](https://nirmata.com/) | [@nirmata](https://github.com/nirmata) | 11 | 12 | ## How to Get Listed 13 | 14 | If your organization is using the `kyverno-envoy-plugin`, please submit a pull request with your details or open an issue on [GitHub](https://github.com/kyverno/kyverno-envoy-plugin/issues) to have your organization added. 15 | 16 | ## Additional Information 17 | 18 | For any questions or to share your experience, join our [Kyverno Slack channel](https://slack.k8s.io/#kyverno). -------------------------------------------------------------------------------- /apis/v1alpha1/doc.go: -------------------------------------------------------------------------------- 1 | // +k8s:openapi-gen=true 2 | // +k8s:deepcopy-gen=package 3 | // +groupName=envoy.kyverno.io 4 | 5 | package v1alpha1 6 | -------------------------------------------------------------------------------- /apis/v1alpha1/types_test.go: -------------------------------------------------------------------------------- 1 | package v1alpha1 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | admissionregistrationv1 "k8s.io/api/admissionregistration/v1" 8 | "k8s.io/utils/ptr" 9 | ) 10 | 11 | func TestAuthorizationPolicySpec_GetFailurePolicy(t *testing.T) { 12 | tests := []struct { 13 | name string 14 | failurePolicy *admissionregistrationv1.FailurePolicyType 15 | want admissionregistrationv1.FailurePolicyType 16 | }{{ 17 | name: "not set", 18 | failurePolicy: nil, 19 | want: admissionregistrationv1.Fail, 20 | }, { 21 | name: "fail", 22 | failurePolicy: ptr.To(admissionregistrationv1.Fail), 23 | want: admissionregistrationv1.Fail, 24 | }, { 25 | name: "ignore", 26 | failurePolicy: ptr.To(admissionregistrationv1.Ignore), 27 | want: admissionregistrationv1.Ignore, 28 | }} 29 | for _, tt := range tests { 30 | t.Run(tt.name, func(t *testing.T) { 31 | s := &AuthorizationPolicySpec{ 32 | FailurePolicy: tt.failurePolicy, 33 | } 34 | got := s.GetFailurePolicy() 35 | assert.Equal(t, tt.want, got) 36 | }) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /apis/v1alpha1/zz_generated.register.go: -------------------------------------------------------------------------------- 1 | //go:build !ignore_autogenerated 2 | // +build !ignore_autogenerated 3 | 4 | /* 5 | Copyright The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | // Code generated by register-gen. DO NOT EDIT. 21 | 22 | package v1alpha1 23 | 24 | import ( 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | runtime "k8s.io/apimachinery/pkg/runtime" 27 | schema "k8s.io/apimachinery/pkg/runtime/schema" 28 | ) 29 | 30 | // GroupName specifies the group name used to register the objects. 31 | const GroupName = "envoy.kyverno.io" 32 | 33 | // GroupVersion specifies the group and the version used to register the objects. 34 | var GroupVersion = v1.GroupVersion{Group: GroupName, Version: "v1alpha1"} 35 | 36 | // SchemeGroupVersion is group version used to register these objects 37 | // Deprecated: use GroupVersion instead. 38 | var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} 39 | 40 | // Resource takes an unqualified resource and returns a Group qualified GroupResource 41 | func Resource(resource string) schema.GroupResource { 42 | return SchemeGroupVersion.WithResource(resource).GroupResource() 43 | } 44 | 45 | var ( 46 | // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. 47 | SchemeBuilder runtime.SchemeBuilder 48 | localSchemeBuilder = &SchemeBuilder 49 | // Deprecated: use Install instead 50 | AddToScheme = localSchemeBuilder.AddToScheme 51 | Install = localSchemeBuilder.AddToScheme 52 | ) 53 | 54 | func init() { 55 | // We only register manually written functions here. The registration of the 56 | // generated functions takes place in the generated files. The separation 57 | // makes the code compile even when the generated files are missing. 58 | localSchemeBuilder.Register(addKnownTypes) 59 | } 60 | 61 | // Adds the list of known types to Scheme. 62 | func addKnownTypes(scheme *runtime.Scheme) error { 63 | scheme.AddKnownTypes(SchemeGroupVersion, 64 | &AuthorizationPolicy{}, 65 | &AuthorizationPolicyList{}, 66 | ) 67 | // AddToGroupVersion allows the serialization of client types like ListOptions. 68 | v1.AddToGroupVersion(scheme, SchemeGroupVersion) 69 | return nil 70 | } 71 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/.helmignore: -------------------------------------------------------------------------------- 1 | .helmignore 2 | ci/ 3 | README.md.gotmpl 4 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: kyverno-lib 3 | repository: file://../kyverno-lib 4 | version: 0.0.0 5 | digest: sha256:74ae1b7230d94ccd45ed668b489009ead0c031c8240e8b76cd05a31f95e679c2 6 | generated: "2024-10-25T21:56:51.136355+02:00" 7 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: kyverno-authz-server 3 | description: Kyverno policies based authorization plugin for Envoy ❤️ 4 | icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png 5 | home: https://kyverno.github.io/kyverno-envoy-plugin 6 | 7 | type: application 8 | version: 0.0.0 9 | appVersion: latest 10 | kubeVersion: ">=1.25.0-0" 11 | 12 | keywords: 13 | - kubernetes 14 | - kyverno 15 | - authz 16 | - policy 17 | - envoy 18 | - istio 19 | - security 20 | 21 | sources: 22 | - https://github.com/kyverno/kyverno-envoy-plugin 23 | 24 | maintainers: 25 | - name: Kyverno 26 | url: https://kyverno.io/ 27 | 28 | dependencies: 29 | - name: kyverno-lib 30 | version: 0.0.0 31 | repository: file://../kyverno-lib 32 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/README.md.gotmpl: -------------------------------------------------------------------------------- 1 | {{ template "chart.header" . }} 2 | {{ template "chart.deprecationWarning" . }} 3 | {{ template "chart.description" . }} 4 | 5 | {{ template "chart.badgesSection" . }} 6 | 7 | A plugin to enforce kyverno policies with Envoy. This plugin allows applying Kyverno policies to APIs managed by Envoy. 8 | 9 | ## Overview 10 | 11 | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/intro/what_is_envoy) is a L7 proxy and communication bus designed for large modern service oriented architectures . Envoy (v1.7.0+) supports an External Authorization filter which calls an authorization service to check if the incoming request is authorized or not. [External Authorization filter](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html) feature will help us to make a decision based on Kyverno policies . 12 | 13 | ## Installing the Chart 14 | 15 | Add `kyverno-envoy-plugin` Helm repository: 16 | 17 | ```shell 18 | helm repo add kyverno-json https://kyverno.github.io/kyverno-envoy-plugin/ 19 | ``` 20 | 21 | Install `kyverno-authz-server` Helm chart: 22 | 23 | ```shell 24 | helm install kyverno-authz-server --namespace kyverno --create-namespace kyverno-envoy-plugin/kyverno-authz-server 25 | ``` 26 | 27 | {{ template "chart.valuesSection" . }} 28 | 29 | {{ template "chart.sourcesSection" . }} 30 | 31 | {{ template "chart.requirementsSection" . }} 32 | 33 | {{ template "chart.maintainersSection" . }} 34 | 35 | {{ template "helm-docs.versionFooter" . }} 36 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Chart version: {{ .Chart.Version }} 2 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | 3 | {{- define "kyverno-authz-server.name" -}} 4 | {{ template "kyverno.lib.names.name" . }} 5 | {{- end -}} 6 | 7 | {{- define "kyverno-authz-server.labels" -}} 8 | {{- template "kyverno.lib.labels.merge" (list 9 | (include "kyverno.lib.labels.common" .) 10 | (include "kyverno-authz-server.labels.selector" .) 11 | ) -}} 12 | {{- end -}} 13 | 14 | {{- define "kyverno-authz-server.labels.selector" -}} 15 | {{- template "kyverno.lib.labels.merge" (list 16 | (include "kyverno.lib.labels.common.selector" .) 17 | (include "kyverno.lib.labels.component" "authz-server") 18 | ) -}} 19 | {{- end -}} 20 | 21 | {{- define "kyverno-authz-server.service-account.name" -}} 22 | {{- if .Values.rbac.create -}} 23 | {{- default (include "kyverno-authz-server.name" .) .Values.rbac.serviceAccount.name -}} 24 | {{- else -}} 25 | {{- required "A service account name is required when `rbac.create` is set to `false`" .Values.rbac.serviceAccount.name -}} 26 | {{- end -}} 27 | {{- end -}} 28 | 29 | {{- define "kyverno-authz-server.image" -}} 30 | {{- printf "%s/%s:%s" .registry .repository (default "latest" .tag) -}} 31 | {{- end -}} 32 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/cluster-role-binding.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.create -}} 2 | kind: ClusterRoleBinding 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | name: {{ template "kyverno-authz-server.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "kyverno-authz-server.labels" . | nindent 4 }} 9 | roleRef: 10 | kind: ClusterRole 11 | name: {{ template "kyverno-authz-server.name" . }} 12 | subjects: 13 | - kind: ServiceAccount 14 | name: {{ template "kyverno-authz-server.service-account.name" . }} 15 | namespace: {{ template "kyverno.lib.namespace" . }} 16 | {{- end -}} 17 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/cluster-role.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.create -}} 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | metadata: 6 | name: {{ template "kyverno-authz-server.name" . }} 7 | labels: 8 | {{- include "kyverno-authz-server.labels" . | nindent 4 }} 9 | rules: 10 | - apiGroups: 11 | - envoy.kyverno.io 12 | resources: 13 | - authorizationpolicies 14 | verbs: 15 | - get 16 | - list 17 | - watch 18 | {{- end -}} 19 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ template "kyverno-authz-server.service-account.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "kyverno-authz-server.labels" . | nindent 4 }} 9 | {{- with .Values.rbac.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "kyverno-authz-server.name" . }} 5 | namespace: {{ template "kyverno.lib.namespace" . }} 6 | labels: 7 | {{- include "kyverno-authz-server.labels" . | nindent 4 }} 8 | {{- with .Values.service.annotations }} 9 | annotations: 10 | {{- tpl (toYaml .) $ | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | type: {{ .Values.service.type }} 14 | ports: 15 | - name: grpc 16 | port: {{ .Values.service.port }} 17 | protocol: TCP 18 | targetPort: grpc 19 | {{- if and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort)) }} 20 | nodePort: {{ .Values.service.nodePort }} 21 | {{- end }} 22 | selector: 23 | {{- include "kyverno-authz-server.labels.selector" . | nindent 4 }} 24 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/validation-webhook/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | 3 | {{- define "validation-webhook.name" -}} 4 | {{ template "kyverno.lib.names.name" . }}-validation 5 | {{- end -}} 6 | 7 | {{- define "validation-webhook.labels" -}} 8 | {{- template "kyverno.lib.labels.merge" (list 9 | (include "kyverno.lib.labels.common" .) 10 | (include "validation-webhook.labels.selector" .) 11 | ) -}} 12 | {{- end -}} 13 | 14 | {{- define "validation-webhook.labels.selector" -}} 15 | {{- template "kyverno.lib.labels.merge" (list 16 | (include "kyverno.lib.labels.common.selector" .) 17 | (include "kyverno.lib.labels.component" "validation-webhook") 18 | ) -}} 19 | {{- end -}} 20 | 21 | {{- define "validation-webhook.service-account.name" -}} 22 | {{- if .Values.rbac.create -}} 23 | {{- default (include "validation-webhook.name" .) .Values.rbac.serviceAccount.name -}} 24 | {{- else -}} 25 | {{- required "A service account name is required when `rbac.create` is set to `false`" .Values.rbac.serviceAccount.name -}} 26 | {{- end -}} 27 | {{- end -}} 28 | 29 | {{- define "validation-webhook.image" -}} 30 | {{- printf "%s/%s:%s" .registry .repository (default "latest" .tag) -}} 31 | {{- end -}} 32 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/validation-webhook/certificates/cert-manager/certificate.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.certificates.certManager -}} 2 | apiVersion: cert-manager.io/v1 3 | kind: Certificate 4 | metadata: 5 | name: {{ template "validation-webhook.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "validation-webhook.labels" . | nindent 4 }} 9 | spec: 10 | secretName: {{ template "validation-webhook.name" . }} 11 | dnsNames: 12 | - {{ printf "%s.%s.svc" (include "validation-webhook.name" .) (include "kyverno.lib.namespace" .) }} 13 | {{- with .Values.certificates.certManager.issuerRef }} 14 | issuerRef: 15 | {{- tpl (toYaml .) $ | nindent 4 }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/validation-webhook/certificates/static/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.certificates.static -}} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ template "validation-webhook.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "validation-webhook.labels" . | nindent 4 }} 9 | type: kubernetes.io/tls 10 | data: 11 | tls.crt: {{ .Values.certificates.static.crt | b64enc }} 12 | tls.key: {{ .Values.certificates.static.key | b64enc }} 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/validation-webhook/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ template "validation-webhook.service-account.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "validation-webhook.labels" . | nindent 4 }} 9 | {{- with .Values.rbac.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/validation-webhook/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "validation-webhook.name" . }} 5 | namespace: {{ template "kyverno.lib.namespace" . }} 6 | labels: 7 | {{- include "validation-webhook.labels" . | nindent 4 }} 8 | {{- with .Values.service.annotations }} 9 | annotations: 10 | {{- tpl (toYaml .) $ | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | type: {{ .Values.service.type }} 14 | ports: 15 | - name: webhook 16 | port: 9443 17 | protocol: TCP 18 | targetPort: 9443 19 | selector: 20 | {{- include "validation-webhook.labels.selector" . | nindent 4 }} 21 | -------------------------------------------------------------------------------- /charts/kyverno-authz-server/templates/validation-webhook/validating-webhook-configuration.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1 2 | kind: ValidatingWebhookConfiguration 3 | metadata: 4 | name: {{ template "validation-webhook.name" . }} 5 | labels: 6 | {{- include "validation-webhook.labels" . | nindent 4 }} 7 | {{- if (or .Values.certificates.certManager .Values.webhook.annotations) }} 8 | annotations: 9 | {{- with .Values.webhook.annotations }} 10 | {{- tpl (toYaml .) $ | nindent 4 }} 11 | {{- end }} 12 | {{- if .Values.certificates.certManager }} 13 | cert-manager.io/inject-ca-from: {{ printf "%s/%s" (include "kyverno.lib.namespace" .) (include "validation-webhook.name" .) }} 14 | {{- end }} 15 | {{- end }} 16 | webhooks: 17 | - name: {{ printf "%s.%s.svc" (include "validation-webhook.name" .) (include "kyverno.lib.namespace" .) }} 18 | clientConfig: 19 | service: 20 | name: {{ template "validation-webhook.name" . }} 21 | namespace: {{ template "kyverno.lib.namespace" . }} 22 | port: 9443 23 | path: /validate-envoy-kyverno-io-v1alpha1-authorizationpolicy 24 | {{- if .Values.certificates.static }} 25 | caBundle: {{ index .Values.certificates.static.crt | b64enc }} 26 | {{- end }} 27 | failurePolicy: {{ .Values.webhook.failurePolicy }} 28 | sideEffects: None 29 | admissionReviewVersions: [ v1 ] 30 | rules: 31 | - apiGroups: 32 | - envoy.kyverno.io 33 | apiVersions: 34 | - v1alpha1 35 | resources: 36 | - authorizationpolicies 37 | operations: 38 | - CREATE 39 | - UPDATE 40 | {{- with .Values.webhook.objectSelector }} 41 | objectSelector: 42 | {{- tpl (toYaml .) $ | nindent 6 }} 43 | {{- end }} 44 | {{- with .Values.webhook.namespaceSelector }} 45 | namespaceSelector: 46 | {{- tpl (toYaml .) $ | nindent 6 }} 47 | {{- end }} 48 | -------------------------------------------------------------------------------- /charts/kyverno-lib/.helmignore: -------------------------------------------------------------------------------- 1 | .helmignore 2 | ci/ 3 | README.md.gotmpl 4 | -------------------------------------------------------------------------------- /charts/kyverno-lib/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: kyverno-lib 3 | description: Kyverno policies based authorization plugin for Envoy ❤️ 4 | icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png 5 | home: https://kyverno.github.io/kyverno-envoy-plugin 6 | 7 | type: library 8 | version: 0.0.0 9 | appVersion: latest 10 | kubeVersion: ">=1.25.0-0" 11 | 12 | keywords: 13 | - kubernetes 14 | - kyverno 15 | - authz 16 | - policy 17 | - envoy 18 | - istio 19 | - security 20 | 21 | sources: 22 | - https://github.com/kyverno/kyverno-envoy-plugin 23 | 24 | maintainers: 25 | - name: Kyverno 26 | url: https://kyverno.io/ 27 | -------------------------------------------------------------------------------- /charts/kyverno-lib/templates/_chart.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | 3 | {{- define "kyverno.lib.chart.name" -}} 4 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} 5 | {{- end -}} 6 | 7 | {{- define "kyverno.lib.chart.version" -}} 8 | {{- .Chart.Version | replace "+" "_" -}} 9 | {{- end -}} 10 | -------------------------------------------------------------------------------- /charts/kyverno-lib/templates/_labels.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | 3 | {{- define "kyverno.lib.labels.merge" -}} 4 | {{- $labels := dict -}} 5 | {{- range . -}} 6 | {{- $labels = merge $labels (fromYaml .) -}} 7 | {{- end -}} 8 | {{- with $labels -}} 9 | {{- toYaml $labels -}} 10 | {{- end -}} 11 | {{- end -}} 12 | 13 | {{- define "kyverno.lib.labels.helm" -}} 14 | helm.sh/chart: {{ template "kyverno.lib.chart.name" . }} 15 | app.kubernetes.io/managed-by: {{ .Release.Service }} 16 | {{- end -}} 17 | 18 | {{- define "kyverno.lib.labels.version" -}} 19 | app.kubernetes.io/version: {{ template "kyverno.lib.chart.version" . }} 20 | {{- end -}} 21 | 22 | {{- define "kyverno.lib.labels.component" -}} 23 | app.kubernetes.io/component: {{ . }} 24 | {{- end -}} 25 | 26 | {{- define "kyverno.lib.labels.name" -}} 27 | app.kubernetes.io/name: {{ . }} 28 | {{- end -}} 29 | 30 | {{- define "kyverno.lib.labels.common" -}} 31 | {{- template "kyverno.lib.labels.merge" (list 32 | (include "kyverno.lib.labels.helm" .) 33 | (include "kyverno.lib.labels.version" .) 34 | ) -}} 35 | {{- end -}} 36 | 37 | {{- define "kyverno.lib.labels.common.selector" -}} 38 | app.kubernetes.io/part-of: {{ template "kyverno.lib.names.fullname" . }} 39 | app.kubernetes.io/instance: {{ .Release.Name }} 40 | {{- end -}} 41 | -------------------------------------------------------------------------------- /charts/kyverno-lib/templates/_names.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | 3 | {{- define "kyverno.lib.names.name" -}} 4 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} 5 | {{- end -}} 6 | 7 | {{- define "kyverno.lib.names.fullname" -}} 8 | {{- if .Values.fullnameOverride -}} 9 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} 10 | {{- else -}} 11 | {{- $name := default .Chart.Name .Values.nameOverride -}} 12 | {{- if contains $name .Release.Name -}} 13 | {{- .Release.Name | trunc 63 | trimSuffix "-" -}} 14 | {{- else -}} 15 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} 16 | {{- end -}} 17 | {{- end -}} 18 | {{- end -}} 19 | 20 | {{- define "kyverno.lib.namespace" -}} 21 | {{ default .Release.Namespace .Values.namespaceOverride }} 22 | {{- end -}} 23 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/.helmignore: -------------------------------------------------------------------------------- 1 | .helmignore 2 | ci/ 3 | README.md.gotmpl 4 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: kyverno-lib 3 | repository: file://../kyverno-lib 4 | version: 0.0.0 5 | digest: sha256:74ae1b7230d94ccd45ed668b489009ead0c031c8240e8b76cd05a31f95e679c2 6 | generated: "2024-10-25T21:49:44.991237+02:00" 7 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: kyverno-sidecar-injector 3 | description: Kyverno policies based authorization plugin for Envoy ❤️ 4 | icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png 5 | home: https://kyverno.github.io/kyverno-envoy-plugin 6 | 7 | type: application 8 | version: 0.0.0 9 | appVersion: latest 10 | kubeVersion: ">=1.25.0-0" 11 | 12 | keywords: 13 | - kubernetes 14 | - kyverno 15 | - authz 16 | - policy 17 | - envoy 18 | - istio 19 | - security 20 | 21 | sources: 22 | - https://github.com/kyverno/kyverno-envoy-plugin 23 | 24 | maintainers: 25 | - name: Kyverno 26 | url: https://kyverno.io/ 27 | 28 | dependencies: 29 | - name: kyverno-lib 30 | version: 0.0.0 31 | repository: file://../kyverno-lib 32 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/README.md.gotmpl: -------------------------------------------------------------------------------- 1 | {{ template "chart.header" . }} 2 | {{ template "chart.deprecationWarning" . }} 3 | {{ template "chart.description" . }} 4 | 5 | {{ template "chart.badgesSection" . }} 6 | 7 | 8 | A plugin to enforce kyverno policies with Envoy. This plugin allows applying Kyverno policies to APIs managed by Envoy. 9 | 10 | ## Overview 11 | 12 | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/intro/what_is_envoy) is a L7 proxy and communication bus designed for large modern service oriented architectures . Envoy (v1.7.0+) supports an External Authorization filter which calls an authorization service to check if the incoming request is authorized or not. [External Authorization filter](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html) feature will help us to make a decision based on Kyverno policies . 13 | 14 | ## Installing the Chart 15 | 16 | Add `kyverno-envoy-plugin` Helm repository: 17 | 18 | ```shell 19 | helm repo add kyverno-json https://kyverno.github.io/kyverno-envoy-plugin/ 20 | ``` 21 | 22 | Install `kyverno-sidecar-injector` Helm chart: 23 | 24 | ```shell 25 | helm install kyverno-sidecar-injector --namespace kyverno --create-namespace kyverno-envoy-plugin/kyverno-sidecar-injector 26 | ``` 27 | 28 | {{ template "chart.valuesSection" . }} 29 | 30 | {{ template "chart.sourcesSection" . }} 31 | 32 | {{ template "chart.requirementsSection" . }} 33 | 34 | {{ template "chart.maintainersSection" . }} 35 | 36 | {{ template "helm-docs.versionFooter" . }} 37 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | Chart version: {{ .Chart.Version }} 2 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | 3 | {{- define "sidecar-injector.name" -}} 4 | {{ template "kyverno.lib.names.name" . }} 5 | {{- end -}} 6 | 7 | {{- define "sidecar-injector.labels" -}} 8 | {{- template "kyverno.lib.labels.merge" (list 9 | (include "kyverno.lib.labels.common" .) 10 | (include "sidecar-injector.labels.selector" .) 11 | ) -}} 12 | {{- end -}} 13 | 14 | {{- define "sidecar-injector.labels.selector" -}} 15 | {{- template "kyverno.lib.labels.merge" (list 16 | (include "kyverno.lib.labels.common.selector" .) 17 | (include "kyverno.lib.labels.component" "sidecar-injector") 18 | ) -}} 19 | {{- end -}} 20 | 21 | {{- define "sidecar-injector.service-account.name" -}} 22 | {{- if .Values.rbac.create -}} 23 | {{- default (include "sidecar-injector.name" .) .Values.rbac.serviceAccount.name -}} 24 | {{- else -}} 25 | {{- required "A service account name is required when `rbac.create` is set to `false`" .Values.rbac.serviceAccount.name -}} 26 | {{- end -}} 27 | {{- end -}} 28 | 29 | {{- define "sidecar-injector.image" -}} 30 | {{- printf "%s/%s:%s" .registry .repository (default "latest" .tag) -}} 31 | {{- end -}} 32 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/certificates/cert-manager/certificate.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.certificates.certManager -}} 2 | apiVersion: cert-manager.io/v1 3 | kind: Certificate 4 | metadata: 5 | name: {{ template "sidecar-injector.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "sidecar-injector.labels" . | nindent 4 }} 9 | spec: 10 | secretName: {{ template "sidecar-injector.name" . }} 11 | dnsNames: 12 | - {{ printf "%s.%s.svc" (include "sidecar-injector.name" .) (include "kyverno.lib.namespace" .) }} 13 | {{- with .Values.certificates.certManager.issuerRef }} 14 | issuerRef: 15 | {{- tpl (toYaml .) $ | nindent 4 }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/certificates/static/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.certificates.static -}} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ template "sidecar-injector.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "sidecar-injector.labels" . | nindent 4 }} 9 | type: kubernetes.io/tls 10 | data: 11 | tls.crt: {{ .Values.certificates.static.crt | b64enc }} 12 | tls.key: {{ .Values.certificates.static.key | b64enc }} 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/service-account.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rbac.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ template "sidecar-injector.service-account.name" . }} 6 | namespace: {{ template "kyverno.lib.namespace" . }} 7 | labels: 8 | {{- include "sidecar-injector.labels" . | nindent 4 }} 9 | {{- with .Values.rbac.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ template "sidecar-injector.name" . }} 5 | namespace: {{ template "kyverno.lib.namespace" . }} 6 | labels: 7 | {{- include "sidecar-injector.labels" . | nindent 4 }} 8 | {{- with .Values.service.annotations }} 9 | annotations: 10 | {{- tpl (toYaml .) $ | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | type: {{ .Values.service.type }} 14 | ports: 15 | - name: https 16 | port: {{ .Values.service.port }} 17 | protocol: TCP 18 | appProtocol: https 19 | targetPort: https 20 | {{- if and (eq .Values.service.type "NodePort") (not (empty .Values.service.nodePort)) }} 21 | nodePort: {{ .Values.service.nodePort }} 22 | {{- end }} 23 | selector: 24 | {{- include "sidecar-injector.labels.selector" . | nindent 4 }} 25 | -------------------------------------------------------------------------------- /charts/kyverno-sidecar-injector/templates/webhook.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: admissionregistration.k8s.io/v1 2 | kind: MutatingWebhookConfiguration 3 | metadata: 4 | name: {{ template "sidecar-injector.name" . }} 5 | labels: 6 | {{- include "sidecar-injector.labels" . | nindent 4 }} 7 | {{- if (or .Values.certificates.certManager .Values.webhook.annotations) }} 8 | annotations: 9 | {{- with .Values.webhook.annotations }} 10 | {{- tpl (toYaml .) $ | nindent 4 }} 11 | {{- end }} 12 | {{- if .Values.certificates.certManager }} 13 | cert-manager.io/inject-ca-from: {{ printf "%s/%s" (include "kyverno.lib.namespace" .) (include "sidecar-injector.name" .) }} 14 | {{- end }} 15 | {{- end }} 16 | webhooks: 17 | - name: {{ printf "%s.%s.svc" (include "sidecar-injector.name" .) (include "kyverno.lib.namespace" .) }} 18 | clientConfig: 19 | service: 20 | name: {{ template "sidecar-injector.name" . }} 21 | namespace: {{ template "kyverno.lib.namespace" . }} 22 | path: /mutate 23 | {{- if .Values.certificates.static }} 24 | caBundle: {{ index .Values.certificates.static.crt | b64enc }} 25 | {{- end }} 26 | failurePolicy: {{ .Values.webhook.failurePolicy }} 27 | sideEffects: None 28 | admissionReviewVersions: [ v1 ] 29 | rules: 30 | - apiGroups: [ '' ] 31 | apiVersions: [ v1 ] 32 | resources: [ pods ] 33 | operations: [ CREATE ] 34 | scope: '*' 35 | {{- with .Values.webhook.objectSelector }} 36 | objectSelector: 37 | {{- tpl (toYaml .) $ | nindent 6 }} 38 | {{- end }} 39 | {{- with .Values.webhook.namespaceSelector }} 40 | namespaceSelector: 41 | {{- tpl (toYaml .) $ | nindent 6 }} 42 | {{- end }} 43 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - 'apis/**/zz_*.go' 3 | - '**/*_test.go' 4 | -------------------------------------------------------------------------------- /docs/demo/istio-mtls/arch-istio-mtls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/docs/demo/istio-mtls/arch-istio-mtls.png -------------------------------------------------------------------------------- /docs/demo/istio-mtls/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | KIND_IMAGE=kindest/node:v1.29.2 4 | ISTIO_REPO=https://istio-release.storage.googleapis.com/charts 5 | ISTIO_NS=istio-system 6 | 7 | # Create Kind cluster 8 | kind create cluster --image $KIND_IMAGE --wait 1m --config - <` 12 | // Envoy sends “403 Forbidden“ HTTP status code by default. 13 | Status *status.Status `cel:"status"` 14 | // An message that contains HTTP response attributes. This message is 15 | // used when the authorization service needs to send custom responses to the 16 | // downstream client or, to modify/add request headers being dispatched to the upstream. 17 | // 18 | // Types that are assignable to HttpResponse: 19 | // 20 | // *CheckResponse_DeniedResponse 21 | // *CheckResponse_OkResponse 22 | OkHttpResponse *authv3.OkHttpResponse `cel:"http_response"` 23 | // Optional response metadata that will be emitted as dynamic metadata to be consumed by the next 24 | // filter. This metadata lives in a namespace specified by the canonical name of extension filter 25 | // that requires it: 26 | // 27 | // - :ref:`envoy.filters.http.ext_authz ` for HTTP filter. 28 | // - :ref:`envoy.filters.network.ext_authz ` for network filter. 29 | DynamicMetadata *structpb.Struct `cel:"dynamic_metadata"` 30 | } 31 | 32 | type DeniedResponse struct { 33 | // Status “OK“ allows the request. Any other status indicates the request should be denied, and 34 | // for HTTP filter, if not overridden by :ref:`denied HTTP response status ` 35 | // Envoy sends “403 Forbidden“ HTTP status code by default. 36 | Status *status.Status `cel:"status"` 37 | // An message that contains HTTP response attributes. This message is 38 | // used when the authorization service needs to send custom responses to the 39 | // downstream client or, to modify/add request headers being dispatched to the upstream. 40 | // 41 | // Types that are assignable to HttpResponse: 42 | // 43 | // *CheckResponse_DeniedResponse 44 | // *CheckResponse_OkResponse 45 | DeniedHttpResponse *authv3.DeniedHttpResponse `cel:"http_response"` 46 | // Optional response metadata that will be emitted as dynamic metadata to be consumed by the next 47 | // filter. This metadata lives in a namespace specified by the canonical name of extension filter 48 | // that requires it: 49 | // 50 | // - :ref:`envoy.filters.http.ext_authz ` for HTTP filter. 51 | // - :ref:`envoy.filters.network.ext_authz ` for network filter. 52 | DynamicMetadata *structpb.Struct `cel:"dynamic_metadata"` 53 | } 54 | -------------------------------------------------------------------------------- /pkg/authz/cel/libs/jwk/impl.go: -------------------------------------------------------------------------------- 1 | package jwk 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/google/cel-go/common/types" 7 | "github.com/google/cel-go/common/types/ref" 8 | "github.com/kyverno/kyverno-envoy-plugin/pkg/authz/cel/utils" 9 | "github.com/lestrrat-go/jwx/v3/jwk" 10 | ) 11 | 12 | type impl struct { 13 | types.Adapter 14 | } 15 | 16 | func (c *impl) fetch(from ref.Val) ref.Val { 17 | if from, err := utils.ConvertToNative[string](from); err != nil { 18 | return types.WrapErr(err) 19 | } else { 20 | set, err := jwk.Fetch(context.Background(), from) 21 | if err != nil { 22 | return types.WrapErr(err) 23 | } 24 | return c.NativeToValue(Set{set}) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /pkg/authz/cel/libs/jwk/lib.go: -------------------------------------------------------------------------------- 1 | package jwk 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/google/cel-go/cel" 7 | "github.com/google/cel-go/common/types" 8 | "github.com/google/cel-go/ext" 9 | ) 10 | 11 | type lib struct{} 12 | 13 | func Lib() cel.EnvOption { 14 | // create the cel lib env option 15 | return cel.Lib(&lib{}) 16 | } 17 | 18 | func (*lib) LibraryName() string { 19 | return "kyverno.jwk" 20 | } 21 | 22 | func (c *lib) CompileOptions() []cel.EnvOption { 23 | return []cel.EnvOption{ 24 | // register native types 25 | ext.NativeTypes(reflect.TypeFor[Set]()), 26 | // extend environment with function overloads 27 | c.extendEnv, 28 | } 29 | } 30 | 31 | func (*lib) ProgramOptions() []cel.ProgramOption { 32 | return []cel.ProgramOption{} 33 | } 34 | 35 | func (*lib) extendEnv(env *cel.Env) (*cel.Env, error) { 36 | // get env type adapter 37 | adapter := env.CELTypeAdapter() 38 | // create implementation with adapter 39 | impl := impl{adapter} 40 | // build our function overloads 41 | libraryDecls := map[string][]cel.FunctionOpt{ 42 | "jwks.Fetch": { 43 | cel.Overload("fetch_string", []*cel.Type{types.StringType}, SetType, cel.UnaryBinding(impl.fetch)), 44 | }, 45 | } 46 | // create env options corresponding to our function overloads 47 | options := []cel.EnvOption{} 48 | for name, overloads := range libraryDecls { 49 | options = append(options, cel.Function(name, overloads...)) 50 | } 51 | // extend environment with our function overloads 52 | return env.Extend(options...) 53 | } 54 | -------------------------------------------------------------------------------- /pkg/authz/cel/libs/jwk/lib_test.go: -------------------------------------------------------------------------------- 1 | package jwk 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/google/cel-go/cel" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func Test_fetch(t *testing.T) { 11 | // { 12 | // jwks := ` 13 | // { 14 | // "keys": [ 15 | // { 16 | // "alg": "ES256", 17 | // "crv": "P-256", 18 | // "kid": "my-key-id", 19 | // "kty": "EC", 20 | // "use": "sig", 21 | // "x": "iTV4PECbWuDaNBMTLmwH0jwBTD3xUXR0S-VWsCYv8Gc", 22 | // "y": "-Cnw8d0XyQztrPZpynrFn8t10lyEb6oWqWcLJWPUB5A" 23 | // } 24 | // ] 25 | // }` 26 | // set, err := jwk.Parse([]byte(jwks)) 27 | // assert.NoError(t, err) 28 | // token := "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJwa2kuZXhhbXBsZS5jb20ifQ.ViJTHHv5FuJM9LsRrTpzts6tZkN8deKiu5x49-M8-nq6Rs6ta-Wn8fN_YVLlpZvwhFu_yfxpfUGhBRc33QSSsw" 29 | // tok, err := jwt.Parse([]byte(token), jwt.WithKeySet(set, jws.WithUseDefault(true) /*, jws.WithRequireKid(false)*/)) 30 | // assert.NoError(t, err) 31 | // assert.NotNil(t, tok) 32 | // } 33 | env, err := cel.NewEnv( 34 | Lib(), 35 | ) 36 | assert.NoError(t, err) 37 | ast, issues := env.Compile("jwks.Fetch('https://www.googleapis.com/oauth2/v3/certs')") 38 | assert.NoError(t, issues.Err()) 39 | prog, err := env.Program(ast) 40 | assert.NoError(t, err) 41 | jwks, _, err := prog.Eval(map[string]any{}) 42 | assert.NoError(t, err) 43 | assert.NotNil(t, jwks.Value()) 44 | } 45 | -------------------------------------------------------------------------------- /pkg/authz/cel/libs/jwk/types.go: -------------------------------------------------------------------------------- 1 | package jwk 2 | 3 | import ( 4 | "github.com/google/cel-go/common/types" 5 | "github.com/lestrrat-go/jwx/v3/jwk" 6 | ) 7 | 8 | var SetType = types.NewOpaqueType("jwk.Set") 9 | 10 | type Set struct { 11 | jwk.Set 12 | } 13 | -------------------------------------------------------------------------------- /pkg/authz/cel/libs/jwt/lib.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/google/cel-go/cel" 7 | "github.com/google/cel-go/common/types" 8 | "github.com/google/cel-go/ext" 9 | "github.com/kyverno/kyverno-envoy-plugin/pkg/authz/cel/libs/jwk" 10 | ) 11 | 12 | type lib struct{} 13 | 14 | func Lib() cel.EnvOption { 15 | // create the cel lib env option 16 | return cel.Lib(&lib{}) 17 | } 18 | 19 | func (*lib) LibraryName() string { 20 | return "kyverno.jwt" 21 | } 22 | 23 | func (c *lib) CompileOptions() []cel.EnvOption { 24 | return []cel.EnvOption{ 25 | // register jwk lib 26 | jwk.Lib(), 27 | // register token type 28 | ext.NativeTypes(reflect.TypeFor[Token]()), 29 | // extend environment with function overloads 30 | c.extendEnv, 31 | } 32 | } 33 | 34 | func (*lib) ProgramOptions() []cel.ProgramOption { 35 | return []cel.ProgramOption{} 36 | } 37 | 38 | func (*lib) extendEnv(env *cel.Env) (*cel.Env, error) { 39 | // get env type adapter 40 | adapter := env.CELTypeAdapter() 41 | // create implementation with adapter 42 | impl := impl{adapter} 43 | // build our function overloads 44 | libraryDecls := map[string][]cel.FunctionOpt{ 45 | "jwt.Decode": { 46 | cel.Overload("decode_string_string", []*cel.Type{types.StringType, types.StringType}, TokenType, cel.BinaryBinding(impl.decode_string_string)), 47 | cel.Overload("decode_string_set", []*cel.Type{types.StringType, jwk.SetType}, TokenType, cel.BinaryBinding(impl.decode_string_set)), 48 | }, 49 | } 50 | // create env options corresponding to our function overloads 51 | options := []cel.EnvOption{} 52 | for name, overloads := range libraryDecls { 53 | options = append(options, cel.Function(name, overloads...)) 54 | } 55 | // extend environment with our function overloads 56 | return env.Extend(options...) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/authz/cel/libs/jwt/token.go: -------------------------------------------------------------------------------- 1 | package jwt 2 | 3 | import ( 4 | "github.com/google/cel-go/common/types" 5 | "google.golang.org/protobuf/types/known/structpb" 6 | ) 7 | 8 | var TokenType = types.NewObjectType("jwt.Token") 9 | 10 | type Token struct { 11 | Claims *structpb.Struct 12 | Valid bool 13 | } 14 | -------------------------------------------------------------------------------- /pkg/authz/cel/utils/convert.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/google/cel-go/common/types/ref" 7 | ) 8 | 9 | func ConvertToNative[T any](value ref.Val) (T, error) { 10 | // try to convert value to native type 11 | response, err := value.ConvertToNative(reflect.TypeFor[T]()) 12 | // if it failed return default value for T and error 13 | if err != nil { 14 | var t T 15 | return t, err 16 | } 17 | // return the converted value 18 | return response.(T), nil 19 | } 20 | -------------------------------------------------------------------------------- /pkg/authz/cel/variables.go: -------------------------------------------------------------------------------- 1 | package cel 2 | 3 | import ( 4 | "github.com/google/cel-go/common/types" 5 | "github.com/google/cel-go/common/types/ref" 6 | ) 7 | 8 | var ( 9 | VariablesType = types.NewObjectType("kyverno.variables") 10 | variablesTypeType = types.NewTypeTypeWithParam(VariablesType) 11 | ) 12 | 13 | type variablesProvider struct { 14 | inner types.Provider 15 | fields map[string]*types.Type 16 | names []string 17 | } 18 | 19 | func NewVariablesProvider(inner types.Provider) *variablesProvider { 20 | return &variablesProvider{ 21 | inner: inner, 22 | fields: make(map[string]*types.Type), 23 | } 24 | } 25 | 26 | func (p *variablesProvider) RegisterField(name string, t *types.Type) { 27 | p.fields[name] = t 28 | p.names = append(p.names, name) 29 | } 30 | 31 | func (p *variablesProvider) EnumValue(enumName string) ref.Val { 32 | return p.inner.EnumValue(enumName) 33 | } 34 | 35 | func (p *variablesProvider) FindIdent(identName string) (ref.Val, bool) { 36 | return p.inner.FindIdent(identName) 37 | } 38 | 39 | func (p *variablesProvider) FindStructType(structType string) (*types.Type, bool) { 40 | if structType == VariablesType.DeclaredTypeName() { 41 | return variablesTypeType, true 42 | } 43 | return p.inner.FindStructType(structType) 44 | } 45 | 46 | func (p *variablesProvider) FindStructFieldNames(structType string) ([]string, bool) { 47 | if structType == VariablesType.DeclaredTypeName() { 48 | return p.names, true 49 | } 50 | return p.inner.FindStructFieldNames(structType) 51 | } 52 | 53 | func (p *variablesProvider) FindStructFieldType(structType, fieldName string) (*types.FieldType, bool) { 54 | if structType == VariablesType.DeclaredTypeName() { 55 | if t, ok := p.fields[fieldName]; ok { 56 | return &types.FieldType{ 57 | Type: t, 58 | }, true 59 | } 60 | return nil, false 61 | } 62 | return p.inner.FindStructFieldType(structType, fieldName) 63 | } 64 | 65 | func (p *variablesProvider) NewValue(structType string, fields map[string]ref.Val) ref.Val { 66 | return p.inner.NewValue(structType, fields) 67 | } 68 | -------------------------------------------------------------------------------- /pkg/authz/server.go: -------------------------------------------------------------------------------- 1 | package authz 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" 8 | "github.com/kyverno/kyverno-envoy-plugin/pkg/policy" 9 | "github.com/kyverno/kyverno-envoy-plugin/pkg/server" 10 | "google.golang.org/grpc" 11 | ) 12 | 13 | func NewServer(network, addr string, provider policy.Provider) server.ServerFunc { 14 | return func(ctx context.Context) error { 15 | // create a server 16 | s := grpc.NewServer() 17 | // setup our authorization service 18 | svc := &service{ 19 | provider: provider, 20 | } 21 | // register our authorization service 22 | authv3.RegisterAuthorizationServer(s, svc) 23 | // create a listener 24 | l, err := net.Listen(network, addr) 25 | if err != nil { 26 | return err 27 | } 28 | // run server 29 | return server.RunGrpc(ctx, s, l) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /pkg/authz/service.go: -------------------------------------------------------------------------------- 1 | package authz 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" 8 | "github.com/kyverno/kyverno-envoy-plugin/pkg/policy" 9 | ) 10 | 11 | type service struct { 12 | provider policy.Provider 13 | } 14 | 15 | func (s *service) Check(ctx context.Context, r *authv3.CheckRequest) (*authv3.CheckResponse, error) { 16 | // execute check 17 | response, err := s.check(ctx, r) 18 | // log error if any 19 | if err != nil { 20 | fmt.Println(err) 21 | } 22 | // return response and error 23 | return response, err 24 | } 25 | 26 | func (s *service) check(ctx context.Context, r *authv3.CheckRequest) (*authv3.CheckResponse, error) { 27 | // fetch compiled policies 28 | policies, err := s.provider.CompiledPolicies(ctx) 29 | if err != nil { 30 | return nil, err 31 | } 32 | // TODO: eliminate allocations 33 | allow := make([]policy.AllowFunc, 0, len(policies)) 34 | deny := make([]policy.DenyFunc, 0, len(policies)) 35 | // iterate over policies 36 | for _, policy := range policies { 37 | // collect allow/deny 38 | a, d := policy.For(r) 39 | allow = append(allow, a) 40 | deny = append(deny, d) 41 | } 42 | // check deny first 43 | for _, deny := range deny { 44 | // execute rule 45 | response, err := deny() 46 | // return error if any 47 | if err != nil { 48 | return nil, err 49 | } 50 | // if the reponse returned by the rule evaluation was not nil, return 51 | if response != nil { 52 | return response, nil 53 | } 54 | } 55 | // check allow 56 | for _, allow := range allow { 57 | // execute rule 58 | response, err := allow() 59 | // return error if any 60 | if err != nil { 61 | return nil, err 62 | } 63 | // if the reponse returned by the rule evaluation was not nil, return 64 | if response != nil { 65 | return response, nil 66 | } 67 | } 68 | // we didn't have a response 69 | return &authv3.CheckResponse{}, nil 70 | } 71 | -------------------------------------------------------------------------------- /pkg/commands/root/command.go: -------------------------------------------------------------------------------- 1 | package root 2 | 3 | import ( 4 | "github.com/kyverno/kyverno-envoy-plugin/pkg/commands/serve" 5 | "github.com/spf13/cobra" 6 | ) 7 | 8 | func Command() *cobra.Command { 9 | root := &cobra.Command{ 10 | Use: "kyverno-envoy-plugin", 11 | Short: "kyverno-envoy-plugin is a plugin for Envoy", 12 | } 13 | root.AddCommand(serve.Command()) 14 | return root 15 | } 16 | -------------------------------------------------------------------------------- /pkg/commands/serve/command.go: -------------------------------------------------------------------------------- 1 | package serve 2 | 3 | import ( 4 | authzserver "github.com/kyverno/kyverno-envoy-plugin/pkg/commands/serve/authz-server" 5 | sidecarinjector "github.com/kyverno/kyverno-envoy-plugin/pkg/commands/serve/sidecar-injector" 6 | validationwebhook "github.com/kyverno/kyverno-envoy-plugin/pkg/commands/serve/validation-webhook" 7 | "github.com/spf13/cobra" 8 | ) 9 | 10 | func Command() *cobra.Command { 11 | command := &cobra.Command{ 12 | Use: "serve", 13 | Short: "Run Kyverno Envoy Plugin servers", 14 | } 15 | command.AddCommand(authzserver.Command()) 16 | command.AddCommand(sidecarinjector.Command()) 17 | command.AddCommand(validationwebhook.Command()) 18 | return command 19 | } 20 | -------------------------------------------------------------------------------- /pkg/commands/serve/sidecar-injector/command.go: -------------------------------------------------------------------------------- 1 | package sidecarinjector 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/kyverno/kyverno-envoy-plugin/pkg/signals" 7 | "github.com/kyverno/kyverno-envoy-plugin/pkg/webhook/mutation" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | func Command() *cobra.Command { 12 | var address string 13 | var certFile string 14 | var keyFile string 15 | var sidecarImage string 16 | command := &cobra.Command{ 17 | Use: "sidecar-injector", 18 | Short: "Start the Kubernetes mutating webhook injecting Kyverno Authz Server sidecars into pod containers", 19 | RunE: func(cmd *cobra.Command, args []string) error { 20 | // setup signals aware context 21 | return signals.Do(context.Background(), func(ctx context.Context) error { 22 | // create server 23 | http := mutation.NewSidecarInjectorServer(address, sidecarImage, certFile, keyFile) 24 | // run server 25 | return http.Run(ctx) 26 | }) 27 | }, 28 | } 29 | command.Flags().StringVar(&address, "address", ":9443", "Address to listen on") 30 | command.Flags().StringVar(&certFile, "cert-file", "", "File containing tls certificate") 31 | command.Flags().StringVar(&keyFile, "key-file", "", "File containing tls private key") 32 | command.Flags().StringVar(&sidecarImage, "sidecar-image", "", "Image to use in sidecar") 33 | return command 34 | } 35 | -------------------------------------------------------------------------------- /pkg/policy/provider.go: -------------------------------------------------------------------------------- 1 | package policy 2 | 3 | import ( 4 | "cmp" 5 | "context" 6 | "fmt" 7 | "slices" 8 | "sync" 9 | 10 | "github.com/kyverno/kyverno-envoy-plugin/apis/v1alpha1" 11 | "golang.org/x/exp/maps" 12 | "k8s.io/apimachinery/pkg/api/errors" 13 | ctrl "sigs.k8s.io/controller-runtime" 14 | "sigs.k8s.io/controller-runtime/pkg/client" 15 | ) 16 | 17 | type Provider interface { 18 | CompiledPolicies(context.Context) ([]CompiledPolicy, error) 19 | } 20 | 21 | func NewKubeProvider(mgr ctrl.Manager, compiler Compiler) (Provider, error) { 22 | r := newPolicyReconciler(mgr.GetClient(), compiler) 23 | if err := ctrl.NewControllerManagedBy(mgr).For(&v1alpha1.AuthorizationPolicy{}).Complete(r); err != nil { 24 | return nil, fmt.Errorf("failed to construct manager: %w", err) 25 | } 26 | return r, nil 27 | } 28 | 29 | type policyReconciler struct { 30 | client client.Client 31 | compiler Compiler 32 | lock *sync.Mutex 33 | policies map[string]CompiledPolicy 34 | sortPolicies func() []CompiledPolicy 35 | } 36 | 37 | func newPolicyReconciler(client client.Client, compiler Compiler) *policyReconciler { 38 | return &policyReconciler{ 39 | client: client, 40 | compiler: compiler, 41 | lock: &sync.Mutex{}, 42 | policies: map[string]CompiledPolicy{}, 43 | sortPolicies: func() []CompiledPolicy { 44 | return nil 45 | }, 46 | } 47 | } 48 | 49 | func mapToSortedSlice[K cmp.Ordered, V any](in map[K]V) []V { 50 | if in == nil { 51 | return nil 52 | } 53 | out := make([]V, 0, len(in)) 54 | keys := maps.Keys(in) 55 | slices.Sort(keys) 56 | for _, key := range keys { 57 | out = append(out, in[key]) 58 | } 59 | return out 60 | } 61 | 62 | func (r *policyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { 63 | var policy v1alpha1.AuthorizationPolicy 64 | // Reset the sorted func on every reconcile so the policies get resorted in next call 65 | resetSortPolicies := func() { 66 | r.sortPolicies = sync.OnceValue(func() []CompiledPolicy { 67 | r.lock.Lock() 68 | defer r.lock.Unlock() 69 | return mapToSortedSlice(r.policies) 70 | }) 71 | } 72 | err := r.client.Get(ctx, req.NamespacedName, &policy) 73 | if errors.IsNotFound(err) { 74 | r.lock.Lock() 75 | defer r.lock.Unlock() 76 | defer resetSortPolicies() 77 | delete(r.policies, req.String()) 78 | return ctrl.Result{}, nil 79 | } 80 | if err != nil { 81 | return ctrl.Result{}, err 82 | } 83 | compiled, errs := r.compiler.Compile(&policy) 84 | if len(errs) > 0 { 85 | fmt.Println(errs) 86 | // No need to retry it 87 | return ctrl.Result{}, nil 88 | } 89 | r.lock.Lock() 90 | defer r.lock.Unlock() 91 | r.policies[req.String()] = compiled 92 | resetSortPolicies() 93 | return ctrl.Result{}, nil 94 | } 95 | 96 | func (r *policyReconciler) CompiledPolicies(ctx context.Context) ([]CompiledPolicy, error) { 97 | return slices.Clone(r.sortPolicies()), nil 98 | } 99 | -------------------------------------------------------------------------------- /pkg/probes/server.go: -------------------------------------------------------------------------------- 1 | package probes 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/kyverno/kyverno-envoy-plugin/pkg/server" 8 | "github.com/kyverno/kyverno-envoy-plugin/pkg/server/handlers" 9 | ) 10 | 11 | func NewServer(addr string) server.ServerFunc { 12 | return func(ctx context.Context) error { 13 | // create mux 14 | mux := http.NewServeMux() 15 | // register health check 16 | mux.Handle("GET /livez", handlers.Healthy(True)) 17 | // register ready check 18 | mux.Handle("GET /readyz", handlers.Ready(True)) 19 | // create server 20 | s := &http.Server{ 21 | Addr: addr, 22 | Handler: mux, 23 | } 24 | // run server 25 | return server.RunHttp(ctx, s, "", "") 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pkg/probes/true.go: -------------------------------------------------------------------------------- 1 | package probes 2 | 3 | func True() bool { 4 | return true 5 | } 6 | -------------------------------------------------------------------------------- /pkg/server/grpc.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | 8 | "google.golang.org/grpc" 9 | "k8s.io/apimachinery/pkg/util/wait" 10 | ) 11 | 12 | func RunGrpc(ctx context.Context, server *grpc.Server, listener net.Listener) error { 13 | defer fmt.Println("GRPC Server stopped") 14 | // create a wait group 15 | var group wait.Group 16 | // wait all tasks in the group are over 17 | defer group.Wait() 18 | // create a cancellable context 19 | ctx, cancel := context.WithCancel(ctx) 20 | // cancel context at the end 21 | defer cancel() 22 | // shutdown server when context is cancelled 23 | group.StartWithContext(ctx, func(ctx context.Context) { 24 | // wait context cancelled 25 | <-ctx.Done() 26 | fmt.Println("GRPC Server shutting down...") 27 | // gracefully shutdown server 28 | server.GracefulStop() 29 | }) 30 | fmt.Printf("GRPC Server starting at %s...\n", listener.Addr()) 31 | // serve 32 | return server.Serve(listener) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/server/handlers/admission.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "errors" 7 | "io" 8 | "net/http" 9 | 10 | "gomodules.xyz/jsonpatch/v2" 11 | admissionv1 "k8s.io/api/admission/v1" 12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | "k8s.io/utils/ptr" 14 | ) 15 | 16 | func AdmissionResponse(r *admissionv1.AdmissionRequest, err error, patch ...jsonpatch.Operation) *admissionv1.AdmissionResponse { 17 | response := admissionv1.AdmissionResponse{ 18 | UID: r.UID, 19 | } 20 | var patchBytes []byte 21 | if err == nil { 22 | if len(patch) != 0 { 23 | patchBytes, err = json.Marshal(patch) 24 | } 25 | } 26 | if err != nil { 27 | response.Allowed = false 28 | response.Result = &metav1.Status{ 29 | Status: metav1.StatusFailure, 30 | Message: err.Error(), 31 | } 32 | } else { 33 | response.Allowed = true 34 | response.Result = &metav1.Status{ 35 | Status: metav1.StatusSuccess, 36 | } 37 | if patchBytes != nil { 38 | response.PatchType = ptr.To(admissionv1.PatchTypeJSONPatch) 39 | response.Patch = patchBytes 40 | } 41 | } 42 | return &response 43 | } 44 | 45 | func AdmissionReview(inner func(context.Context, *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse) http.HandlerFunc { 46 | return func(w http.ResponseWriter, r *http.Request) { 47 | if r.Body == nil { 48 | HttpError(r.Context(), w, r, errors.New("empty body"), http.StatusBadRequest) 49 | return 50 | } 51 | defer r.Body.Close() //nolint:errcheck 52 | body, err := io.ReadAll(r.Body) 53 | if err != nil { 54 | HttpError(r.Context(), w, r, err, http.StatusBadRequest) 55 | return 56 | } 57 | contentType := r.Header.Get("Content-Type") 58 | if contentType != "application/json" { 59 | HttpError(r.Context(), w, r, errors.New("invalid Content-Type"), http.StatusUnsupportedMediaType) 60 | return 61 | } 62 | var admissionReview admissionv1.AdmissionReview 63 | if err := json.Unmarshal(body, &admissionReview); err != nil { 64 | HttpError(r.Context(), w, r, err, http.StatusExpectationFailed) 65 | return 66 | } 67 | admissionResponse := inner(r.Context(), admissionReview.Request) 68 | admissionReview.Response = admissionResponse 69 | responseJSON, err := json.Marshal(admissionReview) 70 | if err != nil { 71 | HttpError(r.Context(), w, r, err, http.StatusInternalServerError) 72 | return 73 | } 74 | w.Header().Set("Content-Type", "application/json; charset=utf-8") 75 | if _, err := w.Write(responseJSON); err != nil { 76 | HttpError(r.Context(), w, r, err, http.StatusInternalServerError) 77 | return 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /pkg/server/handlers/error.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | ) 7 | 8 | func HttpError(ctx context.Context, writer http.ResponseWriter, request *http.Request, err error, code int) { 9 | // logger.Error(err, "an error has occurred", "url", request.URL.String()) 10 | http.Error(writer, err.Error(), code) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/server/handlers/healthy.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func Healthy(f func() bool) http.HandlerFunc { 8 | return func(w http.ResponseWriter, r *http.Request) { 9 | code := http.StatusOK 10 | if !f() { 11 | code = http.StatusInternalServerError 12 | } 13 | w.WriteHeader(code) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pkg/server/handlers/ready.go: -------------------------------------------------------------------------------- 1 | package handlers 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func Ready(f func() bool) http.HandlerFunc { 8 | return func(w http.ResponseWriter, r *http.Request) { 9 | code := http.StatusOK 10 | if !f() { 11 | code = http.StatusInternalServerError 12 | } 13 | w.WriteHeader(code) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pkg/server/http.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "net/http" 8 | "time" 9 | 10 | "go.uber.org/multierr" 11 | "k8s.io/apimachinery/pkg/util/wait" 12 | ) 13 | 14 | func RunHttp(ctx context.Context, server *http.Server, certFile, keyFile string) error { 15 | defer fmt.Println("HTTP Server stopped") 16 | // track shutdown error 17 | var shutdownErr error 18 | // track serve error 19 | serveErr := func(ctx context.Context) error { 20 | // create a wait group 21 | var group wait.Group 22 | // wait all tasks in the group are over 23 | defer group.Wait() 24 | // create a cancellable context 25 | ctx, cancel := context.WithCancel(ctx) 26 | // cancel context at the end 27 | defer cancel() 28 | // shutdown server when context is cancelled 29 | group.StartWithContext(ctx, func(ctx context.Context) { 30 | // wait context cancelled 31 | <-ctx.Done() 32 | fmt.Println("HTTP Server shutting down...") 33 | // create a context with timeout 34 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 35 | defer cancel() 36 | // gracefully shutdown server 37 | shutdownErr = server.Shutdown(ctx) 38 | }) 39 | serve := func() error { 40 | fmt.Printf("HTTP Server starting at %s...\n", server.Addr) 41 | if certFile != "" && keyFile != "" { 42 | // server over https 43 | return server.ListenAndServeTLS(certFile, keyFile) 44 | } else { 45 | // server over http 46 | return server.ListenAndServe() 47 | } 48 | } 49 | // server closed is not an error 50 | if err := serve(); !errors.Is(err, http.ErrServerClosed) { 51 | return err 52 | } 53 | return nil 54 | }(ctx) 55 | // return error if any 56 | return multierr.Combine(serveErr, shutdownErr) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type Server interface { 8 | Run(context.Context) error 9 | } 10 | 11 | type ServerFunc func(context.Context) error 12 | 13 | func (f ServerFunc) Run(ctx context.Context) error { 14 | return f(ctx) 15 | } 16 | -------------------------------------------------------------------------------- /pkg/sidecar/sidecar.go: -------------------------------------------------------------------------------- 1 | package sidecar 2 | 3 | import ( 4 | corev1 "k8s.io/api/core/v1" 5 | ) 6 | 7 | func Sidecar(image string) corev1.Container { 8 | return corev1.Container{ 9 | Name: "kyverno-authz-server", 10 | ImagePullPolicy: corev1.PullIfNotPresent, 11 | Image: image, 12 | Ports: []corev1.ContainerPort{{ 13 | Name: "http", 14 | Protocol: corev1.ProtocolTCP, 15 | ContainerPort: 9080, 16 | }, { 17 | Name: "grpc", 18 | Protocol: corev1.ProtocolTCP, 19 | ContainerPort: 9081, 20 | }}, 21 | Args: []string{ 22 | "serve", 23 | "authz-server", 24 | "--probes-address=:9080", 25 | "--grpc-address=:9081", 26 | }, 27 | } 28 | } 29 | 30 | func Inject(pod corev1.Pod, container corev1.Container) corev1.Pod { 31 | for i, c := range pod.Spec.Containers { 32 | if c.Name == container.Name { 33 | pod.Spec.Containers[i] = container 34 | return pod 35 | } 36 | } 37 | pod.Spec.Containers = append(pod.Spec.Containers, container) 38 | return pod 39 | } 40 | -------------------------------------------------------------------------------- /pkg/sidecar/sidecar_test.go: -------------------------------------------------------------------------------- 1 | package sidecar 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | corev1 "k8s.io/api/core/v1" 8 | ) 9 | 10 | func TestSidecar(t *testing.T) { 11 | tests := []struct { 12 | name string 13 | image string 14 | want corev1.Container 15 | }{{ 16 | image: "foo:bar", 17 | want: corev1.Container{ 18 | Name: "kyverno-authz-server", 19 | ImagePullPolicy: corev1.PullIfNotPresent, 20 | Image: "foo:bar", 21 | Ports: []corev1.ContainerPort{{ 22 | Name: "http", 23 | Protocol: corev1.ProtocolTCP, 24 | ContainerPort: 9080, 25 | }, { 26 | Name: "grpc", 27 | Protocol: corev1.ProtocolTCP, 28 | ContainerPort: 9081, 29 | }}, 30 | Args: []string{ 31 | "serve", 32 | "authz-server", 33 | "--probes-address=:9080", 34 | "--grpc-address=:9081", 35 | }, 36 | }, 37 | }} 38 | for _, tt := range tests { 39 | t.Run(tt.name, func(t *testing.T) { 40 | got := Sidecar(tt.image) 41 | assert.Equal(t, tt.want, got) 42 | }) 43 | } 44 | } 45 | 46 | func TestInject(t *testing.T) { 47 | sidecar := Sidecar("foo:bar") 48 | tests := []struct { 49 | name string 50 | pod corev1.Pod 51 | container corev1.Container 52 | want corev1.Pod 53 | }{{ 54 | name: "no containers", 55 | pod: corev1.Pod{}, 56 | container: sidecar, 57 | want: corev1.Pod{ 58 | Spec: corev1.PodSpec{ 59 | Containers: []corev1.Container{ 60 | sidecar, 61 | }, 62 | }, 63 | }, 64 | }, { 65 | name: "found", 66 | pod: corev1.Pod{ 67 | Spec: corev1.PodSpec{ 68 | Containers: []corev1.Container{ 69 | { 70 | Name: sidecar.Name, 71 | }, 72 | }, 73 | }, 74 | }, 75 | container: sidecar, 76 | want: corev1.Pod{ 77 | Spec: corev1.PodSpec{ 78 | Containers: []corev1.Container{ 79 | sidecar, 80 | }, 81 | }, 82 | }, 83 | }, { 84 | name: "not found", 85 | pod: corev1.Pod{ 86 | Spec: corev1.PodSpec{ 87 | Containers: []corev1.Container{ 88 | { 89 | Name: "not-" + sidecar.Name, 90 | }, 91 | }, 92 | }, 93 | }, 94 | container: sidecar, 95 | want: corev1.Pod{ 96 | Spec: corev1.PodSpec{ 97 | Containers: []corev1.Container{ 98 | { 99 | Name: "not-" + sidecar.Name, 100 | }, 101 | sidecar, 102 | }, 103 | }, 104 | }, 105 | }, 106 | } 107 | for _, tt := range tests { 108 | t.Run(tt.name, func(t *testing.T) { 109 | got := Inject(tt.pod, tt.container) 110 | assert.Equal(t, tt.want, got) 111 | }) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /pkg/signals/context.go: -------------------------------------------------------------------------------- 1 | package signals 2 | 3 | import ( 4 | "context" 5 | "os/signal" 6 | "syscall" 7 | 8 | "k8s.io/apimachinery/pkg/util/wait" 9 | ) 10 | 11 | func Context(ctx context.Context) (context.Context, context.CancelFunc) { 12 | return signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) 13 | } 14 | 15 | func Do(ctx context.Context, callback func(context.Context) error) error { 16 | // create a wait group 17 | var group wait.Group 18 | // wait all tasks in the group are over 19 | defer group.Wait() 20 | // create a signal aware context 21 | ctx, stop := Context(ctx) 22 | // cancel context and restore signals behaviour 23 | defer stop() 24 | // wait until context is cancelled or signals are triggered 25 | group.StartWithContext(ctx, func(ctx context.Context) { 26 | // restore signals behaviour (context has been cancelled at this point) 27 | defer stop() 28 | // wait signals are triggered 29 | <-ctx.Done() 30 | }) 31 | // invoke callback with signals aware context 32 | return callback(ctx) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/signals/context_test.go: -------------------------------------------------------------------------------- 1 | package signals 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestDo(t *testing.T) { 12 | { 13 | err := Do(context.Background(), func(ctx context.Context) error { 14 | return nil 15 | }) 16 | assert.NoError(t, err) 17 | } 18 | { 19 | err := Do(context.Background(), func(ctx context.Context) error { 20 | return errors.New("dummy") 21 | }) 22 | assert.Error(t, err) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pkg/webhook/mutation/sidecar-injector.go: -------------------------------------------------------------------------------- 1 | package mutation 2 | 3 | import ( 4 | "context" 5 | "crypto/tls" 6 | "encoding/json" 7 | "net/http" 8 | "time" 9 | 10 | "github.com/kyverno/kyverno-envoy-plugin/pkg/probes" 11 | "github.com/kyverno/kyverno-envoy-plugin/pkg/server" 12 | "github.com/kyverno/kyverno-envoy-plugin/pkg/server/handlers" 13 | "github.com/kyverno/kyverno-envoy-plugin/pkg/sidecar" 14 | "gomodules.xyz/jsonpatch/v2" 15 | admissionv1 "k8s.io/api/admission/v1" 16 | corev1 "k8s.io/api/core/v1" 17 | ) 18 | 19 | func NewSidecarInjectorServer(addr, sidecarImage, certFile, keyFile string) server.ServerFunc { 20 | return func(ctx context.Context) error { 21 | // create mux 22 | mux := http.NewServeMux() 23 | // register health check 24 | mux.Handle("GET /livez", handlers.Healthy(probes.True)) 25 | // register ready check 26 | mux.Handle("GET /readyz", handlers.Ready(probes.True)) 27 | // register mutation webhook 28 | mux.Handle("/mutate", handlers.AdmissionReview(func(ctx context.Context, r *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse { 29 | var pod corev1.Pod 30 | if err := json.Unmarshal(r.Object.Raw, &pod); err != nil { 31 | return handlers.AdmissionResponse(r, err) 32 | } 33 | pod = sidecar.Inject(pod, sidecar.Sidecar(sidecarImage)) 34 | if data, err := json.Marshal(&pod); err != nil { 35 | return handlers.AdmissionResponse(r, err) 36 | } else if patch, err := jsonpatch.CreatePatch(r.Object.Raw, data); err != nil { 37 | return handlers.AdmissionResponse(r, err) 38 | } else { 39 | return handlers.AdmissionResponse(r, nil, patch...) 40 | } 41 | })) 42 | // create server 43 | s := &http.Server{ 44 | Addr: addr, 45 | Handler: mux, 46 | TLSConfig: &tls.Config{ 47 | MinVersion: tls.VersionTLS12, 48 | CipherSuites: []uint16{ 49 | // AEADs w/ ECDHE 50 | tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 51 | tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 52 | tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 53 | tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 54 | tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 55 | tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 56 | }, 57 | }, 58 | ReadTimeout: 30 * time.Second, 59 | WriteTimeout: 30 * time.Second, 60 | ReadHeaderTimeout: 30 * time.Second, 61 | IdleTimeout: 5 * time.Minute, 62 | } 63 | // run server 64 | return server.RunHttp(ctx, s, certFile, keyFile) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/webhook/validation/validator.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/kyverno/kyverno-envoy-plugin/apis/v1alpha1" 8 | apierrors "k8s.io/apimachinery/pkg/api/errors" 9 | "k8s.io/apimachinery/pkg/runtime" 10 | "k8s.io/apimachinery/pkg/util/validation/field" 11 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission" 12 | ) 13 | 14 | func NewValidator(compile func(*v1alpha1.AuthorizationPolicy) field.ErrorList) *validator { 15 | return &validator{ 16 | compile: compile, 17 | } 18 | } 19 | 20 | type validator struct { 21 | compile func(*v1alpha1.AuthorizationPolicy) field.ErrorList 22 | } 23 | 24 | func (v *validator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { 25 | policy, ok := obj.(*v1alpha1.AuthorizationPolicy) 26 | if !ok { 27 | return nil, fmt.Errorf("expected an AuthorizationPolicy object but got %T", obj) 28 | } 29 | return nil, v.validate(policy) 30 | } 31 | 32 | func (v *validator) ValidateUpdate(ctx context.Context, oldObj, newObj runtime.Object) (admission.Warnings, error) { 33 | policy, ok := newObj.(*v1alpha1.AuthorizationPolicy) 34 | if !ok { 35 | return nil, fmt.Errorf("expected an AuthorizationPolicy object but got %T", newObj) 36 | } 37 | return nil, v.validate(policy) 38 | } 39 | 40 | func (*validator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { 41 | return nil, nil 42 | } 43 | 44 | func (v *validator) validate(policy *v1alpha1.AuthorizationPolicy) error { 45 | if allErrs := v.compile(policy); len(allErrs) > 0 { 46 | return apierrors.NewInvalid( 47 | v1alpha1.SchemeGroupVersion.WithKind("AuthorizationPolicy").GroupKind(), 48 | policy.Name, 49 | allErrs, 50 | ) 51 | } 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cairosvg 2 | lunr 3 | mike 4 | mkdocs 5 | mkdocs-include-markdown-plugin 6 | mkdocs-material 7 | mkdocs-minify-plugin 8 | mkdocs-redirects 9 | mkdocs-rss-plugin 10 | git+https://github.com/eddycharly/openapi2jsonschema.git@v3 11 | Pillow 12 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/allow/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: allow 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get -H "x-force-authorized: true" 26 | check: 27 | (wildcard('*http_code=200', $stdout)): true 28 | finally: 29 | - sleep: 30 | duration: 10s -------------------------------------------------------------------------------- /tests/e2e/authz-server/allow/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/allow/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | allow: 8 | - response: > 9 | envoy 10 | .Allowed() 11 | .Response() 12 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/allow/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/default/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: default 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get -H "x-force-authorized: true" 26 | check: 27 | (wildcard('*http_code=200', $stdout)): true 28 | finally: 29 | - sleep: 30 | duration: 10s -------------------------------------------------------------------------------- /tests/e2e/authz-server/default/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/default/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | deny: 8 | - match: > 9 | false 10 | response: > 11 | envoy 12 | .Denied(403) 13 | .WithBody("Unauthorized Request") 14 | .Response() 15 | allow: 16 | - match: > 17 | false 18 | response: > 19 | envoy 20 | .Allowed() 21 | .Response() 22 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/default/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/deny/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: deny 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get -H "x-force-authorized: true" 26 | check: 27 | ($stdout): |- 28 | Unauthorized Request 29 | http_code=403 30 | finally: 31 | - sleep: 32 | duration: 10s -------------------------------------------------------------------------------- /tests/e2e/authz-server/deny/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/deny/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | deny: 8 | - response: > 9 | envoy 10 | .Denied(403) 11 | .WithBody("Unauthorized Request") 12 | .Response() 13 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/deny/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-false/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: error-with-false 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get 26 | check: 27 | (wildcard('*http_code=200', $stdout)): true 28 | finally: 29 | - sleep: 30 | duration: 10s 31 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-false/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-false/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | failurePolicy: Fail 8 | matchConditions: 9 | - name: error 10 | expression: '(2 / 0) == 1' 11 | - name: 'false' 12 | expression: 'false' 13 | deny: 14 | - response: > 15 | envoy 16 | .Denied(403) 17 | .WithBody("Unauthorized Request") 18 | .Response() 19 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-false/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-true/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: error-with-true 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get 26 | check: 27 | (wildcard('*http_code=403', $stdout)): true 28 | finally: 29 | - sleep: 30 | duration: 10s 31 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-true/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-true/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | failurePolicy: Fail 8 | matchConditions: 9 | - name: error 10 | expression: '(2 / 0) == 1' 11 | - name: 'true' 12 | expression: 'true' 13 | deny: 14 | - response: > 15 | envoy 16 | .Denied(403) 17 | .WithBody("Unauthorized Request") 18 | .Response() 19 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-fail/error-with-true/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-false/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: error-with-false 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get 26 | check: 27 | (wildcard('*http_code=200', $stdout)): true 28 | finally: 29 | - sleep: 30 | duration: 10s 31 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-false/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-false/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | failurePolicy: Ignore 8 | matchConditions: 9 | - name: error 10 | expression: '(2 / 0) == 1' 11 | - name: 'false' 12 | expression: 'false' 13 | deny: 14 | - response: > 15 | envoy 16 | .Denied(403) 17 | .WithBody("Unauthorized Request") 18 | .Response() 19 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-false/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-true/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: error-with-true 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get 26 | check: 27 | (wildcard('*http_code=200', $stdout)): true 28 | finally: 29 | - sleep: 30 | duration: 10s 31 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-true/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-true/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | failurePolicy: Ignore 8 | matchConditions: 9 | - name: error 10 | expression: '(2 / 0) == 1' 11 | - name: 'true' 12 | expression: 'true' 13 | deny: 14 | - response: > 15 | envoy 16 | .Denied(403) 17 | .WithBody("Unauthorized Request") 18 | .Response() 19 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/match-conditions/failure-policy-ignore/error-with-true/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/policy-ordering/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: policy-ordering 5 | spec: 6 | namespace: app 7 | steps: 8 | - try: 9 | - create: 10 | file: ./istio-policy.yaml 11 | - create: 12 | file: ./policy-b.yaml 13 | - create: 14 | file: ./shell.yaml 15 | - wait: 16 | apiVersion: v1 17 | kind: Pod 18 | timeout: 1m 19 | for: 20 | condition: 21 | name: Ready 22 | value: 'true' 23 | - script: 24 | content: > 25 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get -H "x-force-authorized: true" 26 | check: 27 | ($stdout): |- 28 | Unauthorized Request from Policy B 29 | http_code=403 30 | - create: 31 | file: ./policy-a.yaml 32 | - script: 33 | content: > 34 | kubectl exec -n $NAMESPACE deploy/curl -- curl -s -w "\nhttp_code=%{http_code}" httpbin:8000/get -H "x-force-authorized: true" 35 | check: 36 | ($stdout): |- 37 | Unauthorized Request from Policy A 38 | http_code=403 39 | finally: 40 | - sleep: 41 | duration: 10s 42 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/policy-ordering/istio-policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: security.istio.io/v1 2 | kind: AuthorizationPolicy 3 | metadata: 4 | name: policy 5 | namespace: istio-system 6 | spec: 7 | selector: 8 | matchLabels: 9 | ext-authz: enabled 10 | action: CUSTOM 11 | provider: 12 | name: kyverno-authz-server 13 | rules: 14 | - {} 15 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/policy-ordering/policy-a.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy-a 6 | spec: 7 | deny: 8 | - response: > 9 | envoy 10 | .Denied(403) 11 | .WithBody("Unauthorized Request from Policy A") 12 | .Response() 13 | 14 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/policy-ordering/policy-b.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy-b 6 | spec: 7 | deny: 8 | - response: > 9 | envoy 10 | .Denied(403) 11 | .WithBody("Unauthorized Request from Policy B") 12 | .Response() 13 | 14 | -------------------------------------------------------------------------------- /tests/e2e/authz-server/policy-ordering/shell.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: curl 5 | --- 6 | apiVersion: v1 7 | kind: Service 8 | metadata: 9 | name: curl 10 | labels: 11 | app: curl 12 | service: curl 13 | spec: 14 | ports: 15 | - port: 80 16 | name: http 17 | selector: 18 | app: curl 19 | --- 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: curl 24 | spec: 25 | replicas: 1 26 | selector: 27 | matchLabels: 28 | app: curl 29 | template: 30 | metadata: 31 | labels: 32 | app: curl 33 | spec: 34 | terminationGracePeriodSeconds: 0 35 | serviceAccountName: curl 36 | containers: 37 | - name: curl 38 | image: curlimages/curl 39 | command: ["/bin/sleep", "infinity"] 40 | imagePullPolicy: IfNotPresent 41 | volumeMounts: 42 | - mountPath: /etc/curl/tls 43 | name: secret-volume 44 | volumes: 45 | - name: secret-volume 46 | secret: 47 | secretName: curl-secret 48 | optional: true 49 | -------------------------------------------------------------------------------- /tests/e2e/sidecar-injector/injected/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: injected 5 | spec: 6 | namespaceTemplate: 7 | metadata: 8 | labels: 9 | kyverno-injection: enabled 10 | steps: 11 | - try: 12 | - create: 13 | file: ./pod.yaml 14 | - assert: 15 | file: ./pod-assert.yaml 16 | -------------------------------------------------------------------------------- /tests/e2e/sidecar-injector/injected/pod-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod 5 | spec: 6 | containers: 7 | - name: busybox 8 | image: busybox 9 | args: 10 | - sleep 11 | - 1d 12 | - name: kyverno-authz-server 13 | -------------------------------------------------------------------------------- /tests/e2e/sidecar-injector/injected/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod 5 | spec: 6 | containers: 7 | - name: busybox 8 | image: busybox 9 | args: 10 | - sleep 11 | - 1d 12 | -------------------------------------------------------------------------------- /tests/e2e/sidecar-injector/not-injected/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: not-injected 5 | spec: 6 | namespaceTemplate: 7 | metadata: 8 | labels: 9 | kyverno-injection: disabled 10 | steps: 11 | - try: 12 | - create: 13 | file: ./pod.yaml 14 | - assert: 15 | file: ./pod-assert.yaml 16 | -------------------------------------------------------------------------------- /tests/e2e/sidecar-injector/not-injected/pod-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod 5 | spec: 6 | (length(containers)): 1 7 | -------------------------------------------------------------------------------- /tests/e2e/sidecar-injector/not-injected/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: pod 5 | spec: 6 | containers: 7 | - name: busybox 8 | image: busybox 9 | args: 10 | - sleep 11 | - 1d 12 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/match/compilation-failure/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: compilation-failure 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "compilation-failure" is invalid: spec.allow[0].match: Invalid value: "'flop' + 2\n": ERROR: :1:8: found no matching overload for '_+_' applied to '(string, int)' 14 | | 'flop' + 2 15 | | .......^ 16 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/match/compilation-failure/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: compilation-failure 6 | spec: 7 | allow: 8 | - match: > 9 | 'flop' + 2 10 | response: > 11 | envoy 12 | .Allowed() 13 | .Response() 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/match/invalid-output-type/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: invalid-output-type 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "invalid-output-type" is invalid: spec.allow[0].match: Invalid value: "'flop'\n": rule match output is expected to be of type bool 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/match/invalid-output-type/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: invalid-output-type 6 | spec: 7 | allow: 8 | - match: > 9 | 'flop' 10 | response: > 11 | envoy 12 | .Allowed() 13 | .Response() 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/match/valid/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: valid 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/match/valid/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: valid 6 | spec: 7 | allow: 8 | - match: > 9 | false 10 | response: > 11 | envoy 12 | .Allowed() 13 | .Response() 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/response/compilation-failure/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: compilation-failure 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "compilation-failure" is invalid: spec.allow[0].response: Invalid value: "envoy.Allowed() + 1\n": ERROR: :1:17: found no matching overload for '_+_' applied to '(envoy.service.auth.v3.OkHttpResponse, int)' 14 | | envoy.Allowed() + 1 15 | | ................^ 16 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/response/compilation-failure/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: compilation-failure 6 | spec: 7 | allow: 8 | - response: > 9 | envoy.Allowed() + 1 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/response/invalid-output-type/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: invalid-output-type 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "invalid-output-type" is invalid: spec.allow[0].response: Invalid value: "'bye'\n": rule response output is expected to be of type envoy.OkResponse 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/response/invalid-output-type/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: invalid-output-type 6 | spec: 7 | allow: 8 | - response: > 9 | 'bye' 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/response/valid/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: valid 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/allow/response/valid/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: valid 6 | spec: 7 | variables: 8 | - name: force_authorized 9 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 10 | - name: force_unauthenticated 11 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 12 | - name: metadata 13 | expression: '{"my-new-metadata": "my-new-value"}' 14 | deny: 15 | # if force_unauthenticated -> 401 16 | - match: > 17 | variables.force_unauthenticated 18 | response: > 19 | envoy 20 | .Denied(401) 21 | .WithBody("Authentication Failed") 22 | .Response() 23 | # if not force_authorized -> 403 24 | - match: > 25 | !variables.force_authorized 26 | response: > 27 | envoy 28 | .Denied(403) 29 | .WithBody("Unauthorized Request") 30 | .Response() 31 | allow: 32 | # else -> 200 33 | - response: > 34 | envoy 35 | .Allowed() 36 | .WithHeader("x-validated-by", "my-security-checkpoint") 37 | .WithoutHeader("x-force-authorized") 38 | .WithResponseHeader("x-add-custom-response-header", "added") 39 | .Response() 40 | .WithMetadata(variables.metadata) 41 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/match/compilation-failure/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: compilation-failure 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "compilation-failure" is invalid: spec.deny[0].match: Invalid value: "'flop' + 2\n": ERROR: :1:8: found no matching overload for '_+_' applied to '(string, int)' 14 | | 'flop' + 2 15 | | .......^ 16 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/match/compilation-failure/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: compilation-failure 6 | spec: 7 | deny: 8 | - match: > 9 | 'flop' + 2 10 | response: > 11 | envoy 12 | .Denied(403) 13 | .WithBody("Unauthorized Request") 14 | .Response() 15 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/match/invalid-output-type/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: invalid-output-type 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "invalid-output-type" is invalid: spec.deny[0].match: Invalid value: "'flop'\n": rule match output is expected to be of type bool 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/match/invalid-output-type/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: invalid-output-type 6 | spec: 7 | deny: 8 | - match: > 9 | 'flop' 10 | response: > 11 | envoy 12 | .Denied(403) 13 | .WithBody("Unauthorized Request") 14 | .Response() 15 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/match/valid/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: valid 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/match/valid/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: valid 6 | spec: 7 | deny: 8 | - match: > 9 | false 10 | response: > 11 | envoy 12 | .Denied(403) 13 | .WithBody("Unauthorized Request") 14 | .Response() 15 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/response/compilation-failure/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: compilation-failure 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "compilation-failure" is invalid: spec.deny[0].response: Invalid value: "envoy.Allowed() + 1\n": ERROR: :1:17: found no matching overload for '_+_' applied to '(envoy.service.auth.v3.OkHttpResponse, int)' 14 | | envoy.Allowed() + 1 15 | | ................^ 16 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/response/compilation-failure/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: compilation-failure 6 | spec: 7 | deny: 8 | - response: > 9 | envoy.Allowed() + 1 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/response/invalid-output-type/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: invalid-output-type 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "invalid-output-type" is invalid: spec.deny[0].response: Invalid value: "'bye'\n": rule response output is expected to be of type envoy.DeniedResponse 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/response/invalid-output-type/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: invalid-output-type 6 | spec: 7 | deny: 8 | - response: > 9 | 'bye' 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/response/valid/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: valid 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/deny/response/valid/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: valid 6 | spec: 7 | variables: 8 | - name: force_authorized 9 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 10 | - name: force_unauthenticated 11 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 12 | - name: metadata 13 | expression: '{"my-new-metadata": "my-new-value"}' 14 | deny: 15 | # if force_unauthenticated -> 401 16 | - match: > 17 | variables.force_unauthenticated 18 | response: > 19 | envoy 20 | .Denied(401) 21 | .WithBody("Authentication Failed") 22 | .Response() 23 | # if not force_authorized -> 403 24 | - match: > 25 | !variables.force_authorized 26 | response: > 27 | envoy 28 | .Denied(403) 29 | .WithBody("Unauthorized Request") 30 | .Response() 31 | allow: 32 | # else -> 200 33 | - response: > 34 | envoy 35 | .Allowed() 36 | .WithHeader("x-validated-by", "my-security-checkpoint") 37 | .WithoutHeader("x-force-authorized") 38 | .WithResponseHeader("x-add-custom-response-header", "added") 39 | .Response() 40 | .WithMetadata(variables.metadata) 41 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/compilation-failure/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: compilation-failure 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "compilation-failure" is invalid: spec.matchConditions[0].expression: Invalid value: "'flop' + 2\n": ERROR: :1:8: found no matching overload for '_+_' applied to '(string, int)' 14 | | 'flop' + 2 15 | | .......^ 16 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/compilation-failure/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: compilation-failure 6 | spec: 7 | matchConditions: 8 | - name: bad 9 | expression: > 10 | 'flop' + 2 11 | variables: 12 | - name: force_authorized 13 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 14 | - name: force_unauthenticated 15 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 16 | - name: metadata 17 | expression: '{"my-new-metadata": "my-new-value"}' 18 | deny: 19 | # if force_unauthenticated -> 401 20 | - match: > 21 | variables.force_unauthenticated 22 | response: > 23 | envoy 24 | .Denied(401) 25 | .WithBody("Authentication Failed") 26 | .Response() 27 | # if not force_authorized -> 403 28 | - match: > 29 | !variables.force_authorized 30 | response: > 31 | envoy 32 | .Denied(403) 33 | .WithBody("Unauthorized Request") 34 | .Response() 35 | allow: 36 | # else -> 200 37 | - response: > 38 | envoy 39 | .Allowed() 40 | .WithHeader("x-validated-by", "my-security-checkpoint") 41 | .WithoutHeader("x-force-authorized") 42 | .WithResponseHeader("x-add-custom-response-header", "added") 43 | .Response() 44 | .WithMetadata(variables.metadata) 45 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/invalid-output-type/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: invalid-output-type 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "invalid-output-type" is invalid: spec.matchConditions[0].expression: Invalid value: "'flop'\n": matchCondition output is expected to be of type bool 14 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/invalid-output-type/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: invalid-output-type 6 | spec: 7 | matchConditions: 8 | - name: bad 9 | expression: > 10 | 'flop' 11 | variables: 12 | - name: force_authorized 13 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 14 | - name: force_unauthenticated 15 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 16 | - name: metadata 17 | expression: '{"my-new-metadata": "my-new-value"}' 18 | deny: 19 | # if force_unauthenticated -> 401 20 | - match: > 21 | variables.force_unauthenticated 22 | response: > 23 | envoy 24 | .Denied(401) 25 | .WithBody("Authentication Failed") 26 | .Response() 27 | # if not force_authorized -> 403 28 | - match: > 29 | !variables.force_authorized 30 | response: > 31 | envoy 32 | .Denied(403) 33 | .WithBody("Unauthorized Request") 34 | .Response() 35 | allow: 36 | # else -> 200 37 | - response: > 38 | envoy 39 | .Allowed() 40 | .WithHeader("x-validated-by", "my-security-checkpoint") 41 | .WithoutHeader("x-force-authorized") 42 | .WithResponseHeader("x-add-custom-response-header", "added") 43 | .Response() 44 | .WithMetadata(variables.metadata) 45 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/no-variables/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: no-variables 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | expect: 11 | - check: 12 | ($error): |- 13 | admission webhook "kyverno-authz-server-validation.kyverno.svc" denied the request: AuthorizationPolicy.envoy.kyverno.io "policy" is invalid: spec.matchConditions[0].expression: Invalid value: "variables.foo": ERROR: :1:10: undefined field 'foo' 14 | | variables.foo 15 | | .........^ 16 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/no-variables/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: policy 6 | spec: 7 | matchConditions: 8 | - name: check-foo 9 | expression: variables.foo 10 | variables: 11 | - name: foo 12 | expression: > 13 | true 14 | deny: 15 | - response: > 16 | envoy 17 | .Denied(403) 18 | .WithBody("Unauthorized Request") 19 | .Response() 20 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/valid/chainsaw-test.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: chainsaw.kyverno.io/v1alpha1 2 | kind: Test 3 | metadata: 4 | name: valid 5 | spec: 6 | steps: 7 | - try: 8 | - create: 9 | file: ./policy.yaml 10 | -------------------------------------------------------------------------------- /tests/e2e/validation-webhook/match-conditions/valid/policy.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=../../../../../.schemas/json/authorizationpolicy-envoy-v1alpha1.json 2 | apiVersion: envoy.kyverno.io/v1alpha1 3 | kind: AuthorizationPolicy 4 | metadata: 5 | name: valid 6 | spec: 7 | matchConditions: 8 | - name: never 9 | expression: > 10 | false 11 | variables: 12 | - name: force_authorized 13 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 14 | - name: force_unauthenticated 15 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 16 | - name: metadata 17 | expression: '{"my-new-metadata": "my-new-value"}' 18 | deny: 19 | # if force_unauthenticated -> 401 20 | - match: > 21 | variables.force_unauthenticated 22 | response: > 23 | envoy 24 | .Denied(401) 25 | .WithBody("Authentication Failed") 26 | .Response() 27 | # if not force_authorized -> 403 28 | - match: > 29 | !variables.force_authorized 30 | response: > 31 | envoy 32 | .Denied(403) 33 | .WithBody("Unauthorized Request") 34 | .Response() 35 | allow: 36 | # else -> 200 37 | - response: > 38 | envoy 39 | .Allowed() 40 | .WithHeader("x-validated-by", "my-security-checkpoint") 41 | .WithoutHeader("x-force-authorized") 42 | .WithResponseHeader("x-add-custom-response-header", "added") 43 | .Response() 44 | .WithMetadata(variables.metadata) 45 | -------------------------------------------------------------------------------- /tests/performance-test/k6-script.js: -------------------------------------------------------------------------------- 1 | import http from 'k6/http'; 2 | import { check, group, sleep } from 'k6'; 3 | 4 | export const options = { 5 | stages: [ 6 | { duration: '30s', target: 100 }, // Ramp-up to 100 virtual users over 30 seconds 7 | { duration: '1m', target: 100 }, // Stay at 100 virtual users for 1 minute 8 | { duration: '30s', target: 0 }, // Ramp-down to 0 virtual users over 30 seconds 9 | ], 10 | }; 11 | 12 | /* 13 | Replace ip for every scenerio generate the URL with these commands 14 | 15 | echo SERVICE_PORT=$(kubectl -n demo get service testapp -o jsonpath='{.spec.ports[?(@.port==8080)].nodePort}') 16 | echo SERVICE_HOST=$(minikube ip) 17 | echo SERVICE_URL=$SERVICE_HOST:$SERVICE_PORT 18 | echo $SERVICE_URL 19 | 20 | http://192.168.49.2:31541 21 | 22 | */ 23 | 24 | const BASE_URL = 'http://192.168.49.2:31700'; // Replace with your application URL 25 | 26 | export default function () { 27 | group('GET /book with guest token', () => { 28 | const res = http.get(`${BASE_URL}/book`, { 29 | headers: { 'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjIyNDEwODE1MzksIm5iZiI6MTUxNDg1MTEzOSwicm9sZSI6Imd1ZXN0Iiwic3ViIjoiWVd4cFkyVT0ifQ.ja1bgvIt47393ba_WbSBm35NrUhdxM4mOVQN8iXz8lk' }, 30 | }); 31 | check(res, { 32 | 'is status 200': (r) => r.status === 200, 33 | }); 34 | }); 35 | 36 | sleep(1); // Sleep for 1 second between iterations 37 | } 38 | -------------------------------------------------------------------------------- /tests/performance-test/manifest/app.yaml: -------------------------------------------------------------------------------- 1 | # Application Deployment with kyverno-envoy-plugin and Envoy sidecars. 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: testapp 6 | namespace: demo 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: testapp 12 | template: 13 | metadata: 14 | labels: 15 | app: testapp 16 | spec: 17 | containers: 18 | - name: test-application 19 | image: sanskardevops/test-application:0.0.1 20 | ports: 21 | - containerPort: 8080 22 | --- 23 | ### Service to expose sample application 24 | apiVersion: v1 25 | kind: Service 26 | metadata: 27 | name: testapp 28 | namespace: demo 29 | spec: 30 | type: NodePort 31 | selector: 32 | app: testapp 33 | ports: 34 | - port: 8080 35 | targetPort: 8080 36 | -------------------------------------------------------------------------------- /website/apis/config.yaml: -------------------------------------------------------------------------------- 1 | hiddenMemberFields: 2 | - TypeMeta 3 | 4 | hideTypePatterns: 5 | - ParseError$ 6 | - List$ 7 | 8 | externalPackages: 9 | - match: ^k8s\.io/apimachinery/pkg/apis/meta/v1\.Duration$ 10 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration 11 | - match: ^k8s\.io/apimachinery/pkg/apis/meta/v1\.GroupVersionKind$ 12 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#GroupVersionKind 13 | - match: ^k8s\.io/apimachinery/pkg/apis/meta/v1\.GroupVersionResource$ 14 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#GroupVersionResource 15 | - match: ^k8s\.io/apimachinery/pkg/types\.UID$ 16 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/types#UID 17 | - match: ^k8s\.io/apimachinery/pkg/runtime\.RawExtension$ 18 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime/#RawExtension 19 | - match: ^k8s\.io/apimachinery/pkg/api/resource\.QuantityValue$ 20 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#QuantityValue 21 | - match: ^k8s\.io/apimachinery/pkg/api/resource\.Quantity$ 22 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/api/resource#Quantity 23 | - match: ^k8s\.io/apimachinery/pkg/runtime\.Unknown$ 24 | target: https://pkg.go.dev/k8s.io/apimachinery/pkg/runtime#Unknown 25 | - match: ^time\.Duration$ 26 | target: https://pkg.go.dev/time#Duration 27 | - match: ^io.Writer$ 28 | target: https://pkg.go.dev/io#Writer 29 | - match: ^k8s\.io/(api|apimachinery/pkg/apis)/ 30 | target: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#{{- lower .TypeIdentifier -}}-{{- arrIndex .PackageSegments -1 -}}-{{- arrIndex .PackageSegments -2 -}} 31 | 32 | markdownDisabled: false 33 | 34 | stripPrefix: 35 | - k8s.io/api/ 36 | - k8s.io/apimachinery/pkg/apis/ 37 | - github.com/tengqm/kubeconfig/config/kubeadm/v1beta2. 38 | - github.com/tengqm/kubeconfig/config/kubeadm/v1beta3. 39 | - github.com/tengqm/kubeconfig/config/bootstraptoken/v1. 40 | 41 | apis: 42 | - name: policy 43 | title: policy (v1alpha1) 44 | package: github.com/kyverno/kyverno-envoy-plugin 45 | path: apis/v1alpha1 46 | -------------------------------------------------------------------------------- /website/apis/markdown/members.tpl: -------------------------------------------------------------------------------- 1 | {{- define "comment" -}} 2 | {{- $comment := "" -}} 3 | {{- range . -}} 4 | {{- if . -}} 5 | {{- if not (eq (index . 0) '+') -}} 6 | {{- if $comment -}} 7 | {{- $comment = print $comment " " . -}} 8 | {{- else -}} 9 | {{- $comment = . -}} 10 | {{- end -}} 11 | {{- end -}} 12 | {{- end -}} 13 | {{- end -}} 14 | {{- if $comment -}} 15 |

{{ $comment }}

16 | {{- else -}} 17 | *No description provided.* 18 | {{- end -}} 19 | {{- end -}} 20 | 21 | {{- define "typ" -}} 22 | {{- if .Link -}} 23 | [`{{ .DisplayName }}`]({{ .Link }}) 24 | {{- else -}} 25 | `{{ .DisplayName }}` 26 | {{- end -}} 27 | {{- end -}} 28 | 29 | {{- define "members" }} 30 | {{- range .GetMembers }} 31 | {{- if not .Hidden }} 32 | {{- $name := .FieldName }} 33 | {{- $optional := .IsOptional }} 34 | {{- $type := .GetType }} 35 | {{- $inline := .IsInline }} 36 | {{- $comment := .GetComment }} 37 | | `{{ $name }}` | {{ template "typ" $type }} | {{ if not $optional }}:white_check_mark:{{ end }} | {{ if $inline }}:white_check_mark:{{ end }} | {{ template "comment" .CommentLines }} | 38 | {{- end }} 39 | {{- end }} 40 | {{- end }} 41 | -------------------------------------------------------------------------------- /website/apis/markdown/pkg.tpl: -------------------------------------------------------------------------------- 1 | {{ define "packages" -}} 2 | 3 | {{- range $idx, $val := .packages -}} 4 | {{/* Special handling for kubeconfig */}} 5 | {{- if eq .Title "kubeconfig (v1)" -}} 6 | --- 7 | title: {{ .Title }} 8 | content_type: tool-reference 9 | package: v1 10 | auto_generated: true 11 | --- 12 | {{- else -}} 13 | {{- if and .IsMain (ne .GroupName "") -}} 14 | --- 15 | title: {{ .Title }} 16 | content_type: tool-reference 17 | package: {{ .DisplayName }} 18 | auto_generated: true 19 | --- 20 | {{ .GetComment -}} 21 | {{- end -}} 22 | {{- end -}} 23 | {{- end }} 24 | 25 | ## Resource Types 26 | 27 | {{ range .packages -}} 28 | {{- range .VisibleTypes -}} 29 | {{- if .IsExported }} 30 | - [{{ .DisplayName }}]({{ .Link }}) 31 | {{- end -}} 32 | {{- end -}} 33 | {{- end -}} 34 | 35 | {{ range .packages }} 36 | {{ if ne .GroupName "" -}} 37 | {{/* For package with a group name, list all type definitions in it. */}} 38 | {{- range .VisibleTypes }} 39 | {{- if or .Referenced .IsExported -}} 40 | {{ template "type" . }} 41 | {{- end -}} 42 | {{ end }} 43 | {{ else }} 44 | {{/* For package w/o group name, list only types referenced. */}} 45 | {{ $pkgTitle := .Title }} 46 | {{- range .VisibleTypes -}} 47 | {{- if or .Referenced (eq $pkgTitle "kubeconfig (v1)") -}} 48 | {{ template "type" . }} 49 | {{- end -}} 50 | {{- end }} 51 | {{- end }} 52 | {{- end }} 53 | {{- end }} 54 | -------------------------------------------------------------------------------- /website/apis/markdown/type.tpl: -------------------------------------------------------------------------------- 1 | {{- define "type" }} 2 | ## {{ .Name.Name }} {#{{ .Anchor }}} 3 | {{- if eq .Kind "Alias" }} 4 | 5 | (Alias of `{{ .Underlying }}`) 6 | {{- end }} 7 | {{- with .References }} 8 | 9 | **Appears in:** 10 | {{ range . }} 11 | {{- if or .Referenced .IsExported }} 12 | - [{{ .DisplayName }}]({{ .Link }}) 13 | {{- end }} 14 | {{- end }} 15 | {{- end }} 16 | {{- if .GetComment }} 17 | 18 | {{ .GetComment }} 19 | {{- end }} 20 | {{- if .GetMembers }} 21 | 22 | | Field | Type | Required | Inline | Description | 23 | |---|---|---|---|---| 24 | {{- /* . is a apiType */}} 25 | {{- if .IsExported }} 26 | {{- /* Add apiVersion and kind rows if deemed necessary */}} 27 | | `apiVersion` | `string` | :white_check_mark: | | `{{- .APIGroup -}}` | 28 | | `kind` | `string` | :white_check_mark: | | `{{- .Name.Name -}}` | 29 | {{- end }} 30 | {{- /* The actual list of members is in the following template */}} 31 | {{- template "members" . }} 32 | {{- end }} 33 | {{ end }} 34 | -------------------------------------------------------------------------------- /website/docs/cel-extensions/index.md: -------------------------------------------------------------------------------- 1 | # CEL extensions 2 | 3 | The CEL engine used to evaluate variables and authorization rules has been extended with libraries to help processing the input `CheckRequest` and forge the corresponding `OkResponse` and/or `DeniedResponse`. 4 | 5 | ## Envoy plugin libraries 6 | 7 | - [Envoy](./envoy.md) 8 | - [Jwt](./jwt.md) 9 | 10 | ## Common libraries 11 | 12 | The libraries below are common CEL extensions enabled in the Kyverno Authz Server CEL engine: 13 | 14 | - [Optional types](https://pkg.go.dev/github.com/google/cel-go/cel#OptionalTypes) 15 | - [Cross type numeric comparisons](https://pkg.go.dev/github.com/google/cel-go/cel#CrossTypeNumericComparisons) 16 | - [Bindings](https://pkg.go.dev/github.com/google/cel-go/ext#readme-bindings) 17 | - [Encoders](https://pkg.go.dev/github.com/google/cel-go/ext#readme-encoders) 18 | - [Lists](https://pkg.go.dev/github.com/google/cel-go/ext#readme-lists) 19 | - [Math](https://pkg.go.dev/github.com/google/cel-go/ext#readme-math) 20 | - [Protos](https://pkg.go.dev/github.com/google/cel-go/ext#readme-protos) 21 | - [Sets](https://pkg.go.dev/github.com/google/cel-go/ext#readme-sets) 22 | - [Strings](https://pkg.go.dev/github.com/google/cel-go/ext#readme-strings) 23 | 24 | ## Kubernetes libraries 25 | 26 | The libraries below are imported from Kubernetes: 27 | 28 | - CIDR 29 | - Format 30 | - IP 31 | - [Lists](https://kubernetes.io/docs/reference/using-api/cel/#kubernetes-list-library) 32 | - [Regex](https://kubernetes.io/docs/reference/using-api/cel/#kubernetes-regex-library) 33 | - [URL](https://kubernetes.io/docs/reference/using-api/cel/#kubernetes-url-library) 34 | -------------------------------------------------------------------------------- /website/docs/cel-extensions/jwt.md: -------------------------------------------------------------------------------- 1 | # Jwt library 2 | 3 | Policies have native functionality to decode and verify the contents of JWT tokens in order to enforce additional authorization logic on requests. 4 | 5 | ## Types 6 | 7 | ### `` 8 | 9 | *CEL Type / Proto* `jwt.Token` 10 | 11 | | Field | CEL Type / Proto | Docs | 12 | |---|---|---| 13 | | Valid | `bool` | | 14 | | Header | `google.protobuf.Struct` | [Docs](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | 15 | | Claims | `google.protobuf.Struct` | [Docs](https://protobuf.dev/reference/protobuf/google.protobuf/#struct) | 16 | 17 | ## Functions 18 | 19 | ### jwt.Decode 20 | 21 | The `jwt.Decode` function decodes and validates a JWT token. 22 | It accepts two arguments: the token and the secret to verify the signature. 23 | 24 | #### Signature and overloads 25 | 26 | ``` 27 | jwt.Decode( token, key) -> 28 | ``` 29 | 30 | #### Example 31 | 32 | ``` 33 | jwt.Decode("eyJhbGciOiJIUzI1NiI....", "secret") 34 | ``` 35 | -------------------------------------------------------------------------------- /website/docs/community/index.md: -------------------------------------------------------------------------------- 1 | # Community 2 | 3 | The Kyverno Envoy Plugin has a growing community and we would definitely love to see you join and contribute. 4 | 5 | Everyone is welcome to make suggestions, report bugs, open feature requests, contribute code or docs, participate in discussions, write blogs or anything that can benefit the project. 6 | 7 | --- 8 | 9 |
10 | The Kyverno Envoy Plugin is built and maintained under the Kyverno umbrella but decisions are 11 |

Community driven

12 |

Everyone's voice matters

13 |
14 | 15 | --- 16 | 17 | ## Slack channel 18 | 19 | Join our slack channel [#kyverno](https://kubernetes.slack.com/archives/CLGR9BJU9) to meet with users, contributors and maintainers. 20 | 21 | ## RoadMap 22 | 23 | For detailed information on our planned features and upcoming updates, please [view our Roadmap](https://github.com/kyverno/kyverno-envoy-plugin/blob/main/ROADMAP.md). 24 | 25 | ## Contributing 26 | 27 | Please read the [contributing guide](https://github.com/kyverno/kyverno/blob/main/CONTRIBUTING.md) for details around: 28 | 29 | 1. Code of Conduct 30 | 1. Code Culture 31 | 1. Details on how to contribute 32 | 33 | ## Adopters 34 | 35 | If you are using the Kyverno Envoy Plugin and want to share it publicly we always appreciate a bit of support. Pull requests to the [ADOPTERS LIST](https://github.com/kyverno/kyverno-envoy-plugin/blob/main/ADOPTERS.md) will put a smile on our faces :smile: 36 | -------------------------------------------------------------------------------- /website/docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | template: home.html 3 | title: Kyverno Envoy Plugin - Policy based authz! 4 | --- 5 | -------------------------------------------------------------------------------- /website/docs/install/certificates.md: -------------------------------------------------------------------------------- 1 | # Certificates management 2 | 3 | The Kyverno Authz Server comes with a validation webhook and needs a valid certificate to let the api server call into it. 4 | 5 | At deployment time you can either provide your own certificate or use [cert-manager](https://cert-manager.io) to create one for the Kyverno Authz Server. 6 | 7 | ## Bring your own 8 | 9 | If you want to bring your own certificate, you can set `certificates.static` values when installing the helm chart. 10 | 11 | ```bash 12 | # create certificate 13 | openssl req -new -x509 \ 14 | -subj "/CN=kyverno-authz-server-validation.kyverno.svc" \ 15 | -addext "subjectAltName = DNS:kyverno-authz-server-validation.kyverno.svc" \ 16 | -nodes -newkey rsa:4096 -keyout tls.key -out tls.crt 17 | 18 | # install chart with static certificate 19 | helm install kyverno-authz-server \ 20 | --namespace kyverno --create-namespace \ 21 | --wait \ 22 | --repo https://kyverno.github.io/kyverno-envoy-plugin kyverno-authz-server \ 23 | --set-file certificates.static.crt=tls.crt \ 24 | --set-file certificates.static.key=tls.key 25 | ``` 26 | 27 | ## Use cert-manager 28 | 29 | If you don't want to manage the certificate yourself you can rely on [cert-manager](https://cert-manager.io) to create the certificate for you and inject it in the webhook configuration. 30 | 31 | ```bash 32 | # install cert-manager 33 | helm install cert-manager \ 34 | --namespace cert-manager --create-namespace \ 35 | --wait \ 36 | --repo https://charts.jetstack.io cert-manager \ 37 | --set crds.enabled=true 38 | 39 | # create a certificate issuer 40 | kubectl apply -f - < 6 | Click here to go to latest. 7 | 8 | {% endblock %} 9 | 10 | {% block extrahead %} 11 | {% set title = config.site_name %} 12 | {% if page and page.title and not page.is_homepage %} 13 | {% set title = config.site_name ~ " - " ~ page.title | striptags %} 14 | {% endif %} 15 | {% set image = config.site_url ~ '/static/card.png' %} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /website/docs/policies/failure-policy.md: -------------------------------------------------------------------------------- 1 | # Failure policy 2 | 3 | FailurePolicy defines how to handle failures for the policy. 4 | 5 | Failures can occur from CEL expression parse errors, type check errors, runtime errors and invalid or mis-configured policy definitions. 6 | 7 | Allowed values are: 8 | 9 | - `Ignore` 10 | - `Fail` 11 | 12 | If not set, the failure policy defaults to `Fail`. 13 | 14 | !!!info 15 | 16 | FailurePolicy does not define how validations that evaluate to `false` are handled. 17 | 18 | ## Fail 19 | 20 | ```yaml 21 | apiVersion: envoy.kyverno.io/v1alpha1 22 | kind: AuthorizationPolicy 23 | metadata: 24 | name: demo 25 | spec: 26 | # if something fails the request will be denied 27 | failurePolicy: Fail 28 | variables: 29 | - name: force_authorized 30 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") 31 | - name: allowed 32 | expression: variables.force_authorized in ["enabled", "true"] 33 | deny: 34 | - match: > 35 | !variables.allowed 36 | response: > 37 | envoy.Denied(403).Response() 38 | ``` 39 | 40 | ## Ignore 41 | 42 | ```yaml 43 | apiVersion: envoy.kyverno.io/v1alpha1 44 | kind: AuthorizationPolicy 45 | metadata: 46 | name: demo 47 | spec: 48 | # if something fails the failure will be ignored and the request will be allowed 49 | failurePolicy: Ignore 50 | variables: 51 | - name: force_authorized 52 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") 53 | - name: allowed 54 | expression: variables.force_authorized in ["enabled", "true"] 55 | deny: 56 | - match: > 57 | !variables.allowed 58 | response: > 59 | envoy.Denied(403).Response() 60 | ``` 61 | -------------------------------------------------------------------------------- /website/docs/policies/index.md: -------------------------------------------------------------------------------- 1 | # Policies 2 | 3 | A Kyverno `AuthorizationPolicy` is a custom [Kubernetes resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) and can be easily managed via Kubernetes APIs, GitOps workflows, and other existing tools. 4 | 5 | ## Resource Scope 6 | 7 | A Kyverno `AuthorizationPolicy` is a cluster-wide resource. 8 | 9 | ## API Group and Kind 10 | 11 | An `AuthorizationPolicy` belongs to the `envoy.kyverno.io/v1alpha1` group and can only be of kind `AuthorizationPolicy`. 12 | 13 | ```yaml 14 | apiVersion: envoy.kyverno.io/v1alpha1 15 | kind: AuthorizationPolicy 16 | metadata: 17 | name: demo 18 | spec: 19 | # if something fails the request will be denied 20 | failurePolicy: Fail 21 | variables: 22 | # `force_authorized` references the 'x-force-authorized' header 23 | # from the envoy check request (or '' if not present) 24 | - name: force_authorized 25 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") 26 | # `allowed` will be `true` if `variables.force_authorized` has the 27 | # value 'enabled' or 'true' 28 | - name: allowed 29 | expression: variables.force_authorized in ["enabled", "true"] 30 | deny: 31 | # make an authorisation decision based on the value of `variables.allowed` 32 | - match: > 33 | !variables.allowed 34 | response: > 35 | envoy.Denied(403).Response() 36 | allow: 37 | - response: > 38 | envoy.Allowed().Response() 39 | ``` 40 | 41 | ## Envoy External Authorization 42 | 43 | The Kyverno Authz Server implements the [Envoy External Authorization](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter) API. 44 | 45 | A Kyverno `AuthorizationPolicy` analyses an Envoy [CheckRequest](https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto#service-auth-v3-checkrequest) and can make a decision by returning an [OkResponse](../cel-extensions/envoy.md#okresponse) or [DeniedResponse](../cel-extensions/envoy.md#deniedresponse). 46 | 47 | ## CEL language 48 | 49 | An `AuthorizationPolicy` uses the [CEL language](https://github.com/google/cel-spec) to process the `CheckRequest` sent by Envoy. 50 | 51 | CEL is an expression language that’s fast, portable, and safe to execute in performance-critical applications. 52 | 53 | ## Policy structure 54 | 55 | A Kyverno `AuthorizationPolicy` is made of: 56 | 57 | - A [failure policy](./failure-policy.md) 58 | - [Match conditions](./match-conditions.md) if needed 59 | - Eventually some [variables](./variables.md) 60 | - The [authorization rules](./authorization-rules.md) 61 | -------------------------------------------------------------------------------- /website/docs/policies/match-conditions.md: -------------------------------------------------------------------------------- 1 | # Match conditions 2 | 3 | You can define match conditions if you need fine-grained request filtering. 4 | 5 | Match conditions are **CEL expressions**. All match conditions must evaluate to `true` for the request to be evaluated. 6 | 7 | !!!info 8 | 9 | The policy [variables](./variables.md) will NOT be available in match conditions because they are evaluated before the rest of the policy. 10 | 11 | ## Example 12 | 13 | ```yaml 14 | apiVersion: envoy.kyverno.io/v1alpha1 15 | kind: AuthorizationPolicy 16 | metadata: 17 | name: demo 18 | spec: 19 | failurePolicy: Fail 20 | matchConditions: 21 | - name: has-header 22 | expression: object.attributes.request.http.headers[?"x-force-deny"].hasValue() 23 | deny: 24 | - response: > 25 | envoy.Denied(403).Response() 26 | ``` 27 | 28 | In the policy above, the `matchConditions` will be used to deny all requests having the `x-force-deny` header. 29 | 30 | - If an incoming request doesn't have the `x-force-deny` header, then the condition will return `false` and the policy won't apply 31 | - If an incoming request has the `x-force-deny` header, then the condition will return `true` and the `deny` rule will deny the request with status code `403` 32 | 33 | ## Error handling 34 | 35 | In the event of an error evaluating a match condition the policy is not evaluated. Whether to reject the request is determined as follows: 36 | 37 | 1. If any match condition evaluated to `false` (regardless of other errors), then the policy is skipped. 38 | 1. Otherwise: 39 | - for `failurePolicy: Fail`, reject the request (without evaluating the policy). 40 | - for `failurePolicy: Ignore`, proceed with the request but skip the policy. 41 | -------------------------------------------------------------------------------- /website/docs/policies/variables.md: -------------------------------------------------------------------------------- 1 | # Variables 2 | 3 | A Kyverno `AuthorizationPolicy` can define `variables` that will be made available to all authorization rules. 4 | 5 | Variables can be used in composition of other expressions. 6 | Each variable is defined as a named [CEL](https://github.com/google/cel-spec) expression. 7 | The will be available under `variables` in other expressions of the policy. 8 | 9 | The expression of a variable can refer to other variables defined earlier in the list but not those after. Thus, variables must be sorted by the order of first appearance and acyclic. 10 | 11 | !!!info 12 | 13 | The incoming `CheckRequest` from Envoy is made available to the policy under the `object` identifier. 14 | 15 | ## Variables 16 | 17 | ```yaml 18 | apiVersion: envoy.kyverno.io/v1alpha1 19 | kind: AuthorizationPolicy 20 | metadata: 21 | name: demo 22 | spec: 23 | failurePolicy: Fail 24 | variables: 25 | # `force_authorized` references the 'x-force-authorized' header 26 | # from the envoy check request (or '' if not present) 27 | - name: force_authorized 28 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") 29 | # `allowed` will be `true` if `variables.force_authorized` has the 30 | # value 'enabled' or 'true' 31 | - name: allowed 32 | expression: variables.force_authorized in ["enabled", "true"] 33 | deny: 34 | # make an authorisation decision based on the value of `variables.allowed` 35 | - match: > 36 | !variables.allowed 37 | response: > 38 | envoy.Denied(403).Response() 39 | ``` 40 | -------------------------------------------------------------------------------- /website/docs/quick-start/index.md: -------------------------------------------------------------------------------- 1 | # Quick start 2 | 3 | The Kyverno Envoy Plugin is a powerful tool that integrates with the Envoy proxy. 4 | 5 | It allows you to enforce Kyverno policies on incoming and outgoing traffic in a service mesh environment, providing an additional layer of security and control over your applications. 6 | 7 | ## Overview 8 | 9 | [Envoy](https://www.envoyproxy.io/docs/envoy/latest/intro/what_is_envoy) is a Layer 7 proxy and communication bus tailored for large-scale, modern service-oriented architectures. Starting from version 1.7.0, Envoy includes an [External Authorization filter](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html) that interfaces with an authorization service to determine the legitimacy of incoming requests. 10 | 11 | This functionality allows authorization decisions to be offloaded to an external service, which can access the request context. The request context includes details such as the origin and destination of the network activity, as well as specifics of the network request (e.g., HTTP request). This information enables the external service to make a well-informed decision regarding the authorization of the incoming request processed by Envoy. 12 | 13 | ![overview](../schemas/overview.png) 14 | 15 | ## What is the Kyverno Envoy Plugin? 16 | 17 | The [Kyverno Envoy Plugin](https://github.com/kyverno/kyverno-envoy-plugin) is gRPC server that implements [Envoy External Authorization API](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html). 18 | 19 | This allows you to enforce Kyverno policies on incoming and outgoing traffic in a service mesh environment, providing an additional layer of security and control over your applications. You can use this version of Kyverno to enforce fine-grained, context-aware access control policies with Envoy without modifying your microservice. 20 | 21 | ## How does this work? 22 | 23 | In addition to the Envoy sidecar, your application pods will include a Kyverno Authz Server component, either as a sidecar or as a separate pod. When Envoy receives an API request intended for your microservice, it consults the Kyverno Authz Server to determine whether the request should be permitted or not. 24 | 25 | ![filters chain](../schemas/filters-chain.png) 26 | 27 | Performing policy evaluations locally with Envoy is advantageous, as it eliminates the need for an additional network hop for authorization checks, thus enhancing both performance and availability. 28 | 29 | !!!info 30 | 31 | The Kyverno Envoy Plugin is frequently deployed in Kubernetes environments as a sidecar container or as a separate pod. Additionally, it can be used in other environments as a standalone process running alongside Envoy. 32 | 33 | ## Additional Resources 34 | 35 | See the following pages on [envoyproxy.io](https://www.envoyproxy.io/) for more information on external authorization: 36 | 37 | - [External Authorization](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ext_authz_filter.html) to learn about the External Authorization filter. 38 | - [Network](https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/ext_authz_filter#config-network-filters-ext-authz) and [HTTP](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/ext_authz_filter#config-http-filters-ext-authz) for details on configuring the External Authorization filter. 39 | 40 | -------------------------------------------------------------------------------- /website/docs/quick-start/next-steps.md: -------------------------------------------------------------------------------- 1 | # Next steps 2 | 3 | We covered the main components of the Kyverno Envoy Plugin. 4 | 5 | !!!tip 6 | 7 | If there's anything you would like to be improved, please [reach out](https://github.com/kyverno/kyverno-envoy-plugin), we will be happy to discuss and improve as much as we can. 8 | 9 | To continue exploring and learn more about the Kyverno Envoy Plugin: 10 | 11 | - [Start writing your own policies](../policies/index.md) 12 | - [Browse the tutorials section](../tutorials/index.md) 13 | - [Consult the Reference documentation](../reference/index.md) 14 | - [Engage with our Community and start contributing](../community/index.md) 15 | -------------------------------------------------------------------------------- /website/docs/quick-start/sidecar-injector.md: -------------------------------------------------------------------------------- 1 | # Sidecar injector 2 | 3 | This is not ready yet, hopefully it will be available soon! -------------------------------------------------------------------------------- /website/docs/reference/index.md: -------------------------------------------------------------------------------- 1 | # Reference documentation 2 | 3 | !!! info 4 | Select an item in the navigation menu to browse a specific page. 5 | -------------------------------------------------------------------------------- /website/docs/reference/json-schemas.md: -------------------------------------------------------------------------------- 1 | # JSON schemas 2 | 3 | JSON schemas for the Kyverno Envoy Plugin are available: 4 | 5 | - [AuthorizationPolicy (v1alpha1)](https://github.com/kyverno/kyverno-envoy-plugin/blob/main/.schemas/json/authorizationpolicy-envoy-v1alpha1.json) 6 | 7 | They can be used to enable validation and autocompletion in your IDE. 8 | 9 | ## VS code 10 | 11 | In VS code, simply add a comment on top of your YAML resources. 12 | 13 | ### AuthorizationPolicy 14 | 15 | ```yaml 16 | # yaml-language-server: $schema=https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/main/.schemas/json/authorizationpolicy-envoy-v1alpha1.json 17 | apiVersion: envoy.kyverno.io/v1alpha1 18 | kind: AuthorizationPolicy 19 | metadata: 20 | name: demo 21 | spec: 22 | variables: 23 | - name: force_authorized 24 | expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"] 25 | - name: force_unauthenticated 26 | expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"] 27 | - name: metadata 28 | expression: '{"my-new-metadata": "my-new-value"}' 29 | deny: 30 | # if force_unauthenticated -> 401 31 | - match: > 32 | variables.force_unauthenticated 33 | response: > 34 | envoy 35 | .Denied(401) 36 | .WithBody("Authentication Failed") 37 | .Response() 38 | .WithMetadata(variables.metadata) 39 | # if not force_authorized -> 403 40 | - match: > 41 | !variables.force_authorized 42 | response: > 43 | envoy 44 | .Denied(403) 45 | .WithBody("Unauthorized Request") 46 | .Response() 47 | allow: 48 | # else -> 200 49 | - response: > 50 | envoy 51 | .Allowed() 52 | .WithHeader("x-validated-by", "my-security-checkpoint") 53 | .WithoutHeader("x-force-authorized") 54 | .WithResponseHeader("x-add-custom-response-header", "added") 55 | .Response() 56 | .WithMetadata(variables.metadata) 57 | ``` 58 | -------------------------------------------------------------------------------- /website/docs/schemas/dynamic-metadata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/website/docs/schemas/dynamic-metadata.png -------------------------------------------------------------------------------- /website/docs/schemas/filters-chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/website/docs/schemas/filters-chain.png -------------------------------------------------------------------------------- /website/docs/schemas/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/website/docs/schemas/overview.png -------------------------------------------------------------------------------- /website/docs/static/extra.css: -------------------------------------------------------------------------------- 1 | body>header>nav>a>img { 2 | border-radius: 10%; 3 | border: 1px solid #555; 4 | } 5 | 6 | td:nth-child(1) { 7 | text-wrap: nowrap; 8 | } -------------------------------------------------------------------------------- /website/docs/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/website/docs/static/favicon.ico -------------------------------------------------------------------------------- /website/docs/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kyverno/kyverno-envoy-plugin/0b8f6b12b8a2fc09792b0c98afd78fbeac2ec348/website/docs/static/logo.png -------------------------------------------------------------------------------- /website/docs/tutorials/index.md: -------------------------------------------------------------------------------- 1 | # Tutorials 2 | 3 | If you didn't read the Quick start section yet, we really recommend giving it a try to discover and familiarise with the Kyverno Envoy Plugin components first. 4 | 5 | - [Authz server quick start](../quick-start/authz-server.md) 6 | - [Sidecar injector quick start](../quick-start/sidecar-injector.md) -------------------------------------------------------------------------------- /website/mkdocs.yaml: -------------------------------------------------------------------------------- 1 | INHERIT: ./mkdocs.base.yaml 2 | 3 | nav: 4 | - Home: index.md 5 | - Quick start: 6 | - quick-start/index.md 7 | - quick-start/authz-server.md 8 | - quick-start/sidecar-injector.md 9 | - quick-start/next-steps.md 10 | - Install: 11 | - install/certificates.md 12 | - Policies: 13 | - policies/index.md 14 | - policies/failure-policy.md 15 | - policies/match-conditions.md 16 | - policies/variables.md 17 | - policies/authorization-rules.md 18 | - Reference: 19 | - reference/index.md 20 | - reference/json-schemas.md 21 | - APIs: 22 | - v1alpha1: reference/apis/policy.v1alpha1.md 23 | - CEL extensions: 24 | - cel-extensions/index.md 25 | - cel-extensions/envoy.md 26 | - cel-extensions/jwt.md 27 | - Tutorials: 28 | - tutorials/index.md 29 | - tutorials/istio/index.md 30 | - tutorials/envoy-gateway/index.md 31 | - Community: 32 | - community/index.md 33 | - Contributing: community/contribute.md 34 | - Reporting a bug: community/reporting-a-bug.md 35 | - Reporting a docs issue: community/reporting-a-docs-issue.md 36 | - Requesting a change: community/requesting-a-change.md 37 | - Making a pull request: community/making-a-pull-request.md 38 | # - Performance: 39 | # - performance/index.md 40 | --------------------------------------------------------------------------------