Skip to content

Commit 1090d83

Browse files
committed
Initial version of booster initramfs generator
It supports full disk encryption use-case with * plain password * clevis TPM2 and Tang pins
0 parents  commit 1090d83

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3854
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea

.golangci.yml

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
linters:
2+
enable:
3+
- bodyclose
4+
- deadcode
5+
- depguard
6+
- dogsled
7+
- dupl
8+
- errcheck
9+
- funlen
10+
- gochecknoinits
11+
- goconst
12+
- gocritic
13+
- gocyclo
14+
- gofmt
15+
- goimports
16+
- golint
17+
- gomnd
18+
- goprintffuncname
19+
- gosec
20+
- gosimple
21+
- govet
22+
- ineffassign
23+
- interfacer
24+
- lll
25+
- misspell
26+
- nakedret
27+
- rowserrcheck
28+
- scopelint
29+
- staticcheck
30+
- structcheck
31+
- stylecheck
32+
- typecheck
33+
- unconvert
34+
- unparam
35+
- unused
36+
- varcheck
37+
- whitespace
38+
- gochecknoglobals
39+
- gocognit
40+
- godox
41+
- maligned
42+
- prealloc
43+
- wsl

LICENSE

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Copyright 2020 Anatol Pomazau
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4+
5+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6+
7+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Booster - fast and secure initramfs generator
2+
3+
![Booster initramfs generator](docs/booster.png)
4+
5+
Initramfs is a specially crafted small root filesystem that mounted at the early stages of Linux OS boot process.
6+
This initramfs among other things is responsible for unlocking encrypted partitions and mounting it as a root filesystem.
7+
8+
Booster is a tool to create such early boot images. Booster is made with speed and full disk encryption use-case in mind.
9+
10+
Booster advantages:
11+
* Fast image build time and fast boot time.
12+
* Out-of-box support for full disk encryption setup.
13+
* [Clevis](https://github.com/latchset/clevis/) style data binding. The encrypted filesystem can be bound
14+
to TPM2 chip or to a network service. This helps to unlock the drive automatically but only if the TPM2/network service
15+
presents.
16+
* Easy to configure.
17+
* Automatic host configuration discovery. This helps to create minimalistic images specific for the current host.
18+
19+
There are other initramfs generators similar to booster: [mkinitcpio](https://git.archlinux.org/mkinitcpio.git/) and [dracut](https://dracut.wiki.kernel.org/index.php/Main_Page).
20+
21+
### Install
22+
#### Arch Linux
23+
Install [booster-git](https://aur.archlinux.org/packages/booster-git/) package from AUR.
24+
25+
At the installation time this package will create a number of booster images in your `/boot/` directory:
26+
```shell
27+
$ ls -lh /boot/booster-*.img
28+
-rwxr-xr-x 1 root root 3.9M Dec 10 20:51 /boot/booster-linux.img
29+
```
30+
31+
Or optionally the image can be generated manually as `booster -o mybooster.img`. Note that by default booster generates
32+
host specific images with minimum binaries needed for the current host. Providing `-universal` flag to `booster` tool
33+
will add more modules and tools and the result image will be bigger.
34+
35+
Once the image is generated it is time to configure the bootloader.
36+
37+
#### systemd-boot
38+
Here is a sample entry for `systemd-boot` UEFI bootloader:
39+
40+
```
41+
$ cat /boot/loader/entries/booster.conf
42+
title Linux with Booster
43+
linux /vmlinuz-linux
44+
initrd /intel-ucode.img
45+
initrd /booster-linux.img
46+
options rd.luks.uuid=e122d09e-87a9-4b35-83f7-2592ef40cefa root=UUID=08684949-bcbb-47bb-1c17-089aaa59e17e rw
47+
```
48+
49+
where `e122d09e-87a9-4b35-83f7-2592ef40cefa` is a UUID for the LUKS partition and `08684949-bcbb-47bb-1c17-089aaa59e17e` is
50+
a UUID for the encrypted filesystem (e.g. ext4). Please refer for your bootloader documentation for more info about its
51+
configuration.
52+
53+
### Configure
54+
Booster generator has a number of configurable options.
55+
56+
#### Config file
57+
First there is a configuration file located at `/etc/booster.yaml`. It has following fields:
58+
59+
```yaml
60+
network:
61+
dhcp: on
62+
ip: 10.0.2.15/24
63+
gateway: 10.0.2.255
64+
universal: false
65+
modules: nvidia,kernel/sound/usb/
66+
```
67+
68+
`network` node, if presents, initializes network at the boot time. It is needed if mounting a root fs requires access to the network (e.g. in case of Tang binding).
69+
The address can be configured with a static ip (node `ip`) or with DHCPv4 (`dhcp: on`).
70+
71+
`universal` is a boolean flag that tells booster to generate a universal image.
72+
By default `booster` generates a host-specific image that includes kernel modules used at the *current host*.
73+
For example if the host does not have a TPM2 chip then tpm modules are ignored.
74+
*Universal* image includes many kernel modules and tools that might be needed at a broad range of hardware configurations.
75+
76+
`modules` is a comma-separates list of extra modules to add to the generated image. One can use a module name or a path relative
77+
to the modules dir (`/usr/lib/modules/$KERNEL_VERSION`). If the path ends with slash symbol (`/`) then it considered a directory
78+
and all modules from this directory needs to be added recursively. `booster` also takes modules dependencies into account, all dependencies
79+
of the specified modules will be added to the image as well.
80+
81+
#### Command-line arguments
82+
`booster` accepts a list of arguments:
83+
* `-universal` generate a universal image
84+
* `-kernelVersion` use modules for the given kernel version. If the flag is not specified then the current kernel is used (as reported by `uname -r`).
85+
* `-output` output file, by default `booster.img` used
86+
* `-force` overwrite output file if it exists
87+
88+
#### Kernel boot parameter
89+
Some parts of booster boot functionality can be modified with kernel boot parameters. These parameters are usually set through bootloader config.
90+
Booster boot uses following kernel parameters:
91+
* `booster.debug=1` enable booster debug output. It is printed to console at the boot time. This feature might be useful to debug booster issues.
92+
* `root=($PATH|UUID=$UUID)` root device
93+
* `rd.luks.uuid=$UUID` UUID of the LUKS partition where the root partition is enclosed. booster will try to unlock this LUKS device.
94+
* `rd.luks.name=$UUID:$NAME` similar to `rd.luks.uuid` parameter but also specifies the name used for the LUKS device opening.
95+
* `fstype=type` booster will try to detect root filesystem type. But if the autodetection does not work then this kernel parameter is be useful.
96+
Also please file a ticket so we can improve the code that detects filetypes.
97+
98+
### Build
99+
The project consists of 3 components:
100+
* `init` binary that runs as a part of your machine boot process. It is going to be the very first user process run at your machine.
101+
* `generator` tool that creates ramfs image with all components needed to boot the computer
102+
* `integration_tests` tests that involve all components and use QEMU to boot from a generated image
103+
104+
These components use standard Golang tooling. To build any part do `go build`, to run tests do `go test`.
105+
106+
### Run tests
107+
```bash
108+
cd {init,generator,integration_tests}
109+
go test -v
110+
```
111+
112+
### Debugging
113+
If you have a problem with booster boot tool you can enable debug mode to get more
114+
information about what is going on. Just add `booster.debug=1` kernel parameter and booster
115+
provide additional logs.
116+
117+
### Credits
118+
Work on this project has been started as a part of Twitter's hack week. Huge thanks to my employer for its support
119+
of open-source development. Special thanks to [Ian Brown](https://twitter.com/igb).
120+
121+
Booster architecture has been inspired by Michael Stapelberg's project called [distri](https://distr1.org/).
122+
Initial version of booster borrowed a lot of ideas from the distri's initramfs generator.
123+
124+
### Licence
125+
See [license](LICENSE)

docs/booster.png

8.02 KB
Loading

generator/bimap.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import "fmt"
4+
5+
type Bimap struct {
6+
forward, reverse map[string]string
7+
}
8+
9+
func NewBimap() *Bimap {
10+
return &Bimap{
11+
forward: make(map[string]string),
12+
reverse: make(map[string]string),
13+
}
14+
}
15+
16+
func (b *Bimap) Add(key, value string) error {
17+
if v, ok := b.forward[key]; ok {
18+
return fmt.Errorf("provided key already used in mapping %s->%s", key, v)
19+
}
20+
if k, ok := b.reverse[value]; ok {
21+
return fmt.Errorf("provided value already used in mapping %s->%s", k, value)
22+
}
23+
24+
b.forward[key] = value
25+
b.reverse[value] = key
26+
27+
return nil
28+
}

generator/bimap_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import "testing"
4+
5+
func TestBimap(t *testing.T) {
6+
b := NewBimap()
7+
8+
if err := b.Add("f1", "p1"); err != nil {
9+
t.Fatal()
10+
}
11+
if val, _ := b.forward["f1"]; val != "p1" {
12+
t.Fail()
13+
}
14+
if val, _ := b.reverse["p1"]; val != "f1" {
15+
t.Fail()
16+
}
17+
18+
if err := b.Add("f2", "p1"); err == nil {
19+
t.Fail()
20+
}
21+
}

generator/bufferedreaderat.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package main
2+
3+
import "io"
4+
5+
type bufferedReaderAt struct {
6+
r io.Reader
7+
buffer []byte
8+
}
9+
10+
func NewBufferedReaderAt(r io.Reader) io.ReaderAt {
11+
return &bufferedReaderAt{r: r}
12+
}
13+
14+
func (b *bufferedReaderAt) ReadAt(data []byte, off int64) (n int, err error) {
15+
endOff := off + int64(len(data))
16+
need := endOff - int64(len(b.buffer))
17+
if need > 0 {
18+
buf := make([]byte, need)
19+
var rn int
20+
rn, err = io.ReadFull(b.r, buf)
21+
b.buffer = append(b.buffer, buf[:rn]...)
22+
}
23+
if int64(len(b.buffer)) >= off {
24+
n = copy(data, b.buffer[off:])
25+
}
26+
if n == len(data) {
27+
err = nil
28+
}
29+
return
30+
}

generator/config.generator.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
type GeneratorConfig struct {
4+
Network *struct {
5+
Dhcp bool `yaml:",omitempty"`
6+
7+
Ip string `yaml:",omitempty"` // e.g. 10.0.2.15/24
8+
Gateway string `yaml:",omitempty"` // e.g. 10.0.2.255
9+
}
10+
Universal bool `yaml:",omitempty"`
11+
Modules string `yaml:",omitempty"` // comma separated list of extra modules to add to initramfs
12+
}
13+
14+
const generatorConfigPath = "/etc/booster.yaml"

generator/config.init.go

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../init/config.go

generator/go.mod

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module booster
2+
3+
go 1.15
4+
5+
require (
6+
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e
7+
github.com/google/renameio v1.0.0
8+
github.com/klauspost/compress v1.11.3
9+
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8
10+
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742
11+
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
12+
)

generator/go.sum

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e h1:hHg27A0RSSp2Om9lubZpiMgVbvn39bsUmW9U5h0twqc=
2+
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
3+
github.com/google/renameio v1.0.0 h1:xhp2CnJmgQmpJU4RY8chagahUq5mbPPAbiSQstKpVMA=
4+
github.com/google/renameio v1.0.0/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
5+
github.com/klauspost/compress v1.11.3 h1:dB4Bn0tN3wdCzQxnS8r06kV74qN/TAfaIS0bVE8h3jc=
6+
github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
7+
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
8+
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
9+
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 h1:+CBz4km/0KPU3RGTwARGh/noP3bEwtHcq+0YcBQM2JQ=
10+
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
11+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
12+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
13+
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
14+
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)