2020-03-06 03:00:18 +05:30
package apply
import (
2022-09-30 10:12:21 +02:00
"context"
2020-03-06 03:00:18 +05:30
"fmt"
2023-09-14 01:55:19 +02:00
"io"
2022-12-02 20:03:04 +05:30
"net/url"
2020-06-08 17:01:56 +05:30
"os"
2020-07-21 00:41:30 +05:30
"path/filepath"
"strings"
2020-04-03 10:30:52 +05:30
"time"
2021-02-07 20:26:56 -08:00
"github.com/go-git/go-billy/v5/memfs"
2022-12-02 20:03:04 +05:30
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2022-04-25 20:20:40 +08:00
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
2024-02-01 03:58:14 +05:30
kyvernov2beta1 "github.com/kyverno/kyverno/api/kyverno/v2beta1"
2023-09-06 16:44:50 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
2023-12-20 13:45:26 +01:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/deprecations"
2024-02-01 03:58:14 +05:30
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/exception"
2023-09-06 02:06:44 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
2023-09-05 10:55:01 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/output/color"
2023-09-06 01:01:31 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/policy"
2023-09-06 06:48:55 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/processor"
2023-09-06 18:02:23 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/report"
2023-09-06 01:01:31 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/source"
2023-09-06 17:17:12 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/store"
2023-09-05 19:10:27 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/userinfo"
2022-04-14 17:50:18 +05:30
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
2023-09-06 16:03:51 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/variables"
2023-04-12 14:51:03 +02:00
"github.com/kyverno/kyverno/pkg/autogen"
2022-08-31 14:03:47 +08:00
"github.com/kyverno/kyverno/pkg/clients/dclient"
2022-09-20 19:05:18 +05:30
"github.com/kyverno/kyverno/pkg/config"
2023-04-12 14:51:03 +02:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2022-12-03 19:56:09 +01:00
gitutils "github.com/kyverno/kyverno/pkg/utils/git"
2023-04-28 21:54:17 +08:00
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
2020-03-06 03:00:18 +05:30
"github.com/spf13/cobra"
2023-05-10 11:12:53 +03:00
"k8s.io/api/admissionregistration/v1alpha1"
2020-10-15 17:29:07 -07:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2022-11-22 14:37:27 +01:00
"k8s.io/client-go/dynamic"
2022-07-25 07:49:51 +02:00
"k8s.io/client-go/kubernetes"
2023-07-04 18:28:22 +02:00
"sigs.k8s.io/yaml"
2020-03-06 03:00:18 +05:30
)
2023-07-04 18:28:22 +02:00
const divider = "----------------------------------------------------------------------"
2024-02-01 03:58:14 +05:30
type skippedInvalidPolicies struct {
2021-10-14 22:44:11 +05:30
skipped [ ] string
invalid [ ] string
}
2024-02-01 03:58:14 +05:30
type applyCommandConfig struct {
2023-07-03 12:04:07 +02:00
KubeConfig string
Context string
Namespace string
MutateLogPath string
Variables [ ] string
ValuesFile string
UserInfoPath string
Cluster bool
PolicyReport bool
Stdin bool
RegistryAccess bool
AuditWarn bool
ResourcePaths [ ] string
PolicyPaths [ ] string
GitBranch string
warnExitCode int
warnNoPassed bool
2024-02-01 03:58:14 +05:30
exception [ ] string
2022-09-20 19:05:18 +05:30
}
2020-12-07 11:26:04 -08:00
func Command ( ) * cobra . Command {
2023-07-31 17:15:47 +03:00
var removeColor , detailedResults , table bool
2024-02-01 03:58:14 +05:30
applyCommandConfig := & applyCommandConfig { }
2023-09-12 17:20:21 +02:00
cmd := & cobra . Command {
2023-09-12 19:03:37 +02:00
Use : "apply" ,
Short : command . FormatDescription ( true , websiteUrl , false , description ... ) ,
Long : command . FormatDescription ( false , websiteUrl , false , description ... ) ,
Example : command . FormatExamples ( examples ... ) ,
SilenceUsage : true ,
2023-09-13 11:53:19 +02:00
RunE : func ( cmd * cobra . Command , args [ ] string ) ( err error ) {
2023-09-14 01:55:19 +02:00
out := cmd . OutOrStdout ( )
2023-10-27 11:50:36 +02:00
color . Init ( removeColor )
2023-09-13 11:53:19 +02:00
applyCommandConfig . PolicyPaths = args
2023-09-14 01:55:19 +02:00
rc , _ , skipInvalidPolicies , responses , err := applyCommandConfig . applyCommandHelper ( out )
2020-10-30 16:38:19 +05:30
if err != nil {
return err
2020-08-11 22:59:50 +05:30
}
2023-09-14 01:55:19 +02:00
printSkippedAndInvalidPolicies ( out , skipInvalidPolicies )
2023-07-04 18:28:22 +02:00
if applyCommandConfig . PolicyReport {
2023-09-14 01:55:19 +02:00
printReport ( out , responses , applyCommandConfig . AuditWarn )
2023-07-06 13:48:19 +02:00
} else if table {
2023-09-14 13:45:18 +02:00
printTable ( out , detailedResults , applyCommandConfig . AuditWarn , responses ... )
2023-07-04 18:28:22 +02:00
} else {
2023-09-14 01:55:19 +02:00
printViolations ( out , rc )
2023-07-04 18:28:22 +02:00
}
2023-09-07 21:15:57 +05:30
return exit ( rc , applyCommandConfig . warnExitCode , applyCommandConfig . warnNoPassed )
2020-12-20 01:21:31 +05:30
} ,
}
2023-07-03 12:04:07 +02:00
cmd . Flags ( ) . StringSliceVarP ( & applyCommandConfig . ResourcePaths , "resource" , "r" , [ ] string { } , "Path to resource files" )
2022-09-20 19:05:18 +05:30
cmd . Flags ( ) . BoolVarP ( & applyCommandConfig . Cluster , "cluster" , "c" , false , "Checks if policies should be applied to cluster in the current context" )
cmd . Flags ( ) . StringVarP ( & applyCommandConfig . MutateLogPath , "output" , "o" , "" , "Prints the mutated resources in provided file/directory" )
2021-08-02 16:38:43 +05:30
// currently `set` flag supports variable for single policy applied on single resource
2022-09-20 19:05:18 +05:30
cmd . Flags ( ) . StringVarP ( & applyCommandConfig . UserInfoPath , "userinfo" , "u" , "" , "Admission Info including Roles, Cluster Roles and Subjects" )
2023-07-03 12:04:07 +02:00
cmd . Flags ( ) . StringSliceVarP ( & applyCommandConfig . Variables , "set" , "s" , nil , "Variables that are required" )
2022-09-20 19:05:18 +05:30
cmd . Flags ( ) . StringVarP ( & applyCommandConfig . ValuesFile , "values-file" , "f" , "" , "File containing values for policy variables" )
cmd . Flags ( ) . BoolVarP ( & applyCommandConfig . PolicyReport , "policy-report" , "p" , false , "Generates policy report when passed (default policyviolation)" )
cmd . Flags ( ) . StringVarP ( & applyCommandConfig . Namespace , "namespace" , "n" , "" , "Optional Policy parameter passed with cluster flag" )
cmd . Flags ( ) . BoolVarP ( & applyCommandConfig . Stdin , "stdin" , "i" , false , "Optional mutate policy parameter to pipe directly through to kubectl" )
2023-07-03 12:04:07 +02:00
cmd . Flags ( ) . BoolVar ( & applyCommandConfig . RegistryAccess , "registry" , false , "If set to true, access the image registry using local docker credentials to populate external data" )
cmd . Flags ( ) . StringVar ( & applyCommandConfig . KubeConfig , "kubeconfig" , "" , "path to kubeconfig file with authorization and master location information" )
cmd . Flags ( ) . StringVar ( & applyCommandConfig . Context , "context" , "" , "The name of the kubeconfig context to use" )
2022-12-02 20:03:04 +05:30
cmd . Flags ( ) . StringVarP ( & applyCommandConfig . GitBranch , "git-branch" , "b" , "" , "test git repository branch" )
2023-07-03 12:04:07 +02:00
cmd . Flags ( ) . BoolVar ( & applyCommandConfig . AuditWarn , "audit-warn" , false , "If set to true, will flag audit policies as warnings instead of failures" )
2022-12-05 13:15:22 -05:00
cmd . Flags ( ) . IntVar ( & applyCommandConfig . warnExitCode , "warn-exit-code" , 0 , "Set the exit code for warnings; if failures or errors are found, will exit 1" )
2023-07-03 12:04:07 +02:00
cmd . Flags ( ) . BoolVar ( & applyCommandConfig . warnNoPassed , "warn-no-pass" , false , "Specify if warning exit code should be raised if no objects satisfied a policy; can be used together with --warn-exit-code flag" )
2023-07-06 13:48:19 +02:00
cmd . Flags ( ) . BoolVar ( & removeColor , "remove-color" , false , "Remove any color from output" )
2023-07-31 17:15:47 +03:00
cmd . Flags ( ) . BoolVar ( & detailedResults , "detailed-results" , false , "If set to true, display detailed results" )
2023-07-06 13:48:19 +02:00
cmd . Flags ( ) . BoolVarP ( & table , "table" , "t" , false , "Show results in table format" )
2024-02-01 03:58:14 +05:30
cmd . Flags ( ) . StringSliceVar ( & applyCommandConfig . exception , "exception" , nil , "Policy exception to be considered when evaluating policies against resources" )
2020-12-20 01:21:31 +05:30
return cmd
}
2020-08-05 23:53:27 +05:30
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) applyCommandHelper ( out io . Writer ) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , skippedInvalidPolicies , [ ] engineapi . EngineResponse , error ) {
2023-09-11 12:49:02 +02:00
rc , resources1 , skipInvalidPolicies , responses1 , err := c . checkArguments ( )
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-07-04 12:54:22 +02:00
}
2023-09-11 12:49:02 +02:00
rc , resources1 , skipInvalidPolicies , responses1 , err , mutateLogPathIsDir := c . getMutateLogPathIsDir ( skipInvalidPolicies )
2023-07-04 18:28:22 +02:00
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-07-04 18:28:22 +02:00
}
2023-09-11 12:49:02 +02:00
rc , resources1 , skipInvalidPolicies , responses1 , err = c . cleanPreviousContent ( mutateLogPathIsDir , skipInvalidPolicies )
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-07-04 18:28:22 +02:00
}
2023-09-05 19:10:27 +02:00
var userInfo * v1beta1 . RequestInfo
2023-07-04 18:28:22 +02:00
if c . UserInfoPath != "" {
2023-09-18 12:51:35 +02:00
info , err := userinfo . Load ( nil , c . UserInfoPath , "" )
2023-07-04 18:28:22 +02:00
if err != nil {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "failed to load request info (%w)" , err )
2023-07-04 18:28:22 +02:00
}
2023-12-20 13:45:26 +01:00
deprecations . CheckUserInfo ( out , c . UserInfoPath , info )
2023-09-18 12:51:35 +02:00
userInfo = & info . RequestInfo
2022-10-19 22:09:15 +05:30
}
2023-12-20 13:45:26 +01:00
variables , err := variables . New ( out , nil , "" , c . ValuesFile , nil , c . Variables ... )
2020-12-20 01:21:31 +05:30
if err != nil {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "failed to decode yaml (%w)" , err )
2020-12-20 01:21:31 +05:30
}
2023-12-19 15:45:53 +01:00
var store store . Store
rc , resources1 , skipInvalidPolicies , responses1 , err , dClient := c . initStoreAndClusterClient ( & store , skipInvalidPolicies )
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-07-04 18:28:22 +02:00
}
2024-01-23 13:47:38 +02:00
rc , resources1 , skipInvalidPolicies , responses1 , policies , vaps , vapBindings , err := c . loadPolicies ( skipInvalidPolicies )
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-08-18 15:58:47 +05:30
}
2024-01-23 13:47:38 +02:00
resources , err := c . loadResources ( out , policies , vaps , dClient )
2023-09-07 21:15:57 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-09-07 21:15:57 +05:30
}
2024-02-01 03:58:14 +05:30
exceptions , err := exception . Load ( c . exception ... )
if err != nil {
return rc , resources1 , skipInvalidPolicies , responses1 , fmt . Errorf ( "Error: failed to load exceptions (%s)" , err )
}
2023-09-11 12:49:02 +02:00
if ! c . Stdin {
var policyRulesCount int
for _ , policy := range policies {
policyRulesCount += len ( autogen . ComputeRules ( policy ) )
}
2024-01-23 13:47:38 +02:00
policyRulesCount += len ( vaps )
2024-02-01 03:58:14 +05:30
if len ( exceptions ) > 0 {
fmt . Fprintf ( out , "\nApplying %d policy rule(s) to %d resource(s) with %d exception(s)...\n" , policyRulesCount , len ( resources ) , len ( exceptions ) )
} else {
fmt . Fprintf ( out , "\nApplying %d policy rule(s) to %d resource(s)...\n" , policyRulesCount , len ( resources ) )
}
2023-09-11 12:49:02 +02:00
}
2023-12-19 22:33:05 +01:00
2023-09-11 12:49:02 +02:00
rc , resources1 , responses1 , err = c . applyPolicytoResource (
2023-09-14 01:55:19 +02:00
out ,
2023-12-19 15:45:53 +01:00
& store ,
2023-09-11 12:49:02 +02:00
variables ,
policies ,
resources ,
2024-02-01 03:58:14 +05:30
exceptions ,
2023-09-11 12:49:02 +02:00
& skipInvalidPolicies ,
dClient ,
userInfo ,
mutateLogPathIsDir ,
)
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-08-18 15:58:47 +05:30
}
2024-01-23 13:47:38 +02:00
responses2 , err := c . applyValidatingAdmissionPolicytoResource ( vaps , vapBindings , resources1 , rc , dClient )
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-11 12:49:02 +02:00
return rc , resources1 , skipInvalidPolicies , responses1 , err
2023-08-18 15:58:47 +05:30
}
2023-09-11 12:49:02 +02:00
var responses [ ] engineapi . EngineResponse
responses = append ( responses , responses1 ... )
responses = append ( responses , responses2 ... )
return rc , resources1 , skipInvalidPolicies , responses , nil
2023-08-18 15:58:47 +05:30
}
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) getMutateLogPathIsDir ( skipInvalidPolicies skippedInvalidPolicies ) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , skippedInvalidPolicies , [ ] engineapi . EngineResponse , error , bool ) {
2023-08-18 15:58:47 +05:30
mutateLogPathIsDir , err := checkMutateLogPath ( c . MutateLogPath )
if err != nil {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "failed to create file/folder (%w)" , err ) , false
2023-08-18 15:58:47 +05:30
}
return nil , nil , skipInvalidPolicies , nil , err , mutateLogPathIsDir
}
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) applyValidatingAdmissionPolicytoResource (
2024-01-23 13:47:38 +02:00
vaps [ ] v1alpha1 . ValidatingAdmissionPolicy ,
vapBindings [ ] v1alpha1 . ValidatingAdmissionPolicyBinding ,
2023-09-06 16:03:51 +02:00
resources [ ] * unstructured . Unstructured ,
rc * processor . ResultCounts ,
dClient dclient . Interface ,
2023-09-11 12:49:02 +02:00
) ( [ ] engineapi . EngineResponse , error ) {
var responses [ ] engineapi . EngineResponse
2023-08-18 15:58:47 +05:30
for _ , resource := range resources {
2023-09-11 12:49:02 +02:00
processor := processor . ValidatingAdmissionPolicyProcessor {
2024-01-23 13:47:38 +02:00
Policies : vaps ,
Bindings : vapBindings ,
2023-09-11 12:49:02 +02:00
Resource : resource ,
PolicyReport : c . PolicyReport ,
Rc : rc ,
2024-01-23 13:47:38 +02:00
Client : dClient ,
2023-09-11 12:49:02 +02:00
}
ers , err := processor . ApplyPolicyOnResource ( )
if err != nil {
2023-09-12 18:07:06 +02:00
return responses , fmt . Errorf ( "failed to apply policies on resource %s (%w)" , resource . GetName ( ) , err )
2022-07-25 07:49:51 +02:00
}
2023-09-11 12:49:02 +02:00
responses = append ( responses , ers ... )
2023-08-18 15:58:47 +05:30
}
2023-09-11 12:49:02 +02:00
return responses , nil
2023-08-18 15:58:47 +05:30
}
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) applyPolicytoResource (
2023-09-14 01:55:19 +02:00
out io . Writer ,
2023-12-19 15:45:53 +01:00
store * store . Store ,
2023-09-06 16:03:51 +02:00
vars * variables . Variables ,
policies [ ] kyvernov1 . PolicyInterface ,
resources [ ] * unstructured . Unstructured ,
2024-02-01 03:58:14 +05:30
exceptions [ ] * kyvernov2beta1 . PolicyException ,
skipInvalidPolicies * skippedInvalidPolicies ,
2023-09-06 16:03:51 +02:00
dClient dclient . Interface ,
userInfo * v1beta1 . RequestInfo ,
mutateLogPathIsDir bool ,
2023-09-11 12:49:02 +02:00
) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , [ ] engineapi . EngineResponse , error ) {
2023-09-06 16:03:51 +02:00
if vars != nil {
2023-12-19 15:45:53 +01:00
vars . SetInStore ( store )
2023-08-18 15:58:47 +05:30
}
2024-01-29 05:16:09 +05:30
var rc processor . ResultCounts
2023-09-11 15:41:36 +02:00
// validate policies
var validPolicies [ ] kyvernov1 . PolicyInterface
for _ , pol := range policies {
// TODO we should return this info to the caller
2023-09-27 18:21:47 +02:00
_ , err := policyvalidation . Validate ( pol , nil , nil , true , config . KyvernoUserName ( config . KyvernoServiceAccountName ( ) ) )
2023-09-11 15:41:36 +02:00
if err != nil {
log . Log . Error ( err , "policy validation error" )
2024-01-29 05:16:09 +05:30
rc . IncrementError ( 1 )
2023-09-11 15:41:36 +02:00
if strings . HasPrefix ( err . Error ( ) , "variable 'element.name'" ) {
skipInvalidPolicies . invalid = append ( skipInvalidPolicies . invalid , pol . GetName ( ) )
} else {
skipInvalidPolicies . skipped = append ( skipInvalidPolicies . skipped , pol . GetName ( ) )
2023-08-18 15:58:47 +05:30
}
2023-09-11 15:41:36 +02:00
continue
}
validPolicies = append ( validPolicies , pol )
}
2023-12-19 22:33:05 +01:00
2023-09-11 15:41:36 +02:00
var responses [ ] engineapi . EngineResponse
for _ , resource := range resources {
processor := processor . PolicyProcessor {
2023-12-19 15:45:53 +01:00
Store : store ,
2023-09-11 15:41:36 +02:00
Policies : validPolicies ,
Resource : * resource ,
2024-02-01 03:58:14 +05:30
PolicyExceptions : exceptions ,
2023-09-11 15:41:36 +02:00
MutateLogPath : c . MutateLogPath ,
MutateLogPathIsDir : mutateLogPathIsDir ,
Variables : vars ,
UserInfo : userInfo ,
PolicyReport : c . PolicyReport ,
NamespaceSelectorMap : vars . NamespaceSelectors ( ) ,
Stdin : c . Stdin ,
Rc : & rc ,
PrintPatchResource : true ,
Client : dClient ,
AuditWarn : c . AuditWarn ,
Subresources : vars . Subresources ( ) ,
2023-09-14 01:55:19 +02:00
Out : out ,
2023-09-11 15:41:36 +02:00
}
ers , err := processor . ApplyPoliciesOnResource ( )
if err != nil {
2023-09-12 18:07:06 +02:00
return & rc , resources , responses , fmt . Errorf ( "failed to apply policies on resource %v (%w)" , resource . GetName ( ) , err )
2023-09-11 15:41:36 +02:00
}
2023-09-12 17:20:21 +02:00
responses = append ( responses , ers ... )
2020-12-20 01:21:31 +05:30
}
2023-09-11 12:49:02 +02:00
return & rc , resources , responses , nil
2023-08-18 15:58:47 +05:30
}
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) loadResources ( out io . Writer , policies [ ] kyvernov1 . PolicyInterface , vap [ ] v1alpha1 . ValidatingAdmissionPolicy , dClient dclient . Interface ) ( [ ] * unstructured . Unstructured , error ) {
2024-01-23 13:47:38 +02:00
resources , err := common . GetResourceAccordingToResourcePath ( out , nil , c . ResourcePaths , c . Cluster , policies , vap , dClient , c . Namespace , c . PolicyReport , "" )
2023-08-18 15:58:47 +05:30
if err != nil {
2023-09-12 18:07:06 +02:00
return resources , fmt . Errorf ( "failed to load resources (%w)" , err )
2023-08-18 15:58:47 +05:30
}
2023-09-07 21:15:57 +05:30
return resources , nil
2023-08-18 15:58:47 +05:30
}
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) loadPolicies ( skipInvalidPolicies skippedInvalidPolicies ) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , skippedInvalidPolicies , [ ] engineapi . EngineResponse , [ ] kyvernov1 . PolicyInterface , [ ] v1alpha1 . ValidatingAdmissionPolicy , [ ] v1alpha1 . ValidatingAdmissionPolicyBinding , error ) {
2023-07-04 18:28:22 +02:00
// load policies
2022-12-02 20:03:04 +05:30
var policies [ ] kyvernov1 . PolicyInterface
2024-01-23 13:47:38 +02:00
var vaps [ ] v1alpha1 . ValidatingAdmissionPolicy
var vapBindings [ ] v1alpha1 . ValidatingAdmissionPolicyBinding
2022-12-02 20:03:04 +05:30
2023-09-06 01:01:31 +02:00
for _ , path := range c . PolicyPaths {
isGit := source . IsGit ( path )
2023-08-16 21:33:42 +05:30
if isGit {
2023-09-06 01:01:31 +02:00
gitSourceURL , err := url . Parse ( path )
2023-08-16 21:33:42 +05:30
if err != nil {
2024-01-23 13:47:38 +02:00
return nil , nil , skipInvalidPolicies , nil , nil , nil , nil , fmt . Errorf ( "failed to load policies (%w)" , err )
2023-08-16 21:33:42 +05:30
}
pathElems := strings . Split ( gitSourceURL . Path [ 1 : ] , "/" )
if len ( pathElems ) <= 1 {
err := fmt . Errorf ( "invalid URL path %s - expected https://<any_git_source_domain>/:owner/:repository/:branch (without --git-branch flag) OR https://<any_git_source_domain>/:owner/:repository/:directory (with --git-branch flag)" , gitSourceURL . Path )
2024-01-23 13:47:38 +02:00
return nil , nil , skipInvalidPolicies , nil , nil , nil , nil , fmt . Errorf ( "failed to parse URL (%w)" , err )
2023-08-16 21:33:42 +05:30
}
gitSourceURL . Path = strings . Join ( [ ] string { pathElems [ 0 ] , pathElems [ 1 ] } , "/" )
repoURL := gitSourceURL . String ( )
var gitPathToYamls string
2023-09-06 01:01:31 +02:00
c . GitBranch , gitPathToYamls = common . GetGitBranchOrPolicyPaths ( c . GitBranch , repoURL , path )
fs := memfs . New ( )
if _ , err := gitutils . Clone ( repoURL , fs , c . GitBranch ) ; err != nil {
log . Log . V ( 3 ) . Info ( fmt . Sprintf ( "failed to clone repository %v as it is not valid" , repoURL ) , "error" , err )
2024-01-23 13:47:38 +02:00
return nil , nil , skipInvalidPolicies , nil , nil , nil , nil , fmt . Errorf ( "failed to clone repository (%w)" , err )
2023-08-16 21:33:42 +05:30
}
policyYamls , err := gitutils . ListYamls ( fs , gitPathToYamls )
if err != nil {
2024-01-23 13:47:38 +02:00
return nil , nil , skipInvalidPolicies , nil , nil , nil , nil , fmt . Errorf ( "failed to list YAMLs in repository (%w)" , err )
2023-08-16 21:33:42 +05:30
}
2023-09-06 01:01:31 +02:00
for _ , policyYaml := range policyYamls {
2024-01-23 13:47:38 +02:00
policiesFromFile , vapsFromFile , vapBindingsFromFile , err := policy . Load ( fs , "" , policyYaml )
2023-09-06 01:01:31 +02:00
if err != nil {
continue
}
policies = append ( policies , policiesFromFile ... )
2024-01-23 13:47:38 +02:00
vaps = append ( vaps , vapsFromFile ... )
vapBindings = append ( vapBindings , vapBindingsFromFile ... )
2023-09-06 01:01:31 +02:00
}
} else {
2024-01-23 13:47:38 +02:00
policiesFromFile , vapsFromFile , vapBindingsFromFile , err := policy . Load ( nil , "" , path )
2023-09-06 01:01:31 +02:00
if err != nil {
2024-01-23 13:47:38 +02:00
return nil , nil , skipInvalidPolicies , nil , nil , nil , nil , fmt . Errorf ( "failed to load policies (%w)" , err )
2023-09-06 01:01:31 +02:00
}
policies = append ( policies , policiesFromFile ... )
2024-01-23 13:47:38 +02:00
vaps = append ( vaps , vapsFromFile ... )
vapBindings = append ( vapBindings , vapBindingsFromFile ... )
2022-12-02 20:03:04 +05:30
}
2020-12-20 01:21:31 +05:30
}
2023-08-16 21:33:42 +05:30
2024-01-23 13:47:38 +02:00
return nil , nil , skipInvalidPolicies , nil , policies , vaps , vapBindings , nil
2023-08-18 15:58:47 +05:30
}
2021-08-02 16:38:43 +05:30
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) initStoreAndClusterClient ( store * store . Store , skipInvalidPolicies skippedInvalidPolicies ) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , skippedInvalidPolicies , [ ] engineapi . EngineResponse , error , dclient . Interface ) {
2023-08-18 15:58:47 +05:30
store . SetLocal ( true )
store . SetRegistryAccess ( c . RegistryAccess )
if c . Cluster {
store . AllowApiCall ( true )
2020-12-20 01:21:31 +05:30
}
2023-08-18 15:58:47 +05:30
var err error
var dClient dclient . Interface
if c . Cluster {
restConfig , err := config . CreateClientConfigWithContext ( c . KubeConfig , c . Context )
2020-12-20 01:21:31 +05:30
if err != nil {
2023-08-18 15:58:47 +05:30
return nil , nil , skipInvalidPolicies , nil , err , nil
2020-12-20 01:21:31 +05:30
}
2023-08-18 15:58:47 +05:30
kubeClient , err := kubernetes . NewForConfig ( restConfig )
if err != nil {
return nil , nil , skipInvalidPolicies , nil , err , nil
2020-12-20 01:21:31 +05:30
}
2023-08-18 15:58:47 +05:30
dynamicClient , err := dynamic . NewForConfig ( restConfig )
if err != nil {
return nil , nil , skipInvalidPolicies , nil , err , nil
}
dClient , err = dclient . NewClient ( context . Background ( ) , dynamicClient , kubeClient , 15 * time . Minute )
if err != nil {
return nil , nil , skipInvalidPolicies , nil , err , nil
2020-12-20 01:21:31 +05:30
}
2020-03-06 03:00:18 +05:30
}
2023-08-18 15:58:47 +05:30
return nil , nil , skipInvalidPolicies , nil , err , dClient
}
2020-03-06 03:00:18 +05:30
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) cleanPreviousContent ( mutateLogPathIsDir bool , skipInvalidPolicies skippedInvalidPolicies ) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , skippedInvalidPolicies , [ ] engineapi . EngineResponse , error ) {
2023-08-18 15:58:47 +05:30
// empty the previous contents of the file just in case if the file already existed before with some content(so as to perform overwrites)
// the truncation of files for the case when mutateLogPath is dir, is handled under pkg/kyverno/apply/common.go
if ! mutateLogPathIsDir && c . MutateLogPath != "" {
c . MutateLogPath = filepath . Clean ( c . MutateLogPath )
// Necessary for us to include the file via variable as it is part of the CLI.
_ , err := os . OpenFile ( c . MutateLogPath , os . O_TRUNC | os . O_WRONLY , 0 o600 ) // #nosec G304
if err != nil {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "failed to truncate the existing file at %s (%w)" , c . MutateLogPath , err )
2023-05-10 11:12:53 +03:00
}
}
2023-08-18 15:58:47 +05:30
return nil , nil , skipInvalidPolicies , nil , nil
}
2023-05-10 11:12:53 +03:00
2024-02-01 03:58:14 +05:30
func ( c * applyCommandConfig ) checkArguments ( ) ( * processor . ResultCounts , [ ] * unstructured . Unstructured , skippedInvalidPolicies , [ ] engineapi . EngineResponse , error ) {
var skipInvalidPolicies skippedInvalidPolicies
2023-08-18 15:58:47 +05:30
if c . ValuesFile != "" && c . Variables != nil {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "pass the values either using set flag or values_file flag" )
2023-08-18 15:58:47 +05:30
}
if len ( c . PolicyPaths ) == 0 {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "require policy" )
2023-08-18 15:58:47 +05:30
}
if ( len ( c . PolicyPaths ) > 0 && c . PolicyPaths [ 0 ] == "-" ) && len ( c . ResourcePaths ) > 0 && c . ResourcePaths [ 0 ] == "-" {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "a stdin pipe can be used for either policies or resources, not both" )
2023-08-18 15:58:47 +05:30
}
if len ( c . ResourcePaths ) == 0 && ! c . Cluster {
2023-09-12 18:07:06 +02:00
return nil , nil , skipInvalidPolicies , nil , fmt . Errorf ( "resource file(s) or cluster required" )
2023-08-18 15:58:47 +05:30
}
return nil , nil , skipInvalidPolicies , nil , nil
2020-03-06 03:00:18 +05:30
}
2024-02-01 03:58:14 +05:30
func printSkippedAndInvalidPolicies ( out io . Writer , skipInvalidPolicies skippedInvalidPolicies ) {
2021-10-14 22:44:11 +05:30
if len ( skipInvalidPolicies . skipped ) > 0 {
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , divider )
fmt . Fprintln ( out , "Policies Skipped (as required variables are not provided by the user):" )
2021-10-14 22:44:11 +05:30
for i , policyName := range skipInvalidPolicies . skipped {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "%d. %s\n" , i + 1 , policyName )
2021-10-14 22:44:11 +05:30
}
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , divider )
2021-10-14 22:44:11 +05:30
}
if len ( skipInvalidPolicies . invalid ) > 0 {
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , divider )
fmt . Fprintln ( out , "Invalid Policies:" )
2021-10-14 22:44:11 +05:30
for i , policyName := range skipInvalidPolicies . invalid {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "%d. %s\n" , i + 1 , policyName )
2021-08-31 16:24:31 +05:30
}
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , divider )
2021-08-31 16:24:31 +05:30
}
2023-07-04 18:28:22 +02:00
}
2021-08-31 16:24:31 +05:30
2023-09-14 01:55:19 +02:00
func printReport ( out io . Writer , engineResponses [ ] engineapi . EngineResponse , auditWarn bool ) {
2023-09-12 16:33:26 +02:00
clustered , namespaced := report . ComputePolicyReports ( auditWarn , engineResponses ... )
2023-07-04 18:28:22 +02:00
if len ( clustered ) > 0 || len ( namespaced ) > 0 {
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , divider )
fmt . Fprintln ( out , "POLICY REPORT:" )
fmt . Fprintln ( out , divider )
2023-09-11 17:24:10 +02:00
report := report . MergeClusterReports ( clustered )
2023-07-04 18:28:22 +02:00
yamlReport , _ := yaml . Marshal ( report )
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , string ( yamlReport ) )
2020-10-30 16:38:19 +05:30
} else {
2023-09-14 01:55:19 +02:00
fmt . Fprintln ( out , divider )
fmt . Fprintln ( out , "POLICY REPORT: skip generating policy report (no validate policy found/resource skipped)" )
2021-09-03 17:17:22 +05:30
}
2023-07-04 18:28:22 +02:00
}
2020-10-30 16:38:19 +05:30
2023-09-14 01:55:19 +02:00
func printViolations ( out io . Writer , rc * processor . ResultCounts ) {
fmt . Fprintf ( out , "\npass: %d, fail: %d, warn: %d, error: %d, skip: %d \n" , rc . Pass ( ) , rc . Fail ( ) , rc . Warn ( ) , rc . Error ( ) , rc . Skip ( ) )
2023-07-04 18:28:22 +02:00
}
2023-09-07 21:15:57 +05:30
func exit ( rc * processor . ResultCounts , warnExitCode int , warnNoPassed bool ) error {
2023-09-06 06:48:55 +02:00
if rc . Fail ( ) > 0 || rc . Error ( ) > 0 {
2023-09-07 21:15:57 +05:30
return fmt . Errorf ( "exit as fail or error count > 0" )
2023-09-06 06:48:55 +02:00
} else if rc . Warn ( ) > 0 && warnExitCode != 0 {
2023-09-07 21:15:57 +05:30
return fmt . Errorf ( "exit as warnExitCode is %d" , warnExitCode )
2023-09-06 06:48:55 +02:00
} else if rc . Pass ( ) == 0 && warnNoPassed {
2023-09-07 21:15:57 +05:30
return fmt . Errorf ( "exit as warnExitCode is %d" , warnExitCode )
2020-10-30 16:38:19 +05:30
}
2023-09-07 21:15:57 +05:30
return nil
2020-10-30 16:38:19 +05:30
}