mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-13 19:28:55 +00:00
Add Images info to variables context (#1725)
* - remove supportMutateValidate; - refactor new context in the webhook Signed-off-by: Shuting Zhao <shutting06@gmail.com> * add ImageInfo to variables context Signed-off-by: Shuting Zhao <shutting06@gmail.com> * revert unexpected changes Signed-off-by: Shuting Zhao <shutting06@gmail.com>
This commit is contained in:
parent
f9be2651ad
commit
c08843ef77
12 changed files with 310 additions and 113 deletions
|
@ -309,8 +309,6 @@ func main() {
|
|||
// Sync openAPI definitions of resources
|
||||
openAPISync := openapi.NewCRDSync(client, openAPIController)
|
||||
|
||||
supportMutateValidate := utils.HigherThanKubernetesVersion(client, log.Log, 1, 14, 0)
|
||||
|
||||
// WEBHOOK
|
||||
// - https server to provide endpoints called based on rules defined in Mutating & Validation webhook configuration
|
||||
// - reports the results based on the response from the policy engine:
|
||||
|
@ -339,7 +337,6 @@ func main() {
|
|||
reportReqGen,
|
||||
grgen,
|
||||
auditHandler,
|
||||
supportMutateValidate,
|
||||
cleanUp,
|
||||
log.Log.WithName("WebhookServer"),
|
||||
openAPIController,
|
||||
|
|
4
go.mod
4
go.mod
|
@ -5,6 +5,8 @@ go 1.14
|
|||
require (
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible
|
||||
github.com/cornelk/hashmap v1.0.1
|
||||
github.com/distribution/distribution v2.7.1+incompatible
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.2.0
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/gardener/controller-manager-library v0.2.0
|
||||
|
@ -22,6 +24,8 @@ require (
|
|||
github.com/minio/minio v0.0.0-20200114012931-30922148fbb5
|
||||
github.com/onsi/ginkgo v1.14.1
|
||||
github.com/onsi/gomega v1.10.2
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
|
8
go.sum
8
go.sum
|
@ -153,7 +153,11 @@ github.com/dchest/siphash v1.1.0/go.mod h1:q+IRvb2gOSrUnYoPqHiyHXS0FOBBOdl6tONBl
|
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/distribution/distribution v2.7.1+incompatible h1:aGFx4EvJWKEh//lHPLwFhFgwFHKH06TzNVPamrMn04M=
|
||||
github.com/distribution/distribution v2.7.1+incompatible/go.mod h1:EgLm2NgWtdKgzF9NpMzUKgzmR7AMmb0VQi2B+ZzDRjc=
|
||||
github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
|
@ -646,6 +650,10 @@ github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT
|
|||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
|
||||
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6 h1:lNCW6THrCKBiJBpz8kbVGjC7MgdCGKwuvBgc7LoD6sw=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20190826125027-8c72a8bb44f6/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
|
@ -214,6 +215,28 @@ func (ctx *Context) AddNamespace(namespace string) error {
|
|||
return ctx.AddJSON(objRaw)
|
||||
}
|
||||
|
||||
func (ctx *Context) AddImageInfo(resource *unstructured.Unstructured) error {
|
||||
initContainersImgs, containersImgs := extractImageInfo(resource, ctx.log)
|
||||
if len(initContainersImgs) == 0 && len(containersImgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
resourceImg := newResourceImage(initContainersImgs, containersImgs)
|
||||
|
||||
images := struct {
|
||||
Images interface{} `json:"images"`
|
||||
}{
|
||||
Images: resourceImg,
|
||||
}
|
||||
|
||||
objRaw, err := json.Marshal(images)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctx.AddJSON(objRaw)
|
||||
}
|
||||
|
||||
// Checkpoint creates a copy of the internal state.
|
||||
// Prior checkpoints will be overridden.
|
||||
func (ctx *Context) Checkpoint() {
|
||||
|
|
147
pkg/engine/context/imageutils.go
Normal file
147
pkg/engine/context/imageutils.go
Normal file
|
@ -0,0 +1,147 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/distribution/distribution/reference"
|
||||
"github.com/go-logr/logr"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
type imageInfo struct {
|
||||
Registry string `json:"registry,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Tag string `json:"tag,omitempty"`
|
||||
Digest string `json:"digest,omitempty"`
|
||||
}
|
||||
|
||||
type containerImage struct {
|
||||
Name string
|
||||
Image imageInfo
|
||||
}
|
||||
|
||||
type resourceImage struct {
|
||||
Containers map[string]interface{} `json:"containers"`
|
||||
InitContainers map[string]interface{} `json:"initContainers,omitempty"`
|
||||
}
|
||||
|
||||
func newResourceImage(initContainersImgs, containersImgs []*containerImage) resourceImage {
|
||||
initContainers := make(map[string]interface{})
|
||||
containers := make(map[string]interface{})
|
||||
|
||||
for _, resource := range initContainersImgs {
|
||||
initContainers[resource.Name] = resource.Image
|
||||
}
|
||||
|
||||
for _, resource := range containersImgs {
|
||||
containers[resource.Name] = resource.Image
|
||||
}
|
||||
|
||||
return resourceImage{
|
||||
Containers: containers,
|
||||
InitContainers: initContainers,
|
||||
}
|
||||
}
|
||||
|
||||
func extractImageInfo(resource *unstructured.Unstructured, log logr.Logger) (initContainersImgs, containersImgs []*containerImage) {
|
||||
logger := log.WithName("extractImageInfo").WithValues("kind", resource.GetKind(), "ns", resource.GetNamespace(), "name", resource.GetName())
|
||||
|
||||
switch resource.GetKind() {
|
||||
case "Pod":
|
||||
for i, tag := range []string{"initContainers", "containers"} {
|
||||
if initContainers, ok, _ := unstructured.NestedSlice(resource.UnstructuredContent(), "spec", tag); ok {
|
||||
img, err := convertToImageInfo(initContainers)
|
||||
if err != nil {
|
||||
logger.WithName(tag).Error(err, "failed to extract image info")
|
||||
continue
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
initContainersImgs = append(initContainersImgs, img...)
|
||||
} else {
|
||||
containersImgs = append(containersImgs, img...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case "Deployment", "DaemonSet", "Job", "StatefulSet":
|
||||
for i, tag := range []string{"initContainers", "containers"} {
|
||||
if initContainers, ok, _ := unstructured.NestedSlice(resource.UnstructuredContent(), "spec", "template", "spec", tag); ok {
|
||||
img, err := convertToImageInfo(initContainers)
|
||||
if err != nil {
|
||||
logger.WithName(tag).Error(err, "failed to extract image info")
|
||||
continue
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
initContainersImgs = append(initContainersImgs, img...)
|
||||
} else {
|
||||
containersImgs = append(containersImgs, img...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case "CronJob":
|
||||
for i, tag := range []string{"initContainers", "containers"} {
|
||||
if initContainers, ok, _ := unstructured.NestedSlice(resource.UnstructuredContent(), "spec", "jobTemplate", "spec", "template", "spec", tag); ok {
|
||||
img, err := convertToImageInfo(initContainers)
|
||||
if err != nil {
|
||||
logger.WithName(tag).Error(err, "failed to extract image info")
|
||||
continue
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
initContainersImgs = append(initContainersImgs, img...)
|
||||
} else {
|
||||
containersImgs = append(containersImgs, img...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func convertToImageInfo(containers []interface{}) (images []*containerImage, err error) {
|
||||
var errs []string
|
||||
|
||||
for _, ctr := range containers {
|
||||
if container, ok := ctr.(map[string]interface{}); ok {
|
||||
repo, err := reference.Parse(container["image"].(string))
|
||||
if err != nil {
|
||||
errs = append(errs, errors.Wrapf(err, "bad image: %s", container["image"].(string)).Error())
|
||||
continue
|
||||
}
|
||||
|
||||
var registry, name, tag, digest string
|
||||
if named, ok := repo.(reference.Named); ok {
|
||||
registry, name = reference.SplitHostname(named)
|
||||
}
|
||||
|
||||
if tagged, ok := repo.(reference.Tagged); ok {
|
||||
tag = tagged.Tag()
|
||||
}
|
||||
|
||||
if digested, ok := repo.(reference.Digested); ok {
|
||||
digest = digested.Digest().String()
|
||||
}
|
||||
|
||||
images = append(images, &containerImage{
|
||||
Name: container["name"].(string),
|
||||
Image: imageInfo{
|
||||
Registry: registry,
|
||||
Name: name,
|
||||
Tag: tag,
|
||||
Digest: digest,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) == 0 {
|
||||
return images, nil
|
||||
}
|
||||
|
||||
return images, errors.Errorf("%s", strings.Join(errs, ";"))
|
||||
}
|
45
pkg/engine/context/imageutils_test.go
Normal file
45
pkg/engine/context/imageutils_test.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
func Test_extractImageInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
raw []byte
|
||||
containers []*containerImage
|
||||
initContainers []*containerImage
|
||||
}{
|
||||
{
|
||||
raw: []byte(`{"apiVersion": "v1","kind": "Pod","metadata": {"name": "myapp"},"spec": {"initContainers": [{"name": "init","image": "index.docker.io/busybox:v1.2.3"}],"containers": [{"name": "nginx","image": "nginx:latest"}]}}`),
|
||||
initContainers: []*containerImage{{Name: "init", Image: imageInfo{Registry: "index.docker.io", Name: "busybox", Tag: "v1.2.3"}}},
|
||||
containers: []*containerImage{{Name: "nginx", Image: imageInfo{Name: "nginx", Tag: "latest"}}},
|
||||
},
|
||||
{
|
||||
raw: []byte(`{"apiVersion": "apps/v1","kind": "Deployment","metadata": {"name": "myapp"},"spec": {"selector": {"matchLabels": {"app": "myapp"}},"template": {"metadata": {"labels": {"app": "myapp"}},"spec": {"initContainers": [{"name": "init","image": "fictional.registry.example:10443/imagename:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}],"containers": [{"name": "myapp","image": "fictional.registry.example:10443/imagename"}]}}}}`),
|
||||
initContainers: []*containerImage{{Name: "init", Image: imageInfo{Registry: "fictional.registry.example:10443", Name: "imagename", Tag: "tag", Digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}}},
|
||||
containers: []*containerImage{{Name: "myapp", Image: imageInfo{Registry: "fictional.registry.example:10443", Name: "imagename"}}}},
|
||||
{
|
||||
raw: []byte(`{"apiVersion": "batch/v1beta1","kind": "CronJob","metadata": {"name": "hello"},"spec": {"schedule": "*/1 * * * *","jobTemplate": {"spec": {"template": {"spec": {"containers": [{"name": "hello","image": "b.gcr.io/test.example.com/my-app:test.example.com"}]}}}}}}`),
|
||||
containers: []*containerImage{{Name: "hello", Image: imageInfo{Registry: "b.gcr.io", Name: "test.example.com/my-app", Tag: "test.example.com"}}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
resource, err := utils.ConvertToUnstructured(test.raw)
|
||||
assert.Nil(t, err)
|
||||
|
||||
init, container := extractImageInfo(resource, log.Log.WithName("TestExtractImageInfo"))
|
||||
if len(test.initContainers) > 0 {
|
||||
assert.Equal(t, test.initContainers, init, "unexpected initContainers", resource.GetName())
|
||||
}
|
||||
|
||||
if len(test.containers) > 0 {
|
||||
assert.Equal(t, test.containers, container, "unexpected containers", resource.GetName())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,13 @@ package engine
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"gotest.tools/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_VariableSubstitutionOverlay(t *testing.T) {
|
||||
|
|
|
@ -4,13 +4,12 @@ import (
|
|||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
utils2 "github.com/kyverno/kyverno/pkg/utils"
|
||||
"gotest.tools/assert"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
)
|
||||
|
||||
func TestGetAnchorsFromMap_ThereAreAnchors(t *testing.T) {
|
||||
|
|
|
@ -123,6 +123,10 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfo(&resource); err != nil {
|
||||
logger.Error(err, "unable to add image info to variables context")
|
||||
}
|
||||
|
||||
policyContext := &engine.PolicyContext{
|
||||
NewResource: resource,
|
||||
Policy: *policyObj,
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -33,6 +32,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/utils"
|
||||
"github.com/kyverno/kyverno/pkg/webhookconfig"
|
||||
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/generate"
|
||||
"github.com/pkg/errors"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
informers "k8s.io/client-go/informers/core/v1"
|
||||
|
@ -124,8 +124,6 @@ type WebhookServer struct {
|
|||
|
||||
openAPIController *openapi.Controller
|
||||
|
||||
supportMutateValidate bool
|
||||
|
||||
// resCache - controls creation and fetching of resource informer cache
|
||||
resCache resourcecache.ResourceCache
|
||||
|
||||
|
@ -157,7 +155,6 @@ func NewWebhookServer(
|
|||
prGenerator policyreport.GeneratorInterface,
|
||||
grGenerator *webhookgenerate.Generator,
|
||||
auditHandler AuditHandler,
|
||||
supportMutateValidate bool,
|
||||
cleanUp chan<- struct{},
|
||||
log logr.Logger,
|
||||
openAPIController *openapi.Controller,
|
||||
|
@ -191,27 +188,26 @@ func NewWebhookServer(
|
|||
nsLister: namespace.Lister(),
|
||||
nsListerSynced: namespace.Informer().HasSynced,
|
||||
|
||||
crbLister: crbInformer.Lister(),
|
||||
crLister: crInformer.Lister(),
|
||||
crbSynced: crbInformer.Informer().HasSynced,
|
||||
crSynced: crInformer.Informer().HasSynced,
|
||||
eventGen: eventGen,
|
||||
pCache: pCache,
|
||||
webhookRegister: webhookRegistrationClient,
|
||||
statusListener: statusSync,
|
||||
configHandler: configHandler,
|
||||
cleanUp: cleanUp,
|
||||
webhookMonitor: webhookMonitor,
|
||||
certRenewer: certRenewer,
|
||||
prGenerator: prGenerator,
|
||||
grGenerator: grGenerator,
|
||||
grController: grc,
|
||||
auditHandler: auditHandler,
|
||||
log: log,
|
||||
openAPIController: openAPIController,
|
||||
supportMutateValidate: supportMutateValidate,
|
||||
resCache: resCache,
|
||||
debug: debug,
|
||||
crbLister: crbInformer.Lister(),
|
||||
crLister: crInformer.Lister(),
|
||||
crbSynced: crbInformer.Informer().HasSynced,
|
||||
crSynced: crInformer.Informer().HasSynced,
|
||||
eventGen: eventGen,
|
||||
pCache: pCache,
|
||||
webhookRegister: webhookRegistrationClient,
|
||||
statusListener: statusSync,
|
||||
configHandler: configHandler,
|
||||
cleanUp: cleanUp,
|
||||
webhookMonitor: webhookMonitor,
|
||||
certRenewer: certRenewer,
|
||||
prGenerator: prGenerator,
|
||||
grGenerator: grGenerator,
|
||||
grController: grc,
|
||||
auditHandler: auditHandler,
|
||||
log: log,
|
||||
openAPIController: openAPIController,
|
||||
resCache: resCache,
|
||||
debug: debug,
|
||||
}
|
||||
|
||||
mux := httprouter.New()
|
||||
|
@ -307,25 +303,15 @@ func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
logger.V(6).Info("received an admission request in mutating webhook")
|
||||
mutatePolicies := ws.pCache.Get(policycache.Mutate, nil)
|
||||
validatePolicies := ws.pCache.Get(policycache.ValidateEnforce, nil)
|
||||
generatePolicies := ws.pCache.Get(policycache.Generate, nil)
|
||||
|
||||
// Get namespace policies from the cache for the requested resource namespace
|
||||
nsMutatePolicies := ws.pCache.Get(policycache.Mutate, &request.Namespace)
|
||||
mutatePolicies = append(mutatePolicies, nsMutatePolicies...)
|
||||
|
||||
// getRoleRef only if policy has roles/clusterroles defined
|
||||
var roles, clusterRoles []string
|
||||
var err error
|
||||
if containRBACInfo(mutatePolicies, validatePolicies, generatePolicies) {
|
||||
roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get RBAC information for request")
|
||||
}
|
||||
}
|
||||
|
||||
// convert RAW to unstructured
|
||||
resource, err := utils.ConvertResource(request.Object.Raw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
|
||||
if err != nil {
|
||||
|
@ -339,50 +325,44 @@ func (ws *WebhookServer) ResourceMutation(request *v1beta1.AdmissionRequest) *v1
|
|||
}
|
||||
}
|
||||
|
||||
var roles, clusterRoles []string
|
||||
// getRoleRef only if policy has roles/clusterroles defined
|
||||
if containRBACInfo(mutatePolicies, generatePolicies) {
|
||||
if roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler); err != nil {
|
||||
logger.Error(err, "failed to get RBAC information for request")
|
||||
}
|
||||
}
|
||||
|
||||
userRequestInfo := v1.RequestInfo{
|
||||
Roles: roles,
|
||||
ClusterRoles: clusterRoles,
|
||||
AdmissionUserInfo: *request.UserInfo.DeepCopy()}
|
||||
|
||||
// build context
|
||||
ctx := enginectx.NewContext()
|
||||
err = ctx.AddRequest(request)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to load incoming request in context")
|
||||
AdmissionUserInfo: *request.UserInfo.DeepCopy(),
|
||||
}
|
||||
|
||||
err = ctx.AddUserInfo(userRequestInfo)
|
||||
ctx, err := newVariablesContext(request, &userRequestInfo)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to load userInfo in context")
|
||||
logger.Error(err, "unable to build variable context")
|
||||
}
|
||||
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to load service account in context")
|
||||
|
||||
if err := ctx.AddImageInfo(&resource); err != nil {
|
||||
logger.Error(err, "unable to add image info to variables context")
|
||||
}
|
||||
|
||||
var patches []byte
|
||||
patchedResource := request.Object.Raw
|
||||
|
||||
// MUTATION
|
||||
if ws.supportMutateValidate {
|
||||
if resource.GetDeletionTimestamp() == nil {
|
||||
patches = ws.HandleMutation(request, resource, mutatePolicies, ctx, userRequestInfo)
|
||||
logger.V(6).Info("", "generated patches", string(patches))
|
||||
patches = ws.HandleMutation(request, resource, mutatePolicies, ctx, userRequestInfo)
|
||||
logger.V(6).Info("", "generated patches", string(patches))
|
||||
|
||||
// patch the resource with patches before handling validation rules
|
||||
patchedResource = processResourceWithPatches(patches, request.Object.Raw, logger)
|
||||
logger.V(6).Info("", "patchedResource", string(patchedResource))
|
||||
}
|
||||
} else {
|
||||
logger.Info("mutate rules are not supported prior to Kubernetes 1.14.0")
|
||||
}
|
||||
// patch the resource with patches before handling validation rules
|
||||
patchedResource = processResourceWithPatches(patches, request.Object.Raw, logger)
|
||||
logger.V(6).Info("", "patchedResource", string(patchedResource))
|
||||
|
||||
// GENERATE
|
||||
if request.Operation == v1beta1.Create || request.Operation == v1beta1.Update {
|
||||
newRequest := request.DeepCopy()
|
||||
newRequest.Object.Raw = patchedResource
|
||||
go ws.HandleGenerate(newRequest, generatePolicies, ctx, userRequestInfo, ws.configHandler)
|
||||
}
|
||||
newRequest := request.DeepCopy()
|
||||
newRequest.Object.Raw = patchedResource
|
||||
go ws.HandleGenerate(newRequest, generatePolicies, ctx, userRequestInfo, ws.configHandler)
|
||||
|
||||
patchType := v1beta1.PatchTypeJSONPatch
|
||||
return &v1beta1.AdmissionResponse{
|
||||
|
@ -401,16 +381,6 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
|
|||
ws.handleDelete(request)
|
||||
}
|
||||
|
||||
if !ws.supportMutateValidate {
|
||||
logger.Info("mutate and validate rules are not supported prior to Kubernetes 1.14.0")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
Result: &metav1.Status{
|
||||
Status: "Success",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if excludeKyvernoResources(request.Kind.Kind) {
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
|
@ -440,7 +410,6 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
|
|||
if containRBACInfo(policies) {
|
||||
roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request, ws.configHandler)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to get RBAC information for request")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
|
@ -449,30 +418,23 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
|
|||
},
|
||||
}
|
||||
}
|
||||
logger = logger.WithValues("username", request.UserInfo.Username,
|
||||
"groups", request.UserInfo.Groups, "roles", roles, "clusterRoles", clusterRoles)
|
||||
}
|
||||
|
||||
userRequestInfo := v1.RequestInfo{
|
||||
Roles: roles,
|
||||
ClusterRoles: clusterRoles,
|
||||
AdmissionUserInfo: request.UserInfo}
|
||||
|
||||
// build context
|
||||
ctx := enginectx.NewContext()
|
||||
err = ctx.AddRequest(request)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to load incoming request in context")
|
||||
AdmissionUserInfo: *request.UserInfo.DeepCopy(),
|
||||
}
|
||||
|
||||
err = ctx.AddUserInfo(userRequestInfo)
|
||||
ctx, err := newVariablesContext(request, &userRequestInfo)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to load userInfo in context")
|
||||
}
|
||||
|
||||
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to load service account in context")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Status: "Failure",
|
||||
Message: err.Error(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
namespaceLabels := make(map[string]string)
|
||||
|
@ -570,3 +532,20 @@ func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer htt
|
|||
|
||||
return admissionReview
|
||||
}
|
||||
|
||||
func newVariablesContext(request *v1beta1.AdmissionRequest, userRequestInfo *v1.RequestInfo) (*enginectx.Context, error) {
|
||||
ctx := enginectx.NewContext()
|
||||
if err := ctx.AddRequest(request); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load incoming request in context")
|
||||
}
|
||||
|
||||
if err := ctx.AddUserInfo(*userRequestInfo); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load userInfo in context")
|
||||
}
|
||||
|
||||
if err := ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to load service account in context")
|
||||
}
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/policycache"
|
||||
"github.com/kyverno/kyverno/pkg/policyreport"
|
||||
|
@ -18,7 +17,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/resourcecache"
|
||||
"github.com/kyverno/kyverno/pkg/userinfo"
|
||||
"github.com/minio/minio/cmd/logger"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/api/admission/v1beta1"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
@ -168,20 +166,9 @@ func (h *auditHandler) process(request *v1beta1.AdmissionRequest) error {
|
|||
ClusterRoles: clusterRoles,
|
||||
AdmissionUserInfo: request.UserInfo}
|
||||
|
||||
// build context
|
||||
ctx := enginectx.NewContext()
|
||||
err = ctx.AddRequest(request)
|
||||
ctx, err := newVariablesContext(request, &userRequestInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to load incoming request in context")
|
||||
}
|
||||
|
||||
err = ctx.AddUserInfo(userRequestInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to load userInfo in context")
|
||||
}
|
||||
err = ctx.AddServiceAccount(userRequestInfo.AdmissionUserInfo.Username)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to load service account in context")
|
||||
logger.Error(err, "unable to build variable context")
|
||||
}
|
||||
|
||||
namespaceLabels := make(map[string]string)
|
||||
|
|
|
@ -72,6 +72,10 @@ func HandleValidation(
|
|||
return true, ""
|
||||
}
|
||||
|
||||
if err := ctx.AddImageInfo(&newR); err != nil {
|
||||
logger.Error(err, "unable to add image info to variables context")
|
||||
}
|
||||
|
||||
policyContext := &engine.PolicyContext{
|
||||
NewResource: newR,
|
||||
OldResource: oldR,
|
||||
|
|
Loading…
Add table
Reference in a new issue