Repository: falcosecurity/driverkit
Pull request #113 (2021-12-23 15:24:57)

new(driverkit): allow configurable builder images
Signed-off-by: Luca Guerra <luca@guerra.sh>

This PR is co-authored with @Issif .

<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines in the [CONTRIBUTING.md](https://github.com/falcosecurity/.github/CONTRIBUTING.md) file.
2. Please label this pull request according to what type of issue you are addressing.
3. Please add a release note!
4. If the PR is unfinished while opening it specify a wip in the title before the actual title, for example, "wip: my awesome feature"
-->

**What type of PR is this?**

> Uncomment one (or more) `/kind <>` lines:

> /kind bug

> /kind cleanup

> /kind design

> /kind documentation

> /kind failing-test

/kind feature

<!--
Please remove the leading whitespace before the `/kind <>` you uncommented.
-->

**Any specific area of the project related to this PR?**

> Uncomment one (or more) `/area <>` lines:

/area build

> /area cmd

> /area pkg

> /area docs

> /area tests


**What this PR does / why we need it**:

The underlying problem that we're trying to solve is that some new kernel versions might require specific versions of base system libraries (mostly GNU libc) and/or specific compilers in order to build headers or modules compatible with that kernel. Think about GLIBC requirements for Ubuntu Impish or the latest Fedora.

A good step in doing that is allowing the builder image to be configurable. This allows the user to quickly test and configure which image to use to see if it fixes specific issues with a specific distribution. Due to how Driverkit is designed, this can be specified both on the CLI or in the configuration files.

Thanks to @Issif we have improved this PR in various ways, including making it clear which image is used, even when getting help on the command line.

**Which issue(s) this PR fixes**:

<!--
Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
If PR is `kind/failing-tests` or `kind/flaky-test`, please post the related issues/tests in a comment and do not use `Fixes`.
-->

Fixes #

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below.
If the PR requires additional action from users switching to the new release, prepend the string "action required:".
For example, `action required: change the API interface of the rule engine`.
-->

```release-note
new(driverkit): add builderimage option to specify a custom image to be used for building
```


poiana: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/falcosecurity/driverkit/pull/113#" title="Author self-approved">LucaGuerra</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **fntlnz** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @fntlnz` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://prow.falco.org/command-help?repo=falcosecurity%2Fdriverkit).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/falcosecurity/driverkit/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["fntlnz"]} -->
Issif: I like the idea, we saw that for newer kernels for debian we had issues with current image and we need to update it. Allowing us, and users, to create and use their own image will be useful. The point I don't know is how to map an image with an os/kernel version.
leogr: Hey @leodido / @fntlnz 

Is anyone up for a review? :pray: 
FedeDP: I think this one can really help to fix #143 issues with ubuntu and debian, as we might need to user newer gcc versions for those (and possibly others?).
Best thing i can think of, we could use an array of like 3,4 images in our builds, and try them in order from the most ancient to the newest, like "current_image,image_w_gcc9,image_w_gcc10,image_w_gcc11". 
Adding newer gcc to current image is not simple because the required deps (like binutils > 2.35 for gcc10) won't be easily satisfied.
LucaGuerra: @leodido addressed your comments:
* Now the default field for the builder image uses the appropriate `SetDefaults()` function from the defaults library
* I have added a validator for the field. Note that perfect parsing of a Docker image pullstring is very hard to do, but I believe that restricting to letters+digits+separators with the appropriate separator rules is good enough to catch typos and user errors while building yamls or command lines.
poiana: LGTM label has been added.  <details>Git tree hash: 4baaaecaed921b92e8a6d8fe5736407f9743fe30</details>

Patch:
diff --git a/Makefile b/Makefile
index 8cfa1c5..69ee491 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ IMAGE_NAME_DRIVERKIT_REF := $(IMAGE_NAME_DRIVERKIT):$(GIT_REF)
 IMAGE_NAME_DRIVERKIT_COMMIT := $(IMAGE_NAME_DRIVERKIT):$(GIT_COMMIT)
 IMAGE_NAME_DRIVERKIT_LATEST := $(IMAGE_NAME_DRIVERKIT):latest
 
-LDFLAGS := -X github.com/falcosecurity/driverkit/pkg/version.buildTime=$(shell date +%s) -X github.com/falcosecurity/driverkit/pkg/version.gitCommit=${GIT_COMMIT} -X github.com/falcosecurity/driverkit/pkg/version.gitTag=$(if ${GIT_TAG},${GIT_TAG},v0.0.0) -X github.com/falcosecurity/driverkit/pkg/version.commitsFromGitTag=${COMMITS_FROM_GIT_TAG} -X github.com/falcosecurity/driverkit/pkg/driverbuilder.builderBaseImage=${IMAGE_NAME_BUILDER_COMMIT}
+LDFLAGS := -X github.com/falcosecurity/driverkit/pkg/version.buildTime=$(shell date +%s) -X github.com/falcosecurity/driverkit/pkg/version.gitCommit=${GIT_COMMIT} -X github.com/falcosecurity/driverkit/pkg/version.gitTag=$(if ${GIT_TAG},${GIT_TAG},v0.0.0) -X github.com/falcosecurity/driverkit/pkg/version.commitsFromGitTag=${COMMITS_FROM_GIT_TAG} -X github.com/falcosecurity/driverkit/pkg/driverbuilder.BuilderBaseImage=${IMAGE_NAME_BUILDER_COMMIT}
 
 OS_NAME := $(shell uname -s | tr A-Z a-z)
 SQLITE_TAGS :=
diff --git a/cmd/docker.go b/cmd/docker.go
index 3f839df..c71013b 100644
--- a/cmd/docker.go
+++ b/cmd/docker.go
@@ -2,7 +2,6 @@ package cmd
 
 import (
 	"github.com/falcosecurity/driverkit/pkg/driverbuilder"
-	"github.com/sirupsen/logrus"
 	logger "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
@@ -15,7 +14,7 @@ func NewDockerCmd(rootOpts *RootOptions, rootFlags *pflag.FlagSet) *cobra.Comman
 		Use:   "docker",
 		Short: "Build Falco kernel modules and eBPF probes against a docker daemon.",
 		Run: func(c *cobra.Command, args []string) {
-			logrus.WithField("processor", c.Name()).Info("driver building, it will take a few seconds")
+			logger.WithField("processor", c.Name()).Info("driver building, it will take a few seconds")
 			if !configOptions.DryRun {
 				if err := driverbuilder.NewDockerBuildProcessor(viper.GetInt("timeout"), viper.GetString("proxy")).Start(rootOpts.toBuild()); err != nil {
 					logger.WithError(err).Fatal("exiting")
diff --git a/cmd/kubernetes.go b/cmd/kubernetes.go
index d6a1b18..42a1f20 100644
--- a/cmd/kubernetes.go
+++ b/cmd/kubernetes.go
@@ -6,7 +6,6 @@ import (
 
 	"github.com/falcosecurity/driverkit/pkg/driverbuilder"
 	"github.com/falcosecurity/driverkit/pkg/kubernetes/factory"
-	"github.com/sirupsen/logrus"
 	logger "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
@@ -41,7 +40,7 @@ func NewKubernetesCmd(rootOpts *RootOptions, rootFlags *pflag.FlagSet) *cobra.Co
 	kubefactory := factory.NewFactory(configFlags)
 
 	kubernetesCmd.Run = func(cmd *cobra.Command, args []string) {
-		logrus.WithField("processor", cmd.Name()).Info("driver building, it will take a few seconds")
+		logger.WithField("processor", cmd.Name()).Info("driver building, it will take a few seconds")
 		if !configOptions.DryRun {
 			if err := kubernetesRun(cmd, args, kubefactory, rootOpts); err != nil {
 				logger.WithError(err).Fatal("exiting")
diff --git a/cmd/root.go b/cmd/root.go
index 268aee2..9faba86 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -117,6 +117,7 @@ func NewRootCmd() *RootCmd {
 	flags.StringVar(&rootOpts.KernelConfigData, "kernelconfigdata", rootOpts.KernelConfigData, "base64 encoded kernel config data: in some systems it can be found under the /boot directory, in other it is gzip compressed under /proc")
 	flags.StringVar(&rootOpts.ModuleDeviceName, "moduledevicename", rootOpts.ModuleDeviceName, "kernel module device name (the default is falco, so the device will be under /dev/falco*)")
 	flags.StringVar(&rootOpts.ModuleDriverName, "moduledrivername", rootOpts.ModuleDriverName, "kernel module driver name, i.e. the name you see when you check installed modules via lsmod")
+	flags.StringVar(&rootOpts.BuilderImage, "builderimage", rootOpts.BuilderImage, "docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used.")
 	viper.BindPFlags(flags)
 
 	// Flag annotations and custom completions
diff --git a/cmd/root_options.go b/cmd/root_options.go
index b2f3b8b..191aa7e 100644
--- a/cmd/root_options.go
+++ b/cmd/root_options.go
@@ -2,8 +2,8 @@ package cmd
 
 import (
 	"fmt"
-
 	"github.com/creasty/defaults"
+	"github.com/falcosecurity/driverkit/pkg/driverbuilder"
 	"github.com/falcosecurity/driverkit/pkg/driverbuilder/builder"
 	"github.com/falcosecurity/driverkit/validate"
 	"github.com/go-playground/validator/v10"
@@ -26,6 +26,7 @@ type RootOptions struct {
 	KernelRelease    string `validate:"required,ascii" name:"kernel release"`
 	Target           string `validate:"required,target" name:"target"`
 	KernelConfigData string `validate:"omitempty,base64" name:"kernel config data"` // fixme > tag "name" does not seem to work when used at struct level, but works when used at inner level
+	BuilderImage     string `validate:"imagename" name:"builder image"`
 	Output           OutputOptions
 }
 
@@ -33,6 +34,12 @@ func init() {
 	validate.V.RegisterStructValidation(RootOptionsLevelValidation, RootOptions{})
 }
 
+func (ro *RootOptions) SetDefaults() {
+	if defaults.CanUpdate(ro.BuilderImage) {
+		ro.BuilderImage = driverbuilder.BuilderBaseImage
+	}
+}
+
 // NewRootOptions ...
 func NewRootOptions() *RootOptions {
 	rootOpts := &RootOptions{}
@@ -91,16 +98,17 @@ func (ro *RootOptions) toBuild() *builder.Build {
 	}
 
 	return &builder.Build{
-		TargetType:       builder.Type(ro.Target),
-		DriverVersion:    ro.DriverVersion,
-		KernelVersion:    ro.KernelVersion,
-		KernelRelease:    ro.KernelRelease,
-		Architecture:     ro.Architecture,
-		KernelConfigData: kernelConfigData,
-		ModuleFilePath:   ro.Output.Module,
-		ProbeFilePath:    ro.Output.Probe,
-		ModuleDriverName: ro.ModuleDriverName,
-		ModuleDeviceName: ro.ModuleDeviceName,
+		TargetType:         builder.Type(ro.Target),
+		DriverVersion:      ro.DriverVersion,
+		KernelVersion:      ro.KernelVersion,
+		KernelRelease:      ro.KernelRelease,
+		Architecture:       ro.Architecture,
+		KernelConfigData:   kernelConfigData,
+		ModuleFilePath:     ro.Output.Module,
+		ProbeFilePath:      ro.Output.Probe,
+		ModuleDriverName:   ro.ModuleDriverName,
+		ModuleDeviceName:   ro.ModuleDeviceName,
+		CustomBuilderImage: ro.BuilderImage,
 	}
 }
 
diff --git a/go.mod b/go.mod
index 7aa2487..f71f339 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/Masterminds/semver/v3 v3.0.3
 	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
-	github.com/creasty/defaults v1.3.0
+	github.com/creasty/defaults v1.6.0
 	github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0
 	github.com/docker/go-connections v0.4.0 // indirect
 	github.com/docker/go-units v0.4.0 // indirect
diff --git a/go.sum b/go.sum
index 0a54c89..7e46d86 100644
--- a/go.sum
+++ b/go.sum
@@ -50,8 +50,8 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/creasty/defaults v1.3.0 h1:uG+RAxYbJgOPCOdKEcec9ZJXeva7Y6mj/8egdzwmLtw=
-github.com/creasty/defaults v1.3.0/go.mod h1:CIEEvs7oIVZm30R8VxtFJs+4k201gReYyuYHJxZc68I=
+github.com/creasty/defaults v1.6.0 h1:ltuE9cfphUtlrBeomuu8PEyISTXnxqkBIoQfXgv7BSc=
+github.com/creasty/defaults v1.6.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM=
 github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -172,7 +172,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
 github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -207,7 +206,6 @@ github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM
 github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@@ -253,7 +251,6 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@@ -272,7 +269,6 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
 github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
@@ -287,7 +283,6 @@ github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
@@ -319,11 +314,8 @@ github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSf
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
-go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -380,10 +372,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
 golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
-golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
 golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/pkg/driverbuilder/builder/build.go b/pkg/driverbuilder/builder/build.go
index 7332860..a3817c9 100644
--- a/pkg/driverbuilder/builder/build.go
+++ b/pkg/driverbuilder/builder/build.go
@@ -2,14 +2,15 @@ package builder
 
 // Build contains the info about the on-going build.
 type Build struct {
-	TargetType       Type
-	KernelConfigData string
-	KernelRelease    string
-	KernelVersion    uint16
-	DriverVersion    string
-	Architecture     string
-	ModuleFilePath   string
-	ProbeFilePath    string
-	ModuleDriverName string
-	ModuleDeviceName string
+	TargetType         Type
+	KernelConfigData   string
+	KernelRelease      string
+	KernelVersion      uint16
+	DriverVersion      string
+	Architecture       string
+	ModuleFilePath     string
+	ProbeFilePath      string
+	ModuleDriverName   string
+	ModuleDeviceName   string
+	CustomBuilderImage string
 }
diff --git a/pkg/driverbuilder/builder/builders.go b/pkg/driverbuilder/builder/builders.go
index b4c4c87..911ab42 100644
--- a/pkg/driverbuilder/builder/builders.go
+++ b/pkg/driverbuilder/builder/builders.go
@@ -5,7 +5,7 @@ import (
 	"net/http"
 	"path"
 
-	"github.com/sirupsen/logrus"
+	logger "github.com/sirupsen/logrus"
 )
 
 // DriverDirectory is the directory the processor uses to store the driver.
@@ -58,7 +58,7 @@ func getResolvingURLs(urls []string) ([]string, error) {
 		}
 		if res.StatusCode == http.StatusOK {
 			results = append(results, u)
-			logrus.WithField("url", u).Debug("kernel header url found")
+			logger.WithField("url", u).Debug("kernel header url found")
 		}
 	}
 	if len(results) == 0 {
diff --git a/pkg/driverbuilder/builder/ubuntu.go b/pkg/driverbuilder/builder/ubuntu.go
index c731396..eef2fdf 100644
--- a/pkg/driverbuilder/builder/ubuntu.go
+++ b/pkg/driverbuilder/builder/ubuntu.go
@@ -342,7 +342,19 @@ modinfo {{ .ModuleFullPath }}
 {{ if .BuildProbe }}
 # Build the eBPF probe
 cd {{ .DriverBuildDir }}/bpf
-make LLC=/usr/bin/llc-7 CLANG=/usr/bin/clang-7 CC=/usr/bin/gcc-8 KERNELDIR=$sourcedir
+if [[ -x /usr/bin/llc ]]; then
+	LLC_BIN=/usr/bin/llc
+else
+	LLC_BIN=/usr/bin/llc-7
+fi
+
+if [[ -x /usr/bin/clang ]]; then
+	CLANG_BIN=/usr/bin/clang
+else
+	CLANG_BIN=/usr/bin/clang-7
+fi
+
+make LLC=$LLC_BIN CLANG=$CLANG_BIN CC=/usr/bin/gcc-8 KERNELDIR=$sourcedir
 ls -l probe.o
 {{ end }}
 `
diff --git a/pkg/driverbuilder/buildprocessor.go b/pkg/driverbuilder/buildprocessor.go
index 7fe6f8e..045312e 100644
--- a/pkg/driverbuilder/buildprocessor.go
+++ b/pkg/driverbuilder/buildprocessor.go
@@ -8,7 +8,7 @@ type BuildArchitecture string
 
 const BuildArchitectureX86_64 BuildArchitecture = "x86_64"
 
-var builderBaseImage = "falcosecurity/driverkit-builder:latest" // This is overwritten when using the Makefile to build
+var BuilderBaseImage = "falcosecurity/driverkit-builder:latest" // This is overwritten when using the Makefile to build
 
 func (ba BuildArchitecture) String() string {
 	return string(ba)
diff --git a/pkg/driverbuilder/docker.go b/pkg/driverbuilder/docker.go
index ab99cea..aa13533 100644
--- a/pkg/driverbuilder/docker.go
+++ b/pkg/driverbuilder/docker.go
@@ -20,7 +20,6 @@ import (
 	"github.com/docker/docker/client"
 	"github.com/falcosecurity/driverkit/pkg/driverbuilder/builder"
 	"github.com/falcosecurity/driverkit/pkg/signals"
-	"github.com/sirupsen/logrus"
 	logger "github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/util/uuid"
 )
@@ -91,13 +90,18 @@ func (bp *DockerBuildProcessor) Start(b *builder.Build) error {
 		return err
 	}
 
+	builderImage := BuilderBaseImage
+	if len(b.CustomBuilderImage) > 0 {
+		builderImage = b.CustomBuilderImage
+	}
+
 	// Create the container
 	ctx := context.Background()
 	ctx = signals.WithStandardSignals(ctx)
 
-	if _, _, err = cli.ImageInspectWithRaw(ctx, builderBaseImage); client.IsErrNotFound(err) {
-		logger.WithField("image", builderBaseImage).Debug("pulling builder image")
-		pullRes, err := cli.ImagePull(ctx, builderBaseImage, types.ImagePullOptions{})
+	if _, _, err = cli.ImageInspectWithRaw(ctx, builderImage); client.IsErrNotFound(err) {
+		logger.WithField("image", builderImage).Debug("pulling builder image")
+		pullRes, err := cli.ImagePull(ctx, builderImage, types.ImagePullOptions{})
 		if err != nil {
 			return err
 		}
@@ -111,7 +115,7 @@ func (bp *DockerBuildProcessor) Start(b *builder.Build) error {
 	containerCfg := &container.Config{
 		Tty:   true,
 		Cmd:   []string{"/bin/sleep", strconv.Itoa(bp.timeout)},
-		Image: builderBaseImage,
+		Image: builderImage,
 	}
 
 	hostCfg := &container.HostConfig{
@@ -200,14 +204,14 @@ func (bp *DockerBuildProcessor) Start(b *builder.Build) error {
 		if err := copyFromContainer(ctx, cli, cdata.ID, builder.ModuleFullPath, b.ModuleFilePath); err != nil {
 			return err
 		}
-		logrus.WithField("path", b.ModuleFilePath).Info("kernel module available")
+		logger.WithField("path", b.ModuleFilePath).Info("kernel module available")
 	}
 
 	if len(b.ProbeFilePath) > 0 {
 		if err := copyFromContainer(ctx, cli, cdata.ID, builder.ProbeFullPath, b.ProbeFilePath); err != nil {
 			return err
 		}
-		logrus.WithField("path", b.ProbeFilePath).Info("eBPF probe available")
+		logger.WithField("path", b.ProbeFilePath).Info("eBPF probe available")
 	}
 
 	return nil
diff --git a/pkg/driverbuilder/kubernetes.go b/pkg/driverbuilder/kubernetes.go
index 58e681f..5cf5778 100644
--- a/pkg/driverbuilder/kubernetes.go
+++ b/pkg/driverbuilder/kubernetes.go
@@ -149,6 +149,11 @@ func (bp *KubernetesBuildProcessor) buildModule(build *builder.Build) error {
 		)
 	}
 
+	builderImage := BuilderBaseImage
+	if len(build.CustomBuilderImage) > 0 {
+		builderImage = build.CustomBuilderImage
+	}
+
 	pod := &corev1.Pod{
 		ObjectMeta: commonMeta,
 		Spec: corev1.PodSpec{
@@ -157,7 +162,7 @@ func (bp *KubernetesBuildProcessor) buildModule(build *builder.Build) error {
 			Containers: []corev1.Container{
 				{
 					Name:            name,
-					Image:           builderBaseImage,
+					Image:           builderImage,
 					Command:         buildCmd,
 					Env:             envs,
 					ImagePullPolicy: corev1.PullIfNotPresent,
diff --git a/validate/isimagename.go b/validate/isimagename.go
new file mode 100644
index 0000000..e2a45c3
--- /dev/null
+++ b/validate/isimagename.go
@@ -0,0 +1,35 @@
+package validate
+
+import (
+	"github.com/go-playground/validator/v10"
+	"strings"
+)
+
+const letters = "abcdefghijklmnopqrstuvwxyz"
+const digits = "0123456789"
+const separators = "/.-@_:"
+const alphabet = letters + digits + separators
+
+func isImageName(fl validator.FieldLevel) bool {
+	name := fl.Field().String()
+
+	for _, c := range name {
+		if !strings.ContainsRune(alphabet, c) {
+			return false
+		}
+	}
+
+	for _, component := range strings.Split(name, "/") {
+		// a component may not be empty (i.e. double slashes are not allowed)
+		if len(component) == 0 {
+			return false
+		}
+
+		// a component may not start or end with a separator
+		if strings.Contains(separators, component[0:1]) || strings.Contains(separators, component[len(component)-1:]) {
+			return false
+		}
+	}
+
+	return true
+}
diff --git a/validate/validate.go b/validate/validate.go
index 1a6c71e..2c035d2 100644
--- a/validate/validate.go
+++ b/validate/validate.go
@@ -38,6 +38,7 @@ func init() {
 	V.RegisterValidation("target", isTargetSupported)
 	V.RegisterValidation("semver", isSemVer)
 	V.RegisterValidation("proxy", isProxy)
+	V.RegisterValidation("imagename", isImageName)
 
 	eng := en.New()
 	uni := ut.New(eng, eng)


Test patch:
diff --git a/cmd/testdata/autohelp.txt b/cmd/testdata/autohelp.txt
index 19fc21b..265de17 100644
--- a/cmd/testdata/autohelp.txt
+++ b/cmd/testdata/autohelp.txt
@@ -12,6 +12,7 @@ Available Commands:
   kubernetes  Build Falco kernel modules and eBPF probes against a Kubernetes cluster.
 
 Flags:
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used. (default "falcosecurity/driverkit-builder:latest")
   -c, --config string             config file path (default $HOME/.driverkit.yaml if exists)
       --driverversion string      driver version as a git commit hash or as a git tag (default "master")
       --dryrun                    do not actually perform the action
diff --git a/cmd/testdata/dockernoopts.txt b/cmd/testdata/dockernoopts.txt
index 1c71c04..a6941a9 100644
--- a/cmd/testdata/dockernoopts.txt
+++ b/cmd/testdata/dockernoopts.txt
@@ -7,6 +7,7 @@ Usage:
   driverkit docker [flags]
 
 Flags:
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used. (default "falcosecurity/driverkit-builder:latest")
   -c, --config string             config file path (default $HOME/.driverkit.yaml if exists)
       --driverversion string      driver version as a git commit hash or as a git tag (default "master")
       --dryrun                    do not actually perform the action
diff --git a/cmd/testdata/help-flag.txt b/cmd/testdata/help-flag.txt
index ef6fd0b..d3d36e6 100644
--- a/cmd/testdata/help-flag.txt
+++ b/cmd/testdata/help-flag.txt
@@ -11,6 +11,7 @@ Available Commands:
   kubernetes  Build Falco kernel modules and eBPF probes against a Kubernetes cluster.
 
 Flags:
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used. (default "falcosecurity/driverkit-builder:latest")
   -c, --config string             config file path (default $HOME/.driverkit.yaml if exists)
       --driverversion string      driver version as a git commit hash or as a git tag (default "master")
       --dryrun                    do not actually perform the action
diff --git a/cmd/testdata/help.txt b/cmd/testdata/help.txt
index 44aac46..32f5c51 100644
--- a/cmd/testdata/help.txt
+++ b/cmd/testdata/help.txt
@@ -11,6 +11,7 @@ Available Commands:
   kubernetes  Build Falco kernel modules and eBPF probes against a Kubernetes cluster.
 
 Flags:
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used. (default "falcosecurity/driverkit-builder:latest")
   -c, --config string             config file path (default $HOME/.driverkit.yaml if exists)
       --driverversion string      driver version as a git commit hash or as a git tag (default "master")
       --dryrun                    do not actually perform the action
diff --git a/cmd/testdata/invalid-proxyconfig.txt b/cmd/testdata/invalid-proxyconfig.txt
index 409b214..999a209 100644
--- a/cmd/testdata/invalid-proxyconfig.txt
+++ b/cmd/testdata/invalid-proxyconfig.txt
@@ -11,6 +11,7 @@ Available Commands:
   kubernetes  Build Falco kernel modules and eBPF probes against a Kubernetes cluster.
 
 Flags:
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used. (default "falcosecurity/driverkit-builder:latest")
   -c, --config string             config file path (default $HOME/.driverkit.yaml if exists)
       --driverversion string      driver version as a git commit hash or as a git tag (default "master")
       --dryrun                    do not actually perform the action
diff --git a/cmd/testdata/non-existent-processor.txt b/cmd/testdata/non-existent-processor.txt
index dad2861..4b6c997 100644
--- a/cmd/testdata/non-existent-processor.txt
+++ b/cmd/testdata/non-existent-processor.txt
@@ -10,6 +10,7 @@ Available Commands:
   kubernetes  Build Falco kernel modules and eBPF probes against a Kubernetes cluster.
 
 Flags:
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, the default image will be used. (default "falcosecurity/driverkit-builder:latest")
   -c, --config string             config file path (default $HOME/.driverkit.yaml if exists)
       --driverversion string      driver version as a git commit hash or as a git tag (default "master")
       --dryrun                    do not actually perform the action