Skip to content

Commit

Permalink
feat: Support scan latest revision for replicationController from Dep…
Browse files Browse the repository at this point in the history
…loymentConfig (#1352)

In OCP, there is a kind called DeploymentConfig, which manages the replicationController, and as we have revisionHistory for Deployments, similarly there are revision history for Deployment Config as well. Due to which many replication contollers will be present in the cluster. We dont want to scan them as they are not active resource.
So as part of this change, I have added following change
- consider "OPERATOR_CONFIG_AUDIT_SCANNER_SCAN_ONLY_CURRENT_REVISIONS" env var to limit scanning of old replication controller
- ingore pods created from deploymentConfig

resolves: 1351
  • Loading branch information
deven0t authored Jun 1, 2023
1 parent 39fd635 commit bb7e24f
Show file tree
Hide file tree
Showing 11 changed files with 375 additions and 30 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ on:
- 'NOTICE'

env:
GO_VERSION: "1.17"
KIND_VERSION: "v0.11.1"
GO_VERSION: "1.19"
KIND_VERSION: "v0.17.0"
KIND_IMAGE: "kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6"

# Disable permissions granted to the GITHUB_TOKEN for all the available scopes.
Expand All @@ -44,7 +44,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@v4
with:
go-version: ${{ env.GO_VERSION }}
- name: Checkout code
Expand All @@ -57,7 +57,7 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Verify Go code
uses: golangci/golangci-lint-action@v3.2.0
uses: golangci/golangci-lint-action@v3.4.0
with:
args: --verbose
version: latest
Expand Down
8 changes: 8 additions & 0 deletions deploy/helm/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ rules:
- get
- list
- watch
- apiGroups:
- apps.openshift.io
resources:
- deploymentconfigs
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
Expand Down
8 changes: 8 additions & 0 deletions deploy/static/02-starboard-operator.rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ rules:
- get
- list
- watch
- apiGroups:
- apps.openshift.io
resources:
- deploymentconfigs
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
Expand Down
8 changes: 8 additions & 0 deletions deploy/static/starboard.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,14 @@ rules:
- get
- list
- watch
- apiGroups:
- apps.openshift.io
resources:
- deploymentconfigs
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
Expand Down
17 changes: 9 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ require (
github.com/davecgh/go-spew v1.1.1
github.com/emirpasic/gods v1.18.1
github.com/go-logr/logr v1.2.3
github.com/google/go-cmp v0.5.8
github.com/google/go-cmp v0.5.9
github.com/google/go-containerregistry v0.11.0
github.com/google/uuid v1.3.0
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75
github.com/hashicorp/go-version v1.5.0
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.20.0
github.com/open-policy-agent/opa v0.44.0
github.com/openshift/api v0.0.0-20221013123533-341d389bd4a7
github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.0
Expand All @@ -29,7 +30,7 @@ require (
k8s.io/client-go v0.24.4
k8s.io/code-generator v0.24.3
k8s.io/klog/v2 v2.90.1
k8s.io/utils v0.0.0-20220706174534-f6158b442e7c
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d
sigs.k8s.io/controller-runtime v0.12.3
sigs.k8s.io/yaml v1.3.0
)
Expand Down Expand Up @@ -101,15 +102,15 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/mod v0.6.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/oauth2 v0.0.0-20220718184931-c8730f7fcb92 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
golang.org/x/tools v0.1.12 // indirect
golang.org/x/tools v0.2.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
Expand All @@ -118,9 +119,9 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/component-base v0.24.2 // indirect
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect
k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 // indirect
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/kustomize/api v0.11.4 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
)
55 changes: 42 additions & 13 deletions go.sum

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions pkg/configauditreport/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ func (r *ResourceController) reconcileResource(resourceKind kube.Kind) reconcile
"controllerName", controller.Name)
return ctrl.Result{}, nil
}
podAnnotations := resource.GetAnnotations()
// Ignore scanning of pod which is created for deploymentConfig
if value, ok := podAnnotations[kube.DeployerPodForDeploymentLabel]; ok {
log.V(1).Info("Ignoring system pod created for deployment config",
"deploymentConfigName", value)
return ctrl.Result{}, nil
}
}

if r.Config.ConfigAuditScannerScanOnlyCurrentRevisions && resourceKind == kube.KindReplicaSet {
Expand All @@ -171,6 +178,18 @@ func (r *ResourceController) reconcileResource(resourceKind kube.Kind) reconcile
}
}

if r.Config.ConfigAuditScannerScanOnlyCurrentRevisions && resourceKind == kube.KindReplicationController {
controller := metav1.GetControllerOf(resource)
activeReplicaSet, err := r.IsActiveReplicationController(ctx, resource, controller)
if err != nil {
return ctrl.Result{}, fmt.Errorf("failed checking current revision: %w", err)
}
if !activeReplicaSet {
log.V(1).Info("Ignoring inactive ReplicationController", "controllerKind", controller.Kind, "controllerName", controller.Name)
return ctrl.Result{}, nil
}
}

// Skip processing if a resource is a Job controlled by CronJob.
if resourceKind == kube.KindJob {
controller := metav1.GetControllerOf(resource)
Expand Down
36 changes: 31 additions & 5 deletions pkg/kube/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/aquasecurity/starboard/pkg/starboard"
ocpappsv1 "github.com/openshift/api/apps/v1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
batchv1beta1 "k8s.io/api/batch/v1beta1"
Expand Down Expand Up @@ -48,6 +49,7 @@ const (
KindReplicaSet Kind = "ReplicaSet"
KindReplicationController Kind = "ReplicationController"
KindDeployment Kind = "Deployment"
KindDeploymentConfig Kind = "DeploymentConfig"
KindStatefulSet Kind = "StatefulSet"
KindDaemonSet Kind = "DaemonSet"
KindCronJob Kind = "CronJob"
Expand All @@ -74,7 +76,10 @@ const (
)

const (
deploymentAnnotation string = "deployment.kubernetes.io/revision"
deploymentAnnotation string = "deployment.kubernetes.io/revision"
deploymentConfigAnnotation string = "openshift.io/deployment-config.latest-version"

DeployerPodForDeploymentLabel string = "openshift.io/deployment-config.name"
)

// IsBuiltInWorkload returns true if the specified v1.OwnerReference
Expand Down Expand Up @@ -300,7 +305,7 @@ var ErrReplicaSetNotFound = errors.New("replicaset not found")
var ErrNoRunningPods = errors.New("no active pods for controller")
var ErrUnSupportedKind = errors.New("unsupported workload kind")

//CompatibleMgr provide k8s compatible objects (group/api/kind) capabilities
// CompatibleMgr provide k8s compatible objects (group/api/kind) capabilities
type CompatibleMgr interface {
// GetSupportedObjectByKind get specific k8s compatible object (group/api/kind) by kind
GetSupportedObjectByKind(kind Kind) client.Object
Expand All @@ -319,7 +324,7 @@ func NewObjectResolver(c client.Client, cm CompatibleMgr) ObjectResolver {
return ObjectResolver{c, cm}
}

//InitCompatibleMgr initializes a CompatibleObjectMapper who store a map the of supported kinds with it compatible Objects (group/api/kind)
// InitCompatibleMgr initializes a CompatibleObjectMapper who store a map the of supported kinds with it compatible Objects (group/api/kind)
// it dynamically fetches the compatible k8s objects (group/api/kind) by resource from the cluster and store it in kind vs k8s object mapping
// It will enable the operator to support old and new API resources based on cluster version support
func InitCompatibleMgr(restMapper meta.RESTMapper) (CompatibleMgr, error) {
Expand Down Expand Up @@ -356,7 +361,7 @@ func getCompatibleResources() []string {
return []string{cronJobResource}
}

//GetSupportedObjectByKind accept kind and return the supported object (group/api/kind) of the cluster
// GetSupportedObjectByKind accept kind and return the supported object (group/api/kind) of the cluster
func (o *CompatibleObjectMapper) GetSupportedObjectByKind(kind Kind) client.Object {
return o.kindObjectMap[string(kind)]
}
Expand Down Expand Up @@ -404,6 +409,8 @@ func (o *ObjectResolver) ObjectFromObjectRef(ctx context.Context, ref ObjectRef)
obj = &apiextensionsv1.CustomResourceDefinition{}
case KindPodSecurityPolicy:
obj = &policyv1beta1.PodSecurityPolicy{}
case KindDeploymentConfig:
obj = &ocpappsv1.DeploymentConfig{}
default:
return nil, fmt.Errorf("unknown kind: %s", ref.Kind)
}
Expand Down Expand Up @@ -476,7 +483,7 @@ func (o *ObjectResolver) ReplicaSetByDeploymentRef(ctx context.Context, deployme

// ReplicaSetByDeployment returns the current revision of the specified
// Deployment. If the current revision cannot be found the ErrReplicaSetNotFound
//error is returned.
// error is returned.
func (o *ObjectResolver) ReplicaSetByDeployment(ctx context.Context, deployment *appsv1.Deployment) (*appsv1.ReplicaSet, error) {
var rsList appsv1.ReplicaSetList
err := o.Client.List(ctx, &rsList,
Expand Down Expand Up @@ -682,6 +689,25 @@ func (o *ObjectResolver) IsActiveReplicaSet(ctx context.Context, workloadObj cli
return true, nil
}

func (o *ObjectResolver) IsActiveReplicationController(ctx context.Context, workloadObj client.Object, controller *metav1.OwnerReference) (bool, error) {
if controller != nil && controller.Kind == string(KindDeploymentConfig) {
deploymentConfigObj := &ocpappsv1.DeploymentConfig{}

err := o.Client.Get(ctx, client.ObjectKey{
Namespace: workloadObj.GetNamespace(),
Name: controller.Name,
}, deploymentConfigObj)

if err != nil {
return false, err
}
replicasetRevisionAnnotation := workloadObj.GetAnnotations()
latestRevision := fmt.Sprintf("%d", deploymentConfigObj.Status.LatestVersion)
return replicasetRevisionAnnotation[deploymentConfigAnnotation] == latestRevision, nil
}
return true, nil
}

func (o *ObjectResolver) GetPodsByLabelSelector(ctx context.Context, namespace string,
labelSelector labels.Set) ([]corev1.Pod, error) {
podList := &corev1.PodList{}
Expand Down
Loading

0 comments on commit bb7e24f

Please sign in to comment.