github.com/argoproj/argo-cd@v1.8.7/cmd/argocd-util/commands/project_allowlist.go (about)

     1  package commands
     2  
     3  import (
     4  	"bufio"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/ghodss/yaml"
    11  	"github.com/spf13/cobra"
    12  	rbacv1 "k8s.io/api/rbac/v1"
    13  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    14  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    15  	"k8s.io/apimachinery/pkg/runtime/schema"
    16  	"k8s.io/client-go/discovery"
    17  	"k8s.io/client-go/kubernetes/scheme"
    18  	"k8s.io/client-go/tools/clientcmd"
    19  
    20  	"github.com/argoproj/argo-cd/util/errors"
    21  
    22  	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
    23  	"github.com/argoproj/argo-cd/util/cli"
    24  
    25  	// load the gcp plugin (required to authenticate against GKE clusters).
    26  	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
    27  	// load the oidc plugin (required to authenticate with OpenID Connect).
    28  	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
    29  	// load the azure plugin (required to authenticate with AKS clusters).
    30  	_ "k8s.io/client-go/plugin/pkg/client/auth/azure"
    31  )
    32  
    33  // NewProjectAllowListGenCommand generates a project from clusterRole
    34  func NewProjectAllowListGenCommand() *cobra.Command {
    35  	var (
    36  		clientConfig clientcmd.ClientConfig
    37  		out          string
    38  	)
    39  	var command = &cobra.Command{
    40  		Use:   "generate-allow-list CLUSTERROLE_PATH PROJ_NAME",
    41  		Short: "Generates project allow list from the specified clusterRole file",
    42  		Run: func(c *cobra.Command, args []string) {
    43  			if len(args) != 2 {
    44  				c.HelpFunc()(c, args)
    45  				os.Exit(1)
    46  			}
    47  			clusterRoleFileName := args[0]
    48  			projName := args[1]
    49  
    50  			var writer io.Writer
    51  			if out == "-" {
    52  				writer = os.Stdout
    53  			} else {
    54  				f, err := os.Create(out)
    55  				errors.CheckError(err)
    56  				bw := bufio.NewWriter(f)
    57  				writer = bw
    58  				defer func() {
    59  					err = bw.Flush()
    60  					errors.CheckError(err)
    61  					err = f.Close()
    62  					errors.CheckError(err)
    63  				}()
    64  			}
    65  
    66  			globalProj := generateProjectAllowList(clientConfig, clusterRoleFileName, projName)
    67  
    68  			yamlBytes, err := yaml.Marshal(globalProj)
    69  			errors.CheckError(err)
    70  
    71  			_, err = writer.Write(yamlBytes)
    72  			errors.CheckError(err)
    73  		},
    74  	}
    75  	clientConfig = cli.AddKubectlFlagsToCmd(command)
    76  	command.Flags().StringVarP(&out, "out", "o", "-", "Output to the specified file instead of stdout")
    77  
    78  	return command
    79  }
    80  
    81  func generateProjectAllowList(clientConfig clientcmd.ClientConfig, clusterRoleFileName string, projName string) v1alpha1.AppProject {
    82  	yamlBytes, err := ioutil.ReadFile(clusterRoleFileName)
    83  	errors.CheckError(err)
    84  	var obj unstructured.Unstructured
    85  	err = yaml.Unmarshal(yamlBytes, &obj)
    86  	errors.CheckError(err)
    87  
    88  	clusterRole := &rbacv1.ClusterRole{}
    89  	err = scheme.Scheme.Convert(&obj, clusterRole, nil)
    90  	errors.CheckError(err)
    91  
    92  	config, err := clientConfig.ClientConfig()
    93  	errors.CheckError(err)
    94  	disco, err := discovery.NewDiscoveryClientForConfig(config)
    95  	errors.CheckError(err)
    96  	serverResources, err := disco.ServerPreferredResources()
    97  	errors.CheckError(err)
    98  
    99  	resourceList := make([]metav1.GroupKind, 0)
   100  	for _, rule := range clusterRole.Rules {
   101  		if len(rule.APIGroups) <= 0 {
   102  			continue
   103  		}
   104  
   105  		canCreate := false
   106  		for _, verb := range rule.Verbs {
   107  			if strings.EqualFold(verb, "Create") {
   108  				canCreate = true
   109  				break
   110  			}
   111  		}
   112  
   113  		if !canCreate {
   114  			continue
   115  		}
   116  
   117  		ruleApiGroup := rule.APIGroups[0]
   118  		for _, ruleResource := range rule.Resources {
   119  			for _, apiResourcesList := range serverResources {
   120  				gv, err := schema.ParseGroupVersion(apiResourcesList.GroupVersion)
   121  				if err != nil {
   122  					gv = schema.GroupVersion{}
   123  				}
   124  				if ruleApiGroup == gv.Group {
   125  					for _, apiResource := range apiResourcesList.APIResources {
   126  						if apiResource.Name == ruleResource {
   127  							resourceList = append(resourceList, metav1.GroupKind{Group: ruleApiGroup, Kind: apiResource.Kind})
   128  						}
   129  					}
   130  				}
   131  			}
   132  		}
   133  	}
   134  	globalProj := v1alpha1.AppProject{
   135  		TypeMeta: metav1.TypeMeta{
   136  			Kind:       "AppProject",
   137  			APIVersion: "argoproj.io/v1alpha1",
   138  		},
   139  		ObjectMeta: metav1.ObjectMeta{Name: projName},
   140  		Spec:       v1alpha1.AppProjectSpec{},
   141  	}
   142  	globalProj.Spec.NamespaceResourceWhitelist = resourceList
   143  	return globalProj
   144  }