2020-10-15 17:29:07 -07:00
package common
import (
2022-05-11 14:04:40 +02:00
"context"
2020-11-03 02:01:20 +05:30
"fmt"
2022-09-30 15:25:19 +08:00
"io"
2021-02-18 01:00:41 +05:30
"path/filepath"
2021-02-08 23:38:06 +05:30
"strings"
2020-10-15 17:29:07 -07:00
2021-02-07 20:26:56 -08:00
"github.com/go-git/go-billy/v5"
2022-05-17 13:12:43 +02:00
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2023-09-17 22:50:17 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/apis/v1alpha1"
2023-09-06 02:06:44 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/log"
2023-09-05 01:25:06 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/resource"
2022-03-28 16:01:27 +02:00
"github.com/kyverno/kyverno/pkg/autogen"
2022-08-31 14:03:47 +08:00
"github.com/kyverno/kyverno/pkg/clients/dclient"
2022-12-09 22:15:23 +05:30
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2023-07-28 03:32:30 +03:00
"github.com/kyverno/kyverno/pkg/validatingadmissionpolicy"
2023-09-17 22:50:17 +02:00
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
2023-03-22 17:04:32 +01:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-10-15 17:29:07 -07:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2020-11-10 02:37:55 +05:30
"k8s.io/apimachinery/pkg/runtime/schema"
2020-10-15 17:29:07 -07:00
)
// GetResources gets matched resources by the given policies
// the resources are fetched from
// - local paths to resources, if given
// - the k8s cluster, if given
2022-12-09 22:15:23 +05:30
func GetResources (
2023-09-14 01:55:19 +02:00
out io . Writer ,
policies [ ] kyvernov1 . PolicyInterface ,
2023-09-17 22:50:17 +02:00
validatingAdmissionPolicies [ ] admissionregistrationv1alpha1 . ValidatingAdmissionPolicy ,
2023-09-14 01:55:19 +02:00
resourcePaths [ ] string ,
dClient dclient . Interface ,
cluster bool ,
namespace string ,
policyReport bool ,
2022-12-09 22:15:23 +05:30
) ( [ ] * unstructured . Unstructured , error ) {
2020-10-21 20:05:05 +05:30
resources := make ( [ ] * unstructured . Unstructured , 0 )
2020-10-15 17:29:07 -07:00
var err error
2020-10-30 16:38:19 +05:30
2022-12-09 22:15:23 +05:30
if cluster && dClient != nil {
2023-05-10 11:12:53 +03:00
if len ( policies ) > 0 {
matchedResources := & KyvernoResources {
policies : policies ,
2021-09-21 16:16:47 +05:30
}
2020-10-21 20:05:05 +05:30
2023-09-14 01:55:19 +02:00
resources , err = matchedResources . FetchResourcesFromPolicy ( out , resourcePaths , dClient , namespace , policyReport )
2023-05-10 11:12:53 +03:00
if err != nil {
return resources , err
}
2022-12-09 22:15:23 +05:30
}
2020-10-15 17:29:07 -07:00
2023-05-10 11:12:53 +03:00
if len ( validatingAdmissionPolicies ) > 0 {
matchedResources := & ValidatingAdmissionResources {
policies : validatingAdmissionPolicies ,
}
2023-09-14 01:55:19 +02:00
resources , err = matchedResources . FetchResourcesFromPolicy ( out , resourcePaths , dClient , namespace , policyReport )
2023-05-10 11:12:53 +03:00
if err != nil {
return resources , err
}
2021-06-16 07:56:08 +05:30
}
2021-06-16 08:17:31 +05:30
} else if len ( resourcePaths ) > 0 {
2023-09-14 01:55:19 +02:00
resources , err = whenClusterIsFalse ( out , resourcePaths , policyReport )
2021-06-16 08:17:31 +05:30
if err != nil {
return resources , err
}
}
return resources , err
}
2021-06-16 07:56:08 +05:30
2023-09-17 22:50:17 +02:00
func whenClusterIsTrue ( out io . Writer , resourceTypes [ ] schema . GroupVersionKind , subresourceMap map [ schema . GroupVersionKind ] v1alpha1 . Subresource , dClient dclient . Interface , namespace string , resourcePaths [ ] string , policyReport bool ) ( [ ] * unstructured . Unstructured , error ) {
2021-06-16 08:17:31 +05:30
resources := make ( [ ] * unstructured . Unstructured , 0 )
2023-09-14 01:55:19 +02:00
resourceMap , err := getResourcesOfTypeFromCluster ( out , resourceTypes , subresourceMap , dClient , namespace )
2021-06-16 08:17:31 +05:30
if err != nil {
return nil , err
}
if len ( resourcePaths ) == 0 {
for _ , rr := range resourceMap {
resources = append ( resources , rr )
2021-06-16 08:12:03 +05:30
}
2021-06-16 08:17:31 +05:30
} else {
2021-06-16 08:12:03 +05:30
for _ , resourcePath := range resourcePaths {
2021-06-16 08:17:31 +05:30
lenOfResource := len ( resources )
for rn , rr := range resourceMap {
s := strings . Split ( rn , "-" )
if s [ 2 ] == resourcePath {
resources = append ( resources , rr )
2020-11-20 12:27:02 +05:30
}
2020-11-11 15:27:55 +05:30
}
2021-06-16 08:17:31 +05:30
if lenOfResource >= len ( resources ) {
if policyReport {
2023-09-06 02:06:44 +02:00
log . Log . V ( 3 ) . Info ( fmt . Sprintf ( "%s not found in cluster" , resourcePath ) )
2021-06-16 08:17:31 +05:30
} else {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "\n----------------------------------------------------------------------\nresource %s not found in cluster\n----------------------------------------------------------------------\n" , resourcePath )
2021-06-16 08:17:31 +05:30
}
2021-06-16 09:19:58 +05:30
return nil , fmt . Errorf ( "%s not found in cluster" , resourcePath )
2021-06-16 08:12:03 +05:30
}
2020-10-15 17:29:07 -07:00
}
}
2021-06-16 08:17:31 +05:30
return resources , nil
2020-10-15 17:29:07 -07:00
}
2021-02-07 20:26:56 -08:00
2023-09-14 01:55:19 +02:00
func whenClusterIsFalse ( out io . Writer , resourcePaths [ ] string , policyReport bool ) ( [ ] * unstructured . Unstructured , error ) {
2021-06-16 08:17:31 +05:30
resources := make ( [ ] * unstructured . Unstructured , 0 )
for _ , resourcePath := range resourcePaths {
2023-09-05 01:25:06 +02:00
resourceBytes , err := resource . GetFileBytes ( resourcePath )
2021-06-16 08:17:31 +05:30
if err != nil {
if policyReport {
2023-09-06 02:06:44 +02:00
log . Log . V ( 3 ) . Info ( fmt . Sprintf ( "failed to load resources: %s." , resourcePath ) , "error" , err )
2021-06-16 08:17:31 +05:30
} else {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "\n----------------------------------------------------------------------\nfailed to load resources: %s. \nerror: %s\n----------------------------------------------------------------------\n" , resourcePath , err )
2021-06-16 08:17:31 +05:30
}
continue
}
2021-06-16 08:12:03 +05:30
2023-09-05 01:25:06 +02:00
getResources , err := resource . GetUnstructuredResources ( resourceBytes )
2021-06-16 08:17:31 +05:30
if err != nil {
return nil , err
}
2021-06-16 08:12:03 +05:30
2021-06-16 09:19:58 +05:30
resources = append ( resources , getResources ... )
2021-06-16 08:17:31 +05:30
}
return resources , nil
}
2021-06-16 08:12:03 +05:30
2021-02-01 16:22:41 +05:30
// GetResourcesWithTest with gets matched resources by the given policies
2023-09-14 01:55:19 +02:00
func GetResourcesWithTest ( out io . Writer , fs billy . Filesystem , policies [ ] kyvernov1 . PolicyInterface , resourcePaths [ ] string , policyResourcePath string ) ( [ ] * unstructured . Unstructured , error ) {
2021-02-01 16:22:41 +05:30
resources := make ( [ ] * unstructured . Unstructured , 0 )
2022-05-17 08:19:03 +02:00
resourceTypesMap := make ( map [ string ] bool )
2021-02-01 16:22:41 +05:30
for _ , policy := range policies {
2024-04-04 10:09:30 +02:00
for _ , rule := range autogen . ComputeRules ( policy , "" ) {
2021-02-01 16:22:41 +05:30
for _ , kind := range rule . MatchResources . Kinds {
resourceTypesMap [ kind ] = true
}
}
}
if len ( resourcePaths ) > 0 {
for _ , resourcePath := range resourcePaths {
var resourceBytes [ ] byte
var err error
2023-09-06 16:03:51 +02:00
if fs != nil {
2021-06-22 18:56:44 +05:30
filep , err := fs . Open ( filepath . Join ( policyResourcePath , resourcePath ) )
2021-02-01 16:22:41 +05:30
if err != nil {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "Unable to open resource file: %s. error: %s" , resourcePath , err )
2021-02-01 16:22:41 +05:30
continue
}
2022-09-30 15:25:19 +08:00
resourceBytes , _ = io . ReadAll ( filep )
2021-02-01 16:22:41 +05:30
} else {
2023-09-05 01:25:06 +02:00
resourceBytes , err = resource . GetFileBytes ( resourcePath )
2021-02-01 16:22:41 +05:30
}
if err != nil {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "\n----------------------------------------------------------------------\nfailed to load resources: %s. \nerror: %s\n----------------------------------------------------------------------\n" , resourcePath , err )
2021-02-01 16:22:41 +05:30
continue
}
2023-09-05 01:25:06 +02:00
getResources , err := resource . GetUnstructuredResources ( resourceBytes )
2021-02-01 16:22:41 +05:30
if err != nil {
return nil , err
}
2022-05-07 22:14:57 +05:30
resources = append ( resources , getResources ... )
2021-02-01 16:22:41 +05:30
}
}
return resources , nil
}
2020-10-15 17:29:07 -07:00
2023-09-17 22:50:17 +02:00
func getResourcesOfTypeFromCluster ( out io . Writer , resourceTypes [ ] schema . GroupVersionKind , subresourceMap map [ schema . GroupVersionKind ] v1alpha1 . Subresource , dClient dclient . Interface , namespace string ) ( map [ string ] * unstructured . Unstructured , error ) {
2021-06-15 23:35:22 +05:30
r := make ( map [ string ] * unstructured . Unstructured )
2020-10-15 17:29:07 -07:00
for _ , kind := range resourceTypes {
2022-12-09 22:15:23 +05:30
resourceList , err := dClient . ListResource ( context . TODO ( ) , kind . GroupVersion ( ) . String ( ) , kind . Kind , namespace , nil )
2020-10-15 17:29:07 -07:00
if err != nil {
2020-11-18 11:08:24 +05:30
continue
2020-10-15 17:29:07 -07:00
}
2022-12-09 22:15:23 +05:30
gvk := resourceList . GroupVersionKind ( )
2020-10-15 17:29:07 -07:00
for _ , resource := range resourceList . Items {
2022-12-09 22:15:23 +05:30
key := kind . Kind + "-" + resource . GetNamespace ( ) + "-" + resource . GetName ( )
resource . SetGroupVersionKind ( schema . GroupVersionKind {
Group : gvk . Group ,
Version : gvk . Version ,
Kind : kind . Kind ,
} )
2021-06-15 23:35:22 +05:30
r [ key ] = resource . DeepCopy ( )
2022-12-09 22:15:23 +05:30
}
}
for _ , subresource := range subresourceMap {
parentGV := schema . GroupVersion { Group : subresource . ParentResource . Group , Version : subresource . ParentResource . Version }
resourceList , err := dClient . ListResource ( context . TODO ( ) , parentGV . String ( ) , subresource . ParentResource . Kind , namespace , nil )
if err != nil {
continue
}
parentResourceNames := make ( [ ] string , 0 )
for _ , resource := range resourceList . Items {
parentResourceNames = append ( parentResourceNames , resource . GetName ( ) )
}
for _ , parentResourceName := range parentResourceNames {
2023-09-17 22:50:17 +02:00
subresourceName := strings . Split ( subresource . Subresource . Name , "/" ) [ 1 ]
2022-12-09 22:15:23 +05:30
resource , err := dClient . GetResource ( context . TODO ( ) , parentGV . String ( ) , subresource . ParentResource . Kind , namespace , parentResourceName , subresourceName )
if err != nil {
2023-09-14 01:55:19 +02:00
fmt . Fprintf ( out , "Error: %s" , err . Error ( ) )
2022-12-09 22:15:23 +05:30
continue
}
2023-09-17 22:50:17 +02:00
key := subresource . Subresource . Kind + "-" + resource . GetNamespace ( ) + "-" + resource . GetName ( )
2020-10-15 17:29:07 -07:00
resource . SetGroupVersionKind ( schema . GroupVersionKind {
2023-09-17 22:50:17 +02:00
Group : subresource . Subresource . Group ,
Version : subresource . Subresource . Version ,
Kind : subresource . Subresource . Kind ,
2020-10-15 17:29:07 -07:00
} )
2022-12-09 22:15:23 +05:30
r [ key ] = resource . DeepCopy ( )
2020-10-15 17:29:07 -07:00
}
}
2020-10-21 20:05:05 +05:30
return r , nil
2020-10-15 17:29:07 -07:00
}
2022-12-09 22:15:23 +05:30
// GetPatchedAndGeneratedResource converts raw bytes to unstructured object
2022-05-25 19:56:22 +05:30
func GetPatchedAndGeneratedResource ( resourceBytes [ ] byte ) ( unstructured . Unstructured , error ) {
2023-09-05 01:25:06 +02:00
getResource , err := resource . GetUnstructuredResources ( resourceBytes )
2022-05-09 18:55:35 +02:00
if err != nil {
return unstructured . Unstructured { } , err
}
2023-06-13 17:12:13 +08:00
if len ( getResource ) > 0 && getResource [ 0 ] != nil {
resource := * getResource [ 0 ]
return resource , nil
}
return unstructured . Unstructured { } , err
2021-10-01 14:16:33 +05:30
}
2022-03-16 00:50:33 -04:00
// GetKindsFromRule will return the kinds from policy match block
2023-09-17 22:50:17 +02:00
func GetKindsFromRule ( rule kyvernov1 . Rule , client dclient . Interface ) ( map [ schema . GroupVersionKind ] bool , map [ schema . GroupVersionKind ] v1alpha1 . Subresource ) {
2022-12-09 22:15:23 +05:30
resourceTypesMap := make ( map [ schema . GroupVersionKind ] bool )
2023-09-17 22:50:17 +02:00
subresourceMap := make ( map [ schema . GroupVersionKind ] v1alpha1 . Subresource )
2021-09-08 13:07:34 +05:30
for _ , kind := range rule . MatchResources . Kinds {
2022-12-09 22:15:23 +05:30
addGVKToResourceTypesMap ( kind , resourceTypesMap , subresourceMap , client )
2021-09-08 13:07:34 +05:30
}
if rule . MatchResources . Any != nil {
for _ , resFilter := range rule . MatchResources . Any {
for _ , kind := range resFilter . ResourceDescription . Kinds {
2022-12-09 22:15:23 +05:30
addGVKToResourceTypesMap ( kind , resourceTypesMap , subresourceMap , client )
2021-09-08 13:07:34 +05:30
}
}
}
if rule . MatchResources . All != nil {
for _ , resFilter := range rule . MatchResources . All {
for _ , kind := range resFilter . ResourceDescription . Kinds {
2022-12-09 22:15:23 +05:30
addGVKToResourceTypesMap ( kind , resourceTypesMap , subresourceMap , client )
2021-09-08 13:07:34 +05:30
}
}
}
2022-12-09 22:15:23 +05:30
return resourceTypesMap , subresourceMap
}
2023-09-17 22:50:17 +02:00
func getKindsFromValidatingAdmissionPolicy ( policy admissionregistrationv1alpha1 . ValidatingAdmissionPolicy , client dclient . Interface ) ( map [ schema . GroupVersionKind ] bool , map [ schema . GroupVersionKind ] v1alpha1 . Subresource ) {
2023-05-10 11:12:53 +03:00
resourceTypesMap := make ( map [ schema . GroupVersionKind ] bool )
2023-09-17 22:50:17 +02:00
subresourceMap := make ( map [ schema . GroupVersionKind ] v1alpha1 . Subresource )
2023-05-10 11:12:53 +03:00
2023-07-28 03:32:30 +03:00
kinds := validatingadmissionpolicy . GetKinds ( policy )
for _ , kind := range kinds {
addGVKToResourceTypesMap ( kind , resourceTypesMap , subresourceMap , client )
2023-05-10 11:12:53 +03:00
}
2023-07-28 03:32:30 +03:00
return resourceTypesMap , subresourceMap
2023-05-10 11:12:53 +03:00
}
2023-09-17 22:50:17 +02:00
func addGVKToResourceTypesMap ( kind string , resourceTypesMap map [ schema . GroupVersionKind ] bool , subresourceMap map [ schema . GroupVersionKind ] v1alpha1 . Subresource , client dclient . Interface ) {
2023-03-22 17:04:32 +01:00
group , version , kind , subresource := kubeutils . ParseKindSelector ( kind )
gvrss , err := client . Discovery ( ) . FindResources ( group , version , kind , subresource )
2022-12-09 22:15:23 +05:30
if err != nil {
2023-09-06 02:06:44 +02:00
log . Log . Info ( "failed to find resource" , "kind" , kind , "error" , err )
2022-12-09 22:15:23 +05:30
return
}
2023-03-22 17:04:32 +01:00
for parent , child := range gvrss {
// The resource is not a subresource
if parent . SubResource == "" {
resourceTypesMap [ parent . GroupVersionKind ( ) ] = true
} else {
gvk := schema . GroupVersionKind {
Group : child . Group , Version : child . Version , Kind : child . Kind ,
}
2023-09-17 22:50:17 +02:00
subresourceMap [ gvk ] = v1alpha1 . Subresource {
Subresource : child ,
2023-03-22 17:04:32 +01:00
ParentResource : metav1 . APIResource {
Group : parent . Group ,
Version : parent . Version ,
Kind : parent . Kind ,
Name : parent . Resource ,
} ,
}
2022-12-09 22:15:23 +05:30
}
}
2021-09-08 13:07:34 +05:30
}