2019-06-18 18:47:45 +00:00
|
|
|
package webhooks
|
|
|
|
|
|
|
|
import (
|
2019-07-15 23:07:56 +00:00
|
|
|
"fmt"
|
2019-06-18 18:47:45 +00:00
|
|
|
"strings"
|
2019-06-19 21:05:23 +00:00
|
|
|
|
2019-07-19 19:47:20 +00:00
|
|
|
"github.com/golang/glog"
|
2019-11-13 21:41:08 +00:00
|
|
|
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
|
2019-12-31 01:08:50 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/engine/response"
|
2020-01-11 13:03:11 +00:00
|
|
|
engineutils "github.com/nirmata/kyverno/pkg/engine/utils"
|
2019-11-13 21:13:07 +00:00
|
|
|
"k8s.io/api/admission/v1beta1"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2019-06-18 18:47:45 +00:00
|
|
|
)
|
|
|
|
|
2020-01-16 05:46:58 +00:00
|
|
|
// isResponseSuccesful return true if all responses are successful
|
2019-12-31 01:08:50 +00:00
|
|
|
func isResponseSuccesful(engineReponses []response.EngineResponse) bool {
|
2019-08-24 01:34:23 +00:00
|
|
|
for _, er := range engineReponses {
|
|
|
|
if !er.IsSuccesful() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-09-06 17:18:45 +00:00
|
|
|
// returns true -> if there is even one policy that blocks resource request
|
2019-08-24 01:34:23 +00:00
|
|
|
// returns false -> if all the policies are meant to report only, we dont block resource request
|
2019-12-31 01:08:50 +00:00
|
|
|
func toBlockResource(engineReponses []response.EngineResponse) bool {
|
2019-08-24 01:34:23 +00:00
|
|
|
for _, er := range engineReponses {
|
2020-01-06 22:41:02 +00:00
|
|
|
if !er.IsSuccesful() && er.PolicyResponse.ValidationFailureAction == Enforce {
|
2019-09-06 17:18:45 +00:00
|
|
|
glog.V(4).Infof("ValidationFailureAction set to enforce for policy %s , blocking resource request ", er.PolicyResponse.Policy)
|
2019-08-24 01:34:23 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
2019-09-06 17:18:45 +00:00
|
|
|
glog.V(4).Infoln("ValidationFailureAction set to audit, allowing resource request, reporting with policy violation")
|
2019-08-24 01:34:23 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-01-16 19:57:28 +00:00
|
|
|
// getEnforceFailureErrorMsg gets the error messages for failed enforce policy
|
|
|
|
func getEnforceFailureErrorMsg(engineReponses []response.EngineResponse) string {
|
|
|
|
var str []string
|
|
|
|
var resourceInfo string
|
|
|
|
|
|
|
|
for _, er := range engineReponses {
|
|
|
|
if !er.IsSuccesful() && er.PolicyResponse.ValidationFailureAction == Enforce {
|
|
|
|
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))
|
|
|
|
for _, rule := range er.PolicyResponse.Rules {
|
|
|
|
if !rule.Success {
|
|
|
|
str = append(str, rule.ToString())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("Resource %s %s", resourceInfo, strings.Join(str, ";"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// getErrorMsg gets all failed engine response message
|
2019-12-31 01:08:50 +00:00
|
|
|
func getErrorMsg(engineReponses []response.EngineResponse) string {
|
2019-08-24 01:34:23 +00:00
|
|
|
var str []string
|
2019-11-07 01:14:32 +00:00
|
|
|
var resourceInfo string
|
|
|
|
|
2019-08-24 01:34:23 +00:00
|
|
|
for _, er := range engineReponses {
|
|
|
|
if !er.IsSuccesful() {
|
2019-11-07 01:14:32 +00:00
|
|
|
// 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)
|
2020-01-07 01:07:11 +00:00
|
|
|
str = append(str, fmt.Sprintf("failed policy %s:", er.PolicyResponse.Policy))
|
2019-08-24 01:34:23 +00:00
|
|
|
for _, rule := range er.PolicyResponse.Rules {
|
|
|
|
if !rule.Success {
|
|
|
|
str = append(str, rule.ToString())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-07 01:07:11 +00:00
|
|
|
return fmt.Sprintf("Resource %s %s", resourceInfo, strings.Join(str, ";"))
|
2019-08-24 01:34:23 +00:00
|
|
|
}
|
|
|
|
|
2019-07-23 04:55:45 +00:00
|
|
|
//ArrayFlags to store filterkinds
|
2019-06-18 18:47:45 +00: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 04:55:45 +00:00
|
|
|
//Set setter for array flags
|
2019-06-18 18:47:45 +00:00
|
|
|
func (i *ArrayFlags) Set(value string) error {
|
|
|
|
*i = append(*i, value)
|
|
|
|
return nil
|
|
|
|
}
|
2019-06-19 21:05:23 +00:00
|
|
|
|
2019-07-16 02:14:42 +00:00
|
|
|
// Policy Reporting Modes
|
|
|
|
const (
|
2019-09-06 17:18:45 +00:00
|
|
|
Enforce = "enforce" // blocks the request on failure
|
|
|
|
Audit = "audit" // dont block the request on failure, but report failiures as policy violations
|
2019-07-16 02:14:42 +00:00
|
|
|
)
|
2019-07-16 22:53:14 +00:00
|
|
|
|
2019-08-24 01:34:23 +00:00
|
|
|
func processResourceWithPatches(patch []byte, resource []byte) []byte {
|
|
|
|
if patch == nil {
|
2020-01-13 18:15:52 +00:00
|
|
|
return resource
|
2019-08-24 01:34:23 +00:00
|
|
|
}
|
2019-10-08 01:31:14 +00:00
|
|
|
|
2020-01-08 01:06:17 +00:00
|
|
|
resource, err := engineutils.ApplyPatchNew(resource, patch)
|
2019-08-24 01:34:23 +00:00
|
|
|
if err != nil {
|
2019-08-26 23:10:19 +00:00
|
|
|
glog.Errorf("failed to patch resource: %v", err)
|
2019-08-24 01:34:23 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return resource
|
|
|
|
}
|
2019-11-11 22:52:09 +00:00
|
|
|
|
2019-11-13 20:15:51 +00:00
|
|
|
func containRBACinfo(policies []kyverno.ClusterPolicy) bool {
|
2019-11-11 22:52:09 +00:00
|
|
|
for _, policy := range policies {
|
|
|
|
for _, rule := range policy.Spec.Rules {
|
2020-02-17 18:31:03 +00:00
|
|
|
if len(rule.MatchResources.Roles) > 0 || len(rule.MatchResources.ClusterRoles) > 0 || len(rule.ExcludeResources.Roles) > 0 || len(rule.ExcludeResources.ClusterRoles) > 0 {
|
2019-11-11 22:52:09 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2019-11-13 21:13:07 +00:00
|
|
|
|
|
|
|
// extracts the new and old resource as unstructured
|
2020-01-07 19:32:52 +00:00
|
|
|
func extractResources(newRaw []byte, request *v1beta1.AdmissionRequest) (unstructured.Unstructured, unstructured.Unstructured, error) {
|
2019-11-13 21:13:07 +00:00
|
|
|
var emptyResource unstructured.Unstructured
|
2020-01-07 19:32:52 +00:00
|
|
|
|
2019-11-13 21:13:07 +00:00
|
|
|
// New Resource
|
2020-01-11 13:03:11 +00:00
|
|
|
if newRaw == nil {
|
|
|
|
newRaw = request.Object.Raw
|
|
|
|
}
|
2019-11-13 21:13:07 +00:00
|
|
|
if newRaw == nil {
|
|
|
|
return emptyResource, emptyResource, fmt.Errorf("new resource is not defined")
|
|
|
|
}
|
2020-01-07 19:32:52 +00:00
|
|
|
|
|
|
|
new, err := convertResource(newRaw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
|
2019-11-13 21:13:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return emptyResource, emptyResource, fmt.Errorf("failed to convert new raw to unstructured: %v", err)
|
|
|
|
}
|
2020-01-07 19:32:52 +00:00
|
|
|
|
2019-11-13 21:13:07 +00:00
|
|
|
// Old Resource - Optional
|
|
|
|
oldRaw := request.OldObject.Raw
|
|
|
|
if oldRaw == nil {
|
2020-01-07 19:32:52 +00:00
|
|
|
return new, emptyResource, nil
|
2019-11-13 21:13:07 +00:00
|
|
|
}
|
2020-01-07 19:32:52 +00:00
|
|
|
|
|
|
|
old, err := convertResource(oldRaw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
|
2019-11-13 21:13:07 +00:00
|
|
|
if err != nil {
|
|
|
|
return emptyResource, emptyResource, fmt.Errorf("failed to convert old raw to unstructured: %v", err)
|
|
|
|
}
|
2020-01-07 19:32:52 +00:00
|
|
|
return new, old, err
|
2019-11-13 21:13:07 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 19:32:52 +00:00
|
|
|
// convertResource converts raw bytes to an unstructured object
|
|
|
|
func convertResource(raw []byte, group, version, kind, namespace string) (unstructured.Unstructured, error) {
|
2020-01-08 01:06:17 +00:00
|
|
|
obj, err := engineutils.ConvertToUnstructured(raw)
|
2019-11-13 21:13:07 +00:00
|
|
|
if err != nil {
|
2020-01-07 19:32:52 +00:00
|
|
|
return unstructured.Unstructured{}, fmt.Errorf("failed to convert raw to unstructured: %v", err)
|
2019-11-13 21:13:07 +00:00
|
|
|
}
|
2020-01-07 19:32:52 +00:00
|
|
|
|
|
|
|
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: group, Version: version, Kind: kind})
|
|
|
|
obj.SetNamespace(namespace)
|
|
|
|
return *obj, nil
|
2019-11-13 21:13:07 +00:00
|
|
|
}
|