Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 54141ff

Browse files
committed
feat: fetch SPDX SBOM on container creation
Signed-off-by: Dor Serero <[email protected]>
1 parent 5c56568 commit 54141ff

7 files changed

Lines changed: 762 additions & 2 deletions

File tree

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
5555

5656
# Build the image
5757
FROM scratch
58+
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
5859
COPY --from=builder /micromize /micromize
5960

6061
# Access to kernel debug filesystem (tracefs)

charts/micromize/templates/daemonset.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ spec:
6363
valueFrom:
6464
fieldRef:
6565
fieldPath: spec.nodeName
66+
{{- if .Values.registryAuth.existingSecret }}
67+
- name: DOCKER_CONFIG
68+
value: /etc/docker-registry
69+
{{- end }}
6670
volumeMounts:
6771
# Required for pinning BPF maps.
6872
- mountPath: /sys/fs/bpf
@@ -86,6 +90,11 @@ spec:
8690
# Required for container level enrichment.
8791
- mountPath: /host/usr
8892
name: host-usr
93+
{{- if .Values.registryAuth.existingSecret }}
94+
- mountPath: /etc/docker-registry
95+
name: registry-auth
96+
readOnly: true
97+
{{- end }}
8998
resources:
9099
{{- toYaml .Values.resources | nindent 12 }}
91100
volumes:
@@ -110,6 +119,14 @@ spec:
110119
- name: host-usr
111120
hostPath:
112121
path: /usr
122+
{{- if .Values.registryAuth.existingSecret }}
123+
- name: registry-auth
124+
secret:
125+
secretName: {{ .Values.registryAuth.existingSecret }}
126+
items:
127+
- key: .dockerconfigjson
128+
path: config.json
129+
{{- end }}
113130
{{- with .Values.nodeSelector }}
114131
nodeSelector:
115132
{{- toYaml . | nindent 8 }}

charts/micromize/values.schema.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@
8888
},
8989
"podAnnotations": {
9090
"type": "object"
91+
},
92+
"registryAuth": {
93+
"type": "object",
94+
"properties": {
95+
"existingSecret": {
96+
"type": "string",
97+
"description": "Name of an existing Kubernetes secret of type kubernetes.io/dockerconfigjson for private registry authentication"
98+
}
99+
}
91100
}
92101
}
93102
}

charts/micromize/values.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,10 @@ serviceAccount:
4343

4444
podAnnotations: {}
4545

46+
# Registry authentication for SBOM fetching from private registries.
47+
# Provide the name of an existing Kubernetes secret of type
48+
# kubernetes.io/dockerconfigjson. The secret will be mounted and used
49+
# to authenticate when pulling SBOMs from private registries.
50+
registryAuth:
51+
existingSecret: ""
52+

internal/operators/operators.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
package operators
1616

1717
import (
18+
"context"
1819
"fmt"
1920
"log/slog"
2021
"math"
22+
"time"
2123

2224
"github.com/inspektor-gadget/inspektor-gadget/pkg/datasource"
2325
igoperators "github.com/inspektor-gadget/inspektor-gadget/pkg/operators"
@@ -27,6 +29,8 @@ import (
2729
ocihandler "github.com/inspektor-gadget/inspektor-gadget/pkg/operators/oci-handler"
2830
"github.com/inspektor-gadget/inspektor-gadget/pkg/operators/simple"
2931
"github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host"
32+
33+
"github.com/micromize-dev/micromize/internal/sbom"
3034
)
3135

3236
// DataOperator is an alias for igoperators.DataOperator to avoid direct dependency in main
@@ -60,10 +64,12 @@ func NewCLIOperator() igoperators.DataOperator {
6064
func NewImaOperator() igoperators.DataOperator {
6165
slog.Debug("Creating IMA operator")
6266
opPriority := math.MaxInt
67+
sbomFetcher := sbom.NewFetcher()
6368

6469
operatorOptions := []simple.Option{
6570
simple.WithPriority(opPriority),
6671
simple.OnInit(func(gadgetCtx igoperators.GadgetContext) error {
72+
ctx := gadgetCtx.Context()
6773
containersDatasource := gadgetCtx.GetDataSources()["containers"]
6874
if containersDatasource == nil {
6975
slog.Debug("IMA Operator: containers datasource not available, skipping")
@@ -75,14 +81,20 @@ func NewImaOperator() igoperators.DataOperator {
7581
return fmt.Errorf("containers datasource missing event_type field")
7682
}
7783

84+
containerConfigField := containersDatasource.GetField("container_config")
85+
if containerConfigField == nil {
86+
return fmt.Errorf("containers datasource missing container_config field")
87+
}
88+
89+
containerIDField := containersDatasource.GetField("container_id")
90+
7891
if err := containersDatasource.Subscribe(func(source datasource.DataSource, data datasource.Data) error {
7992
eventType, err := eventTypeField.String(data)
8093
if err != nil {
8194
return fmt.Errorf("getting event_type value: %w", err)
8295
}
83-
8496
if eventType == "CREATED" {
85-
slog.Info("IMA Operator: Container created event received")
97+
handleContainerCreated(ctx, sbomFetcher, containerConfigField, containerIDField, data)
8698
}
8799
return nil
88100
}, opPriority); err != nil {
@@ -93,3 +105,47 @@ func NewImaOperator() igoperators.DataOperator {
93105
}
94106
return simple.New("imaOperator", operatorOptions...)
95107
}
108+
109+
func handleContainerCreated(ctx context.Context, fetcher *sbom.Fetcher, configField datasource.FieldAccessor, containerIDField datasource.FieldAccessor, data datasource.Data) {
110+
ociConfig, err := configField.String(data)
111+
if err != nil {
112+
slog.Debug("Failed to read container_config field", "error", err)
113+
return
114+
}
115+
116+
imageRef, err := sbom.ImageRefFromOCIConfig(ociConfig)
117+
if err != nil {
118+
slog.Debug("Failed to parse OCI config", "error", err)
119+
return
120+
}
121+
122+
// Fallback: read image ref from Docker's config.v2.json when
123+
// OCI annotations don't contain the image name (plain Docker).
124+
if imageRef == "" && containerIDField != nil {
125+
containerID, _ := containerIDField.String(data)
126+
imageRef = sbom.ImageRefFromDockerConfig(containerID)
127+
}
128+
129+
imageRef = sbom.NormalizeImageRef(imageRef)
130+
131+
fetchCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
132+
defer cancel()
133+
134+
sbomData, err := fetcher.FetchForImage(fetchCtx, imageRef)
135+
if err != nil {
136+
slog.Error("Failed to fetch SBOM", "error", err)
137+
return
138+
}
139+
if sbomData != nil {
140+
slog.Info("SBOM fetched for container image", "image", imageRef, "size", len(sbomData))
141+
142+
files, err := sbom.ParseFiles(sbomData)
143+
if err != nil {
144+
slog.Error("Failed to parse SBOM files", "error", err)
145+
return
146+
}
147+
for _, f := range files {
148+
slog.Info("SBOM binary file", "image", imageRef, "file", f.FileName, "sha256", f.SHA256)
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)