Repository: falcosecurity/driverkit
Pull request #238 (2022-12-09 11:18:36)

feat(builder-image): config flag for custom base image
config flag for custom base image to override the compile-time defined BaseImage

Signed-off-by: Lyonel Martinez <lyonel.martinez@numberly.com>

**What type of PR is this?**

/kind feature

**Any specific area of the project related to this PR?**

 /area cmd

 /area pkg

 /area docs


**What this PR does / why we need it**:

In order to use proxy images and to avoid defining a single image to the command line and still benefit the auto-choose based on GCC version need by the kernel

**Which issue(s) this PR fixes**:

None

**Special notes for your reviewer**:

I included a mini fix of the Makefile, the `make docs` was erasing builder and builder_image doc.
And it seems that a pretty big part of the docs was missing.

**Does this PR introduce a user-facing change?**:

```release-note
new option: --builderimagebase base image string used to get the different build images 
```


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

This pull-request has been approved by: *<a href="https://github.com/falcosecurity/driverkit/pull/238#" title="Author self-approved">Lowaiz</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign dwindsor for approval by writing `/assign @dwindsor` in a comment. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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":["dwindsor"]} -->
FedeDP: Hi @Lowaiz ! Thanks for this PR
> In order to use proxy images and to avoid defining a single image to the command line and still benefit the auto-choose based on GCC version need by the kernel

If i understood correctly, you want to achieve a situation where you can ship your own `_bookwork/_bullseye/_buster` images, right? 
Can you expand on the use cases?

I actually think it would be great to fetch tags (like `DRIVERKIT_PROVIDED_GCCS`) `docker inspect`ing the provided images, allowing users to fully customize the list of builder images and entirely dropping our static map.
BUT we cannot afford to pull all the builder images before every build; it would increase build time 10x... that's why i used the static map.
Yet it would be so freakingly good to be able to fetch metadata from provided builder images...
Lowaiz: > If i understood correctly, you want to achieve a situation where you can ship your own _bookwork/_bullseye/_buster images, right?
Can you expand on the use cases?

In order to limit requests to docker.io from our infra, we are proxying images by pushing them in our private container registry. So with the Driverkit, we need to push the `driverkit_*` images to our registry, but as the image link is hard coded we couldn't use these images. That why we need the new flag.
So it's not really about shipping our own custom images as we don't modify them when we add them in the registry.

> BUT we cannot afford to pull all the builder images before every build; it would increase build time 10x... that's why i used the static map

The static map is not problematic for us. As I said, the proxyed images are not modified as we want to stick to the official behavior of Driverkit. It might be usefull to add a bit of doc to explain that this new flag assume that you have no custom builder images but only proxy images.

FedeDP: Oh i see, it makes sense! Thank you! I will give this another look asap!
poiana: LGTM label has been added.  <details>Git tree hash: e6532e7fbede4c61e81672573c1d0d6739dc5a7c</details>
FedeDP: Mmmh poiana?
Trying to close and reopen to trigger.
FedeDP: /reopen
poiana: @FedeDP: Reopened this PR.

<details>

In response to [this](https://github.com/falcosecurity/driverkit/pull/238#issuecomment-1357425977):

>/reopen


Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

Patch:
diff --git a/Makefile b/Makefile
index 7583e76..7dda45f 100644
--- a/Makefile
+++ b/Makefile
@@ -132,6 +132,6 @@ ${driverkit_docgen}: ${PWD}/docgen
 
 .PHONY: docs
 docs: ${driverkit_docgen}
-	$(RM) -R docs/*
+	$(RM) -R docs/driverkit*
 	@mkdir -p docs
 	${driverkit_docgen}
diff --git a/cmd/root.go b/cmd/root.go
index cea4e16..237436e 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -144,6 +144,7 @@ func NewRootCmd() *RootCmd {
 	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, an automatically selected image will be used.")
+	flags.StringVar(&rootOpts.BuilderImageBase, "builderimagebase", rootOpts.BuilderImageBase, "base docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.")
 	flags.StringVar(&rootOpts.GCCVersion, "gccversion", rootOpts.GCCVersion, "enforce a specific gcc version for the build")
 
 	flags.StringSliceVar(&rootOpts.KernelUrls, "kernelurls", nil, "list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls \"<URL3>,<URL4>\")")
diff --git a/cmd/root_options.go b/cmd/root_options.go
index 55b1b83..da9591d 100644
--- a/cmd/root_options.go
+++ b/cmd/root_options.go
@@ -33,6 +33,7 @@ type RootOptions struct {
 	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:"omitempty,imagename" name:"builder image"`
+	BuilderImageBase string   `validate:"omitempty,imagename" name:"builder base image"`
 	GCCVersion       string   `validate:"omitempty,semvertolerant" name:"gcc version"`
 	KernelUrls       []string `name:"kernel header urls"`
 	Repo             RepoOptions
@@ -115,21 +116,22 @@ func (ro *RootOptions) toBuild() *builder.Build {
 	}
 
 	build := &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,
-		GCCVersion:         ro.GCCVersion,
-		CustomBuilderImage: ro.BuilderImage,
-		KernelUrls:         ro.KernelUrls,
-		RepoOrg:            ro.Repo.Org,
-		RepoName:           ro.Repo.Name,
+		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,
+		GCCVersion:             ro.GCCVersion,
+		CustomBuilderImage:     ro.BuilderImage,
+		CustomBuilderImageBase: ro.BuilderImageBase,
+		KernelUrls:             ro.KernelUrls,
+		RepoOrg:                ro.Repo.Org,
+		RepoName:               ro.Repo.Name,
 	}
 
 	// attempt the build in case it comes from an invalid config
diff --git a/docs/driverkit.md b/docs/driverkit.md
index a8d84bd..9381d6e 100644
--- a/docs/driverkit.md
+++ b/docs/driverkit.md
@@ -6,6 +6,33 @@ A command line tool to build Falco kernel modules and eBPF probes.
 driverkit
 ```
 
+### Options
+
+```
+      --architecture string       target architecture for the built driver, one of [amd64,arm64] (default "amd64")
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+      --builderimagebase string   base docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+  -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
+      --gccversion string         enforce a specific gcc version for the build
+  -h, --help                      help for driverkit
+      --kernelconfigdata string   base64 encoded kernel config data: in some systems it can be found under the /boot directory, in other it is gzip compressed under /proc
+      --kernelrelease string      kernel release to build the module for, it can be found by executing 'uname -v'
+      --kernelurls strings        list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
+      --kernelversion string      kernel version to build the module for, it's the numeric value after the hash when you execute 'uname -v' (default "1")
+  -l, --loglevel string           log level (default "info")
+      --moduledevicename string   kernel module device name (the default is falco, so the device will be under /dev/falco*) (default "falco")
+      --moduledrivername string   kernel module driver name, i.e. the name you see when you check installed modules via lsmod (default "falco")
+      --output-module string      filepath where to save the resulting kernel module
+      --output-probe string       filepath where to save the resulting eBPF probe
+      --proxy string              the proxy to use to download data
+      --repo-name string          repository github name (default "libs")
+      --repo-org string           repository github organization (default "falcosecurity")
+  -t, --target string             the system to target the build for, one of [almalinux,amazonlinux,amazonlinux2,amazonlinux2022,arch,centos,debian,fedora,flatcar,minikube,opensuse,photon,redhat,rocky,ubuntu,vanilla]
+      --timeout int               timeout in seconds (default 120)
+```
+
 ### SEE ALSO
 
 * [driverkit completion](driverkit_completion.md)	 - Generates completion scripts.
diff --git a/docs/driverkit_docker.md b/docs/driverkit_docker.md
index 653d3cf..0e061d7 100644
--- a/docs/driverkit_docker.md
+++ b/docs/driverkit_docker.md
@@ -6,6 +6,33 @@ Build Falco kernel modules and eBPF probes against a docker daemon.
 driverkit docker [flags]
 ```
 
+### Options
+
+```
+      --architecture string       target architecture for the built driver, one of [amd64,arm64] (default "amd64")
+      --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+      --builderimagebase string   base docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+  -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
+      --gccversion string         enforce a specific gcc version for the build
+  -h, --help                      help for docker
+      --kernelconfigdata string   base64 encoded kernel config data: in some systems it can be found under the /boot directory, in other it is gzip compressed under /proc
+      --kernelrelease string      kernel release to build the module for, it can be found by executing 'uname -v'
+      --kernelurls strings        list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
+      --kernelversion string      kernel version to build the module for, it's the numeric value after the hash when you execute 'uname -v' (default "1")
+  -l, --loglevel string           log level (default "info")
+      --moduledevicename string   kernel module device name (the default is falco, so the device will be under /dev/falco*) (default "falco")
+      --moduledrivername string   kernel module driver name, i.e. the name you see when you check installed modules via lsmod (default "falco")
+      --output-module string      filepath where to save the resulting kernel module
+      --output-probe string       filepath where to save the resulting eBPF probe
+      --proxy string              the proxy to use to download data
+      --repo-name string          repository github name (default "libs")
+      --repo-org string           repository github organization (default "falcosecurity")
+  -t, --target string             the system to target the build for, one of [almalinux,amazonlinux,amazonlinux2,amazonlinux2022,arch,centos,debian,fedora,flatcar,minikube,opensuse,photon,redhat,rocky,ubuntu,vanilla]
+      --timeout int               timeout in seconds (default 120)
+```
+
 ### SEE ALSO
 
 * [driverkit](driverkit.md)	 - A command line tool to build Falco kernel modules and eBPF probes.
diff --git a/docs/driverkit_kubernetes-in-cluster.md b/docs/driverkit_kubernetes-in-cluster.md
index 120c6c3..c27463b 100644
--- a/docs/driverkit_kubernetes-in-cluster.md
+++ b/docs/driverkit_kubernetes-in-cluster.md
@@ -6,6 +6,36 @@ Build Falco kernel modules and eBPF probes against a Kubernetes cluster inside a
 driverkit kubernetes-in-cluster [flags]
 ```
 
+### Options
+
+```
+      --architecture string        target architecture for the built driver, one of [amd64,arm64] (default "amd64")
+      --builderimage string        docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+      --builderimagebase string    base docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+  -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
+      --gccversion string          enforce a specific gcc version for the build
+  -h, --help                       help for kubernetes-in-cluster
+      --image-pull-secret string   ImagePullSecret
+      --kernelconfigdata string    base64 encoded kernel config data: in some systems it can be found under the /boot directory, in other it is gzip compressed under /proc
+      --kernelrelease string       kernel release to build the module for, it can be found by executing 'uname -v'
+      --kernelurls strings         list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
+      --kernelversion string       kernel version to build the module for, it's the numeric value after the hash when you execute 'uname -v' (default "1")
+  -l, --loglevel string            log level (default "info")
+      --moduledevicename string    kernel module device name (the default is falco, so the device will be under /dev/falco*) (default "falco")
+      --moduledrivername string    kernel module driver name, i.e. the name you see when you check installed modules via lsmod (default "falco")
+  -n, --namespace string           If present, the namespace scope for the pods and its config  (default "default")
+      --output-module string       filepath where to save the resulting kernel module
+      --output-probe string        filepath where to save the resulting eBPF probe
+      --proxy string               the proxy to use to download data
+      --repo-name string           repository github name (default "libs")
+      --repo-org string            repository github organization (default "falcosecurity")
+      --run-as-user int            Pods runner user
+  -t, --target string              the system to target the build for, one of [almalinux,amazonlinux,amazonlinux2,amazonlinux2022,arch,centos,debian,fedora,flatcar,minikube,opensuse,photon,redhat,rocky,ubuntu,vanilla]
+      --timeout int                timeout in seconds (default 120)
+```
+
 ### SEE ALSO
 
 * [driverkit](driverkit.md)	 - A command line tool to build Falco kernel modules and eBPF probes.
diff --git a/docs/driverkit_kubernetes.md b/docs/driverkit_kubernetes.md
index 62b2f7f..04b3df4 100644
--- a/docs/driverkit_kubernetes.md
+++ b/docs/driverkit_kubernetes.md
@@ -6,6 +6,52 @@ Build Falco kernel modules and eBPF probes against a Kubernetes cluster.
 driverkit kubernetes [flags]
 ```
 
+### Options
+
+```
+      --architecture string            target architecture for the built driver, one of [amd64,arm64] (default "amd64")
+      --as string                      username to impersonate for the operation, user could be a regular user or a service account in a namespace
+      --as-group stringArray           group to impersonate for the operation, this flag can be repeated to specify multiple groups
+      --as-uid string                  uID to impersonate for the operation
+      --builderimage string            docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+      --builderimagebase string        base docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+      --cache-dir string               default cache directory (default "$HOME/.kube/cache")
+      --certificate-authority string   path to a cert file for the certificate authority
+      --client-certificate string      path to a client certificate file for TLS
+      --client-key string              path to a client key file for TLS
+      --cluster string                 the name of the kubeconfig cluster to use
+  -c, --config string                  config file path (default $HOME/.driverkit.yaml if exists)
+      --context string                 the name of the kubeconfig context to use
+      --driverversion string           driver version as a git commit hash or as a git tag (default "master")
+      --dryrun                         do not actually perform the action
+      --gccversion string              enforce a specific gcc version for the build
+  -h, --help                           help for kubernetes
+      --image-pull-secret string       ImagePullSecret
+      --insecure-skip-tls-verify       if true, the server's certificate will not be checked for validity, this will make your HTTPS connections insecure
+      --kernelconfigdata string        base64 encoded kernel config data: in some systems it can be found under the /boot directory, in other it is gzip compressed under /proc
+      --kernelrelease string           kernel release to build the module for, it can be found by executing 'uname -v'
+      --kernelurls strings             list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
+      --kernelversion string           kernel version to build the module for, it's the numeric value after the hash when you execute 'uname -v' (default "1")
+      --kubeconfig string              path to the kubeconfig file to use for CLI requests
+  -l, --loglevel string                log level (default "info")
+      --moduledevicename string        kernel module device name (the default is falco, so the device will be under /dev/falco*) (default "falco")
+      --moduledrivername string        kernel module driver name, i.e. the name you see when you check installed modules via lsmod (default "falco")
+  -n, --namespace string               If present, the namespace scope for the pods and its config  (default "default")
+      --output-module string           filepath where to save the resulting kernel module
+      --output-probe string            filepath where to save the resulting eBPF probe
+      --proxy string                   the proxy to use to download data
+      --repo-name string               repository github name (default "libs")
+      --repo-org string                repository github organization (default "falcosecurity")
+      --request-timeout string         the length of time to wait before giving up on a single server request, non-zero values should contain a corresponding time unit (e.g, 1s, 2m, 3h), a value of zero means don't timeout requests (default "0")
+      --run-as-user int                Pods runner user
+  -s, --server string                  the address and port of the Kubernetes API server
+  -t, --target string                  the system to target the build for, one of [almalinux,amazonlinux,amazonlinux2,amazonlinux2022,arch,centos,debian,fedora,flatcar,minikube,opensuse,photon,redhat,rocky,ubuntu,vanilla]
+      --timeout int                    timeout in seconds (default 120)
+      --tls-server-name string         server name to use for server certificate validation, if it is not provided, the hostname used to contact the server is used
+      --token string                   bearer token for authentication to the API server
+      --user string                    the name of the kubeconfig user to use
+```
+
 ### SEE ALSO
 
 * [driverkit](driverkit.md)	 - A command line tool to build Falco kernel modules and eBPF probes.
diff --git a/pkg/driverbuilder/builder/build.go b/pkg/driverbuilder/builder/build.go
index c78474c..d6ddf0c 100644
--- a/pkg/driverbuilder/builder/build.go
+++ b/pkg/driverbuilder/builder/build.go
@@ -7,21 +7,22 @@ import (
 
 // Build contains the info about the on-going build.
 type Build struct {
-	TargetType         Type
-	KernelConfigData   string
-	KernelRelease      string
-	KernelVersion      string
-	DriverVersion      string
-	Architecture       string
-	ModuleFilePath     string
-	ProbeFilePath      string
-	ModuleDriverName   string
-	ModuleDeviceName   string
-	CustomBuilderImage string
-	KernelUrls         []string
-	GCCVersion         string
-	RepoOrg            string
-	RepoName           string
+	TargetType             Type
+	KernelConfigData       string
+	KernelRelease          string
+	KernelVersion          string
+	DriverVersion          string
+	Architecture           string
+	ModuleFilePath         string
+	ProbeFilePath          string
+	ModuleDriverName       string
+	ModuleDeviceName       string
+	CustomBuilderImage     string
+	CustomBuilderImageBase string
+	KernelUrls             []string
+	GCCVersion             string
+	RepoOrg                string
+	RepoName               string
 }
 
 func (b *Build) KernelReleaseFromBuildConfig() kernelrelease.KernelRelease {
diff --git a/pkg/driverbuilder/builder/builders.go b/pkg/driverbuilder/builder/builders.go
index 20db978..89dccf4 100644
--- a/pkg/driverbuilder/builder/builders.go
+++ b/pkg/driverbuilder/builder/builders.go
@@ -280,7 +280,14 @@ func (b *Build) GetBuilderImage() string {
 
 	// A bit complicated because we must check that
 	// "auto:tag" custom builder image was not passed
-	builderImage := BaseImage
+	var builderImage string
+
+	if len(b.CustomBuilderImageBase) != 0 {
+		builderImage = b.CustomBuilderImageBase
+	} else {
+		builderImage = BaseImage
+	}
+
 	names := strings.Split(builderImage, ":")
 	// Updated image tag if no "auto" custom builder image was passed
 	if imageTag == "" {


Test patch:
diff --git a/cmd/testdata/templates/flags.txt b/cmd/testdata/templates/flags.txt
index 415c9cb..39d3569 100644
--- a/cmd/testdata/templates/flags.txt
+++ b/cmd/testdata/templates/flags.txt
@@ -1,6 +1,7 @@
 Flags:
       --architecture string       target architecture for the built driver, one of {{ .Architectures }} (default "{{ .CurrentArch }}")
       --builderimage string       docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
+      --builderimagebase string   base docker image to be used to build the kernel module and eBPF probe. If not provided, an automatically selected image will be used.
   -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