Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 25 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,41 @@
# Builder

The Builder is a powerful tool for effortlessly building Linux system images based on config directories. It serves as the primary build tooling for the [gardenlinux](https://github.com/gardenlinux/gardenlinux) project.
The Builder is a powerful tool for effortlessly building Linux system images
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

based on config directories. It serves as the primary build tooling for the
[gardenlinux](https://github.com/gardenlinux/gardenlinux) project.

By default, the Builder runs inside rootless Podman, enabling building without requiring elevated permissions.
By default, the Builder runs inside rootless Podman, enabling building without
requiring elevated permissions.

## Requirements
## Documentation

The Builder has minimal dependencies and only requires a working container engine. We recommend using rootless Podman. Please refer to the [Podman rootless setup guide](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md) for instructions on setting it up.
To learn how to use or contribute to Builder, refer to our
[Documentation](https://gardenlinux-docs.netlify.app/reference/supporting_tools/builder.html)

## Usage
# Community

To utilize the Builder, follow these steps:
To stay up-to-date with recent news about Gardenlinux, subscribe to our mailing
list:

1. Download the latest version of the [build script](https://github.com/gardenlinux/builder/releases/download/latest/build).
2. Run the build script within a config directory.
https://lists.neonephos.org/g/gardenlinux-discussion

```shell
wget https://github.com/gardenlinux/builder/releases/download/latest/build
./build ${target}
```
For updates and statements regarding security issues, we have a security mailing
list for you:

By default, the Builder uses `podman` as the container engine. If you prefer using a different container engine, you can specify it using the `--container-engine` option.
https://lists.neonephos.org/g/gardenlinux-security

If you decide to use `docker` on a system restricting unprivileged user namespaces with apparmor (e.g. Ubuntu 23.10 or newer) an apparmor profile allowing `userns` is required. This can be automatically created and selected by the Builder by opting in to the permanent system change. You can avoid this by:
For embargoed security related topics, this list is for you:

- Using `podman`
- Passing a custom profile using the `--apparmor-profile` option
- Using a system not restricting unprivileged user namespaces

## Config Directory

A config directory serves as the input for the Builder and is used to create a Linux system image. It consists of the following components:

- **`features` directory**: Contains sub-directories for each feature. You can create your own features by referring to [features.md](docs/features.md).

- **`cert` directory** (optional): If you plan to use secure boot, include a `cert` directory.

In addition to the above components, your configuration directory must include the following configuration scripts:

- `get_commit`: This script should output the Git commit used to tag the build artifacts.
- `get_repo`: This script should output the apt package repository to use.
- `get_timestamp`: This script should output the timestamp to be used instead of the real system time, ensuring reproducibility of builds.
- `get_version`: This script should output the version of the package repository to use. For example, use `forky` for Debian or `today` for Garden Linux.
- `keyring.gpg`: The PGP key used to validate the package repository. For Debian, you can obtain this key from the [debian-archive-keyring](https://packages.debian.org/forky/debian-archive-keyring) package.

For a quick start guide on setting up your own config directory with your own features checkout [getting_started.md](docs/getting_started.md).

### Example Config Directory

If you're new to configuring the Builder, you can find a minimal example config directory at [gardenlinux/builder_example](https://github.com/gardenlinux/builder_example). For a more comprehensive example, refer to the main [gardenlinux](https://github.com/gardenlinux/gardenlinux) repository.

Feel free to explore these examples to gain a better understanding of how to effectively structure your own config directory.


## Local Development

To test changes made to the builder locally you can simply create a symlink to the build script inside the builder directory inside a config directory. This will automatically be detected by the build script and the builder re-build iff necessary.

e.g.: if you have the gardenlinux and builder repos both inside the same parent directory and you want to work on the builder you would do the following:

```
cd gardenlinux
ln -f -s ../builder/build build
```

Now you can make your modifications inside the builder directory and running `./build ${target}` inside the gardenlinux repo will use the local builder, rebuilding the build container if necessary.
https://lists.neonephos.org/g/gardenlinux-security-embargo

## Licensing

Copyright 2025 SAP SE or an SAP affiliate company and GardenLinux contributors. Please see our [LICENSE](LICENSE) for
copyright and license information. Detailed information including third-party components and their licensing/copyright
information is available [via the REUSE tool](https://reuse.software).
Copyright 2025 SAP SE or an SAP affiliate company and GardenLinux contributors.
Please see our [LICENSE](LICENSE.md) for copyright and license information.
Detailed information including third-party components and their
licensing/copyright information is available
[via the REUSE tool](https://reuse.software).

<p align="center"><img alt="Bundesministerium für Wirtschaft und Energie (BMWE)-EU funding logo" src="https://apeirora.eu/assets/img/BMWK-EU.png" width="400"/></p>
<p align="center">
<img alt="Bundesministerium für Wirtschaft und Energie (BMWE)-EU funding logo" src="https://apeirora.eu/assets/img/BMWK-EU.png" width="400"/>
</p>
4 changes: 2 additions & 2 deletions build
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ if [ "$use_kms" = 1 ]; then
done
fi

# Default values which can be overriden via 'build.config' file
# Default values which can be overridden via 'build.config' file
tempfs_size=2G

if [[ -f "$PWD"/build.config ]]; then
Expand Down Expand Up @@ -163,7 +163,7 @@ if [ "$container_engine" = "docker" ] \
apparmor_profile=builder
fi

# Apply apparmor profile if seleceted
# Apply apparmor profile if selected
if [ "$apparmor_profile" ]; then
replaced=false
for i in "${!container_run_opts[@]}"; do
Expand Down
4 changes: 2 additions & 2 deletions builder/make_get_image_dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ for feature in "${features[@]}"; do

# Advanced convert scripts are scripts of the form convert.extA~extB.
# Unlike regular convert scripts these don't always get the image.raw as input,
# instead they recieve image.extB as their input.
# instead they receive image.extB as their input.
# This allows for convert scripts to operate on image scripts producing non .raw output
# or for covert scripts to operate on outputs of prior convert scripts.
# or for convert scripts to operate on outputs of prior convert scripts.

for i in "${advanced_convert_scripts[@]}"; do
if [ "$is_feature_script" = 1 ]; then
Expand Down
105 changes: 105 additions & 0 deletions docs/explanation/builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
title: "Builder"
description: "Conceptual overview of the Garden Linux Builder build system, architecture and design philosophy"
related_topics:
- /explanation/builder
- /explanation/flavors
- /explanation/boot-modes
- /explanation/secure-boot
- /reference/builder
- /how-to/secure-boot
- /how-to/choosing-flavors
- /how-to/getting-images
migration_status: "done"
migration_issue: "https://github.com/gardenlinux/gardenlinux/issues/4627"
migration_stakeholder: "@tmang0ld, @yeoldegrove, @ByteOtter"
migration_approved: false
github_org: gardenlinux
github_repo: builder
github_source_path: docs/explanation/builder.md
github_target_path: docs/explanation/builder.md
---

# How the Build System Works

## The Builder

Garden Linux images are produced by [gardenlinux/builder](https://github.com/gardenlinux/builder),
a dedicated build tool maintained separately from the main
[gardenlinux/gardenlinux](https://github.com/gardenlinux/gardenlinux) repository. This separation
means the build infrastructure can evolve independently of the distribution content.

The `./build` script in the `gardenlinux/gardenlinux` repository is the primary entry point. It
automatically fetches the correct builder container image, then delegates all internal build steps
to it. As a result, the only hard dependency on the host system is a working container engine —
no specific Linux distribution, compiler toolchain, or package set is required on the build host.

## Design Philosophy

The build system is designed around three principles:

- **Minimal host dependencies** — The build runs entirely inside a container. Apart from the
container engine itself, the host needs no build tools.
- **Composability** — Images are assembled from reusable [features](/explanation/flavors#feature-based-design)
rather than hand-crafted for each target. The same feature definition is reused across all
platforms that include it.
- **Reproducibility** — The builder container is versioned and pinned, so a given combination
of source code and feature set should produce the same image regardless of when or where it
is built.

## Flavor Names as Build Inputs

The build command takes a *flavor name* as its argument. A flavor name directly encodes what
will be built:

```
<platform>-<feature1>-<feature2>_<feature3>-<arch>
```

For example, `aws-gardener_prod-amd64` tells the builder to produce an AWS image (`aws`) with
the [`gardener`](/reference/features/gardener) and [`_prod`](/reference/features/_prod) features for the `amd64` architecture. The build script parses this
name and assembles the image by combining the specified platform and features.

For a full explanation of how flavors and features compose, including the [CNAME system](/explanation/flavors#the-cname-system) and how
features are joined, see [Flavors](/explanation/flavors).

## Cross-Architecture Builds

By default, the builder targets the native architecture of the build host. Building for a
different architecture (for example, building `arm64` images on an `amd64` host) requires
the host to be able to execute foreign binaries.

The standard mechanism for this on Linux is
[binfmt_misc](https://docs.kernel.org/admin-guide/binfmt-misc.html), a kernel feature that
registers handlers for non-native executable formats. When combined with QEMU user-mode
emulation (`qemu-user-static`), the kernel transparently invokes the correct QEMU binary
whenever the builder attempts to run an `arm64` binary inside the container.

Cross-architecture builds are slower than native builds because every foreign-architecture
instruction goes through QEMU emulation.

## Certificates for Secure Boot and Trusted Boot

Images that use the [`_trustedboot`](/reference/features/_trustedboot),
[`_tpm2`](/reference/features/_tpm2), or [`_secureboot`](/reference/features/_secureboot)
features must be signed with a custom certificate chain. This is because UEFI Secure Boot
validates the bootloader and kernel against enrolled certificates before execution — without
a valid signature, the firmware refuses to boot the image.

The `./cert/build` script generates this certificate chain (Platform Key, Key Exchange Key,
and Signature Database) inside a container, keeping the same minimal-dependency model as the
main build. The private keys are stored locally in the `cert/` directory by default, or in
AWS Key Management Service (KMS) when the `--kms` flag is used.

For the conceptual background on why signing is required and how Secure Boot and Trusted Boot
interact with the USI boot mode, see
[Boot Modes](/explanation/boot-modes) and
[Secure Boot and Trusted Boot](/explanation/secure-boot).

For step-by-step build and deployment instructions, see
[Building Images](/how-to/building-images) and
[Deploying Secure Boot Images](/how-to/secure-boot).

## Related Topics

<RelatedTopics />
148 changes: 0 additions & 148 deletions docs/getting_started.md

This file was deleted.

Loading
Loading