Skip to content

Commit

Permalink
Check for the recommended security requirements of the container-nati…
Browse files Browse the repository at this point in the history
…ve operators
  • Loading branch information
shimritproj committed Apr 8, 2024
1 parent a03bef1 commit 1fbed6f
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 1 deletion.
2 changes: 1 addition & 1 deletion cnf-certification-test/accesscontrol/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import (

"github.com/operator-framework/api/pkg/operators/v1alpha1"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/accesscontrol/namespace"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/accesscontrol/rbac"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/accesscontrol/resources"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/accesscontrol/securitycontextcontainer"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/common"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/common/rbac"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/identifiers"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/networking/netutil"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/networking/services"
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions cnf-certification-test/identifiers/doclinks.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ const (
TestOperatorCrdSchemaIdentifierDocLink = DocOperatorRequirement
TestOperatorCrdVersioningIdentifierDocLink = DocOperatorRequirement
TestOperatorSingleCrdOwnerIdentifierDocLink = DocOperatorRequirement
TestOperatorSecurityRequiremnentsDocLink = DocOperatorRequirement

// Observability Test Suite
TestLoggingIdentifierDocLink = "https://test-network-function.github.io/cnf-best-practices-guide/#cnf-best-practices-logging"
Expand Down
17 changes: 17 additions & 0 deletions cnf-certification-test/identifiers/identifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ var (
TestHelmIsCertifiedIdentifier claim.Identifier
TestOperatorIsInstalledViaOLMIdentifier claim.Identifier
TestOperatorHasSemanticVersioningIdentifier claim.Identifier
TestOperatorSecurityRequiremnents claim.Identifier
TestOperatorCrdVersioningIdentifier claim.Identifier
TestOperatorCrdSchemaIdentifier claim.Identifier
TestOperatorSingleCrdOwnerIdentifier claim.Identifier
Expand Down Expand Up @@ -928,6 +929,22 @@ tag. (2) It does not have any of the following prefixes: default, openshift-, is
},
TagCommon)

TestOperatorSecurityRequiremnents = AddCatalogEntry(
"security-requirements",
common.OperatorTestKey,
`Tests whether a CNF Operator checks the recommended security requirements of the container operators.`,
OperatorSecurityRequiremnents,
NoExceptions,
TestOperatorSecurityRequiremnentsDocLink,
true,
map[string]string{
FarEdge: Mandatory,
Telco: Mandatory,
NonTelco: Mandatory,
Extended: Mandatory,
},
TagCommon)

TestOperatorCrdVersioningIdentifier = AddCatalogEntry(
"crd-versioning",
common.OperatorTestKey,
Expand Down
2 changes: 2 additions & 0 deletions cnf-certification-test/identifiers/remediation.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ const (

OperatorCrdSchemaIdentifierRemediation = `Ensure that the Operator CRD is defined with OpenAPI spec.`

OperatorSecurityRequiremnents = `Ensure that CNF Operator meets recommended security requirements.`

OperatorCrdVersioningRemediation = `Ensure that the Operator CRD has a valid version.`

OperatorSingleCrdOwnerRemediation = `Ensure that a CRD is owned by only one Operator`
Expand Down
60 changes: 60 additions & 0 deletions cnf-certification-test/operator/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import (
"strings"

"github.com/test-network-function/cnf-certification-test/cnf-certification-test/common"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/common/rbac"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/identifiers"
"github.com/test-network-function/cnf-certification-test/cnf-certification-test/operator/phasecheck"
"github.com/test-network-function/cnf-certification-test/internal/clientsholder"

"github.com/test-network-function/cnf-certification-test/cnf-certification-test/operator/version"
"github.com/test-network-function/cnf-certification-test/internal/log"
Expand Down Expand Up @@ -93,6 +95,13 @@ func LoadChecks() {
testOperatorSingleCrdOwner(c, &env)
return nil
}))

checksGroup.Add(checksdb.NewCheck(identifiers.GetTestIDAndLabels(identifiers.TestOperatorSecurityRequiremnents)).
WithSkipCheckFn(testhelper.GetNoOperatorsSkipFn(&env)).
WithCheckFn(func(c *checksdb.Check) error {
testOperatorSecurityRequiremnents(c, &env)
return nil
}))
}

// This function check if the Operator CRD version follows K8s versioning
Expand Down Expand Up @@ -303,3 +312,54 @@ func testOperatorSingleCrdOwner(check *checksdb.Check, env *provider.TestEnviron

check.SetResult(compliantObjects, nonCompliantObjects)
}

func testOperatorSecurityRequiremnents(check *checksdb.Check, env *provider.TestEnvironment) {
var compliantObjects []*testhelper.ReportObject
var nonCompliantObjects []*testhelper.ReportObject
for i := range env.Operators {
operator := env.Operators[i]
check.LogInfo("Testing Operator %q", operator)
for _, put := range env.Pods {
check.LogInfo("Testing Pod %q", put)
if put.IsRunAsUserID(0) {
check.LogError("Pod %q UserID is 0", put.Name)
nonCompliantObjects = append(nonCompliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod has been found with UserID is 0", false))
} else {
check.LogInfo("Pod %q UserID is not 0", put.Name)
compliantObjects = append(compliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod has been found with UserID is not 0", true))
}

if put.IsRunAsNonRoot() {
check.LogInfo("Pod %q is run as not root", put.Name)
compliantObjects = append(compliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod has been found is run as not root", true))
} else {
check.LogError("Pod %q is run as root", put.Name)
nonCompliantObjects = append(nonCompliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod has been found is run as root", false))
}

for _, cut := range put.Containers {
check.LogInfo("Testing Container %q", cut.Name)
if cut.IsReadOnlyRootFilesystem(check.GetLoggger()) {
check.LogInfo("Pod %q container %q is read only root file system.", put.Name, cut.Name)
compliantObjects = append(compliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod has been found read only root file system", true))
} else {
check.LogError("Pod %q container %q is read not only root file system.", put.Name, cut.Name)
nonCompliantObjects = append(nonCompliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod has been found read not only root file system", false))
}
}

// Evaluate the pod's automount service tokens and any attached service accounts
client := clientsholder.GetClientsHolder()
podPassed, newMsg := rbac.EvaluateAutomountTokens(client.K8sClient.CoreV1(), put.Pod)
if !podPassed {
check.LogInfo("Pod %q have automount service tokens set to false", put)
compliantObjects = append(compliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, "Pod %q have automount service tokens set to false", true))
} else {
check.LogError(newMsg)
nonCompliantObjects = append(nonCompliantObjects, testhelper.NewPodReportObject(put.Namespace, put.Name, newMsg, false))
}
}

check.SetResult(compliantObjects, nonCompliantObjects)
}
}
5 changes: 5 additions & 0 deletions pkg/provider/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,8 @@ func (c *Container) HasExecProbes() bool {
func (c *Container) IsTagEmpty() bool {
return c.ContainerImageIdentifier.Tag == ""
}

func (c *Container) IsReadOnlyRootFilesystem(logger *log.Logger) bool {
logger.Info("Testing Container %q", c.Name)
return *(c.SecurityContext.ReadOnlyRootFilesystem)
}
7 changes: 7 additions & 0 deletions pkg/provider/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@ func (p *Pod) GetTopOwner() (topOwners map[string]TopOwner, err error) {
return topOwners, nil
}

func (p *Pod) IsRunAsNonRoot() bool {
if p.Pod.Spec.SecurityContext != nil || *p.Pod.Spec.SecurityContext.RunAsNonRoot {
return true
}
return false
}

// Structure to describe a top owner of a pod
type TopOwner struct {
Kind string
Expand Down

0 comments on commit 1fbed6f

Please sign in to comment.