1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00
kyverno/pkg/webhooks/common.go

188 lines
5.8 KiB
Go
Raw Normal View History

2019-06-18 11:47:45 -07:00
package webhooks
import (
2019-07-15 16:07:56 -07:00
"fmt"
2019-06-18 11:47:45 -07:00
"strings"
2019-06-19 14:05:23 -07:00
2020-03-17 11:05:20 -07:00
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/engine/response"
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
2020-04-22 20:45:15 +05:30
yamlv2 "gopkg.in/yaml.v2"
"k8s.io/api/admission/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
2019-06-18 11:47:45 -07:00
)
2020-12-01 22:50:40 -08:00
// isResponseSuccessful return true if all responses are successful
2020-12-23 15:10:07 -08:00
func isResponseSuccessful(engineReponses []*response.EngineResponse) bool {
2019-08-23 18:34:23 -07:00
for _, er := range engineReponses {
if !er.IsSuccessful() {
2019-08-23 18:34:23 -07:00
return false
}
}
return true
}
// returns true -> if there is even one policy that blocks resource request
2019-08-23 18:34:23 -07:00
// returns false -> if all the policies are meant to report only, we dont block resource request
2020-12-23 15:10:07 -08:00
func toBlockResource(engineReponses []*response.EngineResponse, log logr.Logger) bool {
2019-08-23 18:34:23 -07:00
for _, er := range engineReponses {
2020-07-10 18:12:19 +05:30
if !er.IsSuccessful() && er.PolicyResponse.ValidationFailureAction == common.Enforce {
log.Info("spec.ValidationFailureAction set to enforce blocking resource request", "policy", er.PolicyResponse.Policy)
2019-08-23 18:34:23 -07:00
return true
}
}
2020-11-25 00:21:51 -08:00
log.V(4).Info("spec.ValidationFailureAction set to audit for all applicable policies, won't block resource operation")
2019-08-23 18:34:23 -07:00
return false
}
// getEnforceFailureErrorMsg gets the error messages for failed enforce policy
2020-12-23 15:10:07 -08:00
func getEnforceFailureErrorMsg(engineResponses []*response.EngineResponse) string {
2020-03-06 17:11:33 +05:30
policyToRule := make(map[string]interface{})
var resourceName string
for _, er := range engineResponses {
2020-07-10 18:12:19 +05:30
if !er.IsSuccessful() && er.PolicyResponse.ValidationFailureAction == common.Enforce {
2020-03-06 17:11:33 +05:30
ruleToReason := make(map[string]string)
for _, rule := range er.PolicyResponse.Rules {
if !rule.Success {
2020-03-06 17:11:33 +05:30
ruleToReason[rule.Name] = rule.Message
}
}
2020-03-06 17:11:33 +05:30
resourceName = fmt.Sprintf("%s/%s/%s", er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
2020-03-06 17:11:33 +05:30
policyToRule[er.PolicyResponse.Policy] = ruleToReason
}
}
2020-03-06 17:11:33 +05:30
result, _ := yamlv2.Marshal(policyToRule)
return "\n\nresource " + resourceName + " was blocked due to the following policies\n\n" + string(result)
}
// getErrorMsg gets all failed engine response message
2020-12-23 15:10:07 -08:00
func getErrorMsg(engineReponses []*response.EngineResponse) string {
2019-08-23 18:34:23 -07:00
var str []string
var resourceInfo string
2019-08-23 18:34:23 -07:00
for _, er := range engineReponses {
if !er.IsSuccessful() {
// resource in engineReponses is identical as this was called per admission request
resourceInfo = fmt.Sprintf("%s/%s/%s", er.PolicyResponse.Resource.Kind, er.PolicyResponse.Resource.Namespace, er.PolicyResponse.Resource.Name)
str = append(str, fmt.Sprintf("failed policy %s:", er.PolicyResponse.Policy))
2019-08-23 18:34:23 -07:00
for _, rule := range er.PolicyResponse.Rules {
if !rule.Success {
str = append(str, rule.ToString())
}
}
}
}
return fmt.Sprintf("Resource %s %s", resourceInfo, strings.Join(str, ";"))
2019-08-23 18:34:23 -07:00
}
2019-07-23 00:55:45 -04:00
//ArrayFlags to store filterkinds
2019-06-18 11:47:45 -07:00
type ArrayFlags []string
func (i *ArrayFlags) String() string {
var sb strings.Builder
for _, str := range *i {
sb.WriteString(str)
}
return sb.String()
}
2019-07-23 00:55:45 -04:00
//Set setter for array flags
2019-06-18 11:47:45 -07:00
func (i *ArrayFlags) Set(value string) error {
*i = append(*i, value)
return nil
}
2019-06-19 14:05:23 -07:00
2020-03-17 11:05:20 -07:00
func processResourceWithPatches(patch []byte, resource []byte, log logr.Logger) []byte {
2019-08-23 18:34:23 -07:00
if patch == nil {
return resource
2019-08-23 18:34:23 -07:00
}
2019-10-07 18:31:14 -07:00
resource, err := engineutils.ApplyPatchNew(resource, patch)
2019-08-23 18:34:23 -07:00
if err != nil {
log.Error(err, "failed to patch resource:", "patch", string(patch), "resource", string(resource))
2019-08-23 18:34:23 -07:00
return nil
}
return resource
}
2019-11-11 14:52:09 -08:00
2020-12-01 22:50:40 -08:00
func containRBACInfo(policies ...[]*kyverno.ClusterPolicy) bool {
for _, policySlice := range policies {
for _, policy := range policySlice {
for _, rule := range policy.Spec.Rules {
if len(rule.MatchResources.Roles) > 0 || len(rule.MatchResources.ClusterRoles) > 0 || len(rule.ExcludeResources.Roles) > 0 || len(rule.ExcludeResources.ClusterRoles) > 0 {
return true
}
2019-11-11 14:52:09 -08:00
}
}
}
return false
}
// extracts the new and old resource as unstructured
func extractResources(newRaw []byte, request *v1beta1.AdmissionRequest) (unstructured.Unstructured, unstructured.Unstructured, error) {
var emptyResource unstructured.Unstructured
// New Resource
2020-01-11 18:33:11 +05:30
if newRaw == nil {
newRaw = request.Object.Raw
}
if newRaw == nil {
return emptyResource, emptyResource, fmt.Errorf("new resource is not defined")
}
new, err := convertResource(newRaw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
if err != nil {
return emptyResource, emptyResource, fmt.Errorf("failed to convert new raw to unstructured: %v", err)
}
// Old Resource - Optional
oldRaw := request.OldObject.Raw
if oldRaw == nil {
return new, emptyResource, nil
}
old, err := convertResource(oldRaw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
if err != nil {
return emptyResource, emptyResource, fmt.Errorf("failed to convert old raw to unstructured: %v", err)
}
return new, old, err
}
// convertResource converts raw bytes to an unstructured object
func convertResource(raw []byte, group, version, kind, namespace string) (unstructured.Unstructured, error) {
obj, err := engineutils.ConvertToUnstructured(raw)
if err != nil {
return unstructured.Unstructured{}, fmt.Errorf("failed to convert raw to unstructured: %v", err)
}
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: group, Version: version, Kind: kind})
obj.SetNamespace(namespace)
return *obj, nil
}
2020-05-18 20:01:20 -07:00
func excludeKyvernoResources(kind string) bool {
switch kind {
2020-12-01 22:50:40 -08:00
case "ClusterPolicy":
return true
case "Policy":
return true
case "ClusterPolicyReport":
return true
case "PolicyReport":
return true
case "ReportChangeRequest":
return true
case "GenerateRequest":
return true
case "ClusterReportChangeRequest":
2020-05-18 20:01:20 -07:00
return true
default:
return false
}
}