2020-05-29 15:32:29 +05:30
package common
import (
2020-09-01 09:38:49 -07:00
"bufio"
2020-05-29 15:32:29 +05:30
"encoding/json"
"fmt"
"io/ioutil"
2021-02-08 23:38:06 +05:30
"net/http"
2020-10-19 12:36:55 -07:00
"os"
"path/filepath"
2021-09-03 16:41:13 +05:30
"reflect"
2021-02-02 18:43:19 +05:30
"strings"
2020-08-31 19:32:00 +05:30
2021-02-25 15:21:55 -08:00
jsonpatch "github.com/evanphx/json-patch/v5"
2021-02-07 20:26:56 -08:00
"github.com/go-git/go-billy/v5"
2020-07-29 21:41:58 +05:30
"github.com/go-logr/logr"
2021-10-29 18:13:20 +02:00
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
2022-04-25 20:20:40 +08:00
v1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
2021-10-29 18:13:20 +02:00
report "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
2022-04-14 17:50:18 +05:30
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
2022-04-25 20:20:40 +08:00
"github.com/kyverno/kyverno/pkg/autogen"
2021-02-07 20:26:56 -08:00
client "github.com/kyverno/kyverno/pkg/dclient"
"github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response"
2022-01-19 05:08:49 +05:30
ut "github.com/kyverno/kyverno/pkg/engine/utils"
2022-04-25 20:20:40 +08:00
"github.com/kyverno/kyverno/pkg/engine/variables"
2020-10-07 11:12:31 -07:00
"github.com/kyverno/kyverno/pkg/policymutation"
2021-09-02 00:02:55 +05:30
"github.com/kyverno/kyverno/pkg/policyreport"
2020-10-07 11:12:31 -07:00
"github.com/kyverno/kyverno/pkg/utils"
2021-02-07 20:26:56 -08:00
yamlv2 "gopkg.in/yaml.v2"
2020-11-17 13:07:30 -08:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml"
2021-02-07 20:26:56 -08:00
"sigs.k8s.io/controller-runtime/pkg/log"
2020-05-29 15:32:29 +05:30
)
2021-08-31 21:18:54 +05:30
type ResultCounts struct {
Pass int
Fail int
Warn int
Error int
Skip int
}
2021-02-02 18:43:19 +05:30
type Policy struct {
Name string ` json:"name" `
Resources [ ] Resource ` json:"resources" `
2021-04-29 22:39:44 +05:30
Rules [ ] Rule ` json:"rules" `
}
type Rule struct {
2022-05-07 21:30:11 +01:00
Name string ` json:"name" `
Values map [ string ] interface { } ` json:"values" `
ForeachValues map [ string ] [ ] interface { } ` json:"foreachValues" `
2021-02-02 18:43:19 +05:30
}
type Values struct {
2021-03-10 02:15:45 +05:30
Policies [ ] Policy ` json:"policies" `
2021-09-20 22:16:57 +05:30
GlobalValues map [ string ] string ` json:"globalValues" `
2021-03-10 02:15:45 +05:30
NamespaceSelectors [ ] NamespaceSelector ` json:"namespaceSelector" `
}
2021-04-29 22:39:44 +05:30
type Resource struct {
2022-05-07 21:30:11 +01:00
Name string ` json:"name" `
Values map [ string ] interface { } ` json:"values" `
2021-04-29 22:39:44 +05:30
}
2021-03-10 02:15:45 +05:30
type NamespaceSelector struct {
Name string ` json:"name" `
Labels map [ string ] string ` json:"labels" `
2021-02-02 18:43:19 +05:30
}
2021-11-03 11:16:55 -07:00
// HasVariables - check for variables in the policy
2022-03-31 08:44:00 +02:00
func HasVariables ( policy v1 . PolicyInterface ) [ ] [ ] string {
2021-11-03 11:16:55 -07:00
policyRaw , _ := json . Marshal ( policy )
matches := variables . RegexVariables . FindAllStringSubmatch ( string ( policyRaw ) , - 1 )
return matches
}
2021-08-31 21:18:54 +05:30
// GetPolicies - Extracting the policies from multiple YAML
2022-03-31 08:44:00 +02:00
func GetPolicies ( paths [ ] string ) ( policies [ ] v1 . PolicyInterface , errors [ ] error ) {
2020-11-03 01:25:32 +05:30
for _ , path := range paths {
2020-12-07 11:26:04 -08:00
log . Log . V ( 5 ) . Info ( "reading policies" , "path" , path )
2021-02-08 23:38:06 +05:30
var (
fileDesc os . FileInfo
err error
)
2021-10-29 16:06:03 +01:00
isHTTPPath := IsHTTPRegex . MatchString ( path )
2021-02-08 23:38:06 +05:30
// path clean and retrieving file info can be possible if it's not an HTTP URL
2021-10-29 16:06:03 +01:00
if ! isHTTPPath {
2021-02-08 23:38:06 +05:30
path = filepath . Clean ( path )
fileDesc , err = os . Stat ( path )
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
2020-10-21 20:05:05 +05:30
}
2020-12-07 11:26:04 -08:00
2021-02-08 23:38:06 +05:30
// apply file from a directory is possible only if the path is not HTTP URL
2021-10-29 16:06:03 +01:00
if ! isHTTPPath && fileDesc . IsDir ( ) {
2020-11-03 01:25:32 +05:30
files , err := ioutil . ReadDir ( path )
2020-10-07 06:20:53 +05:30
if err != nil {
2021-02-08 23:38:06 +05:30
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
2020-12-07 11:26:04 -08:00
continue
2020-10-07 06:20:53 +05:30
}
2020-12-07 11:26:04 -08:00
2020-11-03 01:25:32 +05:30
listOfFiles := make ( [ ] string , 0 )
for _ , file := range files {
2020-12-07 11:26:04 -08:00
ext := filepath . Ext ( file . Name ( ) )
if ext == "" || ext == ".yaml" || ext == ".yml" {
listOfFiles = append ( listOfFiles , filepath . Join ( path , file . Name ( ) ) )
}
2020-11-01 23:18:58 +05:30
}
2020-12-07 11:26:04 -08:00
policiesFromDir , errorsFromDir := GetPolicies ( listOfFiles )
errors = append ( errors , errorsFromDir ... )
2020-11-03 01:25:32 +05:30
policies = append ( policies , policiesFromDir ... )
2020-12-07 11:26:04 -08:00
2020-11-03 01:25:32 +05:30
} else {
2021-02-08 23:38:06 +05:30
var fileBytes [ ] byte
2021-10-29 16:06:03 +01:00
if isHTTPPath {
2021-10-14 00:05:13 +02:00
// We accept here that a random URL might be called based on user provided input.
resp , err := http . Get ( path ) // #nosec
2021-02-08 23:38:06 +05:30
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
defer resp . Body . Close ( )
if resp . StatusCode != http . StatusOK {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
fileBytes , err = ioutil . ReadAll ( resp . Body )
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
} else {
2021-10-13 10:48:45 -07:00
path = filepath . Clean ( path )
2021-10-14 00:05:13 +02:00
// We accept the risk of including a user provided file here.
fileBytes , err = ioutil . ReadFile ( path ) // #nosec G304
2021-02-08 23:38:06 +05:30
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
2020-11-03 01:25:32 +05:30
}
2020-12-07 11:26:04 -08:00
policiesFromFile , errFromFile := utils . GetPolicy ( fileBytes )
if errFromFile != nil {
err := fmt . Errorf ( "failed to process %s: %v" , path , errFromFile . Error ( ) )
errors = append ( errors , err )
continue
2020-11-01 23:18:58 +05:30
}
2020-10-21 20:05:05 +05:30
2020-12-07 11:26:04 -08:00
policies = append ( policies , policiesFromFile ... )
2020-11-01 23:18:58 +05:30
}
2020-10-21 20:05:05 +05:30
}
2020-12-07 11:26:04 -08:00
log . Log . V ( 3 ) . Info ( "read policies" , "policies" , len ( policies ) , "errors" , len ( errors ) )
return policies , errors
2020-05-29 15:32:29 +05:30
}
2020-07-07 16:20:55 +05:30
2020-07-29 21:41:58 +05:30
// MutatePolicy - applies mutation to a policy
2022-03-31 08:44:00 +02:00
func MutatePolicy ( policy v1 . PolicyInterface , logger logr . Logger ) ( v1 . PolicyInterface , error ) {
2022-03-28 16:01:27 +02:00
patches , _ := policymutation . GenerateJSONPatchesForDefaults ( policy , logger )
2020-08-19 15:11:21 -07:00
if len ( patches ) == 0 {
return policy , nil
}
2020-07-29 21:41:58 +05:30
patch , err := jsonpatch . DecodePatch ( patches )
if err != nil {
2022-03-31 08:44:00 +02:00
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to decode patch for %s policy" , policy . GetName ( ) ) , err )
2020-07-29 21:41:58 +05:30
}
2022-04-26 11:56:46 +05:30
policyBytes , err := json . Marshal ( policy )
2020-07-29 21:41:58 +05:30
if err != nil {
2022-03-31 08:44:00 +02:00
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to marshal %s policy" , policy . GetName ( ) ) , err )
2020-07-29 21:41:58 +05:30
}
modifiedPolicy , err := patch . Apply ( policyBytes )
if err != nil {
2022-03-31 08:44:00 +02:00
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to apply %s policy" , policy . GetName ( ) ) , err )
2020-07-29 21:41:58 +05:30
}
2022-04-27 16:08:31 +02:00
if policy . IsNamespaced ( ) {
var p v1 . Policy
err = json . Unmarshal ( modifiedPolicy , & p )
if err != nil {
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to unmarshal %s policy" , policy . GetName ( ) ) , err )
}
return & p , nil
} else {
var p v1 . ClusterPolicy
err = json . Unmarshal ( modifiedPolicy , & p )
if err != nil {
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to unmarshal %s policy" , policy . GetName ( ) ) , err )
}
return & p , nil
2020-07-29 21:41:58 +05:30
}
}
2020-08-19 10:21:32 +05:30
2020-10-07 06:20:53 +05:30
// IsInputFromPipe - check if input is passed using pipe
func IsInputFromPipe ( ) bool {
fileInfo , _ := os . Stdin . Stat ( )
return fileInfo . Mode ( ) & os . ModeCharDevice == 0
}
2021-02-02 18:43:19 +05:30
2021-07-24 00:02:48 +05:30
// RemoveDuplicateAndObjectVariables - remove duplicate variables
func RemoveDuplicateAndObjectVariables ( matches [ ] [ ] string ) string {
2021-02-02 18:43:19 +05:30
var variableStr string
for _ , m := range matches {
for _ , v := range m {
foundVariable := strings . Contains ( variableStr , v )
if ! foundVariable {
2022-01-04 17:36:33 -08:00
if ! strings . Contains ( v , "request.object" ) && ! strings . Contains ( v , "element" ) && v == "elementIndex" {
2021-07-24 00:02:48 +05:30
variableStr = variableStr + " " + v
}
2021-02-02 18:43:19 +05:30
}
}
}
return variableStr
}
2021-09-20 22:16:57 +05:30
func GetVariable ( variablesString , valuesFile string , fs billy . Filesystem , isGit bool , policyResourcePath string ) ( map [ string ] string , map [ string ] string , map [ string ] map [ string ] Resource , map [ string ] map [ string ] string , error ) {
2021-04-29 22:39:44 +05:30
valuesMapResource := make ( map [ string ] map [ string ] Resource )
valuesMapRule := make ( map [ string ] map [ string ] Rule )
2021-03-10 02:15:45 +05:30
namespaceSelectorMap := make ( map [ string ] map [ string ] string )
2021-02-03 18:24:50 +05:30
variables := make ( map [ string ] string )
2021-09-20 22:16:57 +05:30
globalValMap := make ( map [ string ] string )
2021-08-01 16:27:47 +05:30
reqObjVars := ""
2021-07-28 10:52:32 +05:30
2021-02-18 01:00:41 +05:30
var yamlFile [ ] byte
var err error
2021-02-02 18:43:19 +05:30
if variablesString != "" {
kvpairs := strings . Split ( strings . Trim ( variablesString , " " ) , "," )
for _ , kvpair := range kvpairs {
kvs := strings . Split ( strings . Trim ( kvpair , " " ) , "=" )
2021-07-24 00:02:48 +05:30
if strings . Contains ( kvs [ 0 ] , "request.object" ) {
2021-08-01 16:27:47 +05:30
if ! strings . Contains ( reqObjVars , kvs [ 0 ] ) {
reqObjVars = reqObjVars + "," + kvs [ 0 ]
}
continue
2021-07-24 00:02:48 +05:30
}
2021-07-28 10:52:32 +05:30
2021-02-02 18:43:19 +05:30
variables [ strings . Trim ( kvs [ 0 ] , " " ) ] = strings . Trim ( kvs [ 1 ] , " " )
}
}
2021-07-24 00:02:48 +05:30
2021-02-02 18:43:19 +05:30
if valuesFile != "" {
2021-02-18 01:00:41 +05:30
if isGit {
2021-06-22 18:56:44 +05:30
filep , err := fs . Open ( filepath . Join ( policyResourcePath , valuesFile ) )
2021-02-18 01:00:41 +05:30
if err != nil {
fmt . Printf ( "Unable to open variable file: %s. error: %s" , valuesFile , err )
}
yamlFile , err = ioutil . ReadAll ( filep )
2021-10-14 00:05:13 +02:00
if err != nil {
fmt . Printf ( "Unable to read variable files: %s. error: %s \n" , filep , err )
}
2021-02-18 01:00:41 +05:30
} else {
2021-10-14 00:05:13 +02:00
// We accept the risk of including a user provided file here.
yamlFile , err = ioutil . ReadFile ( filepath . Join ( policyResourcePath , valuesFile ) ) // #nosec G304
2021-09-03 18:43:11 +05:30
if err != nil {
fmt . Printf ( "\n Unable to open variable file: %s. error: %s \n" , valuesFile , err )
}
2021-02-18 01:00:41 +05:30
}
2021-02-02 18:43:19 +05:30
if err != nil {
2021-09-20 22:16:57 +05:30
return variables , globalValMap , valuesMapResource , namespaceSelectorMap , sanitizederror . NewWithError ( "unable to read yaml" , err )
2021-02-02 18:43:19 +05:30
}
valuesBytes , err := yaml . ToJSON ( yamlFile )
if err != nil {
2021-09-20 22:16:57 +05:30
return variables , globalValMap , valuesMapResource , namespaceSelectorMap , sanitizederror . NewWithError ( "failed to convert json" , err )
2021-02-02 18:43:19 +05:30
}
values := & Values { }
if err := json . Unmarshal ( valuesBytes , values ) ; err != nil {
2021-09-20 22:16:57 +05:30
return variables , globalValMap , valuesMapResource , namespaceSelectorMap , sanitizederror . NewWithError ( "failed to decode yaml" , err )
2021-02-02 18:43:19 +05:30
}
2021-09-20 22:16:57 +05:30
globalValMap = values . GlobalValues
2021-02-02 18:43:19 +05:30
for _ , p := range values . Policies {
2021-04-29 22:39:44 +05:30
resourceMap := make ( map [ string ] Resource )
2021-02-02 18:43:19 +05:30
for _ , r := range p . Resources {
2021-11-18 20:39:35 +05:30
if val , ok := r . Values [ "request.operation" ] ; ok {
if val == "" {
r . Values [ "request.operation" ] = "CREATE"
log . Log . V ( 3 ) . Info ( "No request.operation found, defaulting it to CREATE" , "policy" , p . Name )
}
} else {
if r . Values == nil {
2022-05-07 21:30:11 +01:00
r . Values = make ( map [ string ] interface { } )
2021-11-18 20:39:35 +05:30
}
r . Values [ "request.operation" ] = "CREATE"
log . Log . V ( 3 ) . Info ( "No request.operation found, defaulting it to CREATE" , "policy" , p . Name )
}
2021-07-28 10:52:32 +05:30
for variableInFile := range r . Values {
2021-07-24 00:02:48 +05:30
if strings . Contains ( variableInFile , "request.object" ) {
2021-08-01 16:27:47 +05:30
if ! strings . Contains ( reqObjVars , variableInFile ) {
reqObjVars = reqObjVars + "," + variableInFile
}
delete ( r . Values , variableInFile )
continue
2021-07-24 00:02:48 +05:30
}
}
2021-04-29 22:39:44 +05:30
resourceMap [ r . Name ] = r
}
valuesMapResource [ p . Name ] = resourceMap
if p . Rules != nil {
ruleMap := make ( map [ string ] Rule )
for _ , r := range p . Rules {
ruleMap [ r . Name ] = r
}
valuesMapRule [ p . Name ] = ruleMap
2021-02-02 18:43:19 +05:30
}
}
2021-03-10 02:15:45 +05:30
for _ , n := range values . NamespaceSelectors {
namespaceSelectorMap [ n . Name ] = n . Labels
}
2021-02-02 18:43:19 +05:30
}
2021-08-01 16:27:47 +05:30
if reqObjVars != "" {
2021-08-07 05:46:12 +05:30
fmt . Printf ( ( "\nNOTICE: request.object.* variables are automatically parsed from the supplied resource. Ignoring value of variables `%v`.\n" ) , reqObjVars )
2021-08-01 16:27:47 +05:30
}
2022-03-02 08:29:33 +01:00
storePolicies := make ( [ ] store . Policy , 0 )
2021-04-29 22:39:44 +05:30
for policyName , ruleMap := range valuesMapRule {
storeRules := make ( [ ] store . Rule , 0 )
for _ , rule := range ruleMap {
storeRules = append ( storeRules , store . Rule {
2022-04-25 22:06:31 +05:30
Name : rule . Name ,
Values : rule . Values ,
ForeachValues : rule . ForeachValues ,
2021-04-29 22:39:44 +05:30
} )
}
2022-03-02 08:29:33 +01:00
storePolicies = append ( storePolicies , store . Policy {
2021-04-29 22:39:44 +05:30
Name : policyName ,
Rules : storeRules ,
} )
}
store . SetContext ( store . Context {
2022-03-02 08:29:33 +01:00
Policies : storePolicies ,
2021-04-29 22:39:44 +05:30
} )
2021-09-20 22:16:57 +05:30
return variables , globalValMap , valuesMapResource , namespaceSelectorMap , nil
2021-02-02 18:43:19 +05:30
}
2022-03-02 08:29:33 +01:00
// MutatePolicies - function to apply mutation on policies
2022-03-31 08:44:00 +02:00
func MutatePolicies ( policies [ ] v1 . PolicyInterface ) ( [ ] v1 . PolicyInterface , error ) {
newPolicies := make ( [ ] v1 . PolicyInterface , 0 )
2021-02-02 18:43:19 +05:30
logger := log . Log . WithName ( "apply" )
for _ , policy := range policies {
2022-03-28 16:01:27 +02:00
p , err := MutatePolicy ( policy , logger )
2021-02-02 18:43:19 +05:30
if err != nil {
if ! sanitizederror . IsErrorSanitized ( err ) {
return nil , sanitizederror . NewWithError ( "failed to mutate policy." , err )
}
return nil , err
}
newPolicies = append ( newPolicies , p )
}
return newPolicies , nil
}
// ApplyPolicyOnResource - function to apply policy on resource
2022-03-31 08:44:00 +02:00
func ApplyPolicyOnResource ( policy v1 . PolicyInterface , resource * unstructured . Unstructured ,
2022-05-07 21:30:11 +01:00
mutateLogPath string , mutateLogPathIsDir bool , variables map [ string ] interface { } , userInfo v1beta1 . RequestInfo , policyReport bool ,
2021-11-03 14:06:47 -07:00
namespaceSelectorMap map [ string ] map [ string ] string , stdin bool , rc * ResultCounts ,
printPatchResource bool ) ( [ ] * response . EngineResponse , policyreport . Info , error ) {
2021-07-28 10:52:32 +05:30
2021-10-01 17:52:23 +05:30
var engineResponses [ ] * response . EngineResponse
namespaceLabels := make ( map [ string ] string )
2021-07-28 10:52:32 +05:30
operationIsDelete := false
if variables [ "request.operation" ] == "DELETE" {
operationIsDelete = true
}
2021-02-02 18:43:19 +05:30
2021-03-11 00:24:21 +05:30
policyWithNamespaceSelector := false
2022-01-25 03:06:17 -05:00
OuterLoop :
2022-03-28 16:01:27 +02:00
for _ , p := range autogen . ComputeRules ( policy ) {
2021-03-11 10:31:53 +05:30
if p . MatchResources . ResourceDescription . NamespaceSelector != nil ||
p . ExcludeResources . ResourceDescription . NamespaceSelector != nil {
2021-03-11 00:24:21 +05:30
policyWithNamespaceSelector = true
break
}
2022-01-25 03:06:17 -05:00
for _ , m := range p . MatchResources . Any {
if m . ResourceDescription . NamespaceSelector != nil {
policyWithNamespaceSelector = true
break OuterLoop
}
}
for _ , m := range p . MatchResources . All {
if m . ResourceDescription . NamespaceSelector != nil {
policyWithNamespaceSelector = true
break OuterLoop
}
}
for _ , e := range p . ExcludeResources . Any {
if e . ResourceDescription . NamespaceSelector != nil {
policyWithNamespaceSelector = true
break OuterLoop
}
}
for _ , e := range p . ExcludeResources . All {
if e . ResourceDescription . NamespaceSelector != nil {
policyWithNamespaceSelector = true
break OuterLoop
}
}
2021-03-11 00:24:21 +05:30
}
if policyWithNamespaceSelector {
resourceNamespace := resource . GetNamespace ( )
namespaceLabels = namespaceSelectorMap [ resource . GetNamespace ( ) ]
if resourceNamespace != "default" && len ( namespaceLabels ) < 1 {
2022-02-24 16:39:22 +03:00
return engineResponses , policyreport . Info { } , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to get namespace labels for resource %s. use --values-file flag to pass the namespace labels" , resource . GetName ( ) ) , nil )
2021-03-11 00:24:21 +05:30
}
2021-03-10 02:15:45 +05:30
}
2021-03-11 00:24:21 +05:30
2021-02-02 18:43:19 +05:30
resPath := fmt . Sprintf ( "%s/%s/%s" , resource . GetNamespace ( ) , resource . GetKind ( ) , resource . GetName ( ) )
2022-03-31 08:44:00 +02:00
log . Log . V ( 3 ) . Info ( "applying policy on resource" , "policy" , policy . GetName ( ) , "resource" , resPath )
2021-02-02 18:43:19 +05:30
2021-07-24 00:02:48 +05:30
resourceRaw , err := resource . MarshalJSON ( )
if err != nil {
log . Log . Error ( err , "failed to marshal resource" )
}
2022-04-19 08:35:12 -07:00
updatedResource , err := ut . ConvertToUnstructured ( resourceRaw )
2022-01-19 05:08:49 +05:30
if err != nil {
log . Log . Error ( err , "unable to convert raw resource to unstructured" )
}
ctx := context . NewContext ( )
2021-07-24 00:02:48 +05:30
if operationIsDelete {
2022-04-09 13:52:50 +02:00
err = context . AddOldResource ( ctx , resourceRaw )
2021-07-24 00:02:48 +05:30
} else {
2022-04-09 13:52:50 +02:00
err = context . AddResource ( ctx , resourceRaw )
2021-07-24 00:02:48 +05:30
}
2021-11-03 14:06:47 -07:00
2021-07-24 00:02:48 +05:30
if err != nil {
log . Log . Error ( err , "failed to load resource in context" )
}
2021-02-02 18:43:19 +05:30
for key , value := range variables {
2022-04-09 13:52:50 +02:00
err = ctx . AddVariable ( key , value )
2021-10-11 23:57:43 +02:00
if err != nil {
log . Log . Error ( err , "failed to add variable to context" )
}
2021-02-02 18:43:19 +05:30
}
2022-04-09 13:52:50 +02:00
if err := ctx . AddImageInfos ( resource ) ; err != nil {
2021-11-03 14:06:47 -07:00
if err != nil {
log . Log . Error ( err , "failed to add image variables to context" )
}
}
2022-01-19 05:08:49 +05:30
if err := context . MutateResourceWithImageInfo ( resourceRaw , ctx ) ; err != nil {
log . Log . Error ( err , "failed to add image variables to context" )
}
2022-04-19 08:35:12 -07:00
2022-04-27 08:09:52 -07:00
policyContext := & engine . PolicyContext {
Policy : policy ,
NewResource : * updatedResource ,
JSONContext : ctx ,
NamespaceLabels : namespaceLabels ,
AdmissionInfo : userInfo ,
}
mutateResponse := engine . Mutate ( policyContext )
2021-10-01 14:16:33 +05:30
if mutateResponse != nil {
2021-10-01 17:52:23 +05:30
engineResponses = append ( engineResponses , mutateResponse )
2021-10-01 14:16:33 +05:30
}
2021-10-01 17:52:23 +05:30
2021-10-01 14:16:33 +05:30
err = processMutateEngineResponse ( policy , mutateResponse , resPath , rc , mutateLogPath , stdin , mutateLogPathIsDir , resource . GetName ( ) , printPatchResource )
2021-09-03 12:32:12 +05:30
if err != nil {
if ! sanitizederror . IsErrorSanitized ( err ) {
2021-10-01 17:52:23 +05:30
return engineResponses , policyreport . Info { } , sanitizederror . NewWithError ( "failed to print mutated result" , err )
2021-02-02 18:43:19 +05:30
}
}
if resource . GetKind ( ) == "Pod" && len ( resource . GetOwnerReferences ( ) ) > 0 {
if policy . HasAutoGenAnnotation ( ) {
2022-03-31 08:44:00 +02:00
annotations := policy . GetAnnotations ( )
if _ , ok := annotations [ v1 . PodControllersAnnotation ] ; ok {
delete ( annotations , v1 . PodControllersAnnotation )
policy . SetAnnotations ( annotations )
2021-02-02 18:43:19 +05:30
}
}
}
2021-09-02 03:54:02 +05:30
var policyHasValidate bool
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2022-04-27 08:09:52 -07:00
if rule . HasValidate ( ) || rule . HasImagesValidationChecks ( ) {
2021-09-02 03:54:02 +05:30
policyHasValidate = true
}
}
2022-04-27 08:09:52 -07:00
policyContext . NewResource = mutateResponse . PatchedResource
2021-09-02 03:54:02 +05:30
var info policyreport . Info
2021-09-02 18:15:22 +05:30
var validateResponse * response . EngineResponse
2021-09-02 03:54:02 +05:30
if policyHasValidate {
2022-04-27 08:09:52 -07:00
validateResponse = engine . Validate ( policyContext )
2021-09-03 12:32:12 +05:30
info = ProcessValidateEngineResponse ( policy , validateResponse , resPath , rc , policyReport )
2021-09-02 03:54:02 +05:30
}
2022-04-27 08:09:52 -07:00
if validateResponse != nil && ! validateResponse . IsEmpty ( ) {
2021-10-01 17:52:23 +05:30
engineResponses = append ( engineResponses , validateResponse )
2021-10-01 14:16:33 +05:30
}
2021-02-02 18:43:19 +05:30
2022-05-05 14:06:18 -07:00
verifyImageResponse , _ := engine . VerifyAndPatchImages ( policyContext )
2022-05-04 09:41:59 +05:30
if verifyImageResponse != nil && ! verifyImageResponse . IsEmpty ( ) {
engineResponses = append ( engineResponses , verifyImageResponse )
info = ProcessValidateEngineResponse ( policy , verifyImageResponse , resPath , rc , policyReport )
}
2021-02-02 18:43:19 +05:30
var policyHasGenerate bool
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2021-02-02 18:43:19 +05:30
if rule . HasGenerate ( ) {
policyHasGenerate = true
}
}
if policyHasGenerate {
2021-02-17 02:18:04 +05:30
policyContext := & engine . PolicyContext {
NewResource : * resource ,
2022-03-30 15:04:30 +02:00
Policy : policy ,
2021-02-17 02:18:04 +05:30
ExcludeGroupRole : [ ] string { } ,
ExcludeResourceFunc : func ( s1 , s2 , s3 string ) bool {
return false
} ,
2021-03-10 02:15:45 +05:30
JSONContext : context . NewContext ( ) ,
NamespaceLabels : namespaceLabels ,
2021-02-17 02:18:04 +05:30
}
2022-04-25 20:20:40 +08:00
generateResponse := engine . ApplyBackgroundChecks ( policyContext )
2022-04-27 08:09:52 -07:00
if generateResponse != nil && ! generateResponse . IsEmpty ( ) {
2021-10-01 17:52:23 +05:30
engineResponses = append ( engineResponses , generateResponse )
2021-10-01 14:16:33 +05:30
}
2022-04-27 08:09:52 -07:00
updateResultCounts ( policy , generateResponse , resPath , rc )
2021-02-02 18:43:19 +05:30
}
2021-02-07 20:26:56 -08:00
2021-10-01 17:52:23 +05:30
return engineResponses , info , nil
2021-02-02 18:43:19 +05:30
}
// PrintMutatedOutput - function to print output in provided file or directory
func PrintMutatedOutput ( mutateLogPath string , mutateLogPathIsDir bool , yaml string , fileName string ) error {
var f * os . File
var err error
yaml = yaml + ( "\n---\n\n" )
2021-10-13 10:48:45 -07:00
mutateLogPath = filepath . Clean ( mutateLogPath )
2021-02-02 18:43:19 +05:30
if ! mutateLogPathIsDir {
2021-07-09 18:01:46 -07:00
// truncation for the case when mutateLogPath is a file (not a directory) is handled under pkg/kyverno/apply/test_command.go
2021-10-14 00:05:13 +02:00
f , err = os . OpenFile ( mutateLogPath , os . O_APPEND | os . O_WRONLY , 0600 ) // #nosec G304
2021-02-02 18:43:19 +05:30
} else {
2021-10-14 00:05:13 +02:00
f , err = os . OpenFile ( mutateLogPath + "/" + fileName + ".yaml" , os . O_CREATE | os . O_WRONLY , 0600 ) // #nosec G304
2021-02-02 18:43:19 +05:30
}
if err != nil {
return err
}
if _ , err := f . Write ( [ ] byte ( yaml ) ) ; err != nil {
2021-10-14 00:05:13 +02:00
closeErr := f . Close ( )
if closeErr != nil {
log . Log . Error ( closeErr , "failed to close file" )
}
2021-02-02 18:43:19 +05:30
return err
}
if err := f . Close ( ) ; err != nil {
return err
}
return nil
}
// GetPoliciesFromPaths - get policies according to the resource path
2022-03-31 08:44:00 +02:00
func GetPoliciesFromPaths ( fs billy . Filesystem , dirPath [ ] string , isGit bool , policyResourcePath string ) ( policies [ ] v1 . PolicyInterface , err error ) {
2021-02-02 18:43:19 +05:30
if isGit {
for _ , pp := range dirPath {
2021-06-22 18:56:44 +05:30
filep , err := fs . Open ( filepath . Join ( policyResourcePath , pp ) )
2021-02-18 01:00:41 +05:30
if err != nil {
fmt . Printf ( "Error: file not available with path %s: %v" , filep . Name ( ) , err . Error ( ) )
continue
}
2021-02-02 18:43:19 +05:30
bytes , err := ioutil . ReadAll ( filep )
if err != nil {
fmt . Printf ( "Error: failed to read file %s: %v" , filep . Name ( ) , err . Error ( ) )
2021-02-18 01:00:41 +05:30
continue
2021-02-02 18:43:19 +05:30
}
policyBytes , err := yaml . ToJSON ( bytes )
if err != nil {
fmt . Printf ( "failed to convert to JSON: %v" , err )
continue
}
2022-01-19 05:08:49 +05:30
policiesFromFile , errFromFile := utils . GetPolicy ( policyBytes )
2021-02-02 18:43:19 +05:30
if errFromFile != nil {
2022-05-09 18:55:35 +02:00
fmt . Printf ( "failed to process : %v" , errFromFile . Error ( ) )
2021-02-02 18:43:19 +05:30
continue
}
policies = append ( policies , policiesFromFile ... )
}
} else {
if len ( dirPath ) > 0 && dirPath [ 0 ] == "-" {
if IsInputFromPipe ( ) {
policyStr := ""
scanner := bufio . NewScanner ( os . Stdin )
for scanner . Scan ( ) {
policyStr = policyStr + scanner . Text ( ) + "\n"
}
yamlBytes := [ ] byte ( policyStr )
2022-01-19 05:08:49 +05:30
policies , err = utils . GetPolicy ( yamlBytes )
2021-02-02 18:43:19 +05:30
if err != nil {
return nil , sanitizederror . NewWithError ( "failed to extract the resources" , err )
}
}
} else {
var errors [ ] error
policies , errors = GetPolicies ( dirPath )
if len ( policies ) == 0 {
if len ( errors ) > 0 {
return nil , sanitizederror . NewWithErrors ( "failed to read file" , errors )
}
return nil , sanitizederror . New ( fmt . Sprintf ( "no file found in paths %v" , dirPath ) )
}
if len ( errors ) > 0 && log . Log . V ( 1 ) . Enabled ( ) {
fmt . Printf ( "ignoring errors: \n" )
for _ , e := range errors {
fmt . Printf ( " %v \n" , e . Error ( ) )
}
}
}
2021-02-07 20:26:56 -08:00
}
2021-02-02 18:43:19 +05:30
return
}
// GetResourceAccordingToResourcePath - get resources according to the resource path
2021-02-07 20:26:56 -08:00
func GetResourceAccordingToResourcePath ( fs billy . Filesystem , resourcePaths [ ] string ,
2022-05-03 07:30:04 +02:00
cluster bool , policies [ ] v1 . PolicyInterface , dClient client . Interface , namespace string , policyReport bool , isGit bool , policyResourcePath string ) ( resources [ ] * unstructured . Unstructured , err error ) {
2021-02-02 18:43:19 +05:30
if isGit {
2021-06-22 18:56:44 +05:30
resources , err = GetResourcesWithTest ( fs , policies , resourcePaths , isGit , policyResourcePath )
2021-02-02 18:43:19 +05:30
if err != nil {
return nil , sanitizederror . NewWithError ( "failed to extract the resources" , err )
}
} else {
if len ( resourcePaths ) > 0 && resourcePaths [ 0 ] == "-" {
if IsInputFromPipe ( ) {
resourceStr := ""
scanner := bufio . NewScanner ( os . Stdin )
for scanner . Scan ( ) {
resourceStr = resourceStr + scanner . Text ( ) + "\n"
}
yamlBytes := [ ] byte ( resourceStr )
resources , err = GetResource ( yamlBytes )
if err != nil {
return nil , sanitizederror . NewWithError ( "failed to extract the resources" , err )
}
}
2022-03-21 19:31:23 +05:30
} else {
if len ( resourcePaths ) > 0 {
fileDesc , err := os . Stat ( resourcePaths [ 0 ] )
2022-03-15 13:30:59 +05:30
if err != nil {
2022-03-21 19:31:23 +05:30
return nil , err
2022-03-15 13:30:59 +05:30
}
2022-03-21 19:31:23 +05:30
if fileDesc . IsDir ( ) {
files , err := ioutil . ReadDir ( resourcePaths [ 0 ] )
if err != nil {
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to parse %v" , resourcePaths [ 0 ] ) , err )
}
listOfFiles := make ( [ ] string , 0 )
for _ , file := range files {
ext := filepath . Ext ( file . Name ( ) )
if ext == ".yaml" || ext == ".yml" {
listOfFiles = append ( listOfFiles , filepath . Join ( resourcePaths [ 0 ] , file . Name ( ) ) )
}
2022-03-15 13:30:59 +05:30
}
2022-03-21 19:31:23 +05:30
resourcePaths = listOfFiles
2022-03-15 13:30:59 +05:30
}
}
2022-03-21 19:31:23 +05:30
2021-02-02 18:43:19 +05:30
resources , err = GetResources ( policies , resourcePaths , dClient , cluster , namespace , policyReport )
if err != nil {
return resources , err
}
}
}
return resources , err
2021-02-07 20:26:56 -08:00
}
2021-09-02 00:02:55 +05:30
2022-03-31 08:44:00 +02:00
func ProcessValidateEngineResponse ( policy v1 . PolicyInterface , validateResponse * response . EngineResponse , resPath string , rc * ResultCounts , policyReport bool ) policyreport . Info {
2021-09-02 00:02:55 +05:30
var violatedRules [ ] v1 . ViolatedRule
2022-04-12 09:30:49 +05:30
2021-09-02 00:02:55 +05:30
printCount := 0
2022-03-28 16:01:27 +02:00
for _ , policyRule := range autogen . ComputeRules ( policy ) {
2021-09-02 00:02:55 +05:30
ruleFoundInEngineResponse := false
2022-05-04 09:41:59 +05:30
if ! policyRule . HasValidate ( ) && ! policyRule . HasImagesValidationChecks ( ) && ! policyRule . HasVerifyImages ( ) {
2022-02-09 16:03:54 +05:30
continue
}
2021-09-02 00:02:55 +05:30
for i , valResponseRule := range validateResponse . PolicyResponse . Rules {
if policyRule . Name == valResponseRule . Name {
ruleFoundInEngineResponse = true
vrule := v1 . ViolatedRule {
Name : valResponseRule . Name ,
2022-04-06 21:04:08 +02:00
Type : string ( valResponseRule . Type ) ,
2021-09-02 00:02:55 +05:30
Message : valResponseRule . Message ,
}
2021-10-03 01:31:05 -07:00
switch valResponseRule . Status {
case response . RuleStatusPass :
2021-09-02 03:54:02 +05:30
rc . Pass ++
2021-10-03 01:31:05 -07:00
vrule . Status = report . StatusPass
case response . RuleStatusFail :
2022-05-07 15:33:50 +02:00
ann := policy . GetAnnotations ( )
if scored , ok := ann [ policyreport . ScoredLabel ] ; ok && scored == "false" {
rc . Warn ++
vrule . Status = report . StatusWarn
break
} else {
rc . Fail ++
vrule . Status = report . StatusFail
}
2021-09-02 01:06:29 +05:30
if ! policyReport {
if printCount < 1 {
2022-03-31 08:44:00 +02:00
fmt . Printf ( "\npolicy %s -> resource %s failed: \n" , policy . GetName ( ) , resPath )
2021-09-02 01:06:29 +05:30
printCount ++
}
2021-10-03 01:31:05 -07:00
2021-09-02 01:06:29 +05:30
fmt . Printf ( "%d. %s: %s \n" , i + 1 , valResponseRule . Name , valResponseRule . Message )
}
2021-10-03 01:31:05 -07:00
case response . RuleStatusError :
rc . Error ++
vrule . Status = report . StatusError
case response . RuleStatusWarn :
rc . Warn ++
vrule . Status = report . StatusWarn
case response . RuleStatusSkip :
rc . Skip ++
vrule . Status = report . StatusSkip
2021-09-02 00:02:55 +05:30
}
2021-10-03 01:31:05 -07:00
2021-09-02 00:02:55 +05:30
violatedRules = append ( violatedRules , vrule )
continue
}
}
if ! ruleFoundInEngineResponse {
2021-09-02 03:54:02 +05:30
rc . Skip ++
2021-09-02 00:02:55 +05:30
vruleSkip := v1 . ViolatedRule {
Name : policyRule . Name ,
Type : "Validation" ,
Message : policyRule . Validation . Message ,
2021-10-03 04:00:06 -07:00
Status : report . StatusSkip ,
2021-09-02 00:02:55 +05:30
}
violatedRules = append ( violatedRules , vruleSkip )
}
}
return buildPVInfo ( validateResponse , violatedRules )
}
func buildPVInfo ( er * response . EngineResponse , violatedRules [ ] v1 . ViolatedRule ) policyreport . Info {
info := policyreport . Info {
PolicyName : er . PolicyResponse . Policy . Name ,
Namespace : er . PatchedResource . GetNamespace ( ) ,
Results : [ ] policyreport . EngineResponseResult {
{
Resource : er . GetResourceSpec ( ) ,
Rules : violatedRules ,
} ,
} ,
}
return info
}
2021-09-02 03:54:02 +05:30
2022-04-27 08:09:52 -07:00
func updateResultCounts ( policy v1 . PolicyInterface , engineResponse * response . EngineResponse , resPath string , rc * ResultCounts ) {
2021-09-02 03:54:02 +05:30
printCount := 0
2022-03-28 16:01:27 +02:00
for _ , policyRule := range autogen . ComputeRules ( policy ) {
2021-09-02 03:54:02 +05:30
ruleFoundInEngineResponse := false
2022-04-27 08:09:52 -07:00
for i , ruleResponse := range engineResponse . PolicyResponse . Rules {
if policyRule . Name == ruleResponse . Name {
2021-09-02 03:54:02 +05:30
ruleFoundInEngineResponse = true
2022-05-04 09:41:59 +05:30
2022-04-27 08:09:52 -07:00
if ruleResponse . Status == response . RuleStatusPass {
2021-09-02 03:54:02 +05:30
rc . Pass ++
} else {
if printCount < 1 {
2022-04-27 08:09:52 -07:00
fmt . Println ( "\ninvalid resource" , "policy" , policy . GetName ( ) , "resource" , resPath )
2021-09-02 03:54:02 +05:30
printCount ++
}
2022-04-27 08:09:52 -07:00
fmt . Printf ( "%d. %s - %s\n" , i + 1 , ruleResponse . Name , ruleResponse . Message )
2021-09-02 03:54:02 +05:30
rc . Fail ++
}
continue
}
}
2022-04-27 08:09:52 -07:00
2021-09-02 03:54:02 +05:30
if ! ruleFoundInEngineResponse {
rc . Skip ++
}
}
}
2021-09-02 23:11:35 +05:30
2022-03-31 08:44:00 +02:00
func SetInStoreContext ( mutatedPolicies [ ] v1 . PolicyInterface , variables map [ string ] string ) map [ string ] string {
2022-03-02 08:29:33 +01:00
storePolicies := make ( [ ] store . Policy , 0 )
2021-09-02 23:11:35 +05:30
for _ , policy := range mutatedPolicies {
storeRules := make ( [ ] store . Rule , 0 )
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2022-05-07 21:30:11 +01:00
contextVal := make ( map [ string ] interface { } )
2021-09-02 23:11:35 +05:30
if len ( rule . Context ) != 0 {
for _ , contextVar := range rule . Context {
for k , v := range variables {
if strings . HasPrefix ( k , contextVar . Name ) {
contextVal [ k ] = v
delete ( variables , k )
}
}
}
storeRules = append ( storeRules , store . Rule {
Name : rule . Name ,
Values : contextVal ,
} )
}
}
2022-03-02 08:29:33 +01:00
storePolicies = append ( storePolicies , store . Policy {
2022-03-31 08:44:00 +02:00
Name : policy . GetName ( ) ,
2021-09-02 23:11:35 +05:30
Rules : storeRules ,
} )
}
store . SetContext ( store . Context {
2022-03-02 08:29:33 +01:00
Policies : storePolicies ,
2021-09-02 23:11:35 +05:30
} )
return variables
}
2021-09-03 12:32:12 +05:30
2022-03-31 08:44:00 +02:00
func processMutateEngineResponse ( policy v1 . PolicyInterface , mutateResponse * response . EngineResponse , resPath string , rc * ResultCounts , mutateLogPath string , stdin bool , mutateLogPathIsDir bool , resourceName string , printPatchResource bool ) error {
2021-09-03 12:41:05 +05:30
var policyHasMutate bool
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2021-09-03 12:41:05 +05:30
if rule . HasMutate ( ) {
policyHasMutate = true
}
}
2021-09-03 16:41:13 +05:30
if ! policyHasMutate {
return nil
}
2021-09-03 12:41:05 +05:30
2021-09-03 16:41:13 +05:30
printCount := 0
printMutatedRes := false
2022-03-28 16:01:27 +02:00
for _ , policyRule := range autogen . ComputeRules ( policy ) {
2021-09-03 16:41:13 +05:30
ruleFoundInEngineResponse := false
for i , mutateResponseRule := range mutateResponse . PolicyResponse . Rules {
if policyRule . Name == mutateResponseRule . Name {
ruleFoundInEngineResponse = true
2021-09-26 02:12:31 -07:00
if mutateResponseRule . Status == response . RuleStatusPass {
2021-09-03 16:41:13 +05:30
rc . Pass ++
printMutatedRes = true
2021-10-07 15:25:44 -07:00
} else if mutateResponseRule . Status == response . RuleStatusSkip {
2022-03-31 08:44:00 +02:00
fmt . Printf ( "\nskipped mutate policy %s -> resource %s" , policy . GetName ( ) , resPath )
2021-10-07 15:25:44 -07:00
rc . Skip ++
2021-10-14 01:40:33 +05:30
} else if mutateResponseRule . Status == response . RuleStatusError {
2022-03-31 08:44:00 +02:00
fmt . Printf ( "\nerror while applying mutate policy %s -> resource %s\nerror: %s" , policy . GetName ( ) , resPath , mutateResponseRule . Message )
2021-10-14 01:40:33 +05:30
rc . Error ++
2021-09-03 16:41:13 +05:30
} else {
if printCount < 1 {
2022-03-31 08:44:00 +02:00
fmt . Printf ( "\nfailed to apply mutate policy %s -> resource %s" , policy . GetName ( ) , resPath )
2021-09-03 16:41:13 +05:30
printCount ++
2021-09-03 12:32:12 +05:30
}
2021-09-03 16:41:13 +05:30
fmt . Printf ( "%d. %s - %s \n" , i + 1 , mutateResponseRule . Name , mutateResponseRule . Message )
rc . Fail ++
2021-09-03 12:32:12 +05:30
}
2021-09-03 16:41:13 +05:30
continue
2021-09-03 12:32:12 +05:30
}
}
2021-09-03 16:41:13 +05:30
if ! ruleFoundInEngineResponse {
rc . Skip ++
}
}
2021-09-03 12:32:12 +05:30
2021-10-01 17:52:23 +05:30
if printMutatedRes && printPatchResource {
2021-09-03 16:41:13 +05:30
yamlEncodedResource , err := yamlv2 . Marshal ( mutateResponse . PatchedResource . Object )
if err != nil {
return sanitizederror . NewWithError ( "failed to marshal" , err )
}
2021-09-03 12:32:12 +05:30
2021-09-03 16:41:13 +05:30
if mutateLogPath == "" {
mutatedResource := string ( yamlEncodedResource ) + string ( "\n---" )
if len ( strings . TrimSpace ( mutatedResource ) ) > 0 {
2021-10-01 17:52:23 +05:30
if ! stdin {
2022-03-31 08:44:00 +02:00
fmt . Printf ( "\nmutate policy %s applied to %s:" , policy . GetName ( ) , resPath )
2021-09-03 12:32:12 +05:30
}
2021-10-01 17:52:23 +05:30
fmt . Printf ( "\n" + mutatedResource + "\n" )
2021-09-03 12:32:12 +05:30
}
2021-09-03 16:41:13 +05:30
} else {
err := PrintMutatedOutput ( mutateLogPath , mutateLogPathIsDir , string ( yamlEncodedResource ) , resourceName + "-mutated" )
if err != nil {
return sanitizederror . NewWithError ( "failed to print mutated result" , err )
}
fmt . Printf ( "\n\nMutation:\nMutation has been applied successfully. Check the files." )
}
}
return nil
}
2022-03-31 08:44:00 +02:00
func PrintMutatedPolicy ( mutatedPolicies [ ] v1 . PolicyInterface ) error {
2021-09-03 16:41:13 +05:30
for _ , policy := range mutatedPolicies {
p , err := json . Marshal ( policy )
if err != nil {
return sanitizederror . NewWithError ( "failed to marsal mutated policy" , err )
2021-09-03 12:32:12 +05:30
}
2021-09-03 16:41:13 +05:30
log . Log . V ( 5 ) . Info ( "mutated Policy:" , string ( p ) )
2021-09-03 12:32:12 +05:30
}
return nil
}
2021-09-03 16:41:13 +05:30
2022-05-07 21:30:11 +01:00
func CheckVariableForPolicy ( valuesMap map [ string ] map [ string ] Resource , globalValMap map [ string ] string , policyName string , resourceName string , resourceKind string , variables map [ string ] string , kindOnwhichPolicyIsApplied map [ string ] struct { } , variable string ) ( map [ string ] interface { } , error ) {
2021-09-03 16:41:13 +05:30
// get values from file for this policy resource combination
2022-05-07 21:30:11 +01:00
thisPolicyResourceValues := make ( map [ string ] interface { } )
2021-09-03 16:41:13 +05:30
if len ( valuesMap [ policyName ] ) != 0 && ! reflect . DeepEqual ( valuesMap [ policyName ] [ resourceName ] , Resource { } ) {
thisPolicyResourceValues = valuesMap [ policyName ] [ resourceName ] . Values
}
2021-09-20 22:16:57 +05:30
2021-09-03 16:41:13 +05:30
for k , v := range variables {
thisPolicyResourceValues [ k ] = v
}
2021-09-20 22:16:57 +05:30
if thisPolicyResourceValues == nil && len ( globalValMap ) > 0 {
2022-05-07 21:30:11 +01:00
thisPolicyResourceValues = make ( map [ string ] interface { } )
2021-09-20 22:16:57 +05:30
}
for k , v := range globalValMap {
if _ , ok := thisPolicyResourceValues [ k ] ; ! ok {
thisPolicyResourceValues [ k ] = v
}
}
2021-09-03 16:41:13 +05:30
// skipping the variable check for non matching kind
if _ , ok := kindOnwhichPolicyIsApplied [ resourceKind ] ; ok {
if len ( variable ) > 0 && len ( thisPolicyResourceValues ) == 0 && len ( store . GetContext ( ) . Policies ) == 0 {
return thisPolicyResourceValues , sanitizederror . NewWithError ( fmt . Sprintf ( "policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag" , policyName , resourceName ) , nil )
}
}
return thisPolicyResourceValues , nil
}
2022-03-31 08:44:00 +02:00
func GetKindsFromPolicy ( policy v1 . PolicyInterface ) map [ string ] struct { } {
2021-09-03 16:41:13 +05:30
var kindOnwhichPolicyIsApplied = make ( map [ string ] struct { } )
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2021-09-03 16:41:13 +05:30
for _ , kind := range rule . MatchResources . ResourceDescription . Kinds {
kindOnwhichPolicyIsApplied [ kind ] = struct { } { }
}
for _ , kind := range rule . ExcludeResources . ResourceDescription . Kinds {
kindOnwhichPolicyIsApplied [ kind ] = struct { } { }
}
}
return kindOnwhichPolicyIsApplied
}
2021-10-01 14:16:33 +05:30
//GetPatchedResourceFromPath - get patchedResource from given path
func GetPatchedResourceFromPath ( fs billy . Filesystem , path string , isGit bool , policyResourcePath string ) ( unstructured . Unstructured , error ) {
var patchedResourceBytes [ ] byte
var patchedResource unstructured . Unstructured
var err error
2021-10-01 17:52:23 +05:30
2021-10-01 14:16:33 +05:30
if isGit {
if len ( path ) > 0 {
2022-05-09 18:55:35 +02:00
filep , fileErr := fs . Open ( filepath . Join ( policyResourcePath , path ) )
if fileErr != nil {
fmt . Printf ( "Unable to open patchedResource file: %s. \nerror: %s" , path , fileErr )
2021-10-01 14:16:33 +05:30
}
patchedResourceBytes , err = ioutil . ReadAll ( filep )
}
} else {
patchedResourceBytes , err = getFileBytes ( path )
}
2021-10-01 17:52:23 +05:30
2021-10-01 14:16:33 +05:30
if err != nil {
fmt . Printf ( "\n----------------------------------------------------------------------\nfailed to load patchedResource: %s. \nerror: %s\n----------------------------------------------------------------------\n" , path , err )
return patchedResource , err
}
2021-10-01 17:52:23 +05:30
2021-10-01 14:16:33 +05:30
patchedResource , err = GetPatchedResource ( patchedResourceBytes )
if err != nil {
return patchedResource , err
}
2021-10-01 17:52:23 +05:30
2021-10-01 14:16:33 +05:30
return patchedResource , nil
}
2022-04-12 09:30:49 +05:30
//GetUserInfoFromPath - get the request info as user info from a given path
2022-04-25 20:20:40 +08:00
func GetUserInfoFromPath ( fs billy . Filesystem , path string , isGit bool , policyResourcePath string ) ( v1beta1 . RequestInfo , error ) {
userInfo := & v1beta1 . RequestInfo { }
2022-04-12 09:30:49 +05:30
if isGit {
filep , err := fs . Open ( filepath . Join ( policyResourcePath , path ) )
if err != nil {
fmt . Printf ( "Unable to open userInfo file: %s. \nerror: %s" , path , err )
}
bytes , err := ioutil . ReadAll ( filep )
if err != nil {
fmt . Printf ( "Error: failed to read file %s: %v" , filep . Name ( ) , err . Error ( ) )
}
userInfoBytes , err := yaml . ToJSON ( bytes )
if err != nil {
fmt . Printf ( "failed to convert to JSON: %v" , err )
}
if err := json . Unmarshal ( userInfoBytes , userInfo ) ; err != nil {
fmt . Printf ( "failed to decode yaml: %v" , err )
}
} else {
var errors [ ] error
bytes , err := ioutil . ReadFile ( filepath . Join ( policyResourcePath , path ) )
if err != nil {
errors = append ( errors , sanitizederror . NewWithError ( "unable to read yaml" , err ) )
}
userInfoBytes , err := yaml . ToJSON ( bytes )
if err != nil {
errors = append ( errors , sanitizederror . NewWithError ( "failed to convert json" , err ) )
}
if err := json . Unmarshal ( userInfoBytes , userInfo ) ; err != nil {
errors = append ( errors , sanitizederror . NewWithError ( "failed to decode yaml" , err ) )
}
if len ( errors ) > 0 {
return * userInfo , sanitizederror . NewWithErrors ( "failed to read file" , errors )
}
if len ( errors ) > 0 && log . Log . V ( 1 ) . Enabled ( ) {
fmt . Printf ( "ignoring errors: \n" )
for _ , e := range errors {
fmt . Printf ( " %v \n" , e . Error ( ) )
}
}
}
return * userInfo , nil
}