1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 07:57:07 +00:00
kyverno/pkg/engine/context/context.go

233 lines
5.4 KiB
Go
Raw Normal View History

package context
import (
"encoding/json"
"fmt"
593 feature (#594) * initial commit * background policy validation * correct message * skip non-background policy process for add/update * add Generate Request CR * generate Request Generator Initial * test generate request CR generation * initial commit gr generator * generate controller initial framework * add crd for generate request * gr cleanup controller initial commit * cleanup controller initial * generate mid-commit * generate rule processing * create PV on generate error * embed resource type * testing phase 1- generate resources with variable substitution * fix tests * comment broken test #586 * add printer column for state * return if existing resource for clone * set resync time to 2 mins & remove resource version check in update handler for gr * generate events for reporting * fix logs * initial commit * fix trailing quote in patch * remove comments * initial condition (equal & notequal) * initial support for conditions * initial support fo conditions in generate * support precondition checks * cleanup * re-evaluate GR on namespace update using dynamic informers * add status for generated resources * display loaded variable SA * support delete cleanup of generate request main resources * fix log * remove namespace from SA username * support multiple variables per statement for scalar values * fix fail variables * add check for userInfo * validation checks for conditions * update policy * refactor logs * code review * add openapispec for clusterpolicy preconditions * Update documentation * CR fixes * documentation * CR fixes * update variable * fix logs * update policy * pre-defined variables (serviceAccountName & serviceAccountNamespace) * update test
2020-01-07 15:13:57 -08:00
"strings"
"sync"
jsonpatch "github.com/evanphx/json-patch"
2020-03-17 11:05:20 -07:00
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
"k8s.io/api/admission/v1beta1"
2020-03-17 16:25:34 -07:00
"sigs.k8s.io/controller-runtime/pkg/log"
)
//Interface to manage context operations
type Interface interface {
2020-12-23 15:10:07 -08:00
// AddJSON merges the json with context
AddJSON(dataRaw []byte) error
2020-12-23 15:10:07 -08:00
// AddResource merges resource json under request.object
AddResource(dataRaw []byte) error
2020-12-23 15:10:07 -08:00
// AddUserInfo merges userInfo json under kyverno.userInfo
AddUserInfo(userInfo kyverno.UserInfo) error
2020-12-23 15:10:07 -08:00
// AddServiceAccount merges ServiceAccount types
AddServiceAccount(userName 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
log logr.Logger
}
//NewContext returns a new context
2020-11-24 17:48:54 -08:00
// builtInVars is the list of known variables (e.g. serviceAccountName)
func NewContext(builtInVars ...string) *Context {
ctx := Context{
2020-11-24 17:48:54 -08:00
jsonRaw: []byte(`{}`), // empty json struct
builtInVars: builtInVars,
log: log.Log.WithName("context"),
}
2020-11-24 17:48:54 -08:00
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.MergePatch(ctx.jsonRaw, dataRaw)
if err != nil {
2020-03-17 11:05:20 -07:00
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 {
2020-05-06 01:02:39 +05:30
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 {
2020-03-17 11:05:20 -07:00
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 {
2020-05-05 19:19:47 +05:30
modifiedResource := struct {
Request interface{} `json:"request"`
}{
Request: userRequestInfo,
}
objRaw, err := json.Marshal(modifiedResource)
if err != nil {
2020-03-17 11:05:20 -07:00
ctx.log.Error(err, "failed to marshal the UserInfo")
return err
}
return ctx.AddJSON(objRaw)
}
593 feature (#594) * initial commit * background policy validation * correct message * skip non-background policy process for add/update * add Generate Request CR * generate Request Generator Initial * test generate request CR generation * initial commit gr generator * generate controller initial framework * add crd for generate request * gr cleanup controller initial commit * cleanup controller initial * generate mid-commit * generate rule processing * create PV on generate error * embed resource type * testing phase 1- generate resources with variable substitution * fix tests * comment broken test #586 * add printer column for state * return if existing resource for clone * set resync time to 2 mins & remove resource version check in update handler for gr * generate events for reporting * fix logs * initial commit * fix trailing quote in patch * remove comments * initial condition (equal & notequal) * initial support for conditions * initial support fo conditions in generate * support precondition checks * cleanup * re-evaluate GR on namespace update using dynamic informers * add status for generated resources * display loaded variable SA * support delete cleanup of generate request main resources * fix log * remove namespace from SA username * support multiple variables per statement for scalar values * fix fail variables * add check for userInfo * validation checks for conditions * update policy * refactor logs * code review * add openapispec for clusterpolicy preconditions * Update documentation * CR fixes * documentation * CR fixes * update variable * fix logs * update policy * pre-defined variables (serviceAccountName & serviceAccountNamespace) * update test
2020-01-07 15:13:57 -08:00
2020-12-23 15:10:07 -08:00
//AddServiceAccount removes prefix 'system:serviceaccount:' and namespace, then loads only SA name and SA namespace
func (ctx *Context) AddServiceAccount(userName string) error {
593 feature (#594) * initial commit * background policy validation * correct message * skip non-background policy process for add/update * add Generate Request CR * generate Request Generator Initial * test generate request CR generation * initial commit gr generator * generate controller initial framework * add crd for generate request * gr cleanup controller initial commit * cleanup controller initial * generate mid-commit * generate rule processing * create PV on generate error * embed resource type * testing phase 1- generate resources with variable substitution * fix tests * comment broken test #586 * add printer column for state * return if existing resource for clone * set resync time to 2 mins & remove resource version check in update handler for gr * generate events for reporting * fix logs * initial commit * fix trailing quote in patch * remove comments * initial condition (equal & notequal) * initial support for conditions * initial support fo conditions in generate * support precondition checks * cleanup * re-evaluate GR on namespace update using dynamic informers * add status for generated resources * display loaded variable SA * support delete cleanup of generate request main resources * fix log * remove namespace from SA username * support multiple variables per statement for scalar values * fix fail variables * add check for userInfo * validation checks for conditions * update policy * refactor logs * code review * add openapispec for clusterpolicy preconditions * Update documentation * CR fixes * documentation * CR fixes * update variable * fix logs * update policy * pre-defined variables (serviceAccountName & serviceAccountNamespace) * update test
2020-01-07 15:13:57 -08:00
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 {
2020-03-17 11:05:20 -07:00
ctx.log.Error(err, "failed to marshal the SA")
593 feature (#594) * initial commit * background policy validation * correct message * skip non-background policy process for add/update * add Generate Request CR * generate Request Generator Initial * test generate request CR generation * initial commit gr generator * generate controller initial framework * add crd for generate request * gr cleanup controller initial commit * cleanup controller initial * generate mid-commit * generate rule processing * create PV on generate error * embed resource type * testing phase 1- generate resources with variable substitution * fix tests * comment broken test #586 * add printer column for state * return if existing resource for clone * set resync time to 2 mins & remove resource version check in update handler for gr * generate events for reporting * fix logs * initial commit * fix trailing quote in patch * remove comments * initial condition (equal & notequal) * initial support for conditions * initial support fo conditions in generate * support precondition checks * cleanup * re-evaluate GR on namespace update using dynamic informers * add status for generated resources * display loaded variable SA * support delete cleanup of generate request main resources * fix log * remove namespace from SA username * support multiple variables per statement for scalar values * fix fail variables * add check for userInfo * validation checks for conditions * update policy * refactor logs * code review * add openapispec for clusterpolicy preconditions * Update documentation * CR fixes * documentation * CR fixes * update variable * fix logs * update policy * pre-defined variables (serviceAccountName & serviceAccountNamespace) * update test
2020-01-07 15:13:57 -08:00
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 {
2020-03-17 11:05:20 -07:00
ctx.log.Error(err, "failed to marshal the SA namespace")
593 feature (#594) * initial commit * background policy validation * correct message * skip non-background policy process for add/update * add Generate Request CR * generate Request Generator Initial * test generate request CR generation * initial commit gr generator * generate controller initial framework * add crd for generate request * gr cleanup controller initial commit * cleanup controller initial * generate mid-commit * generate rule processing * create PV on generate error * embed resource type * testing phase 1- generate resources with variable substitution * fix tests * comment broken test #586 * add printer column for state * return if existing resource for clone * set resync time to 2 mins & remove resource version check in update handler for gr * generate events for reporting * fix logs * initial commit * fix trailing quote in patch * remove comments * initial condition (equal & notequal) * initial support for conditions * initial support fo conditions in generate * support precondition checks * cleanup * re-evaluate GR on namespace update using dynamic informers * add status for generated resources * display loaded variable SA * support delete cleanup of generate request main resources * fix log * remove namespace from SA username * support multiple variables per statement for scalar values * fix fail variables * add check for userInfo * validation checks for conditions * update policy * refactor logs * code review * add openapispec for clusterpolicy preconditions * Update documentation * CR fixes * documentation * CR fixes * update variable * fix logs * update policy * pre-defined variables (serviceAccountName & serviceAccountNamespace) * update test
2020-01-07 15:13:57 -08:00
return err
}
if err := ctx.AddJSON(saNsRaw); err != nil {
return err
}
return nil
}
// 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
}