Skip to content

Commit

Permalink
Merge pull request #258 from jetstack/250_Command
Browse files Browse the repository at this point in the history
Add the rbac generation command `go run main.go agent rbac -c agent.yaml` to CLI for easy generation of rbac manifests.
Related #250
  • Loading branch information
Weeblin authored Aug 27, 2021
2 parents 1b64657 + 9858f68 commit d0d0b9f
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 2 deletions.
24 changes: 24 additions & 0 deletions cmd/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package cmd

import (
"fmt"
"io/ioutil"
"log"
"time"

"github.com/jetstack/preflight/pkg/agent"
"github.com/jetstack/preflight/pkg/permissions"
"github.com/spf13/cobra"
)

Expand All @@ -27,9 +30,30 @@ var agentInfoCmd = &cobra.Command{
},
}

var agentRBACCmd = &cobra.Command{
Use: "rbac",
Short: "print the agent's minimal RBAC manifest",
Long: `Print RBAC string by reading GVRs`,
Run: func(cmd *cobra.Command, args []string) {

b, err := ioutil.ReadFile(agent.ConfigFilePath)
if err != nil {
log.Fatalf("Failed to read config file: %s", err)
}
config, err := agent.ParseConfig(b)
if err != nil {
log.Fatalf("Failed to parse config file: %s", err)
}

out := permissions.GenerateFullManifest(config.DataGatherers)
fmt.Print(out)
},
}

func init() {
rootCmd.AddCommand(agentCmd)
agentCmd.AddCommand(agentInfoCmd)
agentCmd.AddCommand(agentRBACCmd)
agentCmd.PersistentFlags().StringVarP(
&agent.ConfigFilePath,
"agent-config-file",
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ require (
github.com/aws/aws-sdk-go v1.36.19
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/d4l3k/messagediff v1.2.1
github.com/fatih/color v1.12.0 // indirect
github.com/fatih/color v1.12.0
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/hashicorp/go-multierror v1.1.0
github.com/jetstack/version-checker v0.2.2-0.20201118163251-4bab9ef088ef
Expand All @@ -21,7 +21,7 @@ require (
github.com/juju/testing v0.0.0-20191001232224-ce9dec17d28b // indirect
github.com/kylelemons/godebug v1.1.0
github.com/leodido/go-urn v1.2.0 // indirect
github.com/maxatome/go-testdeep v1.9.2 // indirect
github.com/maxatome/go-testdeep v1.9.2
github.com/pkg/errors v0.9.1
github.com/pmylund/go-cache v2.1.0+incompatible
github.com/sirupsen/logrus v1.7.0
Expand All @@ -39,6 +39,7 @@ require (
k8s.io/apimachinery v0.20.1
k8s.io/client-go v11.0.0+incompatible
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
sigs.k8s.io/yaml v1.2.0
)

replace k8s.io/client-go => k8s.io/client-go v0.20.1
63 changes: 63 additions & 0 deletions pkg/permissions/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package permissions

import (
"fmt"
"strings"

"github.com/jetstack/preflight/pkg/agent"
"github.com/jetstack/preflight/pkg/datagatherer/k8s"
rbac "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
)

// AgentRBACManifests is a wrapper around the various RBAC structs needed to grant the agent fine-grained permissions as per its dg configs
Expand Down Expand Up @@ -113,3 +115,64 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan

return AgentRBACManifests
}

func createClusterRoleString(clusterRoles []rbac.ClusterRole) string {
var builder strings.Builder
for _, cb := range clusterRoles {
data, err := yaml.Marshal(cb)
if err != nil {
fmt.Print("Cluster Role fails to marshal")
}

builder.WriteString("\n")
builder.Write(data)
builder.WriteString("---")
}

return builder.String()
}
func createRoleBindingString(roleBindings []rbac.RoleBinding) string {
var builder strings.Builder
for _, cb := range roleBindings {
data, err := yaml.Marshal(cb)
if err != nil {
fmt.Print("Role Binding fails to marshal")
}

builder.WriteString("\n")
builder.Write(data)
builder.WriteString("---")
}

return builder.String()
}
func createClusterRoleBindingString(clusterRoleBindings []rbac.ClusterRoleBinding) string {
var builder strings.Builder
for _, cb := range clusterRoleBindings {
data, err := yaml.Marshal(cb)
if err != nil {
fmt.Print("Cluster Role Binding fails to marshal")
}

builder.WriteString("\n")
builder.Write(data)
builder.WriteString("---")
}

return builder.String()
}

func GenerateFullManifest(dataGatherers []agent.DataGatherer) string {
agentRBACManifestsStruct := GenerateAgentRBACManifests(dataGatherers)
agentCLR := createClusterRoleString(agentRBACManifestsStruct.ClusterRoles)
agentCLRB := createClusterRoleBindingString(agentRBACManifestsStruct.ClusterRoleBindings)
agentRB := createRoleBindingString(agentRBACManifestsStruct.RoleBindings)

out := fmt.Sprintf(`%s%s%s`, agentCLR, agentCLRB, agentRB)
out = strings.TrimPrefix(out, "\n")
out = strings.TrimSpace(out)
out = strings.ReplaceAll(out, "\n creationTimestamp: null", "")

return out

}
181 changes: 181 additions & 0 deletions pkg/permissions/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,187 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
)

func TestGenerateAgentRBACManifestsString(t *testing.T) {
testCases := []struct {
description string
dataGatherers []agent.DataGatherer
expectedRBACManifests string
}{
{
description: "Generate ClusterRole and ClusterRoleBinding for simple pod dg use case",
dataGatherers: []agent.DataGatherer{
{
Name: "k8s/pods",
Kind: "k8s-dynamic",
Config: &k8s.ConfigDynamic{
GroupVersionResource: schema.GroupVersionResource{
Version: "v1",
Resource: "pods",
},
},
},
},
expectedRBACManifests: `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jetstack-secure-agent-pods-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jetstack-secure-agent-pods-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jetstack-secure-agent-pods-reader
subjects:
- kind: ServiceAccount
name: agent
namespace: jetstack-secure
---`,
},
{
description: "Generate ClusterRole and RoleBinding for simple pod dg with include namespace \"foobar\"",
dataGatherers: []agent.DataGatherer{
{
Name: "k8s/pods",
Kind: "k8s-dynamic",
Config: &k8s.ConfigDynamic{
IncludeNamespaces: []string{"foobar"},
GroupVersionResource: schema.GroupVersionResource{
Version: "v1",
Resource: "pods",
},
},
},
},
expectedRBACManifests: `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jetstack-secure-agent-pods-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jetstack-secure-agent-pods-reader
namespace: foobar
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jetstack-secure-agent-pods-reader
subjects:
- kind: ServiceAccount
name: agent
namespace: jetstack-secure
---`,
},
{
description: "Generate multiple ClusterRoles and ClusterRoleBindings for simple pod and nodes dg use case",
dataGatherers: []agent.DataGatherer{
{
Name: "k8s/pods",
Kind: "k8s-dynamic",
Config: &k8s.ConfigDynamic{
GroupVersionResource: schema.GroupVersionResource{
Version: "v1",
Resource: "pods",
},
},
},
{
Name: "k8s/nodes",
Kind: "k8s-dynamic",
Config: &k8s.ConfigDynamic{
GroupVersionResource: schema.GroupVersionResource{
Version: "v1",
Resource: "nodes",
},
},
},
},
expectedRBACManifests: `apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jetstack-secure-agent-pods-reader
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: jetstack-secure-agent-nodes-reader
rules:
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jetstack-secure-agent-pods-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jetstack-secure-agent-pods-reader
subjects:
- kind: ServiceAccount
name: agent
namespace: jetstack-secure
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jetstack-secure-agent-nodes-reader
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jetstack-secure-agent-nodes-reader
subjects:
- kind: ServiceAccount
name: agent
namespace: jetstack-secure
---`,
},
}

for _, input := range testCases {
got := GenerateFullManifest(input.dataGatherers)
if input.expectedRBACManifests != got {
t.Errorf("value mismatch, \n**********expected:******************************\n%s\n**********got:******************************\n%s", input.expectedRBACManifests, got)
}
}
}

func TestGenerateAgentRBACManifests(t *testing.T) {
testCases := []struct {
description string
Expand Down

0 comments on commit d0d0b9f

Please sign in to comment.