forked from aquasecurity/trivy-operator
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d54d0ab
commit 701749c
Showing
11 changed files
with
356 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package exposedsecretreport | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"time" | ||
|
||
"github.com/aquasecurity/trivy-operator/pkg/apis/aquasecurity/v1alpha1" | ||
"github.com/aquasecurity/trivy-operator/pkg/kube" | ||
"github.com/aquasecurity/trivy-operator/pkg/trivyoperator" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/util/validation" | ||
"k8s.io/utils/pointer" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
) | ||
|
||
type ReportBuilder struct { | ||
scheme *runtime.Scheme | ||
controller client.Object | ||
container string | ||
hash string | ||
data v1alpha1.ExposedSecretReportData | ||
reportTTL *time.Duration | ||
} | ||
|
||
func NewReportBuilder(scheme *runtime.Scheme) *ReportBuilder { | ||
return &ReportBuilder{ | ||
scheme: scheme, | ||
} | ||
} | ||
|
||
func (b *ReportBuilder) Controller(controller client.Object) *ReportBuilder { | ||
b.controller = controller | ||
return b | ||
} | ||
|
||
func (b *ReportBuilder) Container(name string) *ReportBuilder { | ||
b.container = name | ||
return b | ||
} | ||
|
||
func (b *ReportBuilder) PodSpecHash(hash string) *ReportBuilder { | ||
b.hash = hash | ||
return b | ||
} | ||
|
||
func (b *ReportBuilder) Data(data v1alpha1.ExposedSecretReportData) *ReportBuilder { | ||
b.data = data | ||
return b | ||
} | ||
|
||
func (b *ReportBuilder) ReportTTL(ttl *time.Duration) *ReportBuilder { | ||
b.reportTTL = ttl | ||
return b | ||
} | ||
|
||
func (b *ReportBuilder) reportName() string { | ||
kind := b.controller.GetObjectKind().GroupVersionKind().Kind | ||
name := b.controller.GetName() | ||
reportName := fmt.Sprintf("%s-%s-%s", strings.ToLower(kind), name, b.container) | ||
if len(validation.IsValidLabelValue(reportName)) == 0 { | ||
return reportName | ||
} | ||
|
||
return fmt.Sprintf("%s-%s", strings.ToLower(kind), kube.ComputeHash(name+"-"+b.container)) | ||
} | ||
|
||
func (b *ReportBuilder) Get() (v1alpha1.ExposedSecretReport, error) { | ||
labels := map[string]string{ | ||
trivyoperator.LabelContainerName: b.container, | ||
} | ||
|
||
if b.hash != "" { | ||
labels[trivyoperator.LabelResourceSpecHash] = b.hash | ||
} | ||
|
||
report := v1alpha1.ExposedSecretReport{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: b.reportName(), | ||
Namespace: b.controller.GetNamespace(), | ||
Labels: labels, | ||
}, | ||
Report: b.data, | ||
} | ||
|
||
// TODO: do we support TTL? | ||
if b.reportTTL != nil { | ||
report.Annotations = map[string]string{ | ||
v1alpha1.TTLReportAnnotation: b.reportTTL.String(), | ||
} | ||
} | ||
err := kube.ObjectToObjectMeta(b.controller, &report.ObjectMeta) | ||
if err != nil { | ||
return v1alpha1.ExposedSecretReport{}, err | ||
} | ||
err = controllerutil.SetControllerReference(b.controller, &report, b.scheme) | ||
if err != nil { | ||
return v1alpha1.ExposedSecretReport{}, fmt.Errorf("setting controller reference: %w", err) | ||
} | ||
// The OwnerReferencesPermissionsEnforcement admission controller protects the | ||
// access to metadata.ownerReferences[x].blockOwnerDeletion of an object, so | ||
// that only users with "update" permission to the finalizers subresource of the | ||
// referenced owner can change it. | ||
// We set metadata.ownerReferences[x].blockOwnerDeletion to false so that | ||
// additional RBAC permissions are not required when the OwnerReferencesPermissionsEnforcement | ||
// is enabled. | ||
// See https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#ownerreferencespermissionenforcement | ||
report.OwnerReferences[0].BlockOwnerDeletion = pointer.BoolPtr(false) | ||
return report, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package exposedsecretreport | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/aquasecurity/trivy-operator/pkg/apis/aquasecurity/v1alpha1" | ||
"github.com/aquasecurity/trivy-operator/pkg/kube" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// Writer is the interface that wraps the basic Write method. | ||
// | ||
// Write creates or updates the given slice of v1alpha1.VulnerabilityReport | ||
// instances. | ||
type Writer interface { | ||
Write(context.Context, []v1alpha1.ExposedSecretReport) error | ||
} | ||
|
||
// Reader is the interface that wraps methods for finding v1alpha1.VulnerabilityReport objects. | ||
// | ||
// FindByOwner returns the slice of v1alpha1.VulnerabilityReport instances | ||
// owned by the given kube.ObjectRef or an empty slice if the reports are not found. | ||
// | ||
// FindByOwnerInHierarchy is similar to FindByOwner except it tries to lookup | ||
// v1alpha1.VulnerabilityReport objects owned by related Kubernetes objects. | ||
// For example, if the given owner is a Deployment, but reports are owned by the | ||
// active ReplicaSet (current revision) this method will return the reports. | ||
type Reader interface { | ||
FindByOwner(context.Context, kube.ObjectRef) ([]v1alpha1.ExposedSecretReport, error) | ||
FindByOwnerInHierarchy(ctx context.Context, object kube.ObjectRef) ([]v1alpha1.ExposedSecretReport, error) | ||
} | ||
|
||
type ReadWriter interface { | ||
Reader | ||
Writer | ||
} | ||
|
||
type readWriter struct { | ||
*kube.ObjectResolver | ||
} | ||
|
||
// NewReadWriter constructs a new ReadWriter which is using the client package | ||
// provided by the controller-runtime libraries for interacting with the | ||
// Kubernetes API server. | ||
func NewReadWriter(client client.Client) ReadWriter { | ||
return &readWriter{ | ||
ObjectResolver: &kube.ObjectResolver{Client: client}, | ||
} | ||
} | ||
|
||
func (r *readWriter) Write(ctx context.Context, reports []v1alpha1.ExposedSecretReport) error { | ||
for _, report := range reports { | ||
err := r.createOrUpdate(ctx, report) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (r *readWriter) createOrUpdate(ctx context.Context, report v1alpha1.ExposedSecretReport) error { | ||
var existing v1alpha1.ExposedSecretReport | ||
err := r.Get(ctx, types.NamespacedName{ | ||
Name: report.Name, | ||
Namespace: report.Namespace, | ||
}, &existing) | ||
|
||
if err == nil { | ||
copied := existing.DeepCopy() | ||
copied.Labels = report.Labels | ||
copied.Report = report.Report | ||
|
||
return r.Update(ctx, copied) | ||
} | ||
|
||
if errors.IsNotFound(err) { | ||
return r.Create(ctx, &report) | ||
} | ||
|
||
return err | ||
} | ||
|
||
func (r *readWriter) FindByOwner(ctx context.Context, owner kube.ObjectRef) ([]v1alpha1.ExposedSecretReport, error) { | ||
var list v1alpha1.ExposedSecretReportList | ||
|
||
labels := client.MatchingLabels(kube.ObjectRefToLabels(owner)) | ||
|
||
err := r.List(ctx, &list, labels, client.InNamespace(owner.Namespace)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return list.DeepCopy().Items, nil | ||
} | ||
|
||
func (r *readWriter) FindByOwnerInHierarchy(ctx context.Context, owner kube.ObjectRef) ([]v1alpha1.ExposedSecretReport, error) { | ||
reports, err := r.FindByOwner(ctx, owner) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// no reports found for provided owner, look for reports in related replicaset | ||
if len(reports) == 0 && (owner.Kind == kube.KindDeployment || owner.Kind == kube.KindPod) { | ||
rsName, err := r.RelatedReplicaSetName(ctx, owner) | ||
if err != nil { | ||
return nil, fmt.Errorf("getting replicaset related to %s/%s: %w", owner.Kind, owner.Name, err) | ||
} | ||
reports, err = r.FindByOwner(ctx, kube.ObjectRef{ | ||
Kind: kube.KindReplicaSet, | ||
Name: rsName, | ||
Namespace: owner.Namespace, | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
return reports, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.