2019-05-14 01:17:28 +00:00
package engine
2019-05-10 05:26:22 +00:00
import (
2020-01-10 19:59:05 +00:00
"fmt"
2019-12-27 23:57:43 +00:00
"reflect"
2019-12-26 23:34:19 +00:00
"strings"
2019-08-19 23:40:10 +00:00
"time"
2019-08-09 23:55:43 +00:00
2019-06-26 01:16:02 +00:00
"github.com/golang/glog"
2019-12-26 23:34:19 +00:00
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1"
2020-01-08 01:06:17 +00:00
"github.com/nirmata/kyverno/pkg/engine/mutate"
"github.com/nirmata/kyverno/pkg/engine/rbac"
2019-12-12 23:02:59 +00:00
"github.com/nirmata/kyverno/pkg/engine/response"
2020-01-10 19:59:05 +00:00
"github.com/nirmata/kyverno/pkg/engine/utils"
2020-01-07 23:13:57 +00:00
"github.com/nirmata/kyverno/pkg/engine/variables"
2019-05-10 05:26:22 +00:00
)
2019-12-26 23:34:19 +00:00
const (
PodControllers = "DaemonSet,Deployment,Job,StatefulSet"
PodControllersAnnotation = "pod-policies.kyverno.io/autogen-controllers"
PodTemplateAnnotation = "pod-policies.kyverno.io/autogen-applied"
)
2019-05-13 18:27:47 +00:00
// Mutate performs mutation. Overlay first and then mutation patches
2019-12-12 23:02:59 +00:00
func Mutate ( policyContext PolicyContext ) ( resp response . EngineResponse ) {
2019-08-24 01:34:23 +00:00
startTime := time . Now ( )
2019-11-09 02:57:27 +00:00
policy := policyContext . Policy
2019-11-13 21:13:07 +00:00
resource := policyContext . NewResource
2019-12-13 02:25:54 +00:00
ctx := policyContext . Context
2019-11-09 02:57:27 +00:00
2019-08-24 01:34:23 +00:00
// policy information
func ( ) {
// set policy information
2019-12-12 23:02:59 +00:00
resp . PolicyResponse . Policy = policy . Name
2019-08-24 01:34:23 +00:00
// resource details
2019-12-12 23:02:59 +00:00
resp . PolicyResponse . Resource . Name = resource . GetName ( )
resp . PolicyResponse . Resource . Namespace = resource . GetNamespace ( )
resp . PolicyResponse . Resource . Kind = resource . GetKind ( )
resp . PolicyResponse . Resource . APIVersion = resource . GetAPIVersion ( )
2019-08-24 01:34:23 +00:00
} ( )
glog . V ( 4 ) . Infof ( "started applying mutation rules of policy %q (%v)" , policy . Name , startTime )
defer func ( ) {
2019-12-12 23:02:59 +00:00
resp . PolicyResponse . ProcessingTime = time . Since ( startTime )
glog . V ( 4 ) . Infof ( "finished applying mutation rules policy %v (%v)" , policy . Name , resp . PolicyResponse . ProcessingTime )
glog . V ( 4 ) . Infof ( "Mutation Rules appplied count %v for policy %q" , resp . PolicyResponse . RulesAppliedCount , policy . Name )
2019-08-24 01:34:23 +00:00
} ( )
incrementAppliedRuleCount := func ( ) {
// rules applied succesfully count
2019-12-12 23:02:59 +00:00
resp . PolicyResponse . RulesAppliedCount ++
2019-08-24 01:34:23 +00:00
}
2019-11-14 01:56:56 +00:00
patchedResource := policyContext . NewResource
2019-08-24 01:34:23 +00:00
for _ , rule := range policy . Spec . Rules {
//TODO: to be checked before calling the resources as well
2019-12-26 23:34:19 +00:00
if ! rule . HasMutate ( ) && ! strings . Contains ( PodControllers , resource . GetKind ( ) ) {
2019-08-24 01:34:23 +00:00
continue
}
2019-11-09 02:57:27 +00:00
2020-01-10 19:59:05 +00:00
if paths := validateGeneralRuleInfoVariables ( ctx , rule ) ; len ( paths ) != 0 {
glog . Infof ( "referenced path not present in rule %s, resource %s/%s/%s, path: %s" , rule . Name , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , paths )
resp . PolicyResponse . Rules = append ( resp . PolicyResponse . Rules ,
2020-01-11 01:15:44 +00:00
newPathNotPresentRuleResponse ( rule . Name , utils . Mutation . String ( ) , fmt . Sprintf ( "path not present in rule info: %s" , paths ) ) )
2020-01-10 19:59:05 +00:00
continue
}
2019-11-12 05:23:26 +00:00
startTime := time . Now ( )
2020-01-07 18:33:28 +00:00
if ! rbac . MatchAdmissionInfo ( rule , policyContext . AdmissionInfo ) {
2019-11-12 02:52:26 +00:00
glog . V ( 3 ) . Infof ( "rule '%s' cannot be applied on %s/%s/%s, admission permission: %v" ,
2019-11-09 02:57:27 +00:00
rule . Name , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , policyContext . AdmissionInfo )
continue
}
2019-11-12 05:23:26 +00:00
glog . V ( 4 ) . Infof ( "Time: Mutate matchAdmissionInfo %v" , time . Since ( startTime ) )
2019-11-09 02:57:27 +00:00
2019-08-24 01:34:23 +00:00
// check if the resource satisfies the filter conditions defined in the rule
//TODO: this needs to be extracted, to filter the resource so that we can avoid passing resources that
// dont statisfy a policy rule resource description
ok := MatchesResourceDescription ( resource , rule )
if ! ok {
glog . V ( 4 ) . Infof ( "resource %s/%s does not satisfy the resource description for the rule " , resource . GetNamespace ( ) , resource . GetName ( ) )
continue
}
2020-01-07 23:13:57 +00:00
// evaluate pre-conditions
if ! variables . EvaluateConditions ( ctx , rule . Conditions ) {
glog . V ( 4 ) . Infof ( "resource %s/%s does not satisfy the conditions for the rule " , resource . GetNamespace ( ) , resource . GetName ( ) )
continue
}
2019-08-24 01:34:23 +00:00
// Process Overlay
if rule . Mutation . Overlay != nil {
2019-12-12 23:02:59 +00:00
var ruleResponse response . RuleResponse
2020-01-08 01:06:17 +00:00
ruleResponse , patchedResource = mutate . ProcessOverlay ( ctx , rule , patchedResource )
2020-01-09 20:24:37 +00:00
if ruleResponse . Success == true {
// - variable substitution path is not present
if ruleResponse . PathNotPresent {
glog . V ( 4 ) . Infof ( ruleResponse . Message )
resp . PolicyResponse . Rules = append ( resp . PolicyResponse . Rules , ruleResponse )
continue
}
// - overlay pattern does not match the resource conditions
if ruleResponse . Patches == nil {
glog . V ( 4 ) . Infof ( ruleResponse . Message )
continue
}
2019-11-14 01:56:56 +00:00
glog . Infof ( "Mutate overlay in rule '%s' successfully applied on %s/%s/%s" , rule . Name , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) )
2019-08-24 01:34:23 +00:00
}
2019-11-14 01:56:56 +00:00
2019-12-12 23:02:59 +00:00
resp . PolicyResponse . Rules = append ( resp . PolicyResponse . Rules , ruleResponse )
2019-08-24 01:34:23 +00:00
incrementAppliedRuleCount ( )
}
// Process Patches
if rule . Mutation . Patches != nil {
2019-12-12 23:02:59 +00:00
var ruleResponse response . RuleResponse
2020-01-08 01:06:17 +00:00
ruleResponse , patchedResource = mutate . ProcessPatches ( rule , patchedResource )
2019-11-12 05:03:34 +00:00
glog . Infof ( "Mutate patches in rule '%s' successfully applied on %s/%s/%s" , rule . Name , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) )
2019-12-12 23:02:59 +00:00
resp . PolicyResponse . Rules = append ( resp . PolicyResponse . Rules , ruleResponse )
2019-08-24 01:34:23 +00:00
incrementAppliedRuleCount ( )
}
2019-12-26 23:34:19 +00:00
// insert annotation to podtemplate if resource is pod controller
2019-12-27 23:57:43 +00:00
// skip inserting on existing resource
2020-01-08 18:44:41 +00:00
if reflect . DeepEqual ( policyContext . AdmissionInfo , kyverno . RequestInfo { } ) {
2019-12-27 23:57:43 +00:00
continue
}
2019-12-26 23:34:19 +00:00
if strings . Contains ( PodControllers , resource . GetKind ( ) ) {
var ruleResponse response . RuleResponse
2020-01-08 01:06:17 +00:00
ruleResponse , patchedResource = mutate . ProcessOverlay ( ctx , podTemplateRule , patchedResource )
2019-12-26 23:34:19 +00:00
if ! ruleResponse . Success {
2019-12-27 02:41:14 +00:00
glog . Errorf ( "Failed to insert annotation to podTemplate of %s/%s/%s: %s" , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , ruleResponse . Message )
2019-12-26 23:34:19 +00:00
continue
}
2019-12-27 23:57:43 +00:00
if ruleResponse . Success && ruleResponse . Patches != nil {
2019-12-27 22:59:12 +00:00
glog . V ( 2 ) . Infof ( "Inserted annotation to podTemplate of %s/%s/%s: %s" , resource . GetKind ( ) , resource . GetNamespace ( ) , resource . GetName ( ) , ruleResponse . Message )
2019-12-27 02:41:14 +00:00
resp . PolicyResponse . Rules = append ( resp . PolicyResponse . Rules , ruleResponse )
}
2019-12-26 23:34:19 +00:00
}
2019-08-24 01:34:23 +00:00
}
// send the patched resource
2019-12-12 23:02:59 +00:00
resp . PatchedResource = patchedResource
return resp
2019-08-24 01:34:23 +00:00
}
2019-12-26 23:34:19 +00:00
// podTemplateRule mutate pod template with annotation
// pod-policies.kyverno.io/autogen-applied=true
var podTemplateRule = kyverno . Rule {
2019-12-27 02:41:14 +00:00
Name : "autogen-annotate-podtemplate" ,
2019-12-26 23:34:19 +00:00
Mutation : kyverno . Mutation {
2019-12-27 02:41:14 +00:00
Overlay : map [ string ] interface { } {
"spec" : map [ string ] interface { } {
"template" : map [ string ] interface { } {
"metadata" : map [ string ] interface { } {
"annotations" : map [ string ] interface { } {
"pod-policies.kyverno.io/autogen-applied" : "true" ,
} ,
} ,
} ,
} ,
} ,
2019-12-26 23:34:19 +00:00
} ,
}