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

snap-bootstrap: load partition information from a manifest file for cloudimg-rootfs mode #14713

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

sespiros
Copy link
Contributor

@sespiros sespiros commented Nov 12, 2024

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

@alfonsosanchezbeato
Copy link
Member

@sespiros probably it would be good to rebase this now that the prerequisite has been merged

@alfonsosanchezbeato alfonsosanchezbeato added the Run nested The PR also runs tests inluded in nested suite label Nov 20, 2024
@sespiros sespiros force-pushed the snap-bootstrap-manifest branch from 5c312d1 to 45d1ecd Compare November 21, 2024 17:28
Copy link
Collaborator

@pedronis pedronis left a 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

Copy link

codecov bot commented Dec 3, 2024

Codecov Report

Attention: Patch coverage is 64.10256% with 56 lines in your changes missing coverage. Please review.

Project coverage is 78.24%. Comparing base (24a0034) to head (c4ab893).
Report is 6 commits behind head on master.

Files with missing lines Patch % Lines
cmd/snap-bootstrap/cmd_initramfs_mounts_cvm.go 64.10% 44 Missing and 12 partials ⚠️
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     
Flag Coverage Δ
unittests 78.24% <64.10%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@sespiros sespiros force-pushed the snap-bootstrap-manifest branch from b4d37ea to 6b717d2 Compare December 4, 2024 11:53
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
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.
@sespiros sespiros force-pushed the snap-bootstrap-manifest branch from 6b717d2 to c4ab893 Compare December 5, 2024 10:48
Copy link
Member

@alfonsosanchezbeato alfonsosanchezbeato left a 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 {
Copy link
Member

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()) {
Copy link
Member

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.

Comment on lines +59 to +62
GptLabel string `json:"label"`
RootHash string `json:"root_hash"`
Overlay string `json:"overlay"`
}
Copy link
Member

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"`
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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)},
Copy link
Member

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?

Comment on lines +187 to +188
pm.Opts.UpperDir = filepath.Join(boot.InitramfsRunMntDir, foundWritablePartition, "upper")
pm.Opts.WorkDir = filepath.Join(boot.InitramfsRunMntDir, foundWritablePartition, "work")
Copy link
Member

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
Copy link
Member

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Run nested The PR also runs tests inluded in nested suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants