-
Notifications
You must be signed in to change notification settings - Fork 591
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
snap-bootstrap: load partition information from a manifest file for cloudimg-rootfs mode #14713
base: master
Are you sure you want to change the base?
Conversation
@sespiros probably it would be good to rebase this now that the prerequisite has been merged |
5c312d1
to
45d1ecd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sespiros I think we discussed this at the sprint, my strong preference would be to first move the existing CVM support to a _cvm.go and _cmv_test.go file, and then do this change
45d1ecd
to
b4d37ea
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #14713 +/- ##
==========================================
+ Coverage 78.20% 78.24% +0.03%
==========================================
Files 1151 1146 -5
Lines 151396 151656 +260
==========================================
+ Hits 118402 118656 +254
+ Misses 25662 25656 -6
- Partials 7332 7344 +12
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
b4d37ea
to
6b717d2
Compare
This is a preparatory commit which modifies the existing CVM mode to support mounting multiple overlaid partitions for the rootfs.
In order to provide integrity protection for the root fs, the root fs will be mounted read-only and will be accompanied by dm-verity data from a new auto-discovered partition. To support writable state for the ephemeral CVM scenario, an overlayfs mount is created with an upper layer residing on tmpfs. A writable layer residing on disk can be also supported but it is currently disabled. The filesystem layout in the initramfs will look like: . /run/mnt ├── ... ├── data (where the final merged overlay will be mounted) ├── cloudimg-rootfs (read-only mount of the root fs, folder name is the fs label) ├── .. (future WIP, other partition mounts as separate mounts) └── cloudimg-rootfs-writable (tmpfs mount for the writable upper layer) ├── work └── upper An example final overlay mount command will look like: mount -t overlay overlay -olowerdir=/run/mnt/cloudimg-rootfs,\ upperdir=/run/mnt/cloudimg-rootfs-writable/upper,\ workdir=/run/mnt/cloudimg-rootfs-writable/work \ /run/mnt/data
…verity partition instead
v1 CVM images use the filesystem label to auto-discover an encrypted rootfs partition based on whether it has the '-enc' suffix. The new images use the GPT label to auto-discover the verity partition. In order to keep backwards compatibility, the customization tool will use set both labels to the same one. This commit clarifies that the field in the new structs actually contain GPT label information.
creating the upper and work folders used for setting up the overlayfs mount, was initially handled by snap-bootstrap whether it set up a tmpfs or detected a writable partition on disk but in order to support the writable partition case, it was later discovered that these folders might need to be created during the customization step and might already exist. snap-bootstrap will now create those folders only if it has detected no writable partition in the manifest and has auto-created a tmpfs-based writable partition.
trying to boot an image on a system without a TPM present was failing due to not-finding a TPM device. The source of the error was not the provision step as secbotProvisionForCVM already ignores errors (returns nil) if a TPM device is not found or a template file for provision the TPM is not found.
CVM mode used to mount the rootfs partition with the Ephemeral flag as cloud images contain a fixed fstab entry.
This is a legacy check that is not actually needed now as secbootUnlockVolumeUsingSealedKeyIfEncrypted will only find partitions residing on the disk that the ESP is from.
6b717d2
to
c4ab893
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I have some comments
Opts *systemdMountOptions | ||
} | ||
|
||
type ImageManifestPartition struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this and other new types like ImageManifest or ManifestError do not need to be exported.
@@ -94,6 +94,14 @@ func MockOsutilIsMounted(f func(string) (bool, error)) (restore func()) { | |||
} | |||
} | |||
|
|||
func MockOsReadFile(f func(string) ([]byte, error)) (restore func()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In tests we tend to create the files instead of mocking the read, note that dirs.GlobalRootDir
is set to a temporary folder so this is in principle easy to do.
GptLabel string `json:"label"` | ||
RootHash string `json:"root_hash"` | ||
Overlay string `json:"overlay"` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A description on what is each of these fields would be helpful, or maybe a link to a description of the format if available.
} | ||
|
||
type ImageManifest struct { | ||
Partitions []ImageManifestPartition `json:"partitions"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same: re describing the field
return im, nil | ||
} | ||
|
||
// generateMountsFromManifest is used to parse a manifest file which contains information about which |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strictly speaking, the manifest passed around parsed already, right?
if p.Overlay == "lowerdir" { | ||
// XXX: currently only one lower layer is permitted. The rest, if found, are ignored. | ||
if foundReadOnlyPartition != "" { | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should not this as a minimum be logged? Or should it be considered an error in the manifest?
} else { | ||
// Only one writable partition is permitted. | ||
if foundWritablePartition != "" { | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same regarding log/error out
GptLabel: "cloudimg-rootfs", | ||
Opts: &systemdMountOptions{ | ||
Overlayfs: true, | ||
LowerDirs: []string{filepath.Join(boot.InitramfsRunMntDir, partitionMounts[0].GptLabel)}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is using partitionMounts[0]
assuming an order in the definitions of the partitions in the file? should this always be the read-only partition?
pm.Opts.UpperDir = filepath.Join(boot.InitramfsRunMntDir, foundWritablePartition, "upper") | ||
pm.Opts.WorkDir = filepath.Join(boot.InitramfsRunMntDir, foundWritablePartition, "work") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be done when pm
is defined, splitting the initialization of Opts does not seem necessary.
restore = main.MockOsReadFile(func(path string) ([]byte, error) { | ||
// check attempt to read manifest from specific path | ||
c.Assert(path, Equals, filepath.Join(boot.InitramfsUbuntuSeedDir, "EFI/ubuntu", "manifest.json")) | ||
return []byte(fmt.Sprintf(`{"partitions":[{"label":"cloudimg-rootfs","root_hash":%q,"overlay":"lowerdir"}]}`, expectedRootHash)), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need a test case for when more than one partition is defined?
Rebased on top of #14178 which is approved but not merged. New commits start at commit 2035d4d.Rebased on top of #14789 which is approved but not merged. New commits start at commit c55f509.This refactors cloudimg-rootfs mode and adds support for externally providing a dm-verity root hash for the rootfs that is mounted. This root hash is part of a new manifest file that resides on the ESP.
Subsequent PRs will add support for measuring the manifest to the TPM for remote attestation purposes.
Jira: https://warthogs.atlassian.net/browse/FR-9480