Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite coreos-installer in Rust #65

Merged
merged 3 commits into from
Oct 30, 2019
Merged

Rewrite coreos-installer in Rust #65

merged 3 commits into from
Oct 30, 2019

Conversation

bgilbert
Copy link
Contributor

@bgilbert bgilbert commented Oct 25, 2019

Features:

  • Checks that target disk is not in use
  • Obtains image from local file, remote URL, or stream metadata
  • Streaming fetch and decompression
  • Compression format sniffing
  • Progress reporting
  • GPG signature verification, mandatory unless --insecure specified
  • Does not write partition table until signature is verified
  • Can copy Ignition config to disk
  • Can override Ignition platform ID
  • Can write first-boot kernel arguments
  • Doesn't depend on uniqueness of /boot UUID
  • Wipes destination partition table on error
  • Only executable dependencies: gpg, lsblk, udevadm

Command-line parameters are not compatible with the original, but the intent is that the coreos.inst.* kargs, to be implemented in a separate wrapper script, will maintain compatibility.

@lucab
Copy link
Contributor

lucab commented Oct 25, 2019

It would be useful to turn on travis on this repo, before merging this PR. I don't seem to have the powers to do that myself though.

src/blockdev.rs Outdated Show resolved Hide resolved
src/blockdev.rs Show resolved Hide resolved
src/blockdev.rs Outdated Show resolved Hide resolved
src/source.rs Show resolved Hide resolved
src/blockdev.rs Outdated Show resolved Hide resolved
src/main.rs Outdated Show resolved Hide resolved
src/main.rs Outdated Show resolved Hide resolved
src/main.rs Outdated Show resolved Hide resolved
src/main.rs Outdated Show resolved Hide resolved
src/main.rs Outdated Show resolved Hide resolved
@bgilbert
Copy link
Contributor Author

Thanks for the review! Updated, and Travis is enabled. Also, as we discussed OOB, I've moved the functionality to an install subcommand for future-proofing.

@lucab
Copy link
Contributor

lucab commented Oct 28, 2019

An additional wishlist item that came to my mind: it would be great if we could run the installer from a container, just with the bindmounts for the target (rationale: that would allow us to use any linux-host as a provisioner).
Did you maybe try that, or see any clear blocker? Does it sound useful to you (perhaps coupled with a quay autobuilder task) or am I getting off track?

Copy link
Member

@jlebon jlebon left a comment

Choose a reason for hiding this comment

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

Very nice overall! I like the 1M delayed write trick.

@@ -0,0 +1,91 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, why not just pick up the keys from fedora-gpg-keys/redhat-release-coreos (i.e. /etc/pki/rpm-gpg) ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

coreos-installer should run on arbitrary distros, which may not have those files.

Copy link
Member

Choose a reason for hiding this comment

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

OK so the idea here is that we'll publish binaries instead of/in addition to containers? What I'm trying to avoid is adding yet another spot that needs updating during each major release rollover. Can we pull it in as part of the build process at least?

Copy link
Contributor

Choose a reason for hiding this comment

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

It may make sense to overlay-merge (by filename?) two sets of keys:

  • these hardcoded ones (for fallback)
  • any on-disk ones (possibly fresher)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK so the idea here is that we'll publish binaries instead of/in addition to containers?

It was, but if the container works and the UX for running it isn't too bad, I'd favor shipping that instead of a binary.

any on-disk ones (possibly fresher)

Where would we get these? If from /etc/pki/rpm-gpg, there are no symbolic references for the current key, so we'd have to either import everything we find there (boo) or have a heuristic for importing keys (boo).

If we do ship a bare binary, this would also mean that behavior would differ depending on the host OS, which doesn't seem great.

What I'm trying to avoid is adding yet another spot that needs updating during each major release rollover. Can we pull it in as part of the build process at least?

These are the roots of trust for install images, and IMO it's safer to manage them manually. We can always start that way and add dynamic roots or more automation later on.

In comparison, CL coreos-install intentionally hardcodes the GPG key and does not provide a command-line mechanism for overriding it.

Copy link
Member

Choose a reason for hiding this comment

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

So as an example right now we don't have any CI covering the coreos-installer path. So bumping from f30 to f31 without bumping the keys here would've possibly gone completely unnoticed until it shipped to users. (A gap we should fix of course!)

Where would we get these? If from /etc/pki/rpm-gpg, there are no symbolic references for the current key, so we'd have to either import everything we find there (boo) or have a heuristic for importing keys (boo).

These are the roots of trust for install images, and IMO it's safer to manage them manually. We can always start that way and add dynamic roots or more automation later on.

A big part of this discussion is essentially a direct consequence of coreos/fedora-coreos-tracker#187 (comment). WDYT about:

  • ship in a container with fedora-gpg-keys
  • parse the FCOS version to extract the major release, similar to what is proposed for RoboSignatory itself in that ticket
  • verify download using only that release's specific key from /etc/pki/rpm-gpg

?

This is similar to how Fedora verifies RPMs: https://src.fedoraproject.org/rpms/fedora-repos/blob/a12c809ab2dcb730cbeb4a03c50d20e3d25cc048/f/fedora.repo#_10.

For RHEL, the keys don't rotate nearly as much, so we can just bake it in.

Anyway, I'm cool with how things set up for now, and discussing this stuff in more details later on!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So as an example right now we don't have any CI covering the coreos-installer path. So bumping from f30 to f31 without bumping the keys here would've possibly gone completely unnoticed until it shipped to users. (A gap we should fix of course!)

If nothing else, that'll be addressed when we start running kola on Packet, where every machine will bootstrap with coreos-installer.

ship in a container with fedora-gpg-keys

I'd still prefer not to rely on external keys. It'd be great if cargo install coreos-installer worked properly on e.g. Debian.

parse the FCOS version to extract the major release, similar to what is proposed for RoboSignatory itself in that ticket
verify download using only that release's specific key from /etc/pki/rpm-gpg

I like the idea of binding to a specific key. Will file an issue.

Hmm, maybe stream metadata should list a signing key ID for each artifact?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I guess the key ID is already embedded in the signature, so listing it separately in metadata is probably redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#71

src/main.rs Outdated
extern crate progress_streams;
extern crate reqwest;
extern crate tempdir;
extern crate xz2;
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't need these with Rust 2018.


// do the copy
config_dest.push("config.ign");
let mut config_in = OpenOptions::new()
Copy link
Member

Choose a reason for hiding this comment

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

Why not just std::fs::copy here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We get a bit better control this way:

  • config_out.create_new(true) ensures that we'll fail if the file already exists for some reason. (Which it shouldn't, of course.)
  • std::fs::copy also copies permissions, which may not be desired.

// Rewrite the config. Assume that we will only install
// from metal images and that their bootloader configs will
// always set ignition.platform.id. Fail if those
// assumptions change. This is deliberately simplistic.
Copy link
Member

Choose a reason for hiding this comment

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

This is fine, though should probably no-op return early on if platform is metal.

@bgilbert
Copy link
Contributor Author

it would be great if we could run the installer from a container, just with the bindmounts for the target (rationale: that would allow us to use any linux-host as a provisioner).
Did you maybe try that, or see any clear blocker? Does it sound useful to you (perhaps coupled with a quay autobuilder task) or am I getting off track?

I haven't tried it, but I like the idea. I was originally thinking we'd offer a binary for download, but it does have dynamic library dependencies so that may not work well on other distros:

	liblzma.so.5 => /lib64/liblzma.so.5 (0x00007fb47a786000)
	libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007fb47a6f0000)
	libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007fb47a414000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007fb47a40e000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fb47a3ed000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fb47a3d3000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fb47a20b000)
	libz.so.1 => /lib64/libz.so.1 (0x00007fb47a1f1000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fb47ac29000)

A container image would sidestep the whole problem. I probably won't pursue it immediately, but filed issue #67.

@bgilbert
Copy link
Contributor Author

Updated!

@lucab
Copy link
Contributor

lucab commented Oct 29, 2019

We could (in theory) cross-compile to a static binary with musl, but in practice if it works I'd prefer pursuing the container route.

src/main.rs Outdated Show resolved Hide resolved
insecure: bool,
}

quick_main!(run);

Choose a reason for hiding this comment

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

Is this still needed? main can return a result now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

quick_main still does better pretty-printing than the default main.

src/verify.rs Outdated

use error_chain::bail;
use std::fs::{metadata, set_permissions, OpenOptions};
use std::io;

Choose a reason for hiding this comment

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

This can be combined below:

use std::io{self, Read, Write};

let uname = nix::sys::utsname::uname();
// Args are listed in --help in the order declared here. Please keep
// the entire help text to 80 columns.
let app_matches = App::new("coreos-installer")

Choose a reason for hiding this comment

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

As an alternative to using Clap directly, StructOpt is pretty slick.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice! I played with it a bit and don't think it's worth a refactor right now, but I'll keep it in mind for the future.

Features:

- Checks that target disk is not in use
- Obtains image from local file, remote URL, or stream metadata
- Streaming fetch and decompression
- Compression format sniffing
- Progress reporting
- GPG signature verification, mandatory unless --insecure specified
- Does not write partition table until signature is verified
- Can copy Ignition config to disk
- Can override Ignition platform ID
- Can write first-boot kernel arguments
- Doesn't depend on uniqueness of /boot UUID
- Wipes destination partition table on error
- Only executable dependencies: gpg, lsblk, udevadm

Command-line parameters are not compatible with the original, but the
intent is that the coreos.inst.* kargs, to be implemented in a separate
wrapper script, will maintain compatibility.
Also relicense coreos-iso-embed-ignition.
@lucab
Copy link
Contributor

lucab commented Oct 30, 2019

I don't have any further high-level concerns, and the code itself looks good. I could just stamp the PR but I don't know what are the overarching integration plans wrt. the old one.

@bgilbert @jlebon @arithx how do you want to proceed here?

@jlebon
Copy link
Member

jlebon commented Oct 30, 2019

Would be pretty cool to have the CI here actually do an install of FCOS. I think Travis CI can give you Ubuntu VMs, though we can also hook it up to CoreOS CI!

@bgilbert @jlebon @arithx how do you want to proceed here?

Now that we've branched, I'm thinking let's just merge this, cut a 0.0.1 release, and iterate on top as we uncover issues?

@bgilbert
Copy link
Contributor Author

Now that we've branched, I'm thinking let's just merge this, cut a 0.0.1 release, and iterate on top as we uncover issues?

Yup, we have a legacy branch for existing users. I have a couple followup PRs before releasing, but 👍 to that plan generally.

Copy link
Contributor

@lucab lucab left a comment

Choose a reason for hiding this comment

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

LGTM from my side

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants