Commit graph

86 commits

Author SHA1 Message Date
Will Woods
6164b38fb9 Add STAGE_DESC, STAGE_INFO, and STAGE_OPTS to stages
This commit adds semi-structured documentation to all osbuild stages and
assemblers. The variables added work like this:

* STAGE_DESC: Short description of the stage.
* STAGE_INFO: Longer documentation of the stage, including expected
              behavior, required binaries, etc.
* STAGE_OPTS: A JSON Schema describing the stage's expected/allowed
              options. (see https://json-schema.org/ for details)

It also has a little unittest to check stageinfo - specifically:

1. All (executable) stages in stages/* and assemblers/ must define strings named
   STAGE_DESC, STAGE_INFO, and STAGE_OPTS
2. The contents of STAGE_OPTS must be valid JSON (if you put '{' '}'
   around it)
3. STAGE_OPTS, if non-empty, should have a "properties" object
4. if STAGE_OPTS lists "required" properties, those need to be present
   in the "properties" object.

The test is *not* included in .travis.yml because I'm not sure we want
to fail the build for this, but it's still helpful as a lint-style
check.
2019-11-13 21:47:03 +01:00
Will Woods
9d4b526a25 org.osbuild.rpm: make rpm --install check signatures
It turns out that rpm will happily check signatures on `--install`,
that's just not the default behavior, because of Historical Reasons.

This commit enables RPM's signature checking and drops our manual check,
which will probably speed up the RPM stage a little bit. Fun!

Oh, also there's two bonus code cleanups: one to use f-strings harder,
and one to make sure we ignore whitespace in package checksum strings.
2019-11-13 21:11:39 +01:00
Will Woods
d6ce127a8e org.osbuild.rpm: safe tempfiles
This makes the org.osbuild.rpm stage use safe temporary files for
handling keys and the package manifest.
2019-11-13 21:11:39 +01:00
Will Woods
8b8493cf04 org.osbuild.{dnf,yum}: use safe tempfiles
As a general rule, using temporary files with predictable names is a
security risk. It probably isn't _actually_ a security risk inside
osbuild stages, since they're usually running in some kind of isolated
container environment, but it's still a better idea to use tempfiles.

This makes the dnf and yum stages put their temporary files into a
temporary directory that gets deleted after dnf/yum finishes.
2019-11-13 21:11:39 +01:00
Ondřej Budai
ce6f77cbdc stages: add org.osbuild.chrony stage
lorax-composer supports modifying timeservers, this stage implements it.

I was concerned if I should name this stage timeservers or chrony, but
I've decided to go with chrony. If some day in future Fedora/RHEL
changes the ntp client, we can easily introduce new stage named after
the new ntp client. Additionally, this solution enables us to create
systemd-timesyncd stage, which can change timeservers when chrony is not
installed (in that case systemd-timesyncd takes over the ntp
synchronization).
2019-10-19 18:38:17 +02:00
Ondřej Budai
21d91fd6df stages: add org.osbuild.groups stage
lorax-composer supports adding groups, therefore we need it as well.
2019-10-17 16:14:20 +01:00
Ondřej Budai
d0a3f99342 stages/users: set authorized_keys file permissions to 600
Otherwise user may be unable to login. More information:
https://stackoverflow.com/questions/6377009/adding-public-key-to-ssh-authorized-keys-does-not-log-me-in-automatically
2019-10-17 16:11:01 +01:00
Lars Karlitski
26d29b646b stages/rpm: whitelist checksum algorithms 2019-10-15 22:53:53 +01:00
Lars Karlitski
2b872bbbfb stages: add org.osbuild.rpm
A new stage that downloads a list of packages and installs them using
`rpm`.
2019-10-15 00:00:13 +02:00
Tom Gundersen
21df63ba31 stages/dnf: embed the gpgkey in the pipeline
Downloading the gpg key is fragile and kept causing our tests to fail.
In general, we want to limit the network access, so let's just embed
the gpg keys directly in the pipeline.

Fixes #133.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-10-12 14:59:01 +02:00
Lars Karlitski
3e57f13380 stages/dnf: exclude-packages → exclude_packages 2019-10-03 12:53:01 +02:00
Tom Gundersen
72c3157162 assemblers/qemu: replace grub2-install
Background:

grub2 works in three stages:
 - The first stage is found in the first 440 bytes of the master
   boot record, and its only purpose is to load and execute the
   second stage. This stage is static, and just copied from the rpm
   without modification.
 - The second stage is found in the gap between the MBR and the
   first partition, and may be up to 31kB in size. This stage is
   specific to the host and must contain the instructions for
   finding the right file system and subdirectory for the grub2
   config and modules on the host, as well as the modules needed
   to do this.
 - The third stage is found in the `normal` module, which loads
   grub2.conf, which in turn may load more modules and perform
   arbitrary instructions.

Problem:

grub2-install is responsible for installing all these stages on the
target image. This goes against our design, as modifications outside
the filesystem should happen in the assembler, but modifications to
the filesystem should happen in a stage. In particular, we don't
want the contents of the image to differ in any way from the output
tree that is stored in our content store (the output of our last
stage). This causes a practical problem at the moment, as our
selinux stage is ran before the assembler, and as such the grub
modules do not get selinux labels applied.

It turns out that we could split grub2-install in two as we want,
by passing `--no-bootsector` to it to install only the modules,
and copy/genereta the two first stages as files under /boot and
then run `grub2-bios-setup` to write the stages from /boot into
the image where they belong.

Regrettably, this does not work as both `grub2-install` and
`grub2-bios-setup` introspect the system and block devices they
are being run on to generate the right configuration. This is not
what we want, as we would like to specifcy the config explicitly
and run them independently of the target image. The specific bug
we get in both cases is that the canonical path containing our
object store cannot be found.

Before osbuild this was not a problem, as other installers would
instal and assemble everything directly in the target image as a
loopback device. Something we explicitly do not want to do.

Solution:

This patch essentially reimplements grub2-install, or rather the
parts of it that we need. One change in behavior from the upstream
tool is that we no longer write the level one and level two boot
loaders to /boot before moving them into place, but just write them
directly where they belong (so they do not end up on the
filesystem).

The parts that copy files into /boot are now in the grub2 installer
and the parts that write the level one/two bootloaders are in the
qemu assembler.

This achieves a few principles I think we should always adher to:
 - never run tools from the target image (no chroot)
 - don't read/copy files from the target image that was written
   by other stages. We already try to avoid sharing state, and
   by treating the image as write-only, we avoid accidentally
   sharing state through the target tree.

Based-on-suggestions-from: Javier Martinez Canillas <javierm@redhat.com>
With-god-like-debugging-and-fixes-by: Lars Karlitski <lubreni@redhat.com>
Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-10-02 15:10:37 +02:00
Tom Gundersen
8f9dd5ec7d stages/dnf: support --exclude
This allows given packages to be excluded from the transaction. This
is useful if you want to install a group with certain exceptions.

A common thing to do in kicktstart files is:
```
rm -f /boot/*-rescue*
```

By instead excluding the dracut-rescue-config package we end up
with:
```
"deleted_files": [
  "/etc/kernel/postinst.d",
  "/usr/lib/dracut/dracut.conf.d/02-rescue.conf",
  "/usr/lib/kernel/install.d/51-dracut-rescue.install",
  "/boot/initramfs-0-rescue-ffffffffffffffffffffffffffffffff.img",
  "/boot/vmlinuz-0-rescue-ffffffffffffffffffffffffffffffff"
],
```

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-10-02 13:34:14 +02:00
Tom Gundersen
6ed426773f stages/yum: don't name the repositories
See 840bfd580c.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-09-30 23:48:23 +02:00
Tom Gundersen
840bfd580c stages/dnf: don't name the repositories
The names carry no information, and do not affect the produced image.
Generate them instead.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-09-29 19:04:39 +02:00
Ondřej Budai
3a0a480792 stages: Drop the remove-uniqueness stage
We don't need this stage anymore, random-seed has never been in
the tree and machine-id is now handled by dnf stage.
2019-09-26 23:47:33 +02:00
Ondřej Budai
fd8eb9492f stages/dnf: Remove random seed after dnf run
Some dnf packages introduce random seed file. If we leave in the tree
it would mean all systems running from the created image would use
the same random seed. This can be potentially dangerous, therefore we
just remove the generated random seed from our images.
2019-09-26 23:47:33 +02:00
Ondřej Budai
cc73fa5d10 stages/dnf: Improve dnf stage reproducibility
Normally, machine ID is generated randomly when dnf installs @Core
group. Unfortunately this isn't helping us with reproducibility
of images.

This commit introduces the concept of fake machine ID. Before dnf
command is run in dnf stage, we set the machine ID to a fake one.
This ensures all the scriptlets requiring machine ID have predictable
outputs.

For example GRUB uses machine-id in file names inside
/boot/loader/entries. With fixed machine ID the file names are always
the same and totally predictable.
2019-09-26 23:47:33 +02:00
Lars Karlitski
3009b9255f stages: remove org.osbuild.anaconda
We haven't used or tested it.
2019-09-24 20:17:04 +02:00
Lars Karlitski
bbe4129f36 stages/dnf: remove dnf cache directory
The repository used to install the image might be unrelated to any
repository that's ever used on a system running that image.
2019-09-24 20:17:04 +02:00
Lars Karlitski
57c82a00d0 stages/dnf: verify repository checksum
Require "checksum" option for each repository, which contains the
checksum of the `repodata/repomd.xml` file. This file (indirectly)
contains checksums for all packages.

Verify that the metadata dnf downloaded to install packages matches that
checksum. This way, this stage will give an error when a reposiory
changed between putting together the pipeline and running it.
2019-09-24 20:17:04 +02:00
Lars Karlitski
e23b5a32a2 stages/yum: only write known options to repo file
This is similar to the previous commit for the dnf stage.

Don't pass through arbitrary options. This means that pipeline repo
objects don't have the same options as yum repo files anymore:

1. Hard code repo name to repo id. The name has no influence on the
resulting image and should thus not appear in a pipeline.

2. Set gpgcheck=1 when gpgkey is given. It defaults to false, which
means that all sample and test pipelines didn't verify packages. It
would have failed anyway, because the container doesn't have the key
referenced in /etc. Change all gpgkeys to refer to the key id and import
them manually.

3. Don't allow lists for baseurl and gpgkey. We can add that if we need
it at some point.

Also be less verbose.
2019-09-24 20:17:04 +02:00
Lars Karlitski
0dd939b658 stages/dnf: only write known options to repo file
Don't pass through arbitrary options. This means that pipeline repo
objects don't have the same options as dnf repo files anymore:

1. Hard code repo name to repo id. The name has no influence on the
resulting image and should thus not appear in a pipeline.

2. Set gpgcheck=1 when gpgkey is given. It defaults to false, which
means that all sample and test pipelines didn't verify packages. It
would have failed anyway, because the container doesn't have the key
referenced in /etc. Change all gpgkeys to refer to the key id and import
them manually.

3. Don't allow lists for baseurl and gpgkey. We can add that if we need
it at some point.
2019-09-24 20:17:04 +02:00
Lars Karlitski
93da5caa69 stages/dnf: add mandatory basearch argument
We've been effectively using the basearch of the host, making the stage
non-reproducible: if the same pipeline was run on machines with
different architectures, it would produce different results. However,
pipelines producing different outputs must be different. Thus, this
patch includes the basearch in the pipeline.

In principle, this allows cross-arch builds. dnf should be the only
stage running binaries from the target tree. This is not yet tested.
2019-09-24 20:17:04 +02:00
Lars Karlitski
cd59b94ded tree-wide: always explicitly pass check to subprocess.run
pylint recently started recommending this.
2019-09-24 20:17:04 +02:00
Martin Sehnoutka
27bbb02265 make firewall options optional
there is no need to require all arguments in the firewall stage, so
let's reflect this in the code
2019-09-10 15:40:13 +02:00
Ondřej Budai
7fabcfe333 stages/locale: Refactor locale stage to look like similar ones
The locale stage now cannot be used to set the keymap. Use the keymap
stage instead. Also, the stage was refactored to look like keymap and
timezone stages just to be consistent (systemd-firstboot is now used).
2019-09-10 09:22:26 +02:00
Ondřej Budai
57bdfef754 stages/ansible: Drop the ansible stage
We use chroot connection type to "connect" to the target filesystem
where ansible should run the playbook. However, the target is not booted
system, it's just an image of not-yet-booted one. Unfortunately, many
ansible modules cannot be used inside not-booted system. Also, the core
principle of osbuild is to never boot the currently built image.
Therefore we decided to remove the ansible stage.

If ansible is needed in the future, there is a possibility to add a new
ansible stage, which would run the playbook during the first boot.
2019-09-09 09:11:52 +02:00
Tom Gundersen
fc838a8e20 stages: add test stage
Adds a new systemd unit to the image that will be pulled in by default,
run a given command, forward the output to a virtio serial port and
shutdown the machine.

We add a sample that uses this to verify that systemd conciders the
machine successfully booted. A simple way to run this test from the
commandline is to use
  `$ socat UNIX-LISTEN:qemu.sock -`
to listen for either `running` for success or `degraded` or
`maintenance` for failure.

The image should then be booted using something like
  `$ qemu-kvm -m 1024 -nographic -monitor none -serial none -chardev socket,path=qemu.sock,id=char0 -device virtio-serial -device virtserialport,chardev=char0,id=test0 -snapshot  base.qcow2`

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-08-29 10:25:15 +02:00
Tom Gundersen
a914627c89 stages: add debug shell
This gives shell access into the image on a given tty. Useful for
testing and debugging, while minimally affecting the image.

Note that this must never be used in production, as it allows root
access without a password.

For instance this could be used to verify that an image was fully
booted:

```
[teg@teg-x270 osbuild]$ qemu-kvm -m 1024 -nographic -serial mon:stdio -snapshot  base.qcow2
sh-5.0# systemctl is-system-running --wait
running
```

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-08-27 23:32:04 +03:00
Tom Gundersen
5854ceea42 stages/grub2: make booting in ro/rw mode configurable
Move the decision whether the root fs should be mounted ro or rw
into the pipeline configuration.

Update the pipelines accordingly.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-08-26 09:25:42 +03:00
Tom Gundersen
17d562e75f stages/fstab: add a stage to specify the fstab to be installed
This will allow us to boot in 'ro' mode, and remount later on.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-08-26 09:25:42 +03:00
Tom Gundersen
9af32f1aae stages/dnf: make install_weak_deps optional
Default to True, which is what dnf defaults to, but allow it to be
overridden in the pipeline. Whether this option should be used should
be a distro policy, but for now we just want it to get images compatible
with the official fedora ones.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-08-26 09:25:42 +03:00
Tom Gundersen
b348d858b8 stagse/dnf: don't make verbosity configurable
We don't want non-functional configuration in the pipelne, we want to
restrict ourselves to options that changes the final image.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-08-26 09:25:42 +03:00
Lars Karlitski
f54fbe2912 stages/fix-bls: add workaround for grub2-mkrelpath
grub2-mkrelpath uses /proc/self/mountinfo to find the source of the file
system it is installed to. This breaks in a container.

Add org.osbuild.fix-bls which goes through /boot/loader/entries and
fixes paths by removing anything before /boot.
2019-08-15 09:43:28 +03:00
Lars Karlitski
29c396584f stages/dnf: use nspawn's vfs tree
dracut stumbled over the one we set up (errors about not being able to
access /dev/kmsg). Use the one that systemd-nspawn sets up instead.
2019-08-14 13:49:27 +02:00
Martin Sehnoutka
c27cdd5928 introduce hostname stage
this stage will set /etc/hostname in the image. it uses
systemd-firstboot to perform the change
2019-08-13 13:24:36 +02:00
Lars Karlitski
4c91a23e98 stages/org.osbuild.users: manage users
This stage allows to add or modify users. For now, this includes all
fields available in passwd, setting auxiliary groups, and setting an ssh
key.

Based on a patch by Martin Sehnoutka <msehnout@redhat.com>.
2019-08-12 13:45:30 +02:00
Lars Karlitski
a394e975c1 stages/dnf: supress error from completion module
Disable the module. There's no need to update the completion databse in
the container.
2019-08-12 13:07:11 +02:00
msehnout
dc1466eeca
introduce firewall stage (#61)
as described in lorax documentation, we need to support raw
ports/protocols and services as defined by firewalld:
https://weldr.io/lorax/lorax-composer.html#customizations-firewall
2019-08-07 09:34:22 +02:00
Martin Sehnoutka
28e33c07ce introduce support for user-defined kernel options 2019-08-01 14:59:37 +02:00
Tom Gundersen
8b659ae638 travis: add a test for a yum-based pipeline
Travis uses Ubuntu, which does not ship dnf, so introduce a yum
stage that allows us to test actual generation of trees on Travis.

We use this to generate a tree containing the tools necessary to
create abritrary Fedora-based build images in the future. We base
this on Fedora 27, as that is the last version that is installable
using yum rather than dnf.

In the future, once we support pipelines with nested build-images,
rather than just using the host OS as the build image, this will
allow us to bootstrap arbitrary pipelines on Travis.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-07-31 01:34:31 +02:00
Martin Sehnoutka
0cf93934eb unify messages about files to be removed 2019-07-29 20:13:36 +02:00
Martin Sehnoutka
1ca4d8e6bb introduce keymap stage 2019-07-29 12:39:38 +02:00
Martin Sehnoutka
593c6de385 add timezone stage 2019-07-29 12:05:42 +02:00
Lars Karlitski
f4862457a3 rename io.weldr to org.osbuild (#39) 2019-07-26 09:40:55 +02:00
Tom Gundersen
a17ecd0fca stages/assemblers: symlink the osbulid python library
This way the assemblers/stages are valid in isolation, even without
osbulid installed system-wide. This would be needed to have this work
when --libdir is not the system-wide one, as the library would
otherwise not be in sys.path.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-07-25 21:28:23 +02:00
Martin Sehnoutka
f04cb3836f fix warnings generated by pylint 2019-07-17 13:08:22 +02:00
Tom Gundersen
a428572382 stages/io.weldr.grub2: drop unused functions and options
Since we no longer use grub2-mkconfig, but write static configuration
we can drop most of the helpers.

The partitin table id was never used in the first place. We use
filesystem UUIDs, not partition UUIDs to name our root/boot partitions.

Signed-off-by: Tom Gundersen <teg@jklm.no>
2019-07-11 15:01:44 +02:00
Martin Sehnoutka
5ca90dc052 mount filesystems as rw
d-bus service was unable to start with the previous setup
2019-07-09 10:29:48 +02:00