From d1a14010651cb8e885298bd1e5ae4c61bf8a71e5 Mon Sep 17 00:00:00 2001 From: wenlin Date: Fri, 6 Aug 2021 18:05:15 +0100 Subject: [PATCH 1/9] WIP --- pkg/permissions/generate.go | 36 +++++++++++++ pkg/permissions/generate_test.go | 86 ++++++++------------------------ 2 files changed, 58 insertions(+), 64 deletions(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index 1515fc8a..1aa278f0 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -73,3 +73,39 @@ func GenerateRoles(dataGatherer []agent.DataGatherer) []rbac.ClusterRole { } return out } + +// func SelectNamespace(all, include, exclude) selected { + +// } + +func GenerateBindings(clusterRoles []rbac.ClusterRole) []rbac.ClusterRoleBinding { + out := []rbac.ClusterRoleBinding{} + for _, cr := range clusterRoles { + out = append(out, rbac.ClusterRoleBinding{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("jetstack-secure-agent-%s-reader", cr.TypeMeta.Kind), + }, + + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: cr.ObjectMeta.Name, + APIGroup: "rbac.authorization.k8s.io", + }, + }) + + } + return out +} diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index 6428e9e2..f3bac2da 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -15,23 +15,14 @@ func TestGenerateRBAC(t *testing.T) { // Use these test cases to check if Generate function is correct testCases := []struct { // expectedClusterRoles is the collection of ClusterRole - expectedClusterRoles []rbac.ClusterRole - dataGatherers []agent.DataGatherer - description string + expectedClusterRoleBindings []rbac.ClusterRoleBinding + dataGatherers []agent.DataGatherer + description string }{ { description: "Generate RBAC struct for pods datagatherer", dataGatherers: []agent.DataGatherer{ - { - Name: "k8s/pods", - Kind: "k8s-dynamic", - Config: &k8s.ConfigDynamic{ - GroupVersionResource: schema.GroupVersionResource{ - Version: "v1", - Resource: "pods", - }, - }, - }, + { Name: "k8s/secrets", Kind: "k8s-dynamic", @@ -42,65 +33,31 @@ func TestGenerateRBAC(t *testing.T) { }, }, }, - { - Name: "k8s/awspcaissuer", - Kind: "k8s-dynamic", - Config: &k8s.ConfigDynamic{ - GroupVersionResource: schema.GroupVersionResource{ - Group: "awspca.cert-manager.io", - Version: "v1", - Resource: "awspcaissuers", - }, - }, - }, }, - expectedClusterRoles: []rbac.ClusterRole{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-pods-reader", - }, - Rules: []rbac.PolicyRule{ - { - Verbs: []string{"get", "list", "watch"}, - APIGroups: []string{""}, - Resources: []string{"pods"}, - }, - }, - }, + expectedClusterRoleBindings: []rbac.ClusterRoleBinding{ + { TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", + Kind: "ClusterRoleBinding", APIVersion: "rbac.authorization.k8s.io/v1", }, + ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-secrets-reader", + Name: "jetstack-secure-agent-ClusterRole-reader", }, - Rules: []rbac.PolicyRule{ + + Subjects: []rbac.Subject{ { - Verbs: []string{"get", "list", "watch"}, - APIGroups: []string{""}, - Resources: []string{"secrets"}, + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", }, }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-awspcaissuers-reader", - }, - Rules: []rbac.PolicyRule{ - { - Verbs: []string{"get", "list", "watch"}, - APIGroups: []string{"awspca.cert-manager.io"}, - Resources: []string{"awspcaissuers"}, - }, + + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: "jetstack-secure-agent-secret-reader", + APIGroup: "rbac.authorization.k8s.io", }, }, }, @@ -110,9 +67,10 @@ func TestGenerateRBAC(t *testing.T) { for _, input := range testCases { got := GenerateRoles(input.dataGatherers) - if diff, equal := messagediff.PrettyDiff(input.expectedClusterRoles, got); !equal { + toBeTest := GenerateBindings(got) + if diff, equal := messagediff.PrettyDiff(input.expectedClusterRoleBindings, toBeTest); !equal { t.Errorf("%s:\n%s", input.description, diff) - t.Fatalf("unexpected difference in RBAC cluster role: \ngot \n%v\nwant\n%v", got, input.expectedClusterRoles) + t.Fatalf("unexpected difference in RBAC cluster role: \ngot \n%v\nwant\n%v", got, input.expectedClusterRoleBindings) } } } From 72ab52cf6124eb89fe674509b1f9c4edad8f294a Mon Sep 17 00:00:00 2001 From: wenlin Date: Mon, 9 Aug 2021 09:45:49 +0100 Subject: [PATCH 2/9] Implement simple generation of ClusterRoleses --- go.mod | 1 + go.sum | 2 ++ pkg/permissions/generate_test.go | 14 ++++---------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index e11ee690..cdc92c2e 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +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/pkg/errors v0.9.1 github.com/pmylund/go-cache v2.1.0+incompatible github.com/sirupsen/logrus v1.7.0 diff --git a/go.sum b/go.sum index 7e3c4df2..307fd83b 100644 --- a/go.sum +++ b/go.sum @@ -664,6 +664,8 @@ github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxatome/go-testdeep v1.9.2 h1:5D7u/JkeG0A/HDTbZ/CFFmpYZPeWN+uGQ1IbsEHYlCo= +github.com/maxatome/go-testdeep v1.9.2/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ysdyKe7Dyogw70= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index f3bac2da..0bf57992 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -3,9 +3,9 @@ package permissions import ( "testing" - "github.com/d4l3k/messagediff" "github.com/jetstack/preflight/pkg/agent" "github.com/jetstack/preflight/pkg/datagatherer/k8s" + "github.com/maxatome/go-testdeep/td" rbac "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -35,17 +35,14 @@ func TestGenerateRBAC(t *testing.T) { }, }, expectedClusterRoleBindings: []rbac.ClusterRoleBinding{ - { TypeMeta: metav1.TypeMeta{ Kind: "ClusterRoleBinding", APIVersion: "rbac.authorization.k8s.io/v1", }, - ObjectMeta: metav1.ObjectMeta{ Name: "jetstack-secure-agent-ClusterRole-reader", }, - Subjects: []rbac.Subject{ { Kind: "ServiceAccount", @@ -53,10 +50,9 @@ func TestGenerateRBAC(t *testing.T) { Namespace: "jetstack-secure", }, }, - RoleRef: rbac.RoleRef{ Kind: "ClusterRole", - Name: "jetstack-secure-agent-secret-reader", + Name: "jetstack-secure-agent-secrets-reader", APIGroup: "rbac.authorization.k8s.io", }, }, @@ -68,9 +64,7 @@ func TestGenerateRBAC(t *testing.T) { for _, input := range testCases { got := GenerateRoles(input.dataGatherers) toBeTest := GenerateBindings(got) - if diff, equal := messagediff.PrettyDiff(input.expectedClusterRoleBindings, toBeTest); !equal { - t.Errorf("%s:\n%s", input.description, diff) - t.Fatalf("unexpected difference in RBAC cluster role: \ngot \n%v\nwant\n%v", got, input.expectedClusterRoleBindings) - } + + td.Cmp(t, input.expectedClusterRoleBindings, toBeTest) } } From bdba51c5b87fb0b728abb649642d48186c22ec39 Mon Sep 17 00:00:00 2001 From: wenlin Date: Mon, 9 Aug 2021 10:04:59 +0100 Subject: [PATCH 3/9] Generate single testcase RBAC --- pkg/permissions/generate.go | 4 ++-- pkg/permissions/generate_test.go | 28 +++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index 1aa278f0..89118929 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -40,7 +40,7 @@ rules: return strings.TrimSuffix(ss, "\n") } -func GenerateRoles(dataGatherer []agent.DataGatherer) []rbac.ClusterRole { +func GenerateClusterRoles(dataGatherer []agent.DataGatherer) []rbac.ClusterRole { out := []rbac.ClusterRole{} for _, g := range dataGatherer { @@ -78,7 +78,7 @@ func GenerateRoles(dataGatherer []agent.DataGatherer) []rbac.ClusterRole { // } -func GenerateBindings(clusterRoles []rbac.ClusterRole) []rbac.ClusterRoleBinding { +func GenerateClusterRoleBindings(clusterRoles []rbac.ClusterRole) []rbac.ClusterRoleBinding { out := []rbac.ClusterRoleBinding{} for _, cr := range clusterRoles { out = append(out, rbac.ClusterRoleBinding{ diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index 0bf57992..6fe64370 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -14,7 +14,7 @@ import ( func TestGenerateRBAC(t *testing.T) { // Use these test cases to check if Generate function is correct testCases := []struct { - // expectedClusterRoles is the collection of ClusterRole + expectedClusterRoles []rbac.ClusterRole expectedClusterRoleBindings []rbac.ClusterRoleBinding dataGatherers []agent.DataGatherer description string @@ -22,7 +22,6 @@ func TestGenerateRBAC(t *testing.T) { { description: "Generate RBAC struct for pods datagatherer", dataGatherers: []agent.DataGatherer{ - { Name: "k8s/secrets", Kind: "k8s-dynamic", @@ -34,6 +33,24 @@ func TestGenerateRBAC(t *testing.T) { }, }, }, + expectedClusterRoles: []rbac.ClusterRole{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-secrets-reader", + }, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{""}, + Resources: []string{"secrets"}, + }, + }, + }, + }, expectedClusterRoleBindings: []rbac.ClusterRoleBinding{ { TypeMeta: metav1.TypeMeta{ @@ -62,9 +79,10 @@ func TestGenerateRBAC(t *testing.T) { } for _, input := range testCases { - got := GenerateRoles(input.dataGatherers) - toBeTest := GenerateBindings(got) + gotClusterRoles := GenerateClusterRoles(input.dataGatherers) + gotClusterRoleBindings := GenerateClusterRoleBindings(gotClusterRoles) - td.Cmp(t, input.expectedClusterRoleBindings, toBeTest) + td.Cmp(t, input.expectedClusterRoleBindings, gotClusterRoleBindings) + td.Cmp(t, input.expectedClusterRoles, gotClusterRoles) } } From 6eded64e25ced7156fc335bca4e2c3ea0f395455 Mon Sep 17 00:00:00 2001 From: wenlin Date: Mon, 9 Aug 2021 11:39:50 +0100 Subject: [PATCH 4/9] Correctly generate ClusterRole & CRB --- pkg/permissions/generate.go | 6 +- pkg/permissions/generate_test.go | 100 ++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 8 deletions(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index 89118929..6801b512 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -74,10 +74,6 @@ func GenerateClusterRoles(dataGatherer []agent.DataGatherer) []rbac.ClusterRole return out } -// func SelectNamespace(all, include, exclude) selected { - -// } - func GenerateClusterRoleBindings(clusterRoles []rbac.ClusterRole) []rbac.ClusterRoleBinding { out := []rbac.ClusterRoleBinding{} for _, cr := range clusterRoles { @@ -88,7 +84,7 @@ func GenerateClusterRoleBindings(clusterRoles []rbac.ClusterRole) []rbac.Cluster }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("jetstack-secure-agent-%s-reader", cr.TypeMeta.Kind), + Name: cr.ObjectMeta.Name, }, Subjects: []rbac.Subject{ diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index 6fe64370..6705d1fc 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -22,6 +22,16 @@ func TestGenerateRBAC(t *testing.T) { { description: "Generate RBAC struct for pods datagatherer", dataGatherers: []agent.DataGatherer{ + { + Name: "k8s/pods", + Kind: "k8s-dynamic", + Config: &k8s.ConfigDynamic{ + GroupVersionResource: schema.GroupVersionResource{ + Version: "v1", + Resource: "pods", + }, + }, + }, { Name: "k8s/secrets", Kind: "k8s-dynamic", @@ -32,8 +42,35 @@ func TestGenerateRBAC(t *testing.T) { }, }, }, + { + Name: "k8s/awspcaissuer", + Kind: "k8s-dynamic", + Config: &k8s.ConfigDynamic{ + GroupVersionResource: schema.GroupVersionResource{ + Group: "awspca.cert-manager.io", + Version: "v1", + Resource: "awspcaissuers", + }, + }, + }, }, expectedClusterRoles: []rbac.ClusterRole{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-pods-reader", + }, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{""}, + Resources: []string{"pods"}, + }, + }, + }, { TypeMeta: metav1.TypeMeta{ Kind: "ClusterRole", @@ -50,6 +87,22 @@ func TestGenerateRBAC(t *testing.T) { }, }, }, + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-awspcaissuers-reader", + }, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{"awspca.cert-manager.io"}, + Resources: []string{"awspcaissuers"}, + }, + }, + }, }, expectedClusterRoleBindings: []rbac.ClusterRoleBinding{ { @@ -58,7 +111,28 @@ func TestGenerateRBAC(t *testing.T) { APIVersion: "rbac.authorization.k8s.io/v1", }, ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-ClusterRole-reader", + Name: "jetstack-secure-agent-pods-reader", + }, + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: "jetstack-secure-agent-pods-reader", + APIGroup: "rbac.authorization.k8s.io", + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-secrets-reader", }, Subjects: []rbac.Subject{ { @@ -73,16 +147,36 @@ func TestGenerateRBAC(t *testing.T) { APIGroup: "rbac.authorization.k8s.io", }, }, + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-awspcaissuers-reader", + }, + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: "jetstack-secure-agent-awspcaissuers-reader", + APIGroup: "rbac.authorization.k8s.io", + }, + }, }, }, - // Try adding more test cases } for _, input := range testCases { gotClusterRoles := GenerateClusterRoles(input.dataGatherers) gotClusterRoleBindings := GenerateClusterRoleBindings(gotClusterRoles) - td.Cmp(t, input.expectedClusterRoleBindings, gotClusterRoleBindings) td.Cmp(t, input.expectedClusterRoles, gotClusterRoles) + td.Cmp(t, input.expectedClusterRoleBindings, gotClusterRoleBindings) } } From 641368c0573813d1bc42386aee64bdaccd525f5d Mon Sep 17 00:00:00 2001 From: wenlin Date: Mon, 9 Aug 2021 15:30:45 +0100 Subject: [PATCH 5/9] Fit ClusterRole and CRB into a manifest struct --- pkg/permissions/generate.go | 75 ++++--------- pkg/permissions/generate_test.go | 175 +++++++------------------------ 2 files changed, 62 insertions(+), 188 deletions(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index 6801b512..35b737ea 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -2,7 +2,6 @@ package permissions import ( "fmt" - "strings" "github.com/jetstack/preflight/pkg/agent" "github.com/jetstack/preflight/pkg/datagatherer/k8s" @@ -10,81 +9,53 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func Generate(dataGatherers []agent.DataGatherer) string { - var accumulator string = "" - - for _, g := range dataGatherers { - if g.Kind != "k8s-dynamic" { - continue - } - - genericConfig := g.Config - dyConfig := genericConfig.(*k8s.ConfigDynamic) - - metaName := fmt.Sprint(dyConfig.GroupVersionResource.Resource) - - accumulator = fmt.Sprintf(`%s -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: jetstack-secure-agent-%s-reader -rules: -- apiGroups: ["%s"] - resources: ["%s"] - verbs: ["get", "list", "watch"] ----`, accumulator, metaName, dyConfig.GroupVersionResource.Group, dyConfig.GroupVersionResource.Resource) - } - - s := strings.TrimPrefix(accumulator, "\n") - ss := strings.TrimSuffix(s, "---") - return strings.TrimSuffix(ss, "\n") +// AgentRBACManifests is a wrapper around the various RBAC structs needed to grant the agent fine-grained permissions as per its dg configs +type AgentRBACManifests struct { + // ClusterRoles is a list of roles for resources the agent will collect + ClusterRoles []rbac.ClusterRole + // ClusterRoleBindings is a list of crbs for resources which have no include/exclude ns configured + ClusterRoleBindings []rbac.ClusterRoleBinding + // RoleBindings is a list of namespaced bindings to grant permissions when include/exclude ns set + RoleBindings []rbac.RoleBinding } -func GenerateClusterRoles(dataGatherer []agent.DataGatherer) []rbac.ClusterRole { - out := []rbac.ClusterRole{} +func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACManifests { + // create a new AgentRBACManifest struct + var AgentRBACManifests AgentRBACManifests - for _, g := range dataGatherer { - if g.Kind != "k8s-dynamic" { + for _, dg := range dataGatherers { + if dg.Kind != "k8s-dynamic" { continue } - genericConfig := g.Config - dyConfig := genericConfig.(*k8s.ConfigDynamic) - - metaName := dyConfig.GroupVersionResource.Resource + dyConfig := dg.Config.(*k8s.ConfigDynamic) + metadataName := fmt.Sprintf("jetstack-secure-agent-%s-reader", dyConfig.GroupVersionResource.Resource) - out = append(out, rbac.ClusterRole{ + AgentRBACManifests.ClusterRoles = append(AgentRBACManifests.ClusterRoles, rbac.ClusterRole{ TypeMeta: metav1.TypeMeta{ Kind: "ClusterRole", APIVersion: "rbac.authorization.k8s.io/v1", }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("jetstack-secure-agent-%s-reader", metaName), + Name: metadataName, }, Rules: []rbac.PolicyRule{ { Verbs: []string{"get", "list", "watch"}, APIGroups: []string{dyConfig.GroupVersionResource.Group}, - Resources: []string{metaName}, + Resources: []string{dyConfig.GroupVersionResource.Resource}, }, }, }) - } - return out -} - -func GenerateClusterRoleBindings(clusterRoles []rbac.ClusterRole) []rbac.ClusterRoleBinding { - out := []rbac.ClusterRoleBinding{} - for _, cr := range clusterRoles { - out = append(out, rbac.ClusterRoleBinding{ + AgentRBACManifests.ClusterRoleBindings = append(AgentRBACManifests.ClusterRoleBindings, rbac.ClusterRoleBinding{ TypeMeta: metav1.TypeMeta{ Kind: "ClusterRoleBinding", APIVersion: "rbac.authorization.k8s.io/v1", }, ObjectMeta: metav1.ObjectMeta{ - Name: cr.ObjectMeta.Name, + Name: metadataName, }, Subjects: []rbac.Subject{ @@ -97,11 +68,11 @@ func GenerateClusterRoleBindings(clusterRoles []rbac.ClusterRole) []rbac.Cluster RoleRef: rbac.RoleRef{ Kind: "ClusterRole", - Name: cr.ObjectMeta.Name, + Name: metadataName, APIGroup: "rbac.authorization.k8s.io", }, }) - } - return out + + return AgentRBACManifests } diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index 6705d1fc..2f76ec69 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -11,16 +11,14 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -func TestGenerateRBAC(t *testing.T) { - // Use these test cases to check if Generate function is correct +func TestGenerateAgentRBACManifests(t *testing.T) { testCases := []struct { - expectedClusterRoles []rbac.ClusterRole - expectedClusterRoleBindings []rbac.ClusterRoleBinding - dataGatherers []agent.DataGatherer - description string + description string + dataGatherers []agent.DataGatherer + expectedAgentRBACManifests AgentRBACManifests }{ { - description: "Generate RBAC struct for pods datagatherer", + description: "Generate ClusterRole and ClusterRoleBinding for simple pod dg case", dataGatherers: []agent.DataGatherer{ { Name: "k8s/pods", @@ -32,140 +30,47 @@ func TestGenerateRBAC(t *testing.T) { }, }, }, - { - Name: "k8s/secrets", - Kind: "k8s-dynamic", - Config: &k8s.ConfigDynamic{ - GroupVersionResource: schema.GroupVersionResource{ - Version: "v1", - Resource: "secrets", - }, - }, - }, - { - Name: "k8s/awspcaissuer", - Kind: "k8s-dynamic", - Config: &k8s.ConfigDynamic{ - GroupVersionResource: schema.GroupVersionResource{ - Group: "awspca.cert-manager.io", - Version: "v1", - Resource: "awspcaissuers", - }, - }, - }, }, - expectedClusterRoles: []rbac.ClusterRole{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-pods-reader", - }, - Rules: []rbac.PolicyRule{ - { - Verbs: []string{"get", "list", "watch"}, - APIGroups: []string{""}, - Resources: []string{"pods"}, + expectedAgentRBACManifests: AgentRBACManifests{ + ClusterRoles: []rbac.ClusterRole{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", }, - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-secrets-reader", - }, - Rules: []rbac.PolicyRule{ - { - Verbs: []string{"get", "list", "watch"}, - APIGroups: []string{""}, - Resources: []string{"secrets"}, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-pods-reader", }, - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRole", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-awspcaissuers-reader", - }, - Rules: []rbac.PolicyRule{ - { - Verbs: []string{"get", "list", "watch"}, - APIGroups: []string{"awspca.cert-manager.io"}, - Resources: []string{"awspcaissuers"}, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{""}, + Resources: []string{"pods"}, + }, }, }, }, - }, - expectedClusterRoleBindings: []rbac.ClusterRoleBinding{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRoleBinding", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-pods-reader", - }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: "agent", - Namespace: "jetstack-secure", + ClusterRoleBindings: []rbac.ClusterRoleBinding{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", }, - }, - RoleRef: rbac.RoleRef{ - Kind: "ClusterRole", - Name: "jetstack-secure-agent-pods-reader", - APIGroup: "rbac.authorization.k8s.io", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRoleBinding", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-secrets-reader", - }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: "agent", - Namespace: "jetstack-secure", + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-pods-reader", }, - }, - RoleRef: rbac.RoleRef{ - Kind: "ClusterRole", - Name: "jetstack-secure-agent-secrets-reader", - APIGroup: "rbac.authorization.k8s.io", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRoleBinding", - APIVersion: "rbac.authorization.k8s.io/v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "jetstack-secure-agent-awspcaissuers-reader", - }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: "agent", - Namespace: "jetstack-secure", + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: "jetstack-secure-agent-pods-reader", + APIGroup: "rbac.authorization.k8s.io", }, - }, - RoleRef: rbac.RoleRef{ - Kind: "ClusterRole", - Name: "jetstack-secure-agent-awspcaissuers-reader", - APIGroup: "rbac.authorization.k8s.io", }, }, }, @@ -173,10 +78,8 @@ func TestGenerateRBAC(t *testing.T) { } for _, input := range testCases { - gotClusterRoles := GenerateClusterRoles(input.dataGatherers) - gotClusterRoleBindings := GenerateClusterRoleBindings(gotClusterRoles) + got := GenerateAgentRBACManifests(input.dataGatherers) - td.Cmp(t, input.expectedClusterRoles, gotClusterRoles) - td.Cmp(t, input.expectedClusterRoleBindings, gotClusterRoleBindings) + td.Cmp(t, input.expectedAgentRBACManifests, got) } } From c38ec6bc935026b8e4fe42e3170fd4df68f9d4e2 Mon Sep 17 00:00:00 2001 From: wenlin Date: Mon, 9 Aug 2021 16:51:44 +0100 Subject: [PATCH 6/9] Add making RoleBiding Functionality Signed-off-by: wenlin --- pkg/permissions/generate.go | 77 +++++++++++++++++++++-------- pkg/permissions/generate_test.go | 84 +++++++++++++++++++++++++++++++- 2 files changed, 140 insertions(+), 21 deletions(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index 35b737ea..8ac23dad 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -19,6 +19,7 @@ type AgentRBACManifests struct { RoleBindings []rbac.RoleBinding } +//func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer, konwnNamespaces []string) AgentRBACManifests { func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACManifests { // create a new AgentRBACManifest struct var AgentRBACManifests AgentRBACManifests @@ -31,6 +32,7 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan dyConfig := dg.Config.(*k8s.ConfigDynamic) metadataName := fmt.Sprintf("jetstack-secure-agent-%s-reader", dyConfig.GroupVersionResource.Resource) + // always do this... AgentRBACManifests.ClusterRoles = append(AgentRBACManifests.ClusterRoles, rbac.ClusterRole{ TypeMeta: metav1.TypeMeta{ Kind: "ClusterRole", @@ -48,30 +50,65 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan }, }) - AgentRBACManifests.ClusterRoleBindings = append(AgentRBACManifests.ClusterRoleBindings, rbac.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - Kind: "ClusterRoleBinding", - APIVersion: "rbac.authorization.k8s.io/v1", - }, + // if dyConfig.IncludeNamespaces has more than 0 items in it + // then, for each namespace create a rbac.RoleBinding in that namespace + // AgentRBACManifests.RoleBindings = append(...) + if len(dyConfig.IncludeNamespaces) != 0 { + for _, ns := range dyConfig.IncludeNamespaces { + AgentRBACManifests.RoleBindings = append(AgentRBACManifests.RoleBindings, rbac.RoleBinding{ + TypeMeta: metav1.TypeMeta{ + Kind: "RoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, - ObjectMeta: metav1.ObjectMeta{ - Name: metadataName, - }, + ObjectMeta: metav1.ObjectMeta{ + Name: metadataName, + Namespace: ns, + }, - Subjects: []rbac.Subject{ - { - Kind: "ServiceAccount", - Name: "agent", - Namespace: "jetstack-secure", + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: metadataName, + APIGroup: "rbac.authorization.k8s.io", + }, + }) + } + } else { + // only do this if the dg does not have IncludeNamespaces set + AgentRBACManifests.ClusterRoleBindings = append(AgentRBACManifests.ClusterRoleBindings, rbac.ClusterRoleBinding{ + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", }, - }, - RoleRef: rbac.RoleRef{ - Kind: "ClusterRole", - Name: metadataName, - APIGroup: "rbac.authorization.k8s.io", - }, - }) + ObjectMeta: metav1.ObjectMeta{ + Name: metadataName, + }, + + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: metadataName, + APIGroup: "rbac.authorization.k8s.io", + }, + }) + } + } return AgentRBACManifests diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index 2f76ec69..61bd8e0b 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -18,7 +18,7 @@ func TestGenerateAgentRBACManifests(t *testing.T) { expectedAgentRBACManifests AgentRBACManifests }{ { - description: "Generate ClusterRole and ClusterRoleBinding for simple pod dg case", + description: "Generate ClusterRole and ClusterRoleBinding for simple pod dg use case", dataGatherers: []agent.DataGatherer{ { Name: "k8s/pods", @@ -75,6 +75,88 @@ func TestGenerateAgentRBACManifests(t *testing.T) { }, }, }, + { + description: "Generate RBAC config for simple pod dg use case where single namespace is set", + dataGatherers: []agent.DataGatherer{ + { + Name: "k8s/pods", + Kind: "k8s-dynamic", + Config: &k8s.ConfigDynamic{ + GroupVersionResource: schema.GroupVersionResource{ + Version: "v1", + Resource: "pods", + }, + IncludeNamespaces: []string{"example", "foobar"}, + }, + }, + }, + expectedAgentRBACManifests: AgentRBACManifests{ + ClusterRoles: []rbac.ClusterRole{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "ClusterRole", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-pods-reader", + }, + Rules: []rbac.PolicyRule{ + { + Verbs: []string{"get", "list", "watch"}, + APIGroups: []string{""}, + Resources: []string{"pods"}, + }, + }, + }, + }, + RoleBindings: []rbac.RoleBinding{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "RoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-pods-reader", + Namespace: "example", + }, + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: "jetstack-secure-agent-pods-reader", + APIGroup: "rbac.authorization.k8s.io", + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: "RoleBinding", + APIVersion: "rbac.authorization.k8s.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "jetstack-secure-agent-pods-reader", + Namespace: "foobar", + }, + Subjects: []rbac.Subject{ + { + Kind: "ServiceAccount", + Name: "agent", + Namespace: "jetstack-secure", + }, + }, + RoleRef: rbac.RoleRef{ + Kind: "ClusterRole", + Name: "jetstack-secure-agent-pods-reader", + APIGroup: "rbac.authorization.k8s.io", + }, + }, + }, + }, + }, } for _, input := range testCases { From 56846f67a2ebf0de87e9abd308d714757c343bd7 Mon Sep 17 00:00:00 2001 From: wenlin Date: Thu, 12 Aug 2021 10:56:26 +0100 Subject: [PATCH 7/9] Make the IncludeNamespace working --- pkg/permissions/generate_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/permissions/generate_test.go b/pkg/permissions/generate_test.go index 61bd8e0b..8efbc6de 100644 --- a/pkg/permissions/generate_test.go +++ b/pkg/permissions/generate_test.go @@ -76,7 +76,7 @@ func TestGenerateAgentRBACManifests(t *testing.T) { }, }, { - description: "Generate RBAC config for simple pod dg use case where single namespace is set", + description: "Generate RBAC config for simple pod dg use case where only two namespace are included", dataGatherers: []agent.DataGatherer{ { Name: "k8s/pods", From 861f14154edca103c498b0f48230786abfb48cb0 Mon Sep 17 00:00:00 2001 From: wenlin Date: Thu, 12 Aug 2021 11:17:01 +0100 Subject: [PATCH 8/9] Update generate.go on delete comment and make string into const --- pkg/permissions/generate.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index 8ac23dad..ff651e56 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -19,6 +19,9 @@ type AgentRBACManifests struct { RoleBindings []rbac.RoleBinding } +const agentNamespace = "jetstack-secure" +const agentSubjectName = "agent" + //func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer, konwnNamespaces []string) AgentRBACManifests { func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACManifests { // create a new AgentRBACManifest struct @@ -30,9 +33,8 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan } dyConfig := dg.Config.(*k8s.ConfigDynamic) - metadataName := fmt.Sprintf("jetstack-secure-agent-%s-reader", dyConfig.GroupVersionResource.Resource) + metadataName := fmt.Sprintf("%s-agent-%s-reader", agentNamespace, dyConfig.GroupVersionResource.Resource) - // always do this... AgentRBACManifests.ClusterRoles = append(AgentRBACManifests.ClusterRoles, rbac.ClusterRole{ TypeMeta: metav1.TypeMeta{ Kind: "ClusterRole", @@ -52,7 +54,6 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan // if dyConfig.IncludeNamespaces has more than 0 items in it // then, for each namespace create a rbac.RoleBinding in that namespace - // AgentRBACManifests.RoleBindings = append(...) if len(dyConfig.IncludeNamespaces) != 0 { for _, ns := range dyConfig.IncludeNamespaces { AgentRBACManifests.RoleBindings = append(AgentRBACManifests.RoleBindings, rbac.RoleBinding{ @@ -69,8 +70,8 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan Subjects: []rbac.Subject{ { Kind: "ServiceAccount", - Name: "agent", - Namespace: "jetstack-secure", + Name: agentSubjectName, + Namespace: agentNamespace, }, }, @@ -96,8 +97,8 @@ func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACMan Subjects: []rbac.Subject{ { Kind: "ServiceAccount", - Name: "agent", - Namespace: "jetstack-secure", + Name: agentSubjectName, + Namespace: agentNamespace, }, }, From 38da52c1e4e7457c07ed51cbc98c3ad2edc9c64d Mon Sep 17 00:00:00 2001 From: wenlin Date: Thu, 12 Aug 2021 11:23:42 +0100 Subject: [PATCH 9/9] delete unnessessary comment --- pkg/permissions/generate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/permissions/generate.go b/pkg/permissions/generate.go index ff651e56..61711ea3 100644 --- a/pkg/permissions/generate.go +++ b/pkg/permissions/generate.go @@ -22,7 +22,6 @@ type AgentRBACManifests struct { const agentNamespace = "jetstack-secure" const agentSubjectName = "agent" -//func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer, konwnNamespaces []string) AgentRBACManifests { func GenerateAgentRBACManifests(dataGatherers []agent.DataGatherer) AgentRBACManifests { // create a new AgentRBACManifest struct var AgentRBACManifests AgentRBACManifests