Skip to content

Commit

Permalink
Enhance CLI output and remove the need to specify EKS cluster name
Browse files Browse the repository at this point in the history
  • Loading branch information
christophetd committed Apr 11, 2023
1 parent c3c6027 commit 2d67e07
Show file tree
Hide file tree
Showing 14 changed files with 188 additions and 126 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
./mkat
bin
77 changes: 0 additions & 77 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
@@ -1,77 +0,0 @@
github.com/aws/aws-sdk-go-v2,https://github.com/aws/aws-sdk-go-v2/blob/v1.17.6/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/config,https://github.com/aws/aws-sdk-go-v2/blob/config/v1.18.16/config/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/credentials,https://github.com/aws/aws-sdk-go-v2/blob/credentials/v1.13.16/credentials/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/feature/ec2/imds,https://github.com/aws/aws-sdk-go-v2/blob/feature/ec2/imds/v1.12.24/feature/ec2/imds/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/internal/configsources,https://github.com/aws/aws-sdk-go-v2/blob/internal/configsources/v1.1.30/internal/configsources/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2,https://github.com/aws/aws-sdk-go-v2/blob/internal/endpoints/v2.4.24/internal/endpoints/v2/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/internal/ini,https://github.com/aws/aws-sdk-go-v2/blob/internal/ini/v1.3.31/internal/ini/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/internal/sync/singleflight,https://github.com/aws/aws-sdk-go-v2/blob/v1.17.6/internal/sync/singleflight/LICENSE,BSD-3-Clause
github.com/aws/aws-sdk-go-v2/service/eks,https://github.com/aws/aws-sdk-go-v2/blob/service/eks/v1.27.6/service/eks/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/service/iam,https://github.com/aws/aws-sdk-go-v2/blob/service/iam/v1.19.5/service/iam/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url,https://github.com/aws/aws-sdk-go-v2/blob/service/internal/presigned-url/v1.9.24/service/internal/presigned-url/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/service/sso,https://github.com/aws/aws-sdk-go-v2/blob/service/sso/v1.12.5/service/sso/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/service/ssooidc,https://github.com/aws/aws-sdk-go-v2/blob/service/ssooidc/v1.14.5/service/ssooidc/LICENSE.txt,Apache-2.0
github.com/aws/aws-sdk-go-v2/service/sts,https://github.com/aws/aws-sdk-go-v2/blob/service/sts/v1.18.6/service/sts/LICENSE.txt,Apache-2.0
github.com/aws/smithy-go,https://github.com/aws/smithy-go/blob/v1.13.5/LICENSE,Apache-2.0
github.com/aws/smithy-go/internal/sync/singleflight,https://github.com/aws/smithy-go/blob/v1.13.5/internal/sync/singleflight/LICENSE,BSD-3-Clause
github.com/cpuguy83/go-md2man/v2/md2man,https://github.com/cpuguy83/go-md2man/blob/v2.0.2/LICENSE.md,MIT
github.com/datadog/managed-kubernetes-auditing-toolkit/cmd/managed-kubernetes-auditing-toolkit,Unknown,Unknown
github.com/datadog/managed-kubernetes-auditing-toolkit/cmd/managed-kubernetes-auditing-toolkit/eks,Unknown,Unknown
github.com/datadog/managed-kubernetes-auditing-toolkit/internal/utils,Unknown,Unknown
github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks,Unknown,Unknown
github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks/imds,Unknown,Unknown
github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks/role_relationships,Unknown,Unknown
github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks/secrets,Unknown,Unknown
github.com/davecgh/go-spew/spew,https://github.com/davecgh/go-spew/blob/v1.1.1/LICENSE,ISC
github.com/dominikbraun/graph,https://github.com/dominikbraun/graph/blob/v0.16.1/LICENSE,Apache-2.0
github.com/emicklei/go-restful/v3,https://github.com/emicklei/go-restful/blob/v3.9.0/LICENSE,MIT
github.com/fatih/color,https://github.com/fatih/color/blob/v1.15.0/LICENSE.md,MIT
github.com/go-logr/logr,https://github.com/go-logr/logr/blob/v1.2.3/LICENSE,Apache-2.0
github.com/go-openapi/jsonpointer,https://github.com/go-openapi/jsonpointer/blob/v0.19.5/LICENSE,Apache-2.0
github.com/go-openapi/jsonreference,https://github.com/go-openapi/jsonreference/blob/v0.20.0/LICENSE,Apache-2.0
github.com/go-openapi/swag,https://github.com/go-openapi/swag/blob/v0.19.14/LICENSE,Apache-2.0
github.com/gogo/protobuf,https://github.com/gogo/protobuf/blob/v1.3.2/LICENSE,BSD-3-Clause
github.com/golang/protobuf,https://github.com/golang/protobuf/blob/v1.5.2/LICENSE,BSD-3-Clause
github.com/google/gnostic,https://github.com/google/gnostic/blob/v0.5.7-v3refs/LICENSE,Apache-2.0
github.com/google/go-cmp/cmp,https://github.com/google/go-cmp/blob/v0.5.9/LICENSE,BSD-3-Clause
github.com/google/gofuzz,https://github.com/google/gofuzz/blob/v1.1.0/LICENSE,Apache-2.0
github.com/imdario/mergo,https://github.com/imdario/mergo/blob/v0.3.6/LICENSE,BSD-3-Clause
github.com/jedib0t/go-pretty/v6,https://github.com/jedib0t/go-pretty/blob/v6.4.6/LICENSE,MIT
github.com/jmespath/go-jmespath,https://github.com/jmespath/go-jmespath/blob/v0.4.0/LICENSE,Apache-2.0
github.com/josharian/intern,https://github.com/josharian/intern/blob/v1.0.0/license.md,MIT
github.com/json-iterator/go,https://github.com/json-iterator/go/blob/v1.1.12/LICENSE,MIT
github.com/mailru/easyjson,https://github.com/mailru/easyjson/blob/v0.7.6/LICENSE,MIT
github.com/mattn/go-colorable,https://github.com/mattn/go-colorable/blob/v0.1.13/LICENSE,MIT
github.com/mattn/go-isatty,https://github.com/mattn/go-isatty/blob/v0.0.17/LICENSE,MIT
github.com/mattn/go-runewidth,https://github.com/mattn/go-runewidth/blob/v0.0.13/LICENSE,MIT
github.com/modern-go/concurrent,https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE,Apache-2.0
github.com/modern-go/reflect2,https://github.com/modern-go/reflect2/blob/v1.0.2/LICENSE,Apache-2.0
github.com/munnerz/goautoneg,https://github.com/munnerz/goautoneg/blob/a7dc8b61c822/LICENSE,BSD-3-Clause
github.com/rivo/uniseg,https://github.com/rivo/uniseg/blob/v0.2.0/LICENSE.txt,MIT
github.com/russross/blackfriday/v2,https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt,BSD-2-Clause
github.com/spf13/cobra,https://github.com/spf13/cobra/blob/v1.6.1/LICENSE.txt,Apache-2.0
github.com/spf13/pflag,https://github.com/spf13/pflag/blob/v1.0.5/LICENSE,BSD-3-Clause
golang.org/x/exp,https://cs.opensource.google/go/x/exp/+/10a50721:LICENSE,BSD-3-Clause
golang.org/x/net,https://cs.opensource.google/go/x/net/+/v0.7.0:LICENSE,BSD-3-Clause
golang.org/x/oauth2,https://cs.opensource.google/go/x/oauth2/+/fd043fe5:LICENSE,BSD-3-Clause
golang.org/x/sys/unix,https://cs.opensource.google/go/x/sys/+/v0.6.0:LICENSE,BSD-3-Clause
golang.org/x/term,https://cs.opensource.google/go/x/term/+/v0.5.0:LICENSE,BSD-3-Clause
golang.org/x/text,https://cs.opensource.google/go/x/text/+/v0.7.0:LICENSE,BSD-3-Clause
golang.org/x/time/rate,https://cs.opensource.google/go/x/time/+/90d013bb:LICENSE,BSD-3-Clause
google.golang.org/protobuf,https://github.com/protocolbuffers/protobuf-go/blob/v1.28.1/LICENSE,BSD-3-Clause
gopkg.in/inf.v0,https://github.com/go-inf/inf/blob/v0.9.1/LICENSE,BSD-3-Clause
gopkg.in/yaml.v2,https://github.com/go-yaml/yaml/blob/v2.4.0/LICENSE,Apache-2.0
gopkg.in/yaml.v3,https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE,MIT
k8s.io/api,https://github.com/kubernetes/api/blob/v0.26.2/LICENSE,Apache-2.0
k8s.io/apimachinery/pkg,https://github.com/kubernetes/apimachinery/blob/v0.26.2/LICENSE,Apache-2.0
k8s.io/apimachinery/third_party/forked/golang/reflect,https://github.com/kubernetes/apimachinery/blob/v0.26.2/third_party/forked/golang/LICENSE,BSD-3-Clause
k8s.io/client-go,https://github.com/kubernetes/client-go/blob/v0.26.2/LICENSE,Apache-2.0
k8s.io/klog/v2,https://github.com/kubernetes/klog/blob/v2.80.1/LICENSE,Apache-2.0
k8s.io/kube-openapi/pkg,https://github.com/kubernetes/kube-openapi/blob/172d655c2280/LICENSE,Apache-2.0
k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json,https://github.com/kubernetes/kube-openapi/blob/172d655c2280/pkg/internal/third_party/go-json-experiment/json/LICENSE,BSD-3-Clause
k8s.io/kube-openapi/pkg/validation/spec,https://github.com/kubernetes/kube-openapi/blob/172d655c2280/pkg/validation/spec/LICENSE,Apache-2.0
k8s.io/utils,https://github.com/kubernetes/utils/blob/1a15be271d1d/LICENSE,Apache-2.0
k8s.io/utils/internal/third_party/forked/golang/net,https://github.com/kubernetes/utils/blob/1a15be271d1d/internal/third_party/forked/golang/LICENSE,BSD-3-Clause
sigs.k8s.io/json,https://github.com/kubernetes-sigs/json/blob/f223a00ba0e2/LICENSE,Apache-2.0
sigs.k8s.io/structured-merge-diff/v4,https://github.com/kubernetes-sigs/structured-merge-diff/blob/v4.2.3/LICENSE,Apache-2.0
sigs.k8s.io/yaml,https://github.com/kubernetes-sigs/yaml/blob/v1.3.0/LICENSE,MIT
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
ROOT_DIR := $(dir $(MAKEFILE_PATH))

all:
go build -o mkat ./cmd/managed-kubernetes-auditing-toolkit/main.go
mkdir -p bin
go build -o bin/mkat ./cmd/managed-kubernetes-auditing-toolkit/main.go

test:
go test ./... -v
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func doFindSecretsCommand() error {

if len(secrets) == 0 {
log.Println("No hardcoded AWS secrets found in your AWS cluster")
return nil
}

t := table.NewWriter()
Expand Down
7 changes: 5 additions & 2 deletions cmd/managed-kubernetes-auditing-toolkit/eks/imds.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package eks
import (
"github.com/datadog/managed-kubernetes-auditing-toolkit/internal/utils"
"github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks/imds"
"github.com/fatih/color"
"github.com/spf13/cobra"
"log"
)

func buildTestImdsAccessCommand() *cobra.Command {
Expand All @@ -28,9 +30,10 @@ func doTestImdsAccessCommand() error {
return err
}
if result.IsImdsAccessible {
println("IMDS is accessible and allows any pod to retrieve credentials for the AWS role " + result.NodeRoleName)
warningColor := color.New(color.BgRed, color.FgWhite, color.Bold)
log.Println(warningColor.Sprint("IMDS is accessible") + " and allows any pod to retrieve credentials for the AWS role " + result.NodeRoleName)
} else {
println("IMDS is not accessible in your cluster")
log.Println("IMDS is not accessible in your cluster")
}
return nil
}
19 changes: 18 additions & 1 deletion cmd/managed-kubernetes-auditing-toolkit/eks/main.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
package eks

import (
"errors"
"github.com/common-nighthawk/go-figure"
"github.com/datadog/managed-kubernetes-auditing-toolkit/internal/utils"
"github.com/spf13/cobra"
"log"
)

func BuildEksSubcommand() *cobra.Command {
eksCommand := &cobra.Command{
Use: "eks",
Use: "eks",
Short: "Commands to audit your EKS cluster",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
figure.NewFigure("mkat", "", true).Print()
println()
if !utils.IsEKS() {
return errors.New("You do not seem to be connected to an EKS cluster. Connect to an EKS cluster and try again")
}
clusterName := utils.GetEKSClusterName()
if clusterName != "" {
log.Println("Connected to EKS cluster " + clusterName)
}
return nil
},
}

eksCommand.AddCommand(buildEksRoleRelationshipsCommand())
Expand Down
92 changes: 80 additions & 12 deletions cmd/managed-kubernetes-auditing-toolkit/eks/role_relationships.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package eks

import (
"errors"
"fmt"
"github.com/awalterschulze/gographviz"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/datadog/managed-kubernetes-auditing-toolkit/internal/utils"
"github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks"
"github.com/datadog/managed-kubernetes-auditing-toolkit/pkg/managed-kubernetes-auditing-toolkit/eks/role_relationships"
"github.com/dominikbraun/graph"
"github.com/dominikbraun/graph/draw"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -36,22 +36,22 @@ const DefaultOutputFormat = TextOutputFormat
func buildEksRoleRelationshipsCommand() *cobra.Command {
eksRoleRelationshipsCommand := &cobra.Command{
Use: "find-role-relationships",
Example: "mkat eks find-role-relationships <eks-cluster-name>",
Example: "mkat eks find-role-relationships",
Short: "Find relationships between your EKS service accounts and IAM roles",
Long: "Analyzes your EKS cluster and finds all service accounts that can assume AWS roles, based on their trust policies ",
DisableFlagsInUseLine: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
cmd.Help()
os.Exit(1)
}
if !slices.Contains(availableOutputFormats, outputFormat) {
return fmt.Errorf("invalid output format %s", outputFormat)
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
return doFindRoleRelationshipsCommand(args[0])
cluster := utils.GetEKSClusterName()
if cluster == "" {
return errors.New("unable to determine your current EKS cluster name")
}
return doFindRoleRelationshipsCommand(cluster)
},
}

Expand All @@ -73,6 +73,7 @@ func doFindRoleRelationshipsCommand(targetCluster string) error {
return err
}
if outputFile != "" {
log.Println("Writing " + strings.ToUpper(outputFormat) + " output to " + outputFile)
return os.WriteFile(outputFile, []byte(output), 0644)
} else {
print(output)
Expand Down Expand Up @@ -105,25 +106,92 @@ func getTextOutput(cluster *eks.EKSCluster) (string, error) {
t.SetColumnConfigs([]table.ColumnConfig{
{Number: 1, AutoMerge: true, VAlign: text.VAlignMiddle},
{Number: 2, AutoMerge: true, VAlign: text.VAlignMiddle},
{Number: 3, AutoMerge: true, VAlign: text.VAlignMiddle},
})
t.AppendHeader(table.Row{"Namespace", "Service Account", "Pod", "Assumable Role ARN"})
var found = false
for namespace, pods := range cluster.PodsByNamespace {
for _, pod := range pods {
if pod.ServiceAccount == nil || len(pod.ServiceAccount.AssumableRoles) == 0 {
continue
}
for _, role := range pod.ServiceAccount.AssumableRoles {
t.AppendRow([]interface{}{namespace, pod.ServiceAccount.Name, pod.Name, role.Arn})
found = true
}
}
t.AppendSeparator()
}
if !found {
return "No service accounts found that can assume AWS roles", nil
} else {
return t.Render(), nil
}
}

return t.Render(), nil
type Vertex struct {
Id int
Label string
}

func (v *Vertex) ID() int {
return v.Id
}
func getDotOutput(cluster *eks.EKSCluster) (string, error) {
g := graph.New(graph.StringHash, graph.Directed(), graph.Acyclic())
graphAst, _ := gographviz.ParseString(`digraph G { }`)
graphViz := gographviz.NewGraph()
gographviz.Analyse(graphAst, graphViz)
graphViz.AddAttr("G", "rankdir", "LR")
graphViz.AddAttr("G", "splines", "polyline")
graphViz.AddAttr("G", "ranksep", "1.2")
graphViz.AddAttr("G", "nodesep", "0.8")
graphViz.AddAttr("G", "outputorder", "edgesfirst")
graphViz.AddAttr("G", "overlap", "false")
graphViz.AddAttr("G", "newrank", "true")

for namespace, pods := range cluster.PodsByNamespace {
subgraph := fmt.Sprintf(` "cluster_%s" `, namespace)
graphViz.AddSubGraph("G", subgraph, map[string]string{
"rank": "same",
"label": fmt.Sprintf(`"%s"`, namespace),
"color": "lightgrey",
"style": "rounded",
})
for _, pod := range pods {
if pod.ServiceAccount == nil || len(pod.ServiceAccount.AssumableRoles) == 0 {
continue
}
podLabel := fmt.Sprintf(` "Pod %s/%s" `, namespace, pod.Name)
graphViz.AddNode(subgraph, podLabel, map[string]string{
"fontname": "Helvetica",
"shape": "box",
"style": "filled",
"fillcolor": "lightgrey",
"fontsize": "12",
})
for _, role := range pod.ServiceAccount.AssumableRoles {
parsedArn, _ := arn.Parse(role.Arn)
roleLabel := fmt.Sprintf(`"IAM role %s"`, strings.Split(parsedArn.Resource, "/")[1])
graphViz.AddNode("G", roleLabel, map[string]string{
"fontname": "Helvetica",
"shape": "box",
"style": "filled",
"fillcolor": `"#BFEFFF"`,
"fontsize": "12",
})
graphViz.AddEdge(podLabel, roleLabel, true, map[string]string{
"fontname": "Helvetica",
"color": "black",
"penwidth": "1",
"fontsize": "10",
"weight": "2.0",
})
}
}
}

return graphViz.String(), nil
/*g := graph.New(graph.StringHash, graph.Directed(), graph.Acyclic())
for namespace, pods := range cluster.PodsByNamespace {
for _, pod := range pods {
Expand Down Expand Up @@ -159,7 +227,7 @@ func getDotOutput(cluster *eks.EKSCluster) (string, error) {
g.AddEdge(
podLabel, roleLabel,
graph.EdgeAttribute("label", "can assume"),
//graph.EdgeAttribute("label", "can assume"),
)
}
}
Expand All @@ -170,7 +238,7 @@ func getDotOutput(cluster *eks.EKSCluster) (string, error) {
return "", err
}
return sb.String(), nil
return sb.String(), nil*/
}

func getCsvOutput(cluster *eks.EKSCluster) (string, error) {
Expand Down
3 changes: 3 additions & 0 deletions cmd/managed-kubernetes-auditing-toolkit/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import (
var rootCmd = &cobra.Command{
Use: "mkat",
DisableFlagsInUseLine: true,
SilenceUsage: true,
}

func init() {
rootCmd.CompletionOptions.DisableDefaultCmd = true

rootCmd.AddCommand(eks.BuildEksSubcommand())
rootCmd.AddCommand(&cobra.Command{
Use: "autogen-docs",
Expand Down
1 change: 1 addition & 0 deletions examples/demo-cluster/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This sample folder contains Terraform code to provision test resources in an EKS cluster, including pods, service accounts, and IAM roles configured for IAM Roles for Service Accounts.
Binary file added examples/irsa.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 2d67e07

Please sign in to comment.