Skip to content

Commit

Permalink
Orphan Command Group
Browse files Browse the repository at this point in the history
- orphan service accounts
  • Loading branch information
gadinaor-r7 committed Jul 31, 2024
1 parent 6a26081 commit 0f904da
Show file tree
Hide file tree
Showing 7 changed files with 386 additions and 73 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Available Commands:
generate Generate Role or ClusterRole and reduce the use of wildcards
help Help about any command
lookup RBAC Lookup by subject (user/group/serviceaccount) name
orphan Show orphan resources like ServiceAccounts, Roles, etc.
policy-rules RBAC List Policy Rules For subject (user/group/serviceaccount) name
show Generate ClusterRole with all available permissions from the target cluster
version Print rbac-tool version
Expand All @@ -74,6 +75,7 @@ Use "rbac-tool [command] --help" for more information about a command.

- [The `rbac-tool viz` command](#rbac-tool-viz)
- [The `rbac-tool analysis` command](#rbac-tool-analysis)
- [The `rbac-tool orphan` command](#rbac-tool-orphan)
- [The `rbac-tool lookup` command](#rbac-tool-lookup)
- [The `rbac-tool who-can` command](#rbac-tool-who-can)
- [The `rbac-tool policy-rules` command](#rbac-tool-policy-rules)
Expand Down Expand Up @@ -150,6 +152,16 @@ rbac-tool analysis --cluster-context myctx
rbac-tool analysis --config myruleset.yaml
```

# `rbac-tool orphan`

Analyze RBAC permissions and highlight RBAC related orphan resources such as service accounts, role etc,.

Examples:

```shell script
# Show Orphan ServiceAccount in specific namespace(s)
bin/rbac-tool orphan sa --include-namespaces=somennamespace
```

# `rbac-tool lookup`
Lookup of the Roles/ClusterRoles used attached to User/ServiceAccount/Group with or without [regex](https://regex101.com/)
Expand Down
149 changes: 149 additions & 0 deletions cmd/orphan_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package cmd

import (
"encoding/json"
"fmt"
Orphan "github.com/alcideio/rbac-tool/pkg/orphan"
"github.com/alcideio/rbac-tool/pkg/utils"
v1 "k8s.io/api/core/v1"
"os"
"sort"
"strings"

"github.com/alcideio/rbac-tool/pkg/kube"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
)

func NewCommandOrphanServiceAccounts() *cobra.Command {

clusterContext := ""
output := "table"
excludedNamespaces := ""
includedNamespaces := ""

// Support overrides
cmd := &cobra.Command{
Use: "sa",
Aliases: []string{"serviceaccount", "serviceaccounts", "sas"},
SilenceUsage: true,
SilenceErrors: true,
Example: "rbac-tool orphan",
Short: "Shows the list of Service Accounts defined but not used",
Long: `Shows the list of Service Accounts defined but not used
Examples:
# Show Orphan ServiceAccount
bin/rbac-tool orphan sa --include-namespaces=somennamespace
`,
Hidden: false,
RunE: func(c *cobra.Command, args []string) error {
var err error

client, err := kube.NewClient(clusterContext)
if err != nil {
return fmt.Errorf("failed to create kubernetes client - %v", err)
}

od, err := Orphan.NewDiscoverer(client)
if err != nil {
return fmt.Errorf("failed to create orphan discoverer - %v", err)
}

orphanSAs, err := od.GetOrphanServiceAccounts()
if err != nil {
return fmt.Errorf("failed to get orphan service accounts - %v", err)
}

inNs, exNs := utils.GetNamespaceSets(includedNamespaces, excludedNamespaces)

filteredOrphanSAs := []*v1.ServiceAccount{}
for i, e := range orphanSAs {

if utils.IsNamespaceIncluded(e.Namespace, inNs, exNs) {
filteredOrphanSAs = append(filteredOrphanSAs, orphanSAs[i])
}
}

switch output {
case "table":
rows := [][]string{}

for _, e := range filteredOrphanSAs {

row := []string{
e.Name,
e.Namespace,
}
rows = append(rows, row)
}

sort.Slice(rows, func(i, j int) bool {
if strings.Compare(rows[i][1], rows[j][1]) == 0 {
return (strings.Compare(rows[i][0], rows[j][0]) < 0)
}

return (strings.Compare(rows[i][1], rows[j][1]) < 0)
})

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"SERVICE ACCOUNT", "NAMESPACE"})
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetBorder(false)
table.SetAlignment(tablewriter.ALIGN_LEFT)
//table.SetAutoMergeCells(true)

table.AppendBulk(rows)
table.Render()

return nil
case "yaml":
data, err := yaml.Marshal(&filteredOrphanSAs)
if err != nil {
return fmt.Errorf("Processing error - %v", err)
}
fmt.Fprintln(os.Stdout, string(data))
return nil

case "json":
data, err := json.Marshal(&filteredOrphanSAs)
if err != nil {
return fmt.Errorf("Processing error - %v", err)
}

fmt.Fprintln(os.Stdout, string(data))
return nil

default:
return fmt.Errorf("unsupported output format")
}
},
}

flags := cmd.Flags()
flags.StringVar(&clusterContext, "cluster-context", "", "Cluster Context .use 'kubectl config get-contexts' to list available contexts")
flags.StringVarP(&output, "output", "o", "table", "Output type: table | json | yaml")
flags.StringVar(&excludedNamespaces, "exclude-namespaces", "kube-system", "Comma-delimited list of namespaces to exclude in the analysis")
flags.StringVar(&includedNamespaces, "include-namespaces", "*", "Comma-delimited list of namespaces to include in the analysis")

return cmd
}

func NewCommandOrphan() *cobra.Command {
var orphanCmd = &cobra.Command{
Use: "orphan",
Short: "Show orphan resources like ServiceAccounts, Roles, etc.",
Long: `Show orphan resources like ServiceAccounts, Roles, etc.`,
}

cmds := []*cobra.Command{
NewCommandOrphanServiceAccounts(),
}

orphanCmd.AddCommand(cmds...)

return orphanCmd
}
64 changes: 32 additions & 32 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/spf13/cobra v1.8.0
google.golang.org/protobuf v1.34.0
k8s.io/api v0.20.15
k8s.io/apimachinery v0.20.15
k8s.io/apiserver v0.20.15
k8s.io/client-go v0.20.15
k8s.io/component-helpers v0.20.15
k8s.io/api v0.21.14
k8s.io/apimachinery v0.21.14
k8s.io/apiserver v0.21.14
k8s.io/client-go v0.21.14
k8s.io/component-helpers v0.21.14
k8s.io/klog v1.0.0
k8s.io/kubernetes v1.20.15
sigs.k8s.io/yaml v1.4.0
Expand Down Expand Up @@ -81,31 +81,31 @@ replace (
//
// k8s.io/kubernetes this is evil....but nessecary for audit2rbac
//
k8s.io/api => k8s.io/api v0.20.15
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.20.15
k8s.io/apimachinery => k8s.io/apimachinery v0.20.15
k8s.io/apiserver => k8s.io/apiserver v0.20.15
k8s.io/cli-runtime => k8s.io/cli-runtime v0.20.15
k8s.io/client-go => k8s.io/client-go v0.20.15
k8s.io/cloud-provider => k8s.io/cloud-provider v0.20.15
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.20.15
k8s.io/code-generator => k8s.io/code-generator v0.20.15
k8s.io/component-base => k8s.io/component-base v0.20.15
k8s.io/component-helpers => k8s.io/component-helpers v0.20.15
k8s.io/controller-manager => k8s.io/controller-manager v0.20.15
k8s.io/cri-api => k8s.io/cri-api v0.20.15
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.20.15
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.20.15
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.20.15
k8s.io/kube-proxy => k8s.io/kube-proxy v0.20.15
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.20.15
k8s.io/kubectl => k8s.io/kubectl v0.20.15
k8s.io/kubelet => k8s.io/kubelet v0.20.15
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.20.15
k8s.io/metrics => k8s.io/metrics v0.20.15
k8s.io/mount-utils => k8s.io/mount-utils v0.20.15
k8s.io/node-api => k8s.io/node-api v0.20.15
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.20.15
k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.20.15
k8s.io/sample-controller => k8s.io/sample-controller v0.20.15
k8s.io/api => k8s.io/api v0.21.14
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.21.14
k8s.io/apimachinery => k8s.io/apimachinery v0.21.14
k8s.io/apiserver => k8s.io/apiserver v0.21.14
k8s.io/cli-runtime => k8s.io/cli-runtime v0.21.14
k8s.io/client-go => k8s.io/client-go v0.21.14
k8s.io/cloud-provider => k8s.io/cloud-provider v0.21.14
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.21.14
k8s.io/code-generator => k8s.io/code-generator v0.21.14
k8s.io/component-base => k8s.io/component-base v0.21.14
k8s.io/component-helpers => k8s.io/component-helpers v0.21.14
k8s.io/controller-manager => k8s.io/controller-manager v0.21.14
k8s.io/cri-api => k8s.io/cri-api v0.21.14
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.21.14
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.21.14
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.21.14
k8s.io/kube-proxy => k8s.io/kube-proxy v0.21.14
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.21.14
k8s.io/kubectl => k8s.io/kubectl v0.21.14
k8s.io/kubelet => k8s.io/kubelet v0.21.14
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.21.14
k8s.io/metrics => k8s.io/metrics v0.21.14
k8s.io/mount-utils => k8s.io/mount-utils v0.21.14
k8s.io/node-api => k8s.io/node-api v0.21.14
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.21.14
k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.21.14
k8s.io/sample-controller => k8s.io/sample-controller v0.21.14
)
Loading

0 comments on commit 0f904da

Please sign in to comment.