Initial commit
This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
||||
# Ignore unnecessary files
|
||||
**/*~
|
||||
**/*.log
|
||||
**/.DS_Store
|
||||
**/Thumbs.db
|
||||
|
||||
./.tmp
|
||||
25
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
25
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**What steps did you take and what happened:**
|
||||
[A clear and concise description of what the bug is.]
|
||||
|
||||
|
||||
**What did you expect to happen:**
|
||||
|
||||
|
||||
**Anything else you would like to add:**
|
||||
[Miscellaneous information that will assist in solving the issue.]
|
||||
|
||||
|
||||
**Environment:**
|
||||
|
||||
- Gatekeeper version:
|
||||
- External Data API version:
|
||||
- Kubernetes version: (use `kubectl version`):
|
||||
22
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/feature-request.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the solution you'd like**
|
||||
[A clear and concise description of what you want to happen.]
|
||||
|
||||
|
||||
**Anything else you would like to add:**
|
||||
[Miscellaneous information that will assist in solving the issue.]
|
||||
|
||||
|
||||
**Environment:**
|
||||
|
||||
- Gatekeeper version:
|
||||
- External Data API version:
|
||||
- Kubernetes version: (use `kubectl version`):
|
||||
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
**What this PR does / why we need it**:
|
||||
|
||||
**Which issue(s) this PR fixes** *(optional, using `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close the issue(s) when the PR gets merged)*:
|
||||
Fixes #
|
||||
|
||||
**Special notes for your reviewer**:
|
||||
28
.github/dependabot.yml
vendored
Normal file
28
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
update-types:
|
||||
- "version-update:semver-major"
|
||||
- "version-update:semver-minor"
|
||||
|
||||
- package-ecosystem: docker
|
||||
directory: /
|
||||
schedule:
|
||||
interval: daily
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
78
.github/workflows/codeql.yml
vendored
Normal file
78
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: ["main"]
|
||||
schedule:
|
||||
- cron: "0 0 * * 1"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ["go"]
|
||||
# CodeQL supports [ $supported-codeql-languages ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@128a63446a954579617e875aaab7d2978154e969 # v2.4.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
27
.github/workflows/dependency-review.yml
vendored
Normal file
27
.github/workflows/dependency-review.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Dependency Review Action
|
||||
#
|
||||
# This Action will scan dependency manifest files that change as part of a Pull Request,
|
||||
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
|
||||
# Once installed, if the workflow run is marked as required,
|
||||
# PRs introducing known-vulnerable packages will be blocked from merging.
|
||||
#
|
||||
# Source repository: https://github.com/actions/dependency-review-action
|
||||
name: 'Dependency Review'
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@128a63446a954579617e875aaab7d2978154e969 # v2.4.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@f46c48ed6d4f1227fb2d9ea62bf6bcbed315589e # v3.0.4
|
||||
76
.github/workflows/scorecards.yml
vendored
Normal file
76
.github/workflows/scorecards.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '20 7 * * 2'
|
||||
push:
|
||||
branches: ["main"]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
contents: read
|
||||
actions: read
|
||||
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@128a63446a954579617e875aaab7d2978154e969 # v2.4.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@80e868c13c90f172d68d1f4501dee99e2479f7af # v2.1.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecards on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories:
|
||||
# - `publish_results` will always be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
102
.github/workflows/workflow.yaml
vendored
Normal file
102
.github/workflows/workflow.yaml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
name: build_test
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- "**.md"
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: "Lint"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@128a63446a954579617e875aaab7d2978154e969 # v2.4.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
# source: https://github.com/golangci/golangci-lint-action
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@08e2f20817b15149a52b5b3ebe7de50aff2ba8c5 # v3.4.0
|
||||
with:
|
||||
version: v1.50.0
|
||||
|
||||
helm_build_test:
|
||||
name: "[Helm] Build and Test"
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@128a63446a954579617e875aaab7d2978154e969 # v2.4.0
|
||||
with:
|
||||
egress-policy: audit
|
||||
|
||||
- name: Set up Go 1.19
|
||||
uses: actions/setup-go@4d34df0c2316fe8122ab82dc22947d607c0c91f9 # v4.0.0
|
||||
with:
|
||||
go-version: 1.19
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
- name: Bootstrap e2e
|
||||
env:
|
||||
KIND_VERSION: 0.17.0
|
||||
BATS_VERSION: 1.8.2
|
||||
run: |
|
||||
mkdir -p $GITHUB_WORKSPACE/bin
|
||||
echo "${GITHUB_WORKSPACE}/bin" >> $GITHUB_PATH
|
||||
GOBIN="${GITHUB_WORKSPACE}/bin" go install sigs.k8s.io/kind@v${KIND_VERSION}
|
||||
curl -sSLO https://github.com/bats-core/bats-core/archive/v${BATS_VERSION}.tar.gz && tar -zxvf v${BATS_VERSION}.tar.gz && bash bats-core-${BATS_VERSION}/install.sh ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: Create a kind cluster and install Gatekeeper
|
||||
env:
|
||||
GATEKEEPER_VERSION: 3.11.0
|
||||
KUBERNETES_VERSION: 1.26.0
|
||||
run: |
|
||||
kind create cluster --image kindest/node:v${KUBERNETES_VERSION} --name gatekeeper
|
||||
|
||||
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
|
||||
helm install gatekeeper/gatekeeper \
|
||||
--version ${GATEKEEPER_VERSION} \
|
||||
--set enableExternalData=true \
|
||||
--name-template=gatekeeper \
|
||||
--namespace gatekeeper-system \
|
||||
--create-namespace \
|
||||
--debug
|
||||
|
||||
- name: Build and install external-data-provider
|
||||
run: |
|
||||
./scripts/generate-tls-cert.sh
|
||||
make docker-buildx kind-load-image
|
||||
helm install external-data-provider charts/external-data-provider \
|
||||
--set provider.tls.caBundle="$(cat certs/ca.crt | base64 | tr -d '\n\r')" \
|
||||
--namespace gatekeeper-system \
|
||||
--wait --debug
|
||||
|
||||
- name: Run e2e
|
||||
run: |
|
||||
bats -t test/bats/test.bats
|
||||
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# certificate directory
|
||||
certs/
|
||||
|
||||
# golangci-lint cachce
|
||||
.tmp/
|
||||
|
||||
# binary output
|
||||
bin/
|
||||
42
.golangci.yaml
Normal file
42
.golangci.yaml
Normal file
@@ -0,0 +1,42 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
|
||||
linters-settings:
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- performance
|
||||
gosec:
|
||||
excludes:
|
||||
- G108
|
||||
lll:
|
||||
line-length: 200
|
||||
|
||||
misspell:
|
||||
locale: US
|
||||
staticcheck:
|
||||
# Select the Go version to target. The default is '1.13'.
|
||||
go: "1.19"
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- errcheck
|
||||
- exportloopref
|
||||
- forcetypeassert
|
||||
- gocritic
|
||||
- goconst
|
||||
- godot
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive # replacement for golint
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
- whitespace
|
||||
3
CODE_OF_CONDUCT.md
Normal file
3
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## Community Code of Conduct
|
||||
|
||||
We follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
6
CONTRIBUTING.md
Normal file
6
CONTRIBUTING.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Contributing
|
||||
|
||||
Thanks for your interest in contributing to the Open Policy Agent (OPA) Gatekeeper project!
|
||||
|
||||
Please refer to [Gatekeeper's contribution guide](https://open-policy-agent.github.io/gatekeeper/website/docs/help)
|
||||
to find out how you can help.
|
||||
37
Dockerfile
Normal file
37
Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
ARG BUILDPLATFORM="linux/amd64"
|
||||
ARG BUILDERIMAGE="golang:1.19-bullseye"
|
||||
ARG BASEIMAGE="gcr.io/distroless/static:nonroot"
|
||||
|
||||
FROM --platform=${BUILDPLATFORM} ${BUILDERIMAGE} as builder
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT=""
|
||||
ARG LDFLAGS
|
||||
|
||||
ENV GO111MODULE=on \
|
||||
CGO_ENABLED=0 \
|
||||
GOOS=${TARGETOS} \
|
||||
GOARCH=${TARGETARCH} \
|
||||
GOARM=${TARGETVARIANT}
|
||||
|
||||
WORKDIR /go/src/github.com/open-policy-agent/gatekeeper-external-data-provider
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN make build
|
||||
|
||||
FROM ${BASEIMAGE}
|
||||
|
||||
WORKDIR /
|
||||
|
||||
COPY --from=builder /go/src/github.com/open-policy-agent/gatekeeper-external-data-provider/bin/provider .
|
||||
|
||||
COPY --from=builder --chown=65532:65532 /go/src/github.com/open-policy-agent/gatekeeper-external-data-provider/certs/tls.crt \
|
||||
/go/src/github.com/open-policy-agent/gatekeeper-external-data-provider/certs/tls.key \
|
||||
/certs/
|
||||
|
||||
USER 65532:65532
|
||||
|
||||
ENTRYPOINT ["/provider"]
|
||||
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
37
Makefile
Normal file
37
Makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
REPOSITORY ?= openpolicyagent/gatekeeper-external-data-provider
|
||||
IMG := $(REPOSITORY):dev
|
||||
|
||||
# When updating this, make sure to update the corresponding action in
|
||||
# workflow.yaml
|
||||
GOLANGCI_LINT_VERSION := v1.50.0
|
||||
|
||||
# Detects the location of the user golangci-lint cache.
|
||||
GOLANGCI_LINT_CACHE := $(shell pwd)/.tmp/golangci-lint
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build -o bin/provider main.go
|
||||
|
||||
# lint runs a dockerized golangci-lint, and should give consistent results
|
||||
# across systems.
|
||||
# Source: https://golangci-lint.run/usage/install/#docker
|
||||
.PHONY: lint
|
||||
lint:
|
||||
docker run --rm -v $(shell pwd):/app \
|
||||
-v ${GOLANGCI_LINT_CACHE}:/root/.cache/golangci-lint \
|
||||
-w /app golangci/golangci-lint:${GOLANGCI_LINT_VERSION}-alpine \
|
||||
golangci-lint run -v
|
||||
|
||||
.PHONY: docker-buildx-builder
|
||||
docker-buildx-builder:
|
||||
if ! docker buildx ls | grep -q container-builder; then\
|
||||
docker buildx create --name container-builder --use;\
|
||||
fi
|
||||
|
||||
.PHONY: docker-buildx
|
||||
docker-buildx: docker-buildx-builder
|
||||
docker buildx build --load -t ${IMG} .
|
||||
|
||||
.PHONY: kind-load-image
|
||||
kind-load-image:
|
||||
kind load docker-image ${IMG} --name gatekeeper
|
||||
115
README.md
Normal file
115
README.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# External Data Provider
|
||||
|
||||
A template repository for building external data providers for Gatekeeper.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [ ] [`docker`](https://docs.docker.com/get-docker/)
|
||||
- [ ] [`helm`](https://helm.sh/)
|
||||
- [ ] [`kind`](https://kind.sigs.k8s.io/)
|
||||
- [ ] [`kubectl`](https://kubernetes.io/docs/tasks/tools/#kubectl)
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Create a [kind cluster](https://kind.sigs.k8s.io/docs/user/quick-start/).
|
||||
|
||||
2. Install the latest version of Gatekeeper and enable the external data feature.
|
||||
|
||||
```bash
|
||||
# Add the Gatekeeper Helm repository
|
||||
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
|
||||
|
||||
# Install the latest version of Gatekeeper with the external data feature enabled.
|
||||
helm install gatekeeper/gatekeeper \
|
||||
--set enableExternalData=true \
|
||||
--name-template=gatekeeper \
|
||||
--namespace gatekeeper-system \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
3. Build and deploy the external data provider.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/open-policy-agent/gatekeeper-external-data-provider.git
|
||||
cd external-data-provider
|
||||
|
||||
# if you are not planning to establish mTLS between the provider and Gatekeeper,
|
||||
# deploy the provider to a separate namespace. Otherwise, do not run the following command
|
||||
# and deploy the provider to the same namespace as Gatekeeper.
|
||||
export NAMESPACE=provider-system
|
||||
|
||||
# generate a self-signed certificate for the external data provider
|
||||
./scripts/generate-tls-cert.sh
|
||||
|
||||
# build the image via docker buildx
|
||||
make docker-buildx
|
||||
|
||||
# load the image into kind
|
||||
make kind-load-image
|
||||
|
||||
# Choose one of the following ways to deploy the external data provider:
|
||||
|
||||
# 1. client and server auth enabled (recommended)
|
||||
helm install external-data-provider charts/external-data-provider \
|
||||
--set provider.tls.caBundle="$(cat certs/ca.crt | base64 | tr -d '\n\r')" \
|
||||
--namespace "${NAMESPACE:-gatekeeper-system}"
|
||||
|
||||
# 2. client auth disabled and server auth enabled
|
||||
helm install external-data-provider charts/external-data-provider \
|
||||
--set clientCAFile="" \
|
||||
--set provider.tls.caBundle="$(cat certs/ca.crt | base64 | tr -d '\n\r')" \
|
||||
--namespace "${NAMESPACE:-gatekeeper-system}" \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
4a. Install constraint template and constraint.
|
||||
|
||||
```bash
|
||||
kubectl apply -f validation/external-data-provider-constraint-template.yaml
|
||||
kubectl apply -f validation/external-data-provider-constraint.yaml
|
||||
```
|
||||
|
||||
4b. Test the external data provider by dry-running the following command:
|
||||
|
||||
```bash
|
||||
kubectl run nginx --image=error_nginx --dry-run=server -ojson
|
||||
```
|
||||
|
||||
Gatekeeper should deny the pod admission above because the image field has an `error_nginx` prefix.
|
||||
|
||||
```console
|
||||
Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [deny-images-with-invalid-suffix] invalid response: {"errors": [["error_nginx", "error_nginx_invalid"]], "responses": [], "status_code": 200, "system_error": ""}
|
||||
```
|
||||
|
||||
5a. Install Assign mutation.
|
||||
|
||||
```bash
|
||||
kubectl apply -f mutation/external-data-provider-mutation.yaml
|
||||
```
|
||||
|
||||
5b. Test the external data provider by dry-running the following command:
|
||||
|
||||
```bash
|
||||
kubectl run nginx --image=nginx --dry-run=server -ojson
|
||||
```
|
||||
|
||||
The expected JSON output should have the following image field with `_valid` appended by the external data provider:
|
||||
|
||||
```json
|
||||
"containers": [
|
||||
{
|
||||
"name": "nginx",
|
||||
"image": "nginx_valid",
|
||||
...
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
6. Uninstall the external data provider and Gatekeeper.
|
||||
|
||||
```bash
|
||||
kubectl delete -f validation/
|
||||
kubectl delete -f mutation/
|
||||
helm uninstall external-data-provider --namespace "${NAMESPACE:-gatekeeper-system}"
|
||||
helm uninstall gatekeeper --namespace gatekeeper-system
|
||||
```
|
||||
3
SECURITY.md
Normal file
3
SECURITY.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Security
|
||||
|
||||
See [https://github.com/open-policy-agent/opa/blob/main/SECURITY.md](https://github.com/open-policy-agent/opa/blob/main/SECURITY.md)
|
||||
21
charts/external-data-provider/.helmignore
Normal file
21
charts/external-data-provider/.helmignore
Normal file
@@ -0,0 +1,21 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
8
charts/external-data-provider/Chart.yaml
Normal file
8
charts/external-data-provider/Chart.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: v2
|
||||
description: A Helm chart for a template external data provider
|
||||
name: external-data-provider
|
||||
version: 0.0.2
|
||||
home: https://github.com/open-policy-agent/gatekeeper-external-data-provider
|
||||
sources:
|
||||
- https://github.com/open-policy-agent/gatekeeper-external-data-provider.git
|
||||
appVersion: 0.0.2
|
||||
0
charts/external-data-provider/README.md
Normal file
0
charts/external-data-provider/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: external-data-provider
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
run: external-data-provider
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: external-data-provider
|
||||
spec:
|
||||
containers:
|
||||
- image: openpolicyagent/gatekeeper-external-data-provider:dev
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: external-data-provider
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
runAsGroup: 65532
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65532
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
args:
|
||||
- --cert-dir={{ .Values.certDir }}
|
||||
{{- if .Values.clientCAFile }}
|
||||
- --client-ca-file={{ .Values.clientCAFile }}
|
||||
{{- end }}
|
||||
- --port={{ .Values.port }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.port }}
|
||||
protocol: TCP
|
||||
{{- if .Values.clientCAFile }}
|
||||
volumeMounts:
|
||||
- name: gatekeeper-ca-cert
|
||||
mountPath: /tmp/gatekeeper
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
restartPolicy: Always
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
{{- if .Values.clientCAFile }}
|
||||
volumes:
|
||||
- name: gatekeeper-ca-cert
|
||||
secret:
|
||||
secretName: gatekeeper-webhook-server-cert
|
||||
items:
|
||||
- key: ca.crt
|
||||
path: ca.crt
|
||||
{{- end }}
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: external-data-provider
|
||||
namespace: {{ .Release.Namespace }}
|
||||
spec:
|
||||
ports:
|
||||
- port: {{ .Values.port }}
|
||||
protocol: TCP
|
||||
targetPort: {{ .Values.port }}
|
||||
selector:
|
||||
run: external-data-provider
|
||||
sessionAffinity: None
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: externaldata.gatekeeper.sh/v1beta1
|
||||
kind: Provider
|
||||
metadata:
|
||||
name: external-data-provider
|
||||
spec:
|
||||
url: https://external-data-provider.{{ .Release.Namespace }}:{{ .Values.port }}
|
||||
timeout: {{ .Values.provider.timeout }}
|
||||
caBundle: {{ required "You must provide .Values.provider.tls.caBundle" .Values.provider.tls.caBundle }}
|
||||
7
charts/external-data-provider/values.yaml
Normal file
7
charts/external-data-provider/values.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
certDir: /certs
|
||||
clientCAFile: /tmp/gatekeeper/ca.crt
|
||||
port: 8090
|
||||
provider:
|
||||
timeout: 1
|
||||
tls:
|
||||
caBundle: ""
|
||||
32
go.mod
Normal file
32
go.mod
Normal file
@@ -0,0 +1,32 @@
|
||||
module github.com/open-policy-agent/gatekeeper-external-data-provider
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/open-policy-agent/frameworks/constraint v0.0.0-20221214024800-b745745c4118
|
||||
k8s.io/klog/v2 v2.60.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/open-policy-agent/opa v0.47.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/apimachinery v0.24.7 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
259
go.sum
Normal file
259
go.sum
Normal file
@@ -0,0 +1,259 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
|
||||
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/open-policy-agent/frameworks/constraint v0.0.0-20221214024800-b745745c4118 h1:2i9k9I69KX48JTWxp+u4kfMRNgoP50A6uPPqo93uhow=
|
||||
github.com/open-policy-agent/frameworks/constraint v0.0.0-20221214024800-b745745c4118/go.mod h1:sN/YfAskVfaDy234+bETlOymFLDoLdJZvMdACwenxc8=
|
||||
github.com/open-policy-agent/opa v0.47.2 h1:9QmIumL6MRPYoXboBDSU/c1fG2PN5J4lo800RK36jrc=
|
||||
github.com/open-policy-agent/opa v0.47.2/go.mod h1:I5DbT677OGqfk9gvu5i54oIt0rrVf4B5pedpqDquAXo=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/apimachinery v0.24.7 h1:CYJ+iRJkNFWWdUz5XodHkA6Yk5nRTbudvvQDVGxtuqc=
|
||||
k8s.io/apimachinery v0.24.7/go.mod h1:WR5z9Lpw2mOAeDg20iSSrEBRQMY0p2YXVdYpUIgSr4o=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc=
|
||||
k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
105
main.go
Normal file
105
main.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/handler"
|
||||
"github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/utils"
|
||||
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
timeout = 1 * time.Second
|
||||
defaultPort = 8090
|
||||
|
||||
certName = "tls.crt"
|
||||
keyName = "tls.key"
|
||||
)
|
||||
|
||||
var (
|
||||
certDir string
|
||||
clientCAFile string
|
||||
port int
|
||||
)
|
||||
|
||||
func init() {
|
||||
klog.InitFlags(nil)
|
||||
flag.StringVar(&certDir, "cert-dir", "", "path to directory containing TLS certificates")
|
||||
flag.StringVar(&clientCAFile, "client-ca-file", "", "path to client CA certificate")
|
||||
flag.IntVar(&port, "port", defaultPort, "Port for the server to listen on")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", processTimeout(handler.Handler, timeout))
|
||||
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
Handler: mux,
|
||||
ReadHeaderTimeout: time.Duration(5) * time.Second,
|
||||
}
|
||||
|
||||
config := &tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
if clientCAFile != "" {
|
||||
klog.InfoS("loading Gatekeeper's CA certificate", "clientCAFile", clientCAFile)
|
||||
caCert, err := os.ReadFile(clientCAFile)
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "unable to load Gatekeeper's CA certificate", "clientCAFile", clientCAFile)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
clientCAs := x509.NewCertPool()
|
||||
clientCAs.AppendCertsFromPEM(caCert)
|
||||
|
||||
config.ClientCAs = clientCAs
|
||||
config.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
server.TLSConfig = config
|
||||
}
|
||||
|
||||
if certDir != "" {
|
||||
certFile := filepath.Join(certDir, certName)
|
||||
keyFile := filepath.Join(certDir, keyName)
|
||||
|
||||
klog.InfoS("starting external data provider server", "port", port, "certFile", certFile, "keyFile", keyFile)
|
||||
if err := server.ListenAndServeTLS(certFile, keyFile); err != nil {
|
||||
klog.ErrorS(err, "unable to start external data provider server")
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
klog.Error("TLS certificates are not provided, the server will not be started")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func processTimeout(h http.HandlerFunc, duration time.Duration) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := context.WithTimeout(r.Context(), duration)
|
||||
defer cancel()
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
processDone := make(chan bool)
|
||||
go func() {
|
||||
h(w, r)
|
||||
processDone <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
utils.SendResponse(nil, "operation timed out", w)
|
||||
case <-processDone:
|
||||
}
|
||||
}
|
||||
}
|
||||
20
mutation/external-data-provider-mutation.yaml
Normal file
20
mutation/external-data-provider-mutation.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
apiVersion: mutations.gatekeeper.sh/v1beta1
|
||||
kind: Assign
|
||||
metadata:
|
||||
name: append-valid-suffix-to-image
|
||||
spec:
|
||||
applyTo:
|
||||
- groups: [""]
|
||||
kinds: ["Pod"]
|
||||
versions: ["v1"]
|
||||
match:
|
||||
scope: Namespaced
|
||||
kinds:
|
||||
- apiGroups: ["*"]
|
||||
kinds: ["Pod"]
|
||||
location: "spec.containers[name: *].image"
|
||||
parameters:
|
||||
assign:
|
||||
externalData:
|
||||
provider: external-data-provider
|
||||
dataSource: ValueAtLocation
|
||||
66
pkg/handler/handler.go
Normal file
66
pkg/handler/handler.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
|
||||
"github.com/open-policy-agent/gatekeeper-external-data-provider/pkg/utils"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
func Handler(w http.ResponseWriter, req *http.Request) {
|
||||
// only accept POST requests
|
||||
if req.Method != http.MethodPost {
|
||||
utils.SendResponse(nil, "only POST is allowed", w)
|
||||
return
|
||||
}
|
||||
|
||||
// read request body
|
||||
requestBody, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
utils.SendResponse(nil, fmt.Sprintf("unable to read request body: %v", err), w)
|
||||
return
|
||||
}
|
||||
|
||||
klog.InfoS("received request", "body", requestBody)
|
||||
|
||||
// parse request body
|
||||
var providerRequest externaldata.ProviderRequest
|
||||
err = json.Unmarshal(requestBody, &providerRequest)
|
||||
if err != nil {
|
||||
utils.SendResponse(nil, fmt.Sprintf("unable to unmarshal request body: %v", err), w)
|
||||
return
|
||||
}
|
||||
|
||||
results := make([]externaldata.Item, 0)
|
||||
// iterate over all keys
|
||||
for _, key := range providerRequest.Request.Keys {
|
||||
// Providers should add a caching mechanism to avoid extra calls to external data sources.
|
||||
|
||||
// following checks are for testing purposes only
|
||||
// check if key contains "_systemError" to trigger a system error
|
||||
if strings.HasSuffix(key, "_systemError") {
|
||||
utils.SendResponse(nil, "testing system error", w)
|
||||
return
|
||||
}
|
||||
|
||||
// check if key contains "error_" to trigger an error
|
||||
if strings.HasPrefix(key, "error_") {
|
||||
results = append(results, externaldata.Item{
|
||||
Key: key,
|
||||
Error: key + "_invalid",
|
||||
})
|
||||
} else if !strings.HasSuffix(key, "_valid") {
|
||||
// valid key will have "_valid" appended as return value
|
||||
results = append(results, externaldata.Item{
|
||||
Key: key,
|
||||
Value: key + "_valid",
|
||||
})
|
||||
}
|
||||
}
|
||||
utils.SendResponse(&results, "", w)
|
||||
}
|
||||
40
pkg/utils/utils.go
Normal file
40
pkg/utils/utils.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/open-policy-agent/frameworks/constraint/pkg/externaldata"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
apiVersion = "externaldata.gatekeeper.sh/v1beta1"
|
||||
kind = "ProviderResponse"
|
||||
)
|
||||
|
||||
// sendResponse sends back the response to Gatekeeper.
|
||||
func SendResponse(results *[]externaldata.Item, systemErr string, w http.ResponseWriter) {
|
||||
response := externaldata.ProviderResponse{
|
||||
APIVersion: apiVersion,
|
||||
Kind: kind,
|
||||
Response: externaldata.Response{
|
||||
Idempotent: true, // mutation requires idempotent results
|
||||
},
|
||||
}
|
||||
|
||||
if results != nil {
|
||||
response.Response.Items = *results
|
||||
} else {
|
||||
response.Response.SystemError = systemErr
|
||||
}
|
||||
|
||||
klog.InfoS("sending response", "response", response)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
klog.ErrorS(err, "unable to encode response")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
27
scripts/generate-tls-cert.sh
Executable file
27
scripts/generate-tls-cert.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
REPO_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
|
||||
cd "${REPO_ROOT}" || exit 1
|
||||
NAMESPACE=${NAMESPACE:-gatekeeper-system}
|
||||
|
||||
generate() {
|
||||
# generate CA key and certificate
|
||||
echo "Generating CA key and certificate for external-data-provider..."
|
||||
openssl genrsa -out ca.key 2048
|
||||
openssl req -new -x509 -days 1 -key ca.key -subj "/O=Gatekeeper/CN=Gatekeeper Root CA" -out ca.crt
|
||||
|
||||
# generate server key and certificate
|
||||
echo "Generating server key and certificate for external-data-provider..."
|
||||
openssl genrsa -out tls.key 2048
|
||||
openssl req -newkey rsa:2048 -nodes -keyout tls.key -subj "/CN=external-data-provider.${NAMESPACE}" -out server.csr
|
||||
openssl x509 -req -extfile <(printf "subjectAltName=DNS:external-data-provider.%s" "${NAMESPACE}") -days 1 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out tls.crt
|
||||
}
|
||||
|
||||
mkdir -p "${REPO_ROOT}/certs"
|
||||
pushd "${REPO_ROOT}/certs"
|
||||
generate
|
||||
popd
|
||||
140
test/bats/helpers.bash
Normal file
140
test/bats/helpers.bash
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/bin/bash
|
||||
|
||||
assert_success() {
|
||||
if [[ "$status" != 0 ]]; then
|
||||
echo "expected: 0"
|
||||
echo "actual: $status"
|
||||
echo "output: $output"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_failure() {
|
||||
if [[ "$status" == 0 ]]; then
|
||||
echo "expected: non-zero exit code"
|
||||
echo "actual: $status"
|
||||
echo "output: $output"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_equal() {
|
||||
if [[ "$1" != "$2" ]]; then
|
||||
echo "expected: $1"
|
||||
echo "actual: $2"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_equal() {
|
||||
if [[ "$1" == "$2" ]]; then
|
||||
echo "unexpected: $1"
|
||||
echo "actual: $2"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_match() {
|
||||
if [[ ! "$2" =~ $1 ]]; then
|
||||
echo "expected: $1"
|
||||
echo "actual: $2"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_match() {
|
||||
if [[ "$2" =~ $1 ]]; then
|
||||
echo "expected: $1"
|
||||
echo "actual: $2"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_len() {
|
||||
if [[ "$1" != "${#2}" ]]; then
|
||||
echo "expected len: $1"
|
||||
echo "actual len: ${#2} ($2)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
wait_for_process() {
|
||||
wait_time="$1"
|
||||
sleep_time="$2"
|
||||
cmd="$3"
|
||||
while [ "$wait_time" -gt 0 ]; do
|
||||
if eval "$cmd"; then
|
||||
return 0
|
||||
else
|
||||
sleep "$sleep_time"
|
||||
wait_time=$((wait_time - sleep_time))
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
get_ca_cert() {
|
||||
destination="$1"
|
||||
if [ $(kubectl get secret -n ${GATEKEEPER_NAMESPACE} gatekeeper-webhook-server-cert -o jsonpath='{.data.ca\.crt}' | wc -w) -eq 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
kubectl get secret -n ${GATEKEEPER_NAMESPACE} gatekeeper-webhook-server-cert -o jsonpath='{.data.ca\.crt}' | base64 -d >$destination
|
||||
}
|
||||
|
||||
constraint_enforced() {
|
||||
local kind="$1"
|
||||
local name="$2"
|
||||
local pod_list="$(kubectl -n ${GATEKEEPER_NAMESPACE} get pod -l gatekeeper.sh/operation=webhook -o json)"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "error gathering pods"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ensure pod_count is at least one
|
||||
local pod_count=$(echo "${pod_list}" | jq '.items | length')
|
||||
if [[ ${pod_count} -lt 1 ]]; then
|
||||
echo "Gatekeeper pod count is < 1"
|
||||
return 2
|
||||
fi
|
||||
|
||||
local cstr="$(kubectl get ${kind} ${name} -ojson)"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Error gathering constraint ${kind} ${name}"
|
||||
return 3
|
||||
fi
|
||||
|
||||
echo "checking constraint ${cstr}"
|
||||
|
||||
local ready_count=$(echo "${cstr}" | jq '.metadata.generation as $generation | [.status.byPod[] | select( .operations[] == "webhook" and .observedGeneration == $generation)] | length')
|
||||
echo "ready: ${ready_count}, expected: ${pod_count}"
|
||||
[[ "${ready_count}" -eq "${pod_count}" ]]
|
||||
}
|
||||
|
||||
mutator_enforced() {
|
||||
local kind="$1"
|
||||
local name="$2"
|
||||
local pod_list="$(kubectl -n ${GATEKEEPER_NAMESPACE} get pod -l gatekeeper.sh/operation=webhook -o json)"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "error gathering pods"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# ensure pod_count is at least one
|
||||
local pod_count=$(echo "${pod_list}" | jq '.items | length')
|
||||
if [[ ${pod_count} -lt 1 ]]; then
|
||||
echo "Gatekeeper pod count is < 1"
|
||||
return 2
|
||||
fi
|
||||
|
||||
local cstr="$(kubectl get ${kind} ${name} -ojson)"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Error gathering mutator ${kind} ${name}"
|
||||
return 3
|
||||
fi
|
||||
|
||||
echo "checking mutator ${cstr}"
|
||||
|
||||
local ready_count=$(echo "${cstr}" | jq '.metadata.generation as $generation | [.status.byPod[] | select( .operations[] == "mutation-webhook" and .observedGeneration == $generation)] | length')
|
||||
echo "ready: ${ready_count}, expected: ${pod_count}"
|
||||
[[ "${ready_count}" -eq "${pod_count}" ]]
|
||||
}
|
||||
51
test/bats/test.bats
Normal file
51
test/bats/test.bats
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
WAIT_TIME=120
|
||||
SLEEP_TIME=1
|
||||
GATEKEEPER_NAMESPACE=${GATEKEEPER_NAMESPACE:-gatekeeper-system}
|
||||
|
||||
teardown_file() {
|
||||
kubectl delete -f validation/
|
||||
kubectl delete -f mutation/
|
||||
}
|
||||
|
||||
@test "gatekeeper-controller-manager is running" {
|
||||
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl -n ${GATEKEEPER_NAMESPACE} wait --for=condition=Ready --timeout=60s pod -l control-plane=controller-manager"
|
||||
}
|
||||
|
||||
@test "gatekeeper-audit is running" {
|
||||
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl -n ${GATEKEEPER_NAMESPACE} wait --for=condition=Ready --timeout=60s pod -l control-plane=audit-controller"
|
||||
}
|
||||
|
||||
@test "external-data-provider is running" {
|
||||
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl -n ${GATEKEEPER_NAMESPACE} wait --for=condition=Ready --timeout=60s pod -l run=external-data-provider"
|
||||
}
|
||||
|
||||
@test "external data validation" {
|
||||
run kubectl apply -f validation/external-data-provider-constraint-template.yaml
|
||||
assert_success
|
||||
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "constraint_enforced constrainttemplate k8sexternaldatavalidation"
|
||||
|
||||
run kubectl apply -f validation/external-data-provider-constraint.yaml
|
||||
assert_success
|
||||
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "constraint_enforced k8sexternaldatavalidation deny-images-with-invalid-suffix"
|
||||
|
||||
run kubectl run nginx --image=error_nginx --dry-run=server
|
||||
# should deny pod admission if the image name has an "error_" prefix
|
||||
assert_failure
|
||||
assert_match 'error_nginx' "${output}"
|
||||
assert_match 'error_nginx_invalid' "${output}"
|
||||
}
|
||||
|
||||
@test "external data mutation" {
|
||||
run kubectl apply -f mutation/external-data-provider-mutation.yaml
|
||||
assert_success
|
||||
wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "mutator_enforced Assign append-valid-suffix-to-image"
|
||||
|
||||
run kubectl run nginx --image=nginx --dry-run=server --output json
|
||||
assert_success
|
||||
# should mutate the image field by appending "_valid" suffix
|
||||
assert_match "nginx_valid" "$(jq -r '.spec.containers[0].image' <<< ${output})"
|
||||
}
|
||||
35
validation/external-data-provider-constraint-template.yaml
Normal file
35
validation/external-data-provider-constraint-template.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
apiVersion: templates.gatekeeper.sh/v1
|
||||
kind: ConstraintTemplate
|
||||
metadata:
|
||||
name: k8sexternaldatavalidation
|
||||
spec:
|
||||
crd:
|
||||
spec:
|
||||
names:
|
||||
kind: K8sExternalDataValidation
|
||||
targets:
|
||||
- target: admission.k8s.gatekeeper.sh
|
||||
rego: |
|
||||
package k8sexternaldata
|
||||
|
||||
violation[{"msg": msg}] {
|
||||
# build a list of keys containing images
|
||||
images := [img | img = input.review.object.spec.containers[_].image]
|
||||
|
||||
# send external data request
|
||||
response := external_data({"provider": "external-data-provider", "keys": images})
|
||||
|
||||
response_with_error(response)
|
||||
|
||||
msg := sprintf("invalid response: %v", [response])
|
||||
}
|
||||
|
||||
response_with_error(response) {
|
||||
count(response.errors) > 0
|
||||
errs := response.errors[_]
|
||||
contains(errs[1], "_invalid")
|
||||
}
|
||||
|
||||
response_with_error(response) {
|
||||
count(response.system_error) > 0
|
||||
}
|
||||
10
validation/external-data-provider-constraint.yaml
Normal file
10
validation/external-data-provider-constraint.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
apiVersion: constraints.gatekeeper.sh/v1beta1
|
||||
kind: K8sExternalDataValidation
|
||||
metadata:
|
||||
name: deny-images-with-invalid-suffix
|
||||
spec:
|
||||
enforcementAction: deny
|
||||
match:
|
||||
kinds:
|
||||
- apiGroups: ["*"]
|
||||
kinds: ["Pod"]
|
||||
Reference in New Issue
Block a user