diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml new file mode 100644 index 00000000..6e8d8c97 --- /dev/null +++ b/.github/workflows/integration_test.yml @@ -0,0 +1,43 @@ +name: integration + +on: + push: + branches: [ master, dev ] + pull_request: + branches: [ master, dev ] + +jobs: + integration: + runs-on: ubuntu-latest + strategy: + matrix: + namespace: [policy-system, test-system] + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Install Helm + uses: azure/setup-helm@v3 + - name: Install kubectl + uses: azure/setup-kubectl@v3 + - name: Install kind + uses: helm/kind-action@v1.3.0 + with: + install_only: true + - name: setup go + uses: actions/setup-go@v3 + with: + go-version: '1.17' + cache: true + - name: Run tests + env: + NAMESPACE: ${{ matrix.namespace }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + run: | + make build + + export VERSION=$(cat ./version.txt) + docker build -t weaveworks/policy-agent:${VERSION} . + + cd test/integration + bash deploy.sh + go test -v ./... diff --git a/Makefile b/Makefile index b26391de..c352129b 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ vet: ## Run go vet against code. .PHONY: test test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -v ./... -coverprofile cover.out + KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -v ./internal/... ./controllers/... ./pkg/... -coverprofile cover.out ##@ Build diff --git a/api/v2beta2/policy_types.go b/api/v2beta2/policy_types.go index b3e70c1e..dd691733 100644 --- a/api/v2beta2/policy_types.go +++ b/api/v2beta2/policy_types.go @@ -129,6 +129,11 @@ type PolicySpec struct { //+kubebuilder:validation:Enum=kubernetes;terraform // Provider is policy provider, can be kubernetes, terraform Provider string `json:"provider"` + + //+optional + //+kubebuilder:default:=false + // Mutate is a flag that indicates whether to enable mutation of resources violating this policy or not + Mutate bool `json:"mutate"` } //+kubebuilder:object:root=true diff --git a/config/crd/bases/pac.weave.works_policies.yaml b/config/crd/bases/pac.weave.works_policies.yaml index 8eee1ede..63f708d2 100644 --- a/config/crd/bases/pac.weave.works_policies.yaml +++ b/config/crd/bases/pac.weave.works_policies.yaml @@ -348,6 +348,11 @@ spec: id: description: ID is the policy unique identifier type: string + mutate: + default: false + description: Mutate is a flag that indicates whether to enable mutation + of resources violating this policy or not + type: boolean name: description: Name is the policy name type: string diff --git a/configuration/config.go b/configuration/config.go index 82591896..4106651c 100644 --- a/configuration/config.go +++ b/configuration/config.go @@ -50,6 +50,7 @@ type AdmissionConfig struct { Enabled bool Webhook AdmissionWebhook Sinks SinksConfig + Mutate bool } type AuditConfig struct { diff --git a/docs/README.md b/docs/README.md index 679f2bcf..8aa2ee8a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -68,6 +68,20 @@ This contains the admission module that enforces policies. It uses the `controll > Works with policies of provider `kubernetes` +#### Mutating Resources + +Starting from version `v2.2.0`, the policy agent will support mutating resources. To enable mutating resources set `mutate` flag to `true` in the `admission` configuration section. + +```yaml +admission: + enabled: true + mutate: true # set this field to true to enable mutating resources + sinks: + filesystemSink: + fileName: admission.txt +``` + +> See [here](./policy.md#mutating-resources) how to make policies support mutating resources. ### Terraform Admission diff --git a/docs/mutation.png b/docs/mutation.png new file mode 100644 index 00000000..29b2ba10 Binary files /dev/null and b/docs/mutation.png differ diff --git a/docs/policy.md b/docs/policy.md index efba74f1..694cf226 100644 --- a/docs/policy.md +++ b/docs/policy.md @@ -18,3 +18,24 @@ Here is the Weaveworks [Policy Library](https://github.com/weaveworks/policy-lib It is used in [Multi Tenancy](https://docs.gitops.weave.works/docs/enterprise/multi-tenancy/) feature in [Weave GitOps Enterprise](https://docs.gitops.weave.works/docs/enterprise/intro/) Tenant policies has a special tag `tenancy`. + +## Mutating Resources + + +![](./mutation.png) + +Starting from version `v2.2.0`, the policy agent will support mutating resources. + +To enable mutating resources policies must have field `mutate` set to `true` and the rego code should return the `violating_key` and the `recommended_value` in the violation response. The mutation webhook will use the `violating_key` and `recommended_value` to mutate the resource and return the new mutated resource. + +Example + +``` +result = { + "issue_detected": true, + "msg": sprintf("Replica count must be greater than or equal to '%v'; found '%v'.", [min_replica_count, replicas]), + "violating_key": "spec.replicas", + "recommended_value": min_replica_count +} +``` + diff --git a/go.mod b/go.mod index 2d9dca95..4fccee8b 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/MagalixTechnologies/channel v1.1.0 github.com/MagalixTechnologies/core/logger v1.0.4 github.com/MagalixTechnologies/core/packet v1.0.1 - github.com/MagalixTechnologies/policy-core v1.1.5 + github.com/MagalixTechnologies/policy-core v1.1.6 github.com/MagalixTechnologies/uuid-go v0.0.0-20210127133914-f8f07f7ab96e github.com/elastic/go-elasticsearch/v7 v7.17.1 github.com/fluxcd/pkg/runtime v0.13.1 @@ -25,34 +25,41 @@ require ( github.com/weaveworks/policy-agent/api v0.0.0 go.uber.org/zap v1.19.1 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f - k8s.io/api v0.23.5 - k8s.io/apiextensions-apiserver v0.23.4 - k8s.io/apimachinery v0.23.5 - k8s.io/client-go v0.23.4 - sigs.k8s.io/controller-runtime v0.11.1 + k8s.io/api v0.24.0 + k8s.io/apiextensions-apiserver v0.24.0 + k8s.io/apimachinery v0.24.0 + k8s.io/client-go v0.24.0 + sigs.k8s.io/controller-runtime v0.12.0 ) require ( github.com/MagalixTechnologies/opa-core v1.0.12 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/agnivade/levenshtein v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/emicklei/go-restful v2.9.5+incompatible // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect + github.com/go-errors/errors v1.4.2 // indirect github.com/go-logr/zapr v1.2.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/swag v0.22.3 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.5.7-v3refs // indirect github.com/google/go-cmp v0.5.8 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.2.0 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -60,12 +67,15 @@ require ( github.com/hashicorp/go-retryablehttp v0.6.8 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/magiconair/properties v1.8.5 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/open-policy-agent/opa v0.42.2 // indirect github.com/pelletier/go-toml v1.9.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -92,7 +102,7 @@ require ( golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.28.0 // indirect @@ -100,11 +110,12 @@ require ( gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/component-base v0.23.4 // indirect - k8s.io/klog/v2 v2.30.0 // indirect - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect - k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect - sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect + k8s.io/component-base v0.24.0 // indirect + k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 // indirect + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect + sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.10 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/go.sum b/go.sum index 5ac4d5e7..37b10283 100644 --- a/go.sum +++ b/go.sum @@ -83,14 +83,8 @@ github.com/MagalixTechnologies/core/packet v1.0.1/go.mod h1:419K/Uaw6PeeTcEF+HVL github.com/MagalixTechnologies/opa-core v1.0.12 h1:v9fwq+fwXBnKT7LXK7Ynbb5AkXym+GPEUX5wpdovRu8= github.com/MagalixTechnologies/opa-core v1.0.12/go.mod h1:OOvF4AcJEQ1fAcelaC10CCnn4w4AxoJYvRAJi5yFGgo= github.com/MagalixTechnologies/policy-core v1.0.8/go.mod h1:gM6cocm6aDq7c1DW+JbQlzv1RMM6iwiJojBufSXPUfU= -github.com/MagalixTechnologies/policy-core v1.1.4-0.20220905094853-05b9bb3e692f h1:T6Rzw/JgjcTQNUsOBw5cHq1jrWAPXsVmSVEbPClx/q0= -github.com/MagalixTechnologies/policy-core v1.1.4-0.20220905094853-05b9bb3e692f/go.mod h1:RbahYwsnnuXltrFjcey3nVYmkheHjulMYpy70wJ4Iss= -github.com/MagalixTechnologies/policy-core v1.1.4-0.20221018145312-5eb9fa407b3e h1:Q6aohS8aWx2KEsBCnv2Fdh7lW+0EhBTuFHT9m+MjXKQ= -github.com/MagalixTechnologies/policy-core v1.1.4-0.20221018145312-5eb9fa407b3e/go.mod h1:QiXg0U5XiGVdqe58BD9t+sGGuAh2HzyHvBiFpBAUhyU= -github.com/MagalixTechnologies/policy-core v1.1.4 h1:VuSCQOpYMVAiQAlZ6AazOaLIQkb5adMn9A9mR/deyCg= -github.com/MagalixTechnologies/policy-core v1.1.4/go.mod h1:QiXg0U5XiGVdqe58BD9t+sGGuAh2HzyHvBiFpBAUhyU= -github.com/MagalixTechnologies/policy-core v1.1.5 h1:hn7Hlgzh7hdfZ/GPtTxsI2w5Sv8C7Vr6/gUCDfRAKLQ= -github.com/MagalixTechnologies/policy-core v1.1.5/go.mod h1:QiXg0U5XiGVdqe58BD9t+sGGuAh2HzyHvBiFpBAUhyU= +github.com/MagalixTechnologies/policy-core v1.1.6 h1:IGCYy3wFEkqxV4Hej0W2UfVMKCXYZUf+BokueLlfFBk= +github.com/MagalixTechnologies/policy-core v1.1.6/go.mod h1:0qmPoLR4Ay/ZHMIjJvJD0ps4UIutw6SmTEZHmtwq5ZU= github.com/MagalixTechnologies/uuid-go v0.0.0-20200102125057-aa0bb55c403a/go.mod h1:O74c5ywMyRjVPErmn6fQ8Z3narXcQE+0Qf5vzWQ9HLU= github.com/MagalixTechnologies/uuid-go v0.0.0-20210127133914-f8f07f7ab96e h1:l/ci+0/7XVCFdnLSIvgTM9femU75hXpoCBgVX+w1XTA= github.com/MagalixTechnologies/uuid-go v0.0.0-20210127133914-f8f07f7ab96e/go.mod h1:/ZuJrsOm2BFLXkKN6zBuQ5L35llSU1x40U5eo4Aa6Dg= @@ -123,8 +117,10 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE 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.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= @@ -146,6 +142,7 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +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/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= @@ -164,6 +161,7 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= @@ -393,6 +391,7 @@ github.com/elastic/go-elasticsearch/v7 v7.17.1 h1:49mHcHx7lpCL8cW1aioEwSEVKQF3s+ github.com/elastic/go-elasticsearch/v7 v7.17.1/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= 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/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -442,6 +441,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -469,10 +470,12 @@ github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQ github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= @@ -480,6 +483,8 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -549,9 +554,12 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= +github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +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= @@ -603,7 +611,6 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= @@ -697,6 +704,7 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -746,6 +754,8 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -802,6 +812,7 @@ github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGq github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= 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= @@ -809,9 +820,11 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN 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/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1084,6 +1097,7 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mod h1:HptNXiXVDcJjXe9SqMd0v2FsL9f8dz4GnXgltU6q/co= github.com/yashtewari/glob-intersection v0.1.0 h1:6gJvMYQlTDOL3dMsPF6J0+26vwX9MB8/1q3uAdhmTrg= @@ -1110,6 +1124,7 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3 go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= @@ -1155,6 +1170,7 @@ go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1198,6 +1214,7 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1236,6 +1253,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 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= @@ -1367,6 +1385,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1452,6 +1471,7 @@ golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/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-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1477,8 +1497,9 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1550,6 +1571,7 @@ golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 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= @@ -1780,11 +1802,14 @@ k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= k8s.io/api v0.23.2/go.mod h1:sYuDb3flCtRPI8ghn6qFrcK5ZBu2mhbElxRE95qpwlI= k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ= k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI= -k8s.io/api v0.23.5 h1:zno3LUiMubxD/V1Zw3ijyKO3wxrhbUF1Ck+VjBvfaoA= k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= +k8s.io/api v0.24.0 h1:J0hann2hfxWr1hinZIDefw7Q96wmCBx6SSB8IY0MdDg= +k8s.io/api v0.24.0/go.mod h1:5Jl90IUrJHUJYEMANRURMiVvJ0g7Ax7r3R1bqO8zx8I= k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4= k8s.io/apiextensions-apiserver v0.23.4 h1:AFDUEu/yEf0YnuZhqhIFhPLPhhcQQVuR1u3WCh0rveU= k8s.io/apiextensions-apiserver v0.23.4/go.mod h1:TWYAKymJx7nLMxWCgWm2RYGXHrGlVZnxIlGnvtfYu+g= +k8s.io/apiextensions-apiserver v0.24.0 h1:JfgFqbA8gKJ/uDT++feAqk9jBIwNnL9YGdQvaI9DLtY= +k8s.io/apiextensions-apiserver v0.24.0/go.mod h1:iuVe4aEpe6827lvO6yWQVxiPSpPoSKVjkq+MIdg84cM= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= @@ -1794,25 +1819,29 @@ k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFY k8s.io/apimachinery v0.23.2/go.mod h1:zDqeV0AK62LbCI0CI7KbWCAYdLg+E+8UXJ0rIz5gmS8= k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= -k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.24.0 h1:ydFCyC/DjCvFCHK5OPMKBlxayQytB8pxy8YQInd5UyQ= +k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4= k8s.io/apiserver v0.23.4/go.mod h1:A6l/ZcNtxGfPSqbFDoxxOjEjSKBaQmE+UTveOmMkpNc= +k8s.io/apiserver v0.24.0/go.mod h1:WFx2yiOMawnogNToVvUYT9nn1jaIkMKj41ZYCVycsBA= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA= k8s.io/client-go v0.23.2/go.mod h1:k3YbsWg6GWdHF1THHTQP88X9RhB1DWPo3Dq7KfU/D1c= -k8s.io/client-go v0.23.4 h1:YVWvPeerA2gpUudLelvsolzH7c2sFoXXR5wM/sWqNFU= k8s.io/client-go v0.23.4/go.mod h1:PKnIL4pqLuvYUK1WU7RLTMYKPiIh7MYShLshtRY9cj0= +k8s.io/client-go v0.24.0 h1:lbE4aB1gTHvYFSwm6eD3OF14NhFDKCejlnsGYlSJe5U= +k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw= k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE= k8s.io/code-generator v0.23.4/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk= +k8s.io/code-generator v0.24.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= @@ -1820,6 +1849,8 @@ k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4M k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI= k8s.io/component-base v0.23.4 h1:SziYh48+QKxK+ykJ3Ejqd98XdZIseVBG7sBaNLPqy6M= k8s.io/component-base v0.23.4/go.mod h1:8o3Gg8i2vnUXGPOwciiYlkSaZT+p+7gA9Scoz8y4W4E= +k8s.io/component-base v0.24.0 h1:h5jieHZQoHrY/lHG+HyrSbJeyfuitheBvqvKwKHVC0g= +k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= @@ -1829,25 +1860,30 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/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.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +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-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 h1:nqYOUleKLC/0P1zbU29F5q6aoezM6MOAVz+iyfQbZ5M= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= k8s.io/utils v0.0.0-20211116205334-6203023598ed/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= oras.land/oras-go v1.2.0/go.mod h1:pFNs7oHp2dYsYMSS82HaX5l4mpnGO7hbpPN6EWH2ltc= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= @@ -1857,10 +1893,16 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyz sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.27/go.mod h1:tq2nT0Kx7W+/f2JVE+zxYtUhdjuELJkVpNz+x/QN5R4= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= sigs.k8s.io/controller-runtime v0.11.1 h1:7YIHT2QnHJArj/dk9aUkYhfqfK5cIxPOX5gPECfdZLU= sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= +sigs.k8s.io/controller-runtime v0.12.0 h1:gA4zphrmHFc7ihmY/+GyyE0BxKD+OYdb5+DjD2azFAQ= +sigs.k8s.io/controller-runtime v0.12.0/go.mod h1:BKhxlA4l7FPK4AQcsuL4X6vZeWnKDXez/vp1Y8dxTU0= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +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/kustomize/kyaml v0.13.10 h1:htPMvrk7ZDfTDyrgXIm/2mfmcYJHEmRb6s+yCLgtNms= +sigs.k8s.io/kustomize/kyaml v0.13.10/go.mod h1:PzDV8gSaY8mwdd7nR9zg7Pw5yh9fu8G+ElAXoQVzBq8= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 3ab7b4e3..f8d57c3b 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.1.1" +appVersion: "2.2.0" description: A Helm chart for Kubernetes to configure the policy agent name: policy-agent -version: 2.1.1 +version: 2.2.0 maintainers: - name: Weaveworks email: support@weave.works diff --git a/helm/crds/pac.weave.works_policies.yaml b/helm/crds/pac.weave.works_policies.yaml index 8eee1ede..63f708d2 100644 --- a/helm/crds/pac.weave.works_policies.yaml +++ b/helm/crds/pac.weave.works_policies.yaml @@ -348,6 +348,11 @@ spec: id: description: ID is the policy unique identifier type: string + mutate: + default: false + description: Mutate is a flag that indicates whether to enable mutation + of resources violating this policy or not + type: boolean name: description: Name is the policy name type: string diff --git a/helm/templates/agent.yaml b/helm/templates/agent.yaml index 8e8761f0..a99fc565 100644 --- a/helm/templates/agent.yaml +++ b/helm/templates/agent.yaml @@ -336,3 +336,85 @@ webhooks: resources: - policyconfigs sideEffects: None + +--- + +{{- if and .Values.config.admission.enabled .Values.config.admission.mutate }} +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: policy-agent + labels: + app.kubernetes.io/name: policy-agent + {{- if .Values.useCertManager }} + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/agent-certificate + {{- end }} +webhooks: + - name: mutation.agent.weaveworks + clientConfig: + service: + namespace: {{ .Release.Namespace }} + name: policy-agent + path: /mutation + caBundle: {{ .Values.caCertificate | b64enc }} + rules: + - operations: [ "CREATE" ] + apiVersions: ["*"] + apiGroups: + - "" + - extensions + - apps + - batch + - metrics.k8s.io + - rbac.authorization.k8s.io + - storage.k8s.io + - source.toolkit.fluxcd.io + - gitops.weave.works + - kustomize.toolkit.fluxcd.io + - helm.toolkit.fluxcd.io + - autoscaling + resources: + - namespaces + - pods + - limitranges + - deployments + - replicationcontrollers + - statefulsets + - daemonsets + - replicasets + - jobs + - cronjobs + - services + - clusterrolebindings + - clusterroles + - roles + - rolebindings + - persistentvolumes + - persistentvolumeclaims + - storageclasses + - gitrepositories + - helmrepositories + - buckets + - gitopsclusters + - kustomizations + - helmreleases + - ocirepositories + - horizontalpodautoscalers + timeoutSeconds: 5 + failurePolicy: {{ .Values.failurePolicy }} + admissionReviewVersions: ["v1"] + sideEffects: None + matchPolicy: Equivalent + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + {{- if .Values.excludeNamespaces }} + values: + {{- toYaml .Values.excludeNamespaces | nindent 8 }} + {{- else }} + values: + - {{ .Release.Namespace }} + {{- end }} +{{- end }} diff --git a/helm/values.yaml b/helm/values.yaml index 1e3f5d24..1d6dbddb 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -24,6 +24,7 @@ config: accountId: "" clusterId: "" admission: + # mutate: true // enable mutation policies enabled: true sinks: k8sEventsSink: diff --git a/internal/admission/admission.go b/internal/admission/admission.go index a307def3..71a44028 100644 --- a/internal/admission/admission.go +++ b/internal/admission/admission.go @@ -68,9 +68,11 @@ func (a *AdmissionHandler) Handle(ctx context.Context, req ctrlAdmission.Request if err != nil { return a.handleErrors(err, ErrValidatingResource) } + if len(result.Violations) > 0 { return ctrlAdmission.ValidationResponse(false, generateResponse(result.Violations)) } + return ctrlAdmission.ValidationResponse(true, "") } diff --git a/internal/mutation/mutation.go b/internal/mutation/mutation.go new file mode 100644 index 00000000..58cc996d --- /dev/null +++ b/internal/mutation/mutation.go @@ -0,0 +1,68 @@ +package mutation + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/MagalixTechnologies/core/logger" + "github.com/MagalixTechnologies/policy-core/domain" + "github.com/MagalixTechnologies/policy-core/validation" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrl "sigs.k8s.io/controller-runtime" + ctrlAdmission "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +type MutationHandler struct { + validator validation.Validator +} + +func NewMutationHandler(validator validation.Validator) *MutationHandler { + return &MutationHandler{ + validator: validator, + } +} + +func (m *MutationHandler) handleErrors(err error, errMsg string) ctrlAdmission.Response { + logger.Errorw("validating mutation request error", "error", err, "error-message", errMsg) + errRsp := ctrlAdmission.ValidationResponse(false, errMsg) + errRsp.Result.Code = http.StatusInternalServerError + return errRsp +} + +func (m *MutationHandler) Handle(ctx context.Context, req ctrlAdmission.Request) ctrlAdmission.Response { + if req.Namespace == metav1.NamespacePublic || req.Namespace == metav1.NamespaceSystem { + return ctrlAdmission.ValidationResponse(true, "exclude default system namespaces") + } + + var entitySpec map[string]interface{} + err := json.Unmarshal(req.Object.Raw, &entitySpec) + if err != nil { + return m.handleErrors(err, fmt.Sprintf("failed to unmarshal entity %s/%s spec into a map", req.Namespace, req.Name)) + } + + entity := domain.NewEntityFromSpec(entitySpec) + result, err := m.validator.Validate(ctx, entity, string(req.AdmissionRequest.Operation)) + if err != nil { + return m.handleErrors(err, fmt.Sprintf("failed to validate entity %s/%s", req.Namespace, req.Name)) + } + + if result.Mutation != nil { + logger.Infow("mutating resource", "name", req.Name, "namespace", req.Namespace) + mutated, err := result.Mutation.NewResource() + if err != nil { + return m.handleErrors(err, fmt.Sprintf("failed to mutate entity %s/%s ", req.Namespace, req.Name)) + } + return ctrlAdmission.PatchResponseFromRaw(result.Mutation.OldResource(), mutated) + } + + return ctrlAdmission.Allowed("") +} + +// Run starts the mutation webhook server +func (m *MutationHandler) Run(mgr ctrl.Manager) error { + webhook := ctrlAdmission.Webhook{Handler: m} + mgr.GetWebhookServer().Register("/mutation", &webhook) + return nil +} diff --git a/internal/policies/policy.go b/internal/policies/policy.go index dbaefe35..8d36ac80 100644 --- a/internal/policies/policy.go +++ b/internal/policies/policy.go @@ -85,6 +85,7 @@ func (p *PoliciesWatcher) GetAll(ctx context.Context) ([]domain.Policy, error) { Namespace: policiesCRD.Items[i].Namespace, ResourceVersion: policiesCRD.Items[i].ResourceVersion, }, + Mutate: policyCRD.Mutate, } for _, standardCRD := range policyCRD.Standards { diff --git a/internal/terraform/terraform.go b/internal/terraform/terraform.go index fa15bfca..564d341c 100644 --- a/internal/terraform/terraform.go +++ b/internal/terraform/terraform.go @@ -12,7 +12,7 @@ import ( ) const ( - TypeTerraform = "Terraform" + TypeTFAdmission = "TFAdmission" ) type Response struct { diff --git a/main.go b/main.go index 4e2970f0..943720c8 100644 --- a/main.go +++ b/main.go @@ -27,6 +27,7 @@ import ( "github.com/weaveworks/policy-agent/internal/clients/gateway" "github.com/weaveworks/policy-agent/internal/clients/kube" "github.com/weaveworks/policy-agent/internal/entities/k8s" + "github.com/weaveworks/policy-agent/internal/mutation" crd "github.com/weaveworks/policy-agent/internal/policies" "github.com/weaveworks/policy-agent/internal/sink/elastic" "github.com/weaveworks/policy-agent/internal/sink/filesystem" @@ -340,6 +341,7 @@ func main() { auditor.TypeAudit, config.AccountID, config.ClusterID, + false, auditSinks..., ) auditControllerInterval := time.Duration(config.Audit.Interval) * time.Hour @@ -365,6 +367,7 @@ func main() { admission.TypeAdmission, config.AccountID, config.ClusterID, + false, admissionSinks..., ) admissionServer := admission.NewAdmissionHandler( @@ -376,6 +379,23 @@ func main() { if err != nil { return fmt.Errorf("failed to start admission server: %w", err) } + + if config.Admission.Mutate { + validator := validation.NewOPAValidator( + policiesSource, + false, + admission.TypeAdmission, + config.AccountID, + config.ClusterID, + true, + ) + mutationServer := mutation.NewMutationHandler(validator) + logger.Info("starting mutation server...") + err = mutationServer.Run(mgr) + if err != nil { + return fmt.Errorf("failed to start mutation server: %w", err) + } + } } if config.TFAdmission.Enabled { @@ -388,9 +408,10 @@ func main() { validator := validation.NewOPAValidator( policiesSource, false, - terraform.TypeTerraform, + terraform.TypeTFAdmission, config.AccountID, config.ClusterID, + false, terraformSinks..., ) diff --git a/test/integration/data/resources/admission_test_resources.yaml b/test/integration/data/resources/admission_test_resources.yaml new file mode 100644 index 00000000..851fb698 --- /dev/null +++ b/test/integration/data/resources/admission_test_resources.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: orphan-deployment + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: orphan-deployment + template: + metadata: + labels: + app: orphan-deployment + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: true + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-deployment + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: test-deployment + template: + metadata: + labels: + app: test-deployment + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: true + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: helm-app-deployment + namespace: default + labels: + helm.toolkit.fluxcd.io/name: helm-app + helm.toolkit.fluxcd.io/namespace: flux-system +spec: + replicas: 1 + selector: + matchLabels: + app: helm-app-deployment + template: + metadata: + labels: + app: helm-app-deployment + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: true + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kustomize-app-deployment + namespace: default + labels: + kustomize.toolkit.fluxcd.io/name: kustomize-app + kustomize.toolkit.fluxcd.io/namespace: flux-system +spec: + replicas: 1 + selector: + matchLabels: + app: kustomize-app-deployment + template: + metadata: + labels: + app: kustomize-app-deployment + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: true + diff --git a/test/integration/data/resources/audit_test_resources.yaml b/test/integration/data/resources/audit_test_resources.yaml new file mode 100644 index 00000000..79820a96 --- /dev/null +++ b/test/integration/data/resources/audit_test_resources.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment-1 + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: deployment-1 + template: + metadata: + labels: + app: deployment-1 + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: true + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment-2 + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: deployment-2 + template: + metadata: + labels: + app: deployment-2 + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: true diff --git a/test/integration/data/resources/mutation_test_resources.yaml b/test/integration/data/resources/mutation_test_resources.yaml new file mode 100644 index 00000000..c44ae2d1 --- /dev/null +++ b/test/integration/data/resources/mutation_test_resources.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-mutation-deployment + namespace: default +spec: + replicas: 1 + selector: + matchLabels: + app: test-mutation-deployment + template: + metadata: + labels: + app: test-mutation-deployment + spec: + containers: + - name: ubuntu + image: ubuntu:latest + command: ["sleep", "100d"] + securityContext: + privileged: false diff --git a/test/integration/data/state/policies.yaml b/test/integration/data/state/policies.yaml new file mode 100644 index 00000000..3840e864 --- /dev/null +++ b/test/integration/data/state/policies.yaml @@ -0,0 +1,257 @@ +apiVersion: pac.weave.works/v2beta2 +kind: Policy +metadata: + name: weave.policies.containers-minimum-replica-count +spec: + id: weave.policies.containers-minimum-replica-count + name: Containers Minimum Replica Count + enabled: false + description: "Use this Policy to to check the replica count of your workloads. The value set in the Policy is greater than or equal to the amount desired, so if the replica count is lower than what is specified, the Policy will be in violation. \n" + how_to_solve: | + The replica count should be a value equal or greater than what is set in the Policy. + ``` + spec: + replicas: + ``` + https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment + category: weave.categories.reliability + severity: medium + mutate: false + targets: + kinds: + - Deployment + - StatefulSet + - ReplicaSet + - ReplicationController + - HorizontalPodAutoscaler + standards: + - id: weave.standards.soc2-type-i + controls: + - weave.controls.soc2-type-i.2.1.1 + tags: [soc2-type1] + parameters: + - name: replica_count + type: integer + required: true + value: 2 + - name: exclude_namespaces + type: array + required: false + value: + - name: exclude_label_key + type: string + required: false + value: + - name: exclude_label_value + type: string + required: false + value: + code: |- + package weave.advisor.pods.replica_count + + import future.keywords.in + + min_replica_count := input.parameters.replica_count + exclude_namespaces := input.parameters.exclude_namespaces + exclude_label_key := input.parameters.exclude_label_key + exclude_label_value := input.parameters.exclude_label_value + + controller_input := input.review.object + + violation[result] { + isExcludedNamespace == false + not exclude_label_value == controller_input.metadata.labels[exclude_label_key] + not replicas >= min_replica_count + result = { + "issue detected": true, + "msg": sprintf("Replica count must be greater than or equal to '%v'; found '%v'.", [min_replica_count, replicas]), + "violating_key": violating_key, + "recommended_value": min_replica_count, + } + } + + replicas := controller_input.spec.replicas { + controller_input.kind in {"Deployment", "StatefulSet", "ReplicaSet", "ReplicationController"} + } else := controller_input.spec.minReplicas { + controller_input.kind == "HorizontalPodAutoscaler" + } + + violating_key := "spec.replicas" { + controller_input.kind in {"Deployment", "StatefulSet", "ReplicaSet", "ReplicationController"} + } else := "spec.minReplicas" { + controller_input.kind == "HorizontalPodAutoscaler" + } + + isExcludedNamespace = true { + controller_input.metadata.namespace + controller_input.metadata.namespace in exclude_namespaces + } else = false + +--- + +apiVersion: pac.weave.works/v2beta2 +kind: Policy +metadata: + name: weave.policies.containers-running-in-privileged-mode +spec: + id: weave.policies.containers-running-in-privileged-mode + name: Containers Running In Privileged Mode + enabled: true + description: | + This Policy reports if containers are running in privileged mode. A privileged container is given access to all devices on the host. This allows the container nearly all the same access as processes running on the host. + + By default a container is not allowed to access any devices on the host, but a "privileged" container is given access to all devices on the host. This allows the container nearly all the same access as processes running on the host. This is useful for containers that want to use linux capabilities like manipulating the network stack and accessing devices. + how_to_solve: "Look at the following path to see what the settings are. \n```\n...\n spec:\n containers:\n - securityContext:\n privileged: \n```\nhttps://kubernetes.io/docs/tasks/configure-pod-container/security-context/\n" + category: weave.categories.pod-security + severity: high + mutate: false + targets: {kinds: [Deployment, Job, ReplicationController, ReplicaSet, DaemonSet, StatefulSet, CronJob]} + standards: + - id: weave.standards.pci-dss + controls: + - weave.controls.pci-dss.2.2.4 + - weave.controls.pci-dss.2.2.5 + - id: weave.standards.cis-benchmark + controls: + - weave.controls.cis-benchmark.5.2.1 + - id: weave.standards.mitre-attack + controls: + - weave.controls.mitre-attack.4.1 + - id: weave.standards.nist-800-190 + controls: + - weave.controls.nist-800-190.3.3.1 + - id: weave.standards.gdpr + controls: + - weave.controls.gdpr.25 + - weave.controls.gdpr.32 + - weave.controls.gdpr.24 + - id: weave.standards.soc2-type-i + controls: + - weave.controls.soc2-type-i.1.6.1 + tags: [pci-dss, cis-benchmark, mitre-attack, nist800-190, gdpr, soc2-type1, default] + parameters: + - name: privilege + type: boolean + required: true + value: false + - name: exclude_namespaces + type: array + required: false + value: + - name: exclude_label_key + type: string + required: false + value: + - name: exclude_label_value + type: string + required: false + value: + code: | + package weave.advisor.podSecurity.privileged + + import future.keywords.in + + privilege := input.parameters.privilege + exclude_namespaces := input.parameters.exclude_namespaces + exclude_label_key := input.parameters.exclude_label_key + exclude_label_value := input.parameters.exclude_label_value + + violation[result] { + isExcludedNamespace == false + not exclude_label_value == controller_input.metadata.labels[exclude_label_key] + some i + container := controller_spec.containers[i] + security_context_priv := container.securityContext.privileged + not security_context_priv == privilege + result = { + "issue detected": true, + "msg": sprintf("Container %s should set privileged to '%v'; detected '%v'", [container.name, privilege, security_context_priv]), + "violating_key": sprintf("spec.template.spec.containers[%v].securityContext.privileged", [i]), + "recommended_value": privilege + } + } + + is_array_contains(array,str) { + array[_] = str + } + + # Controller input + controller_input = input.review.object + + # controller_container acts as an iterator to get containers from the template + controller_spec = controller_input.spec.template.spec { + contains_kind(controller_input.kind, {"StatefulSet" , "DaemonSet", "Deployment", "Job"}) + } else = controller_input.spec { + controller_input.kind == "Pod" + } else = controller_input.spec.jobTemplate.spec.template.spec { + controller_input.kind == "CronJob" + } + + contains_kind(kind, kinds) { + kinds[_] = kind + } + + isExcludedNamespace = true { + controller_input.metadata.namespace + controller_input.metadata.namespace in exclude_namespaces + } else = false + +--- + +apiVersion: pac.weave.works/v2beta2 +kind: Policy +metadata: + name: weave.policies.missing-owner-label +spec: + id: weave.policies.missing-owner-label + name: Missing Owner Label + enabled: false + description: "Custom labels can help enforce organizational standards for each artifact deployed. This Policy ensure a custom label key is set in the entity's `metadata`. The Policy detects the presence of the following: \n\n### owner\nA label key of `owner` will help identify who the owner of this entity is. \n\n### app.kubernetes.io/name\nThe name of the application\t\n\n### app.kubernetes.io/instance\nA unique name identifying the instance of an application\t \n\n### app.kubernetes.io/version\nThe current version of the application (e.g., a semantic version, revision hash, etc.)\n\n### app.kubernetes.io/part-of\nThe name of a higher level application this one is part of\t\n\n### app.kubernetes.io/managed-by\nThe tool being used to manage the operation of an application\t\n\n### app.kubernetes.io/created-by\nThe controller/user who created this resource\t\n" + how_to_solve: "Add these custom labels to `metadata`.\n* owner\n* app.kubernetes.io/name\n* app.kubernetes.io/instance\n* app.kubernetes.io/version\n* app.kubernetes.io/name\n* app.kubernetes.io/part-of\n* app.kubernetes.io/managed-by\n* app.kubernetes.io/created-by\n\n```\nmetadata:\n labels:\n