Repository: falcosecurity/driverkit
Pull request #155 (2022-06-10 16:35:34)

New: add ability to override kernel urls
Signed-off-by: johnbrydon <jbrydon@secureworks.com>

```
./driverkit docker --output-module /tmp/falco_azure.ko --timeout 120 --target ubuntu-aws --kernelrelease 4.15.0-1130-azure-4.15 --kernelversion 62 --kernelurls http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure-4.15/linux-azure-4.15-headers-4.15.0-1130_4.15.0-1130.143_all.deb --kernelurls http://security.ubuntu.com/ubuntu/pool/main/l/linux-azure-4.15/linux-headers-4.15.0-1130-azure_4.15.0-1130.143_amd64.deb -l debug

DEBU running without a configuration file         
DEBU running with options                          arch=amd64 driverversion=master kernelrelease=4.15.0-1130-azure-4.15 kernelurls="[http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure-4.15/linux-azure-4.15-headers-4.15.0-1130_4.15.0-1130.143_all.deb http://security.ubuntu.com/ubuntu/pool/main/l/linux-azure-4.15/linux-headers-4.15.0-1130-azure_4.15.0-1130.143_amd64.deb]" kernelversion=62 output-module=/tmp/falco_azure.ko target=ubuntu-aws
INFO driver building, it will take a few seconds   processor=docker
DEBU doing a new docker build                     
DEBU kernel header url found                       url="http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure-4.15/linux-azure-4.15-headers-4.15.0-1130_4.15.0-1130.143_all.deb"
DEBU kernel header url found                       url="http://security.ubuntu.com/ubuntu/pool/main/l/linux-azure-4.15/linux-headers-4.15.0-1130-azure_4.15.0-1130.143_amd64.deb"
.... 
DEBU filename:       /tmp/driver/module.ko 
DEBU schema_version: 1.0.0                        
DEBU api_version:    1.0.0                        
DEBU build_commit:   master                       
DEBU version:        master                       
DEBU author:         the Falco authors            
DEBU license:        GPL                          
DEBU srcversion:     3FFDAAA91B8B6B0EADA4FAD      
DEBU depends:                                     
DEBU retpoline:      Y                            
DEBU name:           falco                        
DEBU vermagic:       4.15.0-1130-azure SMP mod_unload modversions  
DEBU parm:           max_consumers:Maximum number of consumers that can simultaneously open the devices (uint) 
DEBU parm:           verbose:Enable verbose logging (bool) 
DEBU log pipe close                                error=EOF
INFO kernel module available                       path=/tmp/falco_azure.ko
```

**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

**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**:

- Add option for user to supply kernel headers urls via command line.
- Add option to read kernel headers urls from config file.
- Add option to read current kernel-crawler headers section.
This above are benefits as it allows us to keep up to date with latest kernel locations without requiring a code change.

**Which issue(s) this PR fixes**:

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:
yes

```release-note
new option added to cli and config file to read kernel urls.
```


dwindsor: @FedeDP 
dwindsor: Thanks for this! This allows us to be much more flexible with builders. 
dwindsor: Again, thank you for this! 🙏

Could you please post a screenshot to the description of this MR with the following:

- An example command line invocation for building a `ubuntu-azure` kernel using the `ubuntu-aws` target using the new `--kernelurls` argument
- Output showing successful generation of the driver (as in #130 )


poiana: LGTM label has been added.  <details>Git tree hash: 86195b0b340c7837ecad04729dcdd9eb3ac63309</details>
poiana: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/falcosecurity/driverkit/pull/155#pullrequestreview-1004442182" title="Approved">dwindsor</a>*, *<a href="https://github.com/falcosecurity/driverkit/pull/155#" title="Author self-approved">johnbrydon</a>*

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

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

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

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: /lgtm

Patch:
diff --git a/cmd/root.go b/cmd/root.go
index 0ccfb9d..fa3633f 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -37,19 +37,34 @@ func persistentValidateFunc(rootCommand *RootCmd, rootOpts *RootOptions) func(c
 			"output-probe":  "output.probe",
 		}
 		rootCommand.c.Flags().VisitAll(func(f *pflag.Flag) {
-			if name := f.Name; !skip[name] {
-				value := viper.GetString(name)
-				if value == "" {
-					// fallback to nested options in config file, if any
-					if nestedName, ok := nested[name]; ok {
-						value = viper.GetString(nestedName)
-					}
-				}
-				// set the value, if any, otherwise let the default
-				if value != "" {
-					rootCommand.c.Flags().Set(name, value)
-				}
-			}
+		    if name := f.Name; !skip[name] {
+                if name == "kernelurls" {
+                    // Slice types need special treatment when used as flags. If we call 'Set(name, value)',
+                    // rather than replace, it appends. Since viper will already have the cli options set
+                    // if supplied, we only need this step if rootCommand doesn't already have them e.g.
+                    // not set on CLI so read from config.
+                    if cli_urls, err := rootCommand.c.Flags().GetStringSlice(name); err == nil && len(cli_urls) != 0 {
+                       return
+                    }
+                    value := viper.GetStringSlice(name)
+                    if len(value) != 0 {
+                        strValue := strings.Join(value, ",")
+                        rootCommand.c.Flags().Set(name, strValue)
+                    }
+                } else {
+                    value := viper.GetString(name)
+                    if value == "" {
+                        // fallback to nested options in config file, if any
+                        if nestedName, ok := nested[name]; ok {
+                            value = viper.GetString(nestedName)
+                        }
+                    }
+                    // set the value, if any, otherwise let the default
+                    if value != "" {
+                        rootCommand.c.Flags().Set(name, value)
+                    }
+                }
+            }
 		})
 
 		// Avoid sensitive info into default values help line
@@ -120,6 +135,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, the default image will be used.")
+	flags.StringSliceVar(&rootOpts.KernelUrls, "kernelurls", nil, "list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls \"<URL3>,<URL4>\")")
 
 	viper.BindPFlags(flags)
 
diff --git a/cmd/root_options.go b/cmd/root_options.go
index 12ccaff..fd1b0e3 100644
--- a/cmd/root_options.go
+++ b/cmd/root_options.go
@@ -18,15 +18,16 @@ type OutputOptions struct {
 
 // RootOptions ...
 type RootOptions struct {
-	Architecture     string `validate:"required,oneof=amd64 arm64" name:"architecture"`
-	DriverVersion    string `default:"master" validate:"eq=master|sha1|semver" name:"driver version"`
-	KernelVersion    uint16 `default:"1" validate:"omitempty,number" name:"kernel version"`
-	ModuleDriverName string `default:"falco" validate:"max=60" name:"kernel module driver name"`
-	ModuleDeviceName string `default:"falco" validate:"excludes=/,max=255" name:"kernel module device name"`
-	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"`
+	Architecture     string   `validate:"required,oneof=amd64 arm64" name:"architecture"`
+	DriverVersion    string   `default:"master" validate:"eq=master|sha1|semver" name:"driver version"`
+	KernelVersion    uint16   `default:"1" validate:"omitempty,number" name:"kernel version"`
+	ModuleDriverName string   `default:"falco" validate:"max=60" name:"kernel module driver name"`
+	ModuleDeviceName string   `default:"falco" validate:"excludes=/,max=255" name:"kernel module device name"`
+	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"`
+	KernelUrls       []string `name:"kernel header urls"`
 	Output           OutputOptions
 }
 
@@ -88,6 +89,9 @@ func (ro *RootOptions) Log() {
 		fields["target"] = ro.Target
 	}
 	fields["arch"] = ro.Architecture
+	if len(ro.KernelUrls) > 0 {
+        fields["kernelurls"] = ro.KernelUrls
+    }
 
 	logger.WithFields(fields).Debug("running with options")
 }
@@ -110,6 +114,7 @@ func (ro *RootOptions) toBuild() *builder.Build {
 		ModuleDriverName:   ro.ModuleDriverName,
 		ModuleDeviceName:   ro.ModuleDeviceName,
 		CustomBuilderImage: ro.BuilderImage,
+		KernelUrls:         ro.KernelUrls,
 	}
 }
 
diff --git a/docs/driverkit.md b/docs/driverkit.md
index a5092c9..fd9ebe9 100644
--- a/docs/driverkit.md
+++ b/docs/driverkit.md
@@ -20,6 +20,7 @@ driverkit
   -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 []string       list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
       --kernelversion uint16      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")
diff --git a/docs/driverkit_docker.md b/docs/driverkit_docker.md
index 2008b04..9d6e268 100644
--- a/docs/driverkit_docker.md
+++ b/docs/driverkit_docker.md
@@ -20,6 +20,7 @@ driverkit docker [flags]
   -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 []string       list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
       --kernelversion uint16      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")
diff --git a/docs/driverkit_kubernetes.md b/docs/driverkit_kubernetes.md
index 101cab1..958b598 100644
--- a/docs/driverkit_kubernetes.md
+++ b/docs/driverkit_kubernetes.md
@@ -29,6 +29,7 @@ driverkit kubernetes [flags]
       --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 []string            list of kernel header urls (e.g. --kernelurls <URL1> --kernelurls <URL2> --kernelurls "<URL3>,<URL4>")
       --kernelversion uint16           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")
diff --git a/pkg/driverbuilder/builder/amazonlinux.go b/pkg/driverbuilder/builder/amazonlinux.go
index 8059902..208bdda 100644
--- a/pkg/driverbuilder/builder/amazonlinux.go
+++ b/pkg/driverbuilder/builder/amazonlinux.go
@@ -118,19 +118,23 @@ func script(c Config, targetType Type) (string, error) {
 	kv := kernelReleaseFromBuildConfig(c.Build)
 
 	var urls []string
-	var packages []string
-	// Check (and filter) existing kernels before continuing
-	packages, err = fetchAmazonLinuxPackagesURLs(kv, targetType)
-	if err != nil {
-		return "", err
-	}
-	urls, err = getResolvingURLs(packages)
-	if err != nil {
-		return "", err
-	}
-	if len(urls) != 2 {
-		return "", fmt.Errorf("target %s needs to find both kernel and kernel-devel packages", targetType)
-	}
+    if c.KernelUrls == nil {
+        // Check (and filter) existing kernels before continuing
+        var packages []string
+        packages, err = fetchAmazonLinuxPackagesURLs(kv, targetType)
+        if err != nil {
+            return "", err
+        }
+        urls, err = getResolvingURLs(packages)
+    } else {
+        urls, err = getResolvingURLs(c.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
+    if len(urls) < 2 {
+        return "", fmt.Errorf("target %s needs to find both kernel and kernel-devel packages", targetType)
+    }
 
 	td := amazonlinuxTemplateData{
 		DriverBuildDir:     DriverDirectory,
diff --git a/pkg/driverbuilder/builder/build.go b/pkg/driverbuilder/builder/build.go
index a3817c9..8c94c5d 100644
--- a/pkg/driverbuilder/builder/build.go
+++ b/pkg/driverbuilder/builder/build.go
@@ -13,4 +13,5 @@ type Build struct {
 	ModuleDriverName   string
 	ModuleDeviceName   string
 	CustomBuilderImage string
+	KernelUrls         []string
 }
diff --git a/pkg/driverbuilder/builder/centos.go b/pkg/driverbuilder/builder/centos.go
index efee3da..a8ba62d 100644
--- a/pkg/driverbuilder/builder/centos.go
+++ b/pkg/driverbuilder/builder/centos.go
@@ -30,10 +30,15 @@ func (c centos) Script(cfg Config) (string, error) {
 	kr := kernelReleaseFromBuildConfig(cfg.Build)
 
 	var urls []string
-	urls, err = getResolvingURLs(fetchCentosKernelURLS(kr))
-	if err != nil {
-		return "", err
-	}
+    if cfg.KernelUrls == nil {
+        // Check (and filter) existing kernels before continuing
+        urls, err = getResolvingURLs(fetchCentosKernelURLS(kr))
+    } else {
+        urls, err = getResolvingURLs(cfg.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
 
 	td := centosTemplateData{
 		DriverBuildDir:    DriverDirectory,
diff --git a/pkg/driverbuilder/builder/debian.go b/pkg/driverbuilder/builder/debian.go
index 077b95b..60a979b 100644
--- a/pkg/driverbuilder/builder/debian.go
+++ b/pkg/driverbuilder/builder/debian.go
@@ -36,15 +36,19 @@ func (v debian) Script(c Config) (string, error) {
 	}
 
 	var urls []string
-	var kurls []string
-	kurls, err = fetchDebianKernelURLs(kr)
-	if err != nil {
-		return "", err
-	}
-	urls, err = getResolvingURLs(kurls)
-	if err != nil {
-		return "", err
-	}
+    if c.KernelUrls == nil {
+        var kurls []string
+        kurls, err = fetchDebianKernelURLs(kr)
+        if err != nil {
+            return "", err
+        }
+        urls, err = getResolvingURLs(kurls)
+    } else {
+        urls, err = getResolvingURLs(c.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
 	if len(urls) < 2 {
 		return "", fmt.Errorf("specific kernel headers not found")
 	}
diff --git a/pkg/driverbuilder/builder/flatcar.go b/pkg/driverbuilder/builder/flatcar.go
index 64aaaa8..a8f26e8 100644
--- a/pkg/driverbuilder/builder/flatcar.go
+++ b/pkg/driverbuilder/builder/flatcar.go
@@ -55,11 +55,16 @@ func (c flatcar) Script(cfg Config) (string, error) {
 		return "", err
 	}
 
-	// Check (and filter) existing kernels before continuing
-	urls, err := getResolvingURLs(fetchFlatcarKernelURLS(flatcarInfo.KernelVersion))
-	if err != nil {
-		return "", err
-	}
+	var urls []string
+    if cfg.KernelUrls == nil {
+        // Check (and filter) existing kernels before continuing
+        urls, err = getResolvingURLs(fetchFlatcarKernelURLS(flatcarInfo.KernelVersion))
+    } else {
+        urls, err = getResolvingURLs(cfg.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
 
 	td := flatcarTemplateData{
 		DriverBuildDir:    DriverDirectory,
diff --git a/pkg/driverbuilder/builder/rocky.go b/pkg/driverbuilder/builder/rocky.go
index 0a0ebb7..d8611f4 100644
--- a/pkg/driverbuilder/builder/rocky.go
+++ b/pkg/driverbuilder/builder/rocky.go
@@ -30,10 +30,15 @@ func (c rocky) Script(cfg Config) (string, error) {
 	kr := kernelReleaseFromBuildConfig(cfg.Build)
 
 	var urls []string
-	urls, err = getResolvingURLs(fetchRockyKernelURLS(kr))
-	if err != nil {
-		return "", err
-	}
+    if cfg.KernelUrls == nil {
+        // Check (and filter) existing kernels before continuing
+        urls, err = getResolvingURLs(fetchRockyKernelURLS(kr))
+    } else {
+        urls, err = getResolvingURLs(cfg.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
 
 	td := rockyTemplateData{
 		DriverBuildDir:    DriverDirectory,
diff --git a/pkg/driverbuilder/builder/ubuntu.go b/pkg/driverbuilder/builder/ubuntu.go
index d41b348..22e6d26 100644
--- a/pkg/driverbuilder/builder/ubuntu.go
+++ b/pkg/driverbuilder/builder/ubuntu.go
@@ -38,13 +38,17 @@ func (v ubuntuGeneric) Script(c Config) (string, error) {
 	kr := kernelReleaseFromBuildConfig(c.Build)
 
 	var urls []string
-	urls, err = ubuntuGenericHeadersURLFromRelease(kr, c.Build.KernelVersion)
-	if err != nil {
-		return "", err
-	}
-	if len(urls) != 2 {
-		return "", fmt.Errorf("specific kernel headers not found")
-	}
+    if c.KernelUrls == nil {
+        urls, err = ubuntuGenericHeadersURLFromRelease(kr, c.Build.KernelVersion)
+    } else {
+        urls, err = getResolvingURLs(c.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
+    if len(urls) < 2 {
+        return "", fmt.Errorf("specific kernel headers not found")
+    }
 
 	td := ubuntuTemplateData{
 		DriverBuildDir:       DriverDirectory,
@@ -86,13 +90,17 @@ func (v ubuntuAWS) Script(c Config) (string, error) {
 	kr := kernelReleaseFromBuildConfig(c.Build)
 
 	var urls []string
-	urls, err = ubuntuAWSHeadersURLFromRelease(kr, c.Build.KernelVersion)
-	if err != nil {
-		return "", err
-	}
-	if len(urls) != 2 {
-		return "", fmt.Errorf("specific kernel headers not found")
-	}
+    if c.KernelUrls == nil {
+        urls, err = ubuntuAWSHeadersURLFromRelease(kr, c.KernelVersion)
+    } else {
+        urls, err = getResolvingURLs(c.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
+    if len(urls) < 2 {
+        return "", fmt.Errorf("specific kernel headers not found")
+    }
 
 	td := ubuntuTemplateData{
 		DriverBuildDir:       DriverDirectory,
diff --git a/pkg/driverbuilder/builder/vanilla.go b/pkg/driverbuilder/builder/vanilla.go
index 6cb0a7a..44a971e 100644
--- a/pkg/driverbuilder/builder/vanilla.go
+++ b/pkg/driverbuilder/builder/vanilla.go
@@ -94,11 +94,15 @@ func (v vanilla) Script(c Config) (string, error) {
 	kv := kernelReleaseFromBuildConfig(c.Build)
 
 	var urls []string
-	// Check (and filter) existing kernels before continuing
-	urls, err = getResolvingURLs([]string{fetchVanillaKernelURLFromKernelVersion(kv)})
-	if err != nil {
-		return "", err
-	}
+    if c.KernelUrls == nil {
+        // Check (and filter) existing kernels before continuing
+        urls, err = getResolvingURLs([]string{fetchVanillaKernelURLFromKernelVersion(kv)})
+    } else {
+        urls, err = getResolvingURLs(c.KernelUrls)
+    }
+    if err != nil {
+        return "", err
+    }
 
 	td := vanillaTemplateData{
 		DriverBuildDir:     DriverDirectory,


Test patch:
diff --git a/cmd/cli_test.go b/cmd/cli_test.go
index faca71e..07ce4f3 100644
--- a/cmd/cli_test.go
+++ b/cmd/cli_test.go
@@ -82,6 +82,10 @@ var tests = []testCase{
 			"4.15.0-1057-aws",
 			"--kernelversion",
 			"59",
+			"--kernelurls",
+			"https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-aws-headers-4.15.0-1057_4.15.0-1057.59_all.deb",
+			"--kernelurls",
+			"https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-headers-4.15.0-1057-aws_4.15.0-1057.59_amd64.deb",
 			"--target",
 			"ubuntu-aws",
 			"--output-module",
@@ -108,6 +112,10 @@ var tests = []testCase{
 			"4.15.0-1057-aws",
 			"--kernelversion",
 			"59",
+			"--kernelurls",
+			"https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-aws-headers-4.15.0-1057_4.15.0-1057.59_all.deb",
+			"--kernelurls",
+			"https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-headers-4.15.0-1057-aws_4.15.0-1057.59_amd64.deb",
 			"--target",
 			"ubuntu-aws",
 			"--output-module",
@@ -130,6 +138,10 @@ var tests = []testCase{
 			"docker",
 			"--kernelrelease",
 			"4.15.0-1057-aws",
+			"--kernelurls",
+			"https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-aws-headers-4.15.0-1057_4.15.0-1057.59_all.deb",
+			"--kernelurls",
+			"https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-headers-4.15.0-1057-aws_4.15.0-1057.59_amd64.deb",
 			"-t",
 			"ubuntu-aws",
 			"--loglevel",
@@ -154,6 +166,20 @@ var tests = []testCase{
 			fmtRuntimeArch: true,
 		},
 	},
+	{
+	    descr: "docker/from-config-file-using-urls",
+        args: []string{
+            "docker",
+            "-c",
+            "testdata/configs/2.yaml",
+            "--loglevel",
+            "debug",
+        },
+        expect: expect{
+            out:            "testdata/docker-override-urls-from-config-debug.txt",
+            fmtRuntimeArch: true,
+        },
+    },
 	{
 		descr: "docker/override-from-config-file",
 		env: map[string]string{
@@ -172,6 +198,30 @@ var tests = []testCase{
 			fmtRuntimeArch: true,
 		},
 	},
+	{
+	    descr: "docker/build-related-target-azure",
+	    args: []string{
+	        "docker",
+	        "--kernelrelease",
+	        "4.15.0-1057-azure",
+	        "--kernelversion",
+	        "62",
+	        "--kernelurls",
+	        "http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure/linux-azure-headers-4.15.0-1057_4.15.0-1057.62_all.deb",
+	        "--kernelurls",
+	        "http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure/linux-headers-4.15.0-1057-azure_4.15.0-1057.62_amd64.deb",
+	        "--target",
+	        "ubuntu-aws",
+	        "--output-module",
+	        "/tmp/falco-ubuntu-azure.ko",
+	        "--loglevel",
+	        "debug",
+        },
+        expect: expect{
+            out:            "testdata/docker-related-target-debug.txt",
+            fmtRuntimeArch: true,
+        },
+    },
 	{
 		descr: "complete/docker/targets",
 		args: []string{
diff --git a/cmd/testdata/autohelp.txt b/cmd/testdata/autohelp.txt
index 8464a23..a69fdc5 100644
--- a/cmd/testdata/autohelp.txt
+++ b/cmd/testdata/autohelp.txt
@@ -20,6 +20,7 @@ Flags:
   -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 uint16      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")
diff --git a/cmd/testdata/configs/2.yaml b/cmd/testdata/configs/2.yaml
new file mode 100644
index 0000000..9260a15
--- /dev/null
+++ b/cmd/testdata/configs/2.yaml
@@ -0,0 +1,10 @@
+kernelrelease: 4.15.0-1057-aws
+kernelversion: 59
+kernelurls: [
+    "https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-aws-headers-4.15.0-1057_4.15.0-1057.59_all.deb",
+    "https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-headers-4.15.0-1057-aws_4.15.0-1057.59_amd64.deb",
+]
+target: ubuntu-aws
+output:
+    module: /tmp/falco-ubuntu-aws.ko
+driverversion: master
diff --git a/cmd/testdata/docker-override-urls-from-config-debug.txt b/cmd/testdata/docker-override-urls-from-config-debug.txt
new file mode 100644
index 0000000..c035e86
--- /dev/null
+++ b/cmd/testdata/docker-override-urls-from-config-debug.txt
@@ -0,0 +1,3 @@
+INFO using config file                             file=testdata/configs/2.yaml
+DEBU running with options                          arch=%s driverversion=master kernelrelease=4.15.0-1057-aws kernelurls="[https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-aws-headers-4.15.0-1057_4.15.0-1057.59_all.deb https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-headers-4.15.0-1057-aws_4.15.0-1057.59_amd64.deb]" kernelversion=59 output-module=/tmp/falco-ubuntu-aws.ko target=ubuntu-aws
+INFO driver building, it will take a few seconds   processor=docker
diff --git a/cmd/testdata/docker-related-target-debug.txt b/cmd/testdata/docker-related-target-debug.txt
new file mode 100644
index 0000000..091c9aa
--- /dev/null
+++ b/cmd/testdata/docker-related-target-debug.txt
@@ -0,0 +1,3 @@
+DEBU running without a configuration file         
+DEBU running with options                          arch=%s driverversion=master kernelrelease=4.15.0-1057-azure kernelurls="[http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure/linux-azure-headers-4.15.0-1057_4.15.0-1057.62_all.deb http://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-azure/linux-headers-4.15.0-1057-azure_4.15.0-1057.62_amd64.deb]" kernelversion=62 output-module=/tmp/falco-ubuntu-azure.ko target=ubuntu-aws
+INFO driver building, it will take a few seconds   processor=docker
diff --git a/cmd/testdata/docker-with-flags-debug.txt b/cmd/testdata/docker-with-flags-debug.txt
index d53a980..3091121 100644
--- a/cmd/testdata/docker-with-flags-debug.txt
+++ b/cmd/testdata/docker-with-flags-debug.txt
@@ -1,3 +1,3 @@
 DEBU running without a configuration file         
-DEBU running with options                          arch=%s driverversion=master kernelrelease=4.15.0-1057-aws kernelversion=59 output-module=/tmp/falco-ubuntu-aws.ko target=ubuntu-aws
+DEBU running with options                          arch=%s driverversion=master kernelrelease=4.15.0-1057-aws kernelurls="[https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-aws-headers-4.15.0-1057_4.15.0-1057.59_all.deb https://mirrors.edge.kernel.org/ubuntu/pool/main/l/linux-aws/linux-headers-4.15.0-1057-aws_4.15.0-1057.59_amd64.deb]" kernelversion=59 output-module=/tmp/falco-ubuntu-aws.ko target=ubuntu-aws
 INFO driver building, it will take a few seconds   processor=docker
diff --git a/cmd/testdata/dockernoopts.txt b/cmd/testdata/dockernoopts.txt
index 39504de..fd4bf87 100644
--- a/cmd/testdata/dockernoopts.txt
+++ b/cmd/testdata/dockernoopts.txt
@@ -15,6 +15,7 @@ Flags:
   -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 uint16      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")
diff --git a/cmd/testdata/help-flag.txt b/cmd/testdata/help-flag.txt
index 797ef07..0bd22b4 100644
--- a/cmd/testdata/help-flag.txt
+++ b/cmd/testdata/help-flag.txt
@@ -19,6 +19,7 @@ Flags:
   -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 uint16      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")
diff --git a/cmd/testdata/help.txt b/cmd/testdata/help.txt
index 78d5d0b..8bc7ccf 100644
--- a/cmd/testdata/help.txt
+++ b/cmd/testdata/help.txt
@@ -19,6 +19,7 @@ Flags:
   -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 uint16      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")
diff --git a/cmd/testdata/invalid-proxyconfig.txt b/cmd/testdata/invalid-proxyconfig.txt
index c32b004..57dab24 100644
--- a/cmd/testdata/invalid-proxyconfig.txt
+++ b/cmd/testdata/invalid-proxyconfig.txt
@@ -19,6 +19,7 @@ Flags:
   -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 uint16      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")
diff --git a/cmd/testdata/non-existent-processor.txt b/cmd/testdata/non-existent-processor.txt
index 761ccbb..d005317 100644
--- a/cmd/testdata/non-existent-processor.txt
+++ b/cmd/testdata/non-existent-processor.txt
@@ -18,6 +18,7 @@ Flags:
   -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 uint16      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")