mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 16:06:56 +00:00
* add image verification * inline policy list Signed-off-by: Jim Bugwadia <jim@nirmata.com> * cosign version and dependencies updates Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add registry initialization Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add build tag to exclude k8schain for cloud providers Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add build tag to exclude k8schain for cloud providers Signed-off-by: Jim Bugwadia <jim@nirmata.com> * generate deep copy and other fixtures Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix deep copy issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * mutate images to add digest Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add certificates to Kyverno container for HTTPS lookups Signed-off-by: Jim Bugwadia <jim@nirmata.com> * align flag syntax Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update docs Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update dependencies Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update dependencies Signed-off-by: Jim Bugwadia <jim@nirmata.com> * patch image with digest and fix checks Signed-off-by: Jim Bugwadia <jim@nirmata.com> * hardcode image for demos Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add default registry (docker.io) before calling reference.Parse Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix definition Signed-off-by: Jim Bugwadia <jim@nirmata.com> * increase webhook timeout Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix args Signed-off-by: Jim Bugwadia <jim@nirmata.com> * run gofmt Signed-off-by: Jim Bugwadia <jim@nirmata.com> * rename for clarity Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix HasImageVerify check Signed-off-by: Jim Bugwadia <jim@nirmata.com> * align make test commands Signed-off-by: Jim Bugwadia <jim@nirmata.com> * align make test commands Signed-off-by: Jim Bugwadia <jim@nirmata.com> * align make test commands Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix linter error Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * handle API conflict and retry Signed-off-by: Jim Bugwadia <jim@nirmata.com> * format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix reviewdog issues Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix make for unit tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * improve error message Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix durations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * handle errors in tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * print policy name Signed-off-by: Jim Bugwadia <jim@nirmata.com> * update tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add retries and duration to error log Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix time check in tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * round creation times in test Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix retry loop Signed-off-by: Jim Bugwadia <jim@nirmata.com> * remove timing check for policy creation Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix e2e error - policy not found Signed-off-by: Shuting Zhao <shutting06@gmail.com> * update string comparison method Signed-off-by: Shuting Zhao <shutting06@gmail.com> * fix test Generate_Namespace_Label_Actions Signed-off-by: Shuting Zhao <shutting06@gmail.com> * add debug info for e2e tests Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix error Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix generate bug Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix format Signed-off-by: Jim Bugwadia <jim@nirmata.com> * add check for update operations Signed-off-by: Jim Bugwadia <jim@nirmata.com> * increase time for deleteing a resource Signed-off-by: Jim Bugwadia <jim@nirmata.com> * fix check Signed-off-by: Jim Bugwadia <jim@nirmata.com> Co-authored-by: Shuting Zhao <shutting06@gmail.com>
289 lines
6.6 KiB
Go
289 lines
6.6 KiB
Go
package context
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
|
|
jsonpatch "github.com/evanphx/json-patch/v5"
|
|
"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"
|
|
)
|
|
|
|
//Interface to manage context operations
|
|
type Interface interface {
|
|
|
|
// AddJSON merges the json with context
|
|
AddJSON(dataRaw []byte) error
|
|
|
|
// AddResource merges resource json under request.object
|
|
AddResource(dataRaw []byte) error
|
|
|
|
// AddUserInfo merges userInfo json under kyverno.userInfo
|
|
AddUserInfo(userInfo kyverno.UserInfo) error
|
|
|
|
// AddServiceAccount merges ServiceAccount types
|
|
AddServiceAccount(userName string) error
|
|
|
|
// AddNamespace merges resource json under request.namespace
|
|
AddNamespace(namespace string) error
|
|
|
|
EvalInterface
|
|
}
|
|
|
|
//EvalInterface ... to evaluate
|
|
type EvalInterface interface {
|
|
Query(query string) (interface{}, error)
|
|
}
|
|
|
|
//Context stores the data resources as JSON
|
|
type Context struct {
|
|
mutex sync.RWMutex
|
|
jsonRaw []byte
|
|
jsonRawCheckpoint []byte
|
|
builtInVars []string
|
|
images *Images
|
|
log logr.Logger
|
|
}
|
|
|
|
//NewContext returns a new context
|
|
// builtInVars is the list of known variables (e.g. serviceAccountName)
|
|
func NewContext(builtInVars ...string) *Context {
|
|
ctx := Context{
|
|
jsonRaw: []byte(`{}`), // empty json struct
|
|
builtInVars: builtInVars,
|
|
log: log.Log.WithName("context"),
|
|
}
|
|
|
|
return &ctx
|
|
}
|
|
|
|
// InvalidVariableErr represents error for non-white-listed variables
|
|
type InvalidVariableErr struct {
|
|
variable string
|
|
whiteList []string
|
|
}
|
|
|
|
func (i InvalidVariableErr) Error() string {
|
|
return fmt.Sprintf("variable %s cannot be used, allowed variables: %v", i.variable, i.whiteList)
|
|
}
|
|
|
|
// AddJSON merges json data
|
|
func (ctx *Context) AddJSON(dataRaw []byte) error {
|
|
var err error
|
|
ctx.mutex.Lock()
|
|
defer ctx.mutex.Unlock()
|
|
// merge json
|
|
ctx.jsonRaw, err = jsonpatch.MergeMergePatches(ctx.jsonRaw, dataRaw)
|
|
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to merge JSON data")
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddRequest adds an admission request to context
|
|
func (ctx *Context) AddRequest(request *v1beta1.AdmissionRequest) error {
|
|
modifiedResource := struct {
|
|
Request interface{} `json:"request"`
|
|
}{
|
|
Request: request,
|
|
}
|
|
|
|
objRaw, err := json.Marshal(modifiedResource)
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to marshal the request")
|
|
return err
|
|
}
|
|
return ctx.AddJSON(objRaw)
|
|
}
|
|
|
|
//AddResource data at path: request.object
|
|
func (ctx *Context) AddResource(dataRaw []byte) error {
|
|
|
|
// unmarshal the resource struct
|
|
var data interface{}
|
|
if err := json.Unmarshal(dataRaw, &data); err != nil {
|
|
ctx.log.Error(err, "failed to unmarshal the resource")
|
|
return err
|
|
}
|
|
|
|
modifiedResource := struct {
|
|
Request interface{} `json:"request"`
|
|
}{
|
|
Request: struct {
|
|
Object interface{} `json:"object"`
|
|
}{
|
|
Object: data,
|
|
},
|
|
}
|
|
|
|
objRaw, err := json.Marshal(modifiedResource)
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to marshal the resource")
|
|
return err
|
|
}
|
|
return ctx.AddJSON(objRaw)
|
|
}
|
|
|
|
//AddUserInfo adds userInfo at path request.userInfo
|
|
func (ctx *Context) AddUserInfo(userRequestInfo kyverno.RequestInfo) error {
|
|
modifiedResource := struct {
|
|
Request interface{} `json:"request"`
|
|
}{
|
|
Request: userRequestInfo,
|
|
}
|
|
|
|
objRaw, err := json.Marshal(modifiedResource)
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to marshal the UserInfo")
|
|
return err
|
|
}
|
|
return ctx.AddJSON(objRaw)
|
|
}
|
|
|
|
//AddServiceAccount removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace
|
|
func (ctx *Context) AddServiceAccount(userName string) error {
|
|
saPrefix := "system:serviceaccount:"
|
|
var sa string
|
|
saName := ""
|
|
saNamespace := ""
|
|
if len(userName) <= len(saPrefix) {
|
|
sa = ""
|
|
} else {
|
|
sa = userName[len(saPrefix):]
|
|
}
|
|
// filter namespace
|
|
groups := strings.Split(sa, ":")
|
|
if len(groups) >= 2 {
|
|
saName = groups[1]
|
|
saNamespace = groups[0]
|
|
}
|
|
|
|
saNameObj := struct {
|
|
SA string `json:"serviceAccountName"`
|
|
}{
|
|
SA: saName,
|
|
}
|
|
saNameRaw, err := json.Marshal(saNameObj)
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to marshal the SA")
|
|
return err
|
|
}
|
|
if err := ctx.AddJSON(saNameRaw); err != nil {
|
|
return err
|
|
}
|
|
|
|
saNsObj := struct {
|
|
SA string `json:"serviceAccountNamespace"`
|
|
}{
|
|
SA: saNamespace,
|
|
}
|
|
saNsRaw, err := json.Marshal(saNsObj)
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to marshal the SA namespace")
|
|
return err
|
|
}
|
|
if err := ctx.AddJSON(saNsRaw); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddNamespace merges resource json under request.namespace
|
|
func (ctx *Context) AddNamespace(namespace string) error {
|
|
modifiedResource := struct {
|
|
Request interface{} `json:"request"`
|
|
}{
|
|
Request: struct {
|
|
Namespace string `json:"namespace"`
|
|
}{
|
|
Namespace: namespace,
|
|
},
|
|
}
|
|
|
|
objRaw, err := json.Marshal(modifiedResource)
|
|
if err != nil {
|
|
ctx.log.Error(err, "failed to marshal the resource")
|
|
return err
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
images := newImages(initContainersImgs, containersImgs)
|
|
if images == nil {
|
|
return nil
|
|
}
|
|
|
|
ctx.images = images
|
|
imagesTag := struct {
|
|
Images interface{} `json:"images"`
|
|
}{
|
|
Images: images,
|
|
}
|
|
|
|
objRaw, err := json.Marshal(imagesTag)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ctx.AddJSON(objRaw)
|
|
}
|
|
|
|
func (ctx *Context) ImageInfo() *Images {
|
|
return ctx.images
|
|
}
|
|
|
|
// Checkpoint creates a copy of the internal state.
|
|
// Prior checkpoints will be overridden.
|
|
func (ctx *Context) Checkpoint() {
|
|
ctx.mutex.Lock()
|
|
defer ctx.mutex.Unlock()
|
|
|
|
ctx.jsonRawCheckpoint = make([]byte, len(ctx.jsonRaw))
|
|
copy(ctx.jsonRawCheckpoint, ctx.jsonRaw)
|
|
}
|
|
|
|
// Restore restores internal state from a prior checkpoint, if one exists.
|
|
// If a prior checkpoint does not exist, the state will not be changed.
|
|
func (ctx *Context) Restore() {
|
|
ctx.mutex.Lock()
|
|
defer ctx.mutex.Unlock()
|
|
|
|
if ctx.jsonRawCheckpoint == nil || len(ctx.jsonRawCheckpoint) == 0 {
|
|
return
|
|
}
|
|
|
|
ctx.jsonRaw = make([]byte, len(ctx.jsonRawCheckpoint))
|
|
copy(ctx.jsonRaw, ctx.jsonRawCheckpoint)
|
|
}
|
|
|
|
// AddBuiltInVars adds given pattern to the builtInVars
|
|
func (ctx *Context) AddBuiltInVars(pattern string) {
|
|
ctx.mutex.Lock()
|
|
defer ctx.mutex.Unlock()
|
|
|
|
builtInVarsCopy := ctx.builtInVars
|
|
ctx.builtInVars = append(builtInVarsCopy, pattern)
|
|
}
|
|
|
|
func (ctx *Context) getBuiltInVars() []string {
|
|
ctx.mutex.RLock()
|
|
defer ctx.mutex.RUnlock()
|
|
|
|
vars := ctx.builtInVars
|
|
return vars
|
|
}
|