Update ScanSA calls to account for blank service accounts (#1871)

The original check in ScanSA assumed the service account on the pod spec
was not blank. It can be blank and when it is kubernetes will default
to using the 'default' service account. This change extends the check
logic to also include that.
mine
Dan Ramich 2022-12-03 07:12:27 -07:00 committed by GitHub
parent b0c7f8d61c
commit 3f280ca133
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 56 additions and 6 deletions

View File

@ -98,7 +98,7 @@ func (c *CronJob) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, erro
if err != nil {
return nil, errors.New("expecting CronJob resource")
}
if cj.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName == n {
if serviceAccountMatches(cj.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName, n) {
refs = append(refs, Ref{
GVR: c.GVR(),
FQN: client.FQN(cj.Namespace, cj.Name),

View File

@ -167,7 +167,7 @@ func (d *Deployment) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, e
if err != nil {
return nil, errors.New("expecting Deployment resource")
}
if dp.Spec.Template.Spec.ServiceAccountName == n {
if serviceAccountMatches(dp.Spec.Template.Spec.ServiceAccountName, n) {
refs = append(refs, Ref{
GVR: d.GVR(),
FQN: client.FQN(dp.Namespace, dp.Name),

View File

@ -187,7 +187,7 @@ func (d *DaemonSet) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, er
if err != nil {
return nil, errors.New("expecting DaemonSet resource")
}
if ds.Spec.Template.Spec.ServiceAccountName == n {
if serviceAccountMatches(ds.Spec.Template.Spec.ServiceAccountName, n) {
refs = append(refs, Ref{
GVR: d.GVR(),
FQN: client.FQN(ds.Namespace, ds.Name),

View File

@ -14,6 +14,8 @@ import (
"k8s.io/cli-runtime/pkg/printers"
)
const defaultServiceAccount = "default"
var (
inverseRx = regexp.MustCompile(`\A\!`)
fuzzyRx = regexp.MustCompile(`\A\-f`)
@ -81,3 +83,13 @@ func ToYAML(o runtime.Object, showManaged bool) (string, error) {
return buff.String(), nil
}
// serviceAccountMatches validates that the ServiceAccount referenced in the PodSpec matches the incoming
// ServiceAccount. If the PodSpec ServiceAccount is blank kubernetes will use the "default" ServiceAccount
// when deploying the pod, so if the incoming SA is "default" and podSA is an empty string that is also a match.
func serviceAccountMatches(podSA, saName string) bool {
if podSA == "" {
podSA = defaultServiceAccount
}
return podSA == saName
}

View File

@ -4,6 +4,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
)
func TestToPerc(t *testing.T) {
@ -19,3 +20,40 @@ func TestToPerc(t *testing.T) {
assert.Equal(t, u.e, toPerc(u.v1, u.v2))
}
}
func TestServiceAccountMatches(t *testing.T) {
uu := []struct {
podTemplate *v1.PodSpec
saName string
expect bool
}{
{podTemplate: &v1.PodSpec{
ServiceAccountName: "",
},
saName: defaultServiceAccount,
expect: true,
},
{podTemplate: &v1.PodSpec{
ServiceAccountName: "",
},
saName: "foo",
expect: false,
},
{podTemplate: &v1.PodSpec{
ServiceAccountName: "foo",
},
saName: "foo",
expect: true,
},
{podTemplate: &v1.PodSpec{
ServiceAccountName: "foo",
},
saName: "bar",
expect: false,
},
}
for _, u := range uu {
assert.Equal(t, u.expect, serviceAccountMatches(u.podTemplate.ServiceAccountName, u.saName))
}
}

View File

@ -91,7 +91,7 @@ func (j *Job) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, error) {
if err != nil {
return nil, errors.New("expecting Job resource")
}
if job.Spec.Template.Spec.ServiceAccountName == n {
if serviceAccountMatches(job.Spec.Template.Spec.ServiceAccountName, n) {
refs = append(refs, Ref{
GVR: j.GVR(),
FQN: client.FQN(job.Namespace, job.Name),

View File

@ -242,7 +242,7 @@ func (p *Pod) ScanSA(ctx context.Context, fqn string, wait bool) (Refs, error) {
if len(pod.ObjectMeta.OwnerReferences) > 0 {
continue
}
if pod.Spec.ServiceAccountName == n {
if serviceAccountMatches(pod.Spec.ServiceAccountName, n) {
refs = append(refs, Ref{
GVR: p.GVR(),
FQN: client.FQN(pod.Namespace, pod.Name),

View File

@ -184,7 +184,7 @@ func (s *StatefulSet) ScanSA(ctx context.Context, fqn string, wait bool) (Refs,
if err != nil {
return nil, errors.New("expecting StatefulSet resource")
}
if sts.Spec.Template.Spec.ServiceAccountName == n {
if serviceAccountMatches(sts.Spec.Template.Spec.ServiceAccountName, n) {
refs = append(refs, Ref{
GVR: s.GVR(),
FQN: client.FQN(sts.Namespace, sts.Name),