diff --git a/cmd/generate_cmd.go b/cmd/generate_cmd.go index 2a06667..9b42bb1 100644 --- a/cmd/generate_cmd.go +++ b/cmd/generate_cmd.go @@ -27,6 +27,9 @@ func NewCommandGenerateClusterRole() *cobra.Command { //expandGroups := []string{} allowedVerb := []string{} denyResources := []string{} + namespace := "" + roleName := "" + var useSubresources bool // Support overrides cmd := &cobra.Command{ @@ -55,19 +58,38 @@ rbac-tool gen --generated-type=ClusterRole --deny-resources=secrets., --allowed- if err != nil { return fmt.Errorf("Failed to create kubernetes client - %v", err) } + var computedPolicyRules []rbacv1.PolicyRule - computedPolicyRules, err := generateRules(generateKind, kubeClient.ServerPreferredResources, sets.NewString(denyResources...), sets.NewString(allowedGroups...), sets.NewString(allowedVerb...)) - if err != nil { - return err + if useSubresources { + _, allResources, err := kubeClient.Client.Discovery().ServerGroupsAndResources() + if err != nil { + return fmt.Errorf("failed to read ServerGroupsAndResources - %v", err) + } + computedPolicyRules, err = generateRules(generateKind, allResources, sets.NewString(denyResources...), sets.NewString(allowedGroups...), sets.NewString(allowedVerb...)) + if err != nil { + return fmt.Errorf("failed to read ServerGroupsAndResources - %v", err) + } + } else { + computedPolicyRules, err = generateRules(generateKind, kubeClient.ServerPreferredResources, sets.NewString(denyResources...), sets.NewString(allowedGroups...), sets.NewString(allowedVerb...)) + if err != nil { + return fmt.Errorf("failed to read ServerGroupsAndResources - %v", err) + } } - obj, err := generateRole(generateKind, computedPolicyRules) - if err != nil { - return err + if generateKind == "Role" { + obj, err := generateRole(computedPolicyRules, namespace, roleName) + if err != nil { + return err + } + fmt.Fprintln(os.Stdout, obj) + } else { + obj, err := generateClusterRole(computedPolicyRules, roleName) + if err != nil { + return err + } + fmt.Fprintln(os.Stdout, obj) } - fmt.Fprintln(os.Stdout, obj) - return nil }, } @@ -80,36 +102,26 @@ rbac-tool gen --generated-type=ClusterRole --deny-resources=secrets., --allowed- flags.StringSliceVar(&allowedGroups, "allowed-groups", []string{"*"}, "Comma separated list of API groups we would like to allow '*'") flags.StringSliceVar(&allowedVerb, "allowed-verbs", []string{"*"}, "Comma separated list of verbs to include. To include all use '*'") flags.StringSliceVar(&denyResources, "deny-resources", []string{""}, "Comma separated list of resource.group - for example secret. to deny secret (core group) access") + flags.StringVarP(&namespace, "namespace", "n", "myNamespace", "Namespace to deploy Role to") + flags.StringVarP(&roleName, "roleName", "r", "myRole", "Name of Role or ClusterRole") + flags.BoolVarP(&useSubresources, "useSubresources", "s", false, "Include Kubernetes subresources in generated (Cluster)Roles") return cmd } -func generateRole(generateKind string, rules []rbacv1.PolicyRule) (string, error) { +func generateRole(rules []rbacv1.PolicyRule, namespace string, roleName string) (string, error) { var obj runtime.Object - if generateKind == "ClusterRole" { - obj = &rbacv1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "custom-cluster-role", - }, - Rules: rules, - } - } else { - obj = &rbacv1.Role{ - TypeMeta: metav1.TypeMeta{ - Kind: "Role", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "custom-role", - Namespace: "mynamespace", - }, - Rules: rules, - } + obj = &rbacv1.Role{ + TypeMeta: metav1.TypeMeta{ + Kind: "Role", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: roleName, + Namespace: namespace, + }, + Rules: rules, } serializer := k8sJson.NewSerializerWithOptions(k8sJson.DefaultMetaFactory, nil, nil, k8sJson.SerializerOptions{Yaml: true, Pretty: true, Strict: true}) @@ -122,6 +134,29 @@ func generateRole(generateKind string, rules []rbacv1.PolicyRule) (string, error return writer.String(), nil } +func generateClusterRole(rules []rbacv1.PolicyRule, roleName string) (string, error) { + var obj runtime.Object + + obj = &rbacv1.ClusterRole{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: roleName, + }, + Rules: rules, + } + serializer := k8sJson.NewSerializerWithOptions(k8sJson.DefaultMetaFactory, nil, nil, k8sJson.SerializerOptions{Yaml: true, Pretty: true, Strict: true}) + var writer = bytes.NewBufferString("") + err := serializer.Encode(obj, writer) + if err != nil { + return "", err + } + + return writer.String(), nil +} + func generateRules(generateKind string, apiresourceList []*metav1.APIResourceList, denyResources sets.String, includeGroups sets.String, allowedVerbs sets.String) ([]rbacv1.PolicyRule, error) { isRole := generateKind == "Role" errs := []error{} diff --git a/cmd/show_permissions_cmd.go b/cmd/show_permissions_cmd.go index 2b15b8e..27b2b44 100644 --- a/cmd/show_permissions_cmd.go +++ b/cmd/show_permissions_cmd.go @@ -22,12 +22,13 @@ import ( func NewCommandGenerateShowPermissions() *cobra.Command { clusterContext := "" - generateKind := "ClusterRole" forGroups := []string{"*"} withVerb := []string{"*"} scope := "cluster" denyVerb := []string{} denyResource := []string{} + namespace := "" + roleName := "" // Support overrides cmd := &cobra.Command{ @@ -85,14 +86,20 @@ rbac-tool show --scope=namespaced --without-verbs=create,update,patch,delete,del } if scope == "namespaced" { - generateKind = "Role" - } - obj, err := generateRole(generateKind, computedPolicyRules) - if err != nil { - return err - } + obj, err := generateRole(computedPolicyRules, namespace, roleName) + if err != nil { + return err + } + + fmt.Fprintln(os.Stdout, obj) + } else { + obj, err := generateClusterRole(computedPolicyRules, roleName) + if err != nil { + return err + } - fmt.Fprintln(os.Stdout, obj) + fmt.Fprintln(os.Stdout, obj) + } return nil },