Skip to content

Commit 0e786fa

Browse files
authored
Merge pull request #35 from sysdiglabs/kh_psp_with_role_and_rolebindings
Kh psp with role and rolebindings
2 parents 49d3faa + 8696fb8 commit 0e786fa

File tree

10 files changed

+497
-38
lines changed

10 files changed

+497
-38
lines changed

advisor/advisor.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"os"
77

8+
"github.com/sysdiglabs/kube-psp-advisor/advisor/types"
9+
810
"github.com/sysdiglabs/kube-psp-advisor/advisor/processor"
911
"github.com/sysdiglabs/kube-psp-advisor/advisor/report"
1012

@@ -19,6 +21,8 @@ type Advisor struct {
1921
k8sClient *kubernetes.Clientset
2022
processor *processor.Processor
2123
report *report.Report
24+
grants []types.PSPGrant
25+
grantWarnings string
2226
}
2327

2428
// Create an podSecurityPolicy advisor instance
@@ -33,6 +37,7 @@ func NewAdvisor(kubeconfig string) (*Advisor, error) {
3337
podSecurityPolicy: nil,
3438
processor: p,
3539
report: nil,
40+
grants: []types.PSPGrant{},
3641
}, nil
3742
}
3843

@@ -49,6 +54,8 @@ func (advisor *Advisor) Process(namespace string) error {
4954

5055
advisor.report = advisor.processor.GenerateReport(cssList, pssList)
5156

57+
advisor.grants, advisor.grantWarnings = advisor.processor.GeneratePSPGrant(cssList, pssList)
58+
5259
return nil
5360
}
5461

@@ -72,3 +79,41 @@ func (advisor *Advisor) PrintPodSecurityPolicy() error {
7279
func (advisor *Advisor) GetPodSecurityPolicy() *v1beta1.PodSecurityPolicy {
7380
return advisor.podSecurityPolicy
7481
}
82+
83+
func (advisor *Advisor) PrintPodSecurityPolicyWithGrants() error {
84+
var err error
85+
e := k8sJSON.NewYAMLSerializer(k8sJSON.DefaultMetaFactory, nil, nil)
86+
87+
if advisor.grantWarnings != "" {
88+
fmt.Println(advisor.grantWarnings)
89+
printYamlSeparator()
90+
}
91+
92+
for _, pspGrant := range advisor.grants {
93+
fmt.Println(pspGrant.Comment)
94+
95+
if err = e.Encode(pspGrant.PodSecurityPolicy, os.Stdout); err != nil {
96+
return err
97+
}
98+
99+
printYamlSeparator()
100+
101+
if err = e.Encode(pspGrant.Role, os.Stdout); err != nil {
102+
return err
103+
}
104+
105+
printYamlSeparator()
106+
107+
if err = e.Encode(pspGrant.RoleBinding, os.Stdout); err != nil {
108+
return err
109+
}
110+
111+
printYamlSeparator()
112+
}
113+
114+
return nil
115+
}
116+
117+
func printYamlSeparator() {
118+
fmt.Println("---")
119+
}

advisor/processor/generate.go

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package processor
22

33
import (
44
"fmt"
5+
"sort"
56

67
"github.com/sysdiglabs/kube-psp-advisor/advisor/report"
78
"github.com/sysdiglabs/kube-psp-advisor/advisor/types"
@@ -55,12 +56,60 @@ func (p *Processor) SetNamespace(ns string) {
5556
p.namespace = ns
5657
}
5758

58-
// GeneratePSP generate Pod Security Policy
59+
// GeneratePSP generates Pod Security Policy
5960
func (p *Processor) GeneratePSP(cssList []types.ContainerSecuritySpec, pssList []types.PodSecuritySpec) *v1beta1.PodSecurityPolicy {
60-
6161
return p.gen.GeneratePSP(cssList, pssList, p.namespace, p.serverGitVersion)
6262
}
6363

64+
// GeneratePSPGrant generates Pod Security Policies, Roles, RoleBindings for service accounts to use PSP
65+
func (p *Processor) GeneratePSPGrant(cssList []types.ContainerSecuritySpec, pssList []types.PodSecuritySpec) ([]types.PSPGrant, string) {
66+
saSecuritySpecMap := map[string]*types.SASecuritySpec{}
67+
pspGrantList := []types.PSPGrant{}
68+
grantWarnings := ""
69+
70+
for _, css := range cssList {
71+
key := fmt.Sprintf("%s:%s", css.Namespace, css.ServiceAccount)
72+
if _, exists := saSecuritySpecMap[key]; !exists {
73+
saSecuritySpecMap[key] = types.NewSASecuritySpec(css.Namespace, css.ServiceAccount)
74+
}
75+
saSecuritySpecMap[key].AddContainerSecuritySpec(css)
76+
}
77+
78+
for _, pss := range pssList {
79+
key := fmt.Sprintf("%s:%s", pss.Namespace, pss.ServiceAccount)
80+
if _, exists := saSecuritySpecMap[key]; !exists {
81+
saSecuritySpecMap[key] = types.NewSASecuritySpec(pss.Namespace, pss.ServiceAccount)
82+
}
83+
saSecuritySpecMap[key].AddPodSecuritySpec(pss)
84+
}
85+
86+
saSecuritySpecList := types.SASecuritySpecList{}
87+
88+
// convert saSecuritySpecMap into list and then sort
89+
for _, saSecuritySpec := range saSecuritySpecMap {
90+
saSecuritySpecList = append(saSecuritySpecList, saSecuritySpec)
91+
}
92+
93+
sort.Sort(saSecuritySpecList)
94+
95+
for _, s := range saSecuritySpecList {
96+
if !s.IsDefaultServiceAccount() {
97+
pspGrant := types.PSPGrant{
98+
Comment: s.GenerateComment(),
99+
Role: s.GenerateRole(),
100+
RoleBinding: s.GenerateRoleBinding(),
101+
PodSecurityPolicy: p.gen.GeneratePSPWithName(s.ContainerSecuritySpecList, s.PodSecuritySpecList, s.Namespace, p.serverGitVersion, s.GeneratePSPName()),
102+
}
103+
104+
pspGrantList = append(pspGrantList, pspGrant)
105+
} else {
106+
grantWarnings += s.GenerateComment()
107+
}
108+
}
109+
110+
return pspGrantList, grantWarnings
111+
}
112+
64113
// GenerateReport generate a JSON report
65114
func (p *Processor) GenerateReport(cssList []types.ContainerSecuritySpec, pssList []types.PodSecuritySpec) *report.Report {
66115
r := report.NewReport()

advisor/processor/get.go

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package processor
22

33
import (
4+
"fmt"
5+
46
"github.com/sysdiglabs/kube-psp-advisor/advisor/types"
57

68
"k8s.io/api/core/v1"
7-
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
v1meta "k8s.io/apimachinery/pkg/apis/meta/v1"
810
)
911

1012
const (
@@ -23,14 +25,15 @@ func (p *Processor) getSecuritySpecFromDaemonSets() ([]types.ContainerSecuritySp
2325
cspList := []types.ContainerSecuritySpec{}
2426
pspList := []types.PodSecuritySpec{}
2527

26-
daemonSetList, err := clientset.AppsV1().DaemonSets(p.namespace).List(v12.ListOptions{})
28+
daemonSetList, err := clientset.AppsV1().DaemonSets(p.namespace).List(v1meta.ListOptions{})
2729

2830
if err != nil {
2931
return cspList, pspList, err
3032
}
3133

3234
for _, ds := range daemonSetList.Items {
33-
sa := p.serviceAccountMap[ds.Spec.Template.Spec.ServiceAccountName]
35+
sa := p.GetServiceAccount(ds.Namespace, ds.Spec.Template.Spec.ServiceAccountName)
36+
3437
cspList2, podSecurityPosture := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
3538
Name: ds.Name,
3639
Kind: DaemonSet,
@@ -48,7 +51,7 @@ func (p *Processor) getSecuritySpecFromReplicaSets() ([]types.ContainerSecurityS
4851
cssList := []types.ContainerSecuritySpec{}
4952
pssList := []types.PodSecuritySpec{}
5053

51-
replicaSetList, err := clientset.AppsV1().ReplicaSets(p.namespace).List(v12.ListOptions{})
54+
replicaSetList, err := clientset.AppsV1().ReplicaSets(p.namespace).List(v1meta.ListOptions{})
5255

5356
if err != nil {
5457
return cssList, pssList, err
@@ -59,7 +62,7 @@ func (p *Processor) getSecuritySpecFromReplicaSets() ([]types.ContainerSecurityS
5962
continue
6063
}
6164

62-
sa := p.serviceAccountMap[rs.Spec.Template.Spec.ServiceAccountName]
65+
sa := p.GetServiceAccount(rs.Namespace, rs.Spec.Template.Spec.ServiceAccountName)
6366
cspList2, psc := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
6467
Name: rs.Name,
6568
Kind: ReplicaSet,
@@ -77,14 +80,14 @@ func (p *Processor) getSecuritySpecFromStatefulSets() ([]types.ContainerSecurity
7780
cssList := []types.ContainerSecuritySpec{}
7881
pssList := []types.PodSecuritySpec{}
7982

80-
statefulSetList, err := clientset.AppsV1().StatefulSets(p.namespace).List(v12.ListOptions{})
83+
statefulSetList, err := clientset.AppsV1().StatefulSets(p.namespace).List(v1meta.ListOptions{})
8184

8285
if err != nil {
8386
return cssList, pssList, err
8487
}
8588

8689
for _, sts := range statefulSetList.Items {
87-
sa := p.serviceAccountMap[sts.Spec.Template.Spec.ServiceAccountName]
90+
sa := p.GetServiceAccount(sts.Namespace, sts.Spec.Template.Spec.ServiceAccountName)
8891
cspList2, pss := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
8992
Name: sts.Name,
9093
Kind: StatefulSet,
@@ -102,14 +105,14 @@ func (p *Processor) getSecuritySpecFromReplicationController() ([]types.Containe
102105
cssList := []types.ContainerSecuritySpec{}
103106
pssList := []types.PodSecuritySpec{}
104107

105-
replicationControllerList, err := clientset.CoreV1().ReplicationControllers(p.namespace).List(v12.ListOptions{})
108+
replicationControllerList, err := clientset.CoreV1().ReplicationControllers(p.namespace).List(v1meta.ListOptions{})
106109

107110
if err != nil {
108111
return cssList, pssList, err
109112
}
110113

111114
for _, rc := range replicationControllerList.Items {
112-
sa := p.serviceAccountMap[rc.Spec.Template.Spec.ServiceAccountName]
115+
sa := p.GetServiceAccount(rc.Namespace, rc.Spec.Template.Spec.ServiceAccountName)
113116
cspList2, pss := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
114117
Name: rc.Name,
115118
Kind: ReplicationController,
@@ -127,14 +130,14 @@ func (p *Processor) getSecuritySpecFromCronJobs() ([]types.ContainerSecuritySpec
127130
cssList := []types.ContainerSecuritySpec{}
128131
pssList := []types.PodSecuritySpec{}
129132

130-
jobList, err := clientset.BatchV1beta1().CronJobs(p.namespace).List(v12.ListOptions{})
133+
jobList, err := clientset.BatchV1beta1().CronJobs(p.namespace).List(v1meta.ListOptions{})
131134

132135
if err != nil {
133136
return cssList, pssList, err
134137
}
135138

136139
for _, cronJob := range jobList.Items {
137-
sa := p.serviceAccountMap[cronJob.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName]
140+
sa := p.GetServiceAccount(cronJob.Namespace, cronJob.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName)
138141
cspList2, pss := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
139142
Name: cronJob.Name,
140143
Kind: CronJob,
@@ -152,7 +155,7 @@ func (p *Processor) getSecuritySpecFromJobs() ([]types.ContainerSecuritySpec, []
152155
cssList := []types.ContainerSecuritySpec{}
153156
pssList := []types.PodSecuritySpec{}
154157

155-
jobList, err := clientset.BatchV1().Jobs(p.namespace).List(v12.ListOptions{})
158+
jobList, err := clientset.BatchV1().Jobs(p.namespace).List(v1meta.ListOptions{})
156159

157160
if err != nil {
158161
return cssList, pssList, err
@@ -162,7 +165,7 @@ func (p *Processor) getSecuritySpecFromJobs() ([]types.ContainerSecuritySpec, []
162165
if len(job.OwnerReferences) > 0 {
163166
continue
164167
}
165-
sa := p.serviceAccountMap[job.Spec.Template.Spec.ServiceAccountName]
168+
sa := p.GetServiceAccount(job.Namespace, job.Spec.Template.Spec.ServiceAccountName)
166169
cspList2, pss := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
167170
Name: job.Name,
168171
Kind: Job,
@@ -180,14 +183,14 @@ func (p *Processor) getSecuritySpecFromDeployments() ([]types.ContainerSecurityS
180183
cssList := []types.ContainerSecuritySpec{}
181184
pssList := []types.PodSecuritySpec{}
182185

183-
deployments, err := clientset.AppsV1().Deployments(p.namespace).List(v12.ListOptions{})
186+
deployments, err := clientset.AppsV1().Deployments(p.namespace).List(v1meta.ListOptions{})
184187

185188
if err != nil {
186189
return cssList, pssList, err
187190
}
188191

189192
for _, deploy := range deployments.Items {
190-
sa := p.serviceAccountMap[deploy.Spec.Template.Spec.ServiceAccountName]
193+
sa := p.GetServiceAccount(deploy.Namespace, deploy.Spec.Template.Spec.ServiceAccountName)
191194
cspList2, pss := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
192195
Name: deploy.Name,
193196
Kind: Deployment,
@@ -205,7 +208,7 @@ func (p *Processor) getSecuritySpecFromPods() ([]types.ContainerSecuritySpec, []
205208
cssList := []types.ContainerSecuritySpec{}
206209
pssList := []types.PodSecuritySpec{}
207210

208-
pods, err := clientset.CoreV1().Pods(p.namespace).List(v12.ListOptions{})
211+
pods, err := clientset.CoreV1().Pods(p.namespace).List(v1meta.ListOptions{})
209212

210213
if err != nil {
211214
return cssList, pssList, err
@@ -216,7 +219,7 @@ func (p *Processor) getSecuritySpecFromPods() ([]types.ContainerSecuritySpec, []
216219
continue
217220
}
218221

219-
sa := p.serviceAccountMap[pod.Spec.ServiceAccountName]
222+
sa := p.GetServiceAccount(pod.Namespace, pod.Spec.ServiceAccountName)
220223
cspList2, podSecurityPosture := p.gen.GetSecuritySpecFromPodSpec(types.Metadata{
221224
Name: pod.Name,
222225
Kind: Pod,
@@ -232,14 +235,32 @@ func (p *Processor) getSecuritySpecFromPods() ([]types.ContainerSecuritySpec, []
232235
func (p *Processor) getServiceAccountMap() (map[string]v1.ServiceAccount, error) {
233236
serviceAccountMap := map[string]v1.ServiceAccount{}
234237

235-
serviceAccounts, err := p.k8sClient.CoreV1().ServiceAccounts(p.namespace).List(v12.ListOptions{})
238+
serviceAccounts, err := p.k8sClient.CoreV1().ServiceAccounts(p.namespace).List(v1meta.ListOptions{})
236239
if err != nil {
237240
return serviceAccountMap, err
238241
}
239242

243+
// service account is an namespaced object
240244
for _, sa := range serviceAccounts.Items {
241-
serviceAccountMap[sa.Name] = sa
245+
key := fmt.Sprintf("%s:%s", sa.Namespace, sa.Name)
246+
serviceAccountMap[key] = sa
242247
}
243248

244249
return serviceAccountMap, nil
245250
}
251+
252+
func (p *Processor) GetServiceAccount(ns, saName string) v1.ServiceAccount {
253+
if saName == "" {
254+
saName = "default"
255+
}
256+
257+
key := fmt.Sprintf("%s:%s", ns, saName)
258+
259+
sa, exists := p.serviceAccountMap[key]
260+
261+
if !exists {
262+
return v1.ServiceAccount{}
263+
}
264+
265+
return sa
266+
}

0 commit comments

Comments
 (0)