2019-05-14 01:17:28 +00:00
package engine
2019-05-10 05:26:22 +00:00
import (
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"
2019-12-12 23:02:59 +00:00
"github.com/nirmata/kyverno/pkg/engine/response"
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
2019-11-12 05:23:26 +00:00
startTime := time . Now ( )
2019-11-09 02:57:27 +00:00
if ! 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
}
// Process Overlay
if rule . Mutation . Overlay != nil {
2019-12-12 23:02:59 +00:00
var ruleResponse response . RuleResponse
2019-12-13 02:25:54 +00:00
ruleResponse , patchedResource = processOverlay ( ctx , rule , patchedResource )
2019-11-07 00:16:29 +00:00
if ruleResponse . Success == true && ruleResponse . Patches == nil {
2019-08-24 01:34:23 +00:00
// overlay pattern does not match the resource conditions
2019-11-12 05:03:34 +00:00
glog . V ( 4 ) . Infof ( ruleResponse . Message )
2019-08-24 01:34:23 +00:00
continue
2019-11-14 01:56:56 +00:00
} else if ruleResponse . Success == true {
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
2019-11-14 01:56:56 +00:00
ruleResponse , patchedResource = 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
if strings . Contains ( PodControllers , resource . GetKind ( ) ) {
var ruleResponse response . RuleResponse
ruleResponse , patchedResource = processOverlay ( ctx , podTemplateRule , patchedResource )
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 02:41:14 +00:00
if 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
} ,
}