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

repack: do not include Volume paths in new layers #127

Merged
merged 4 commits into from Jul 19, 2017

Conversation

cyphar
Copy link
Member

@cyphar cyphar commented Jun 3, 2017

This is (unfortunately) not mandated in the specification, but in
order to avoid accidentally spilling private information into published
layers (which is one use of Volumes) we must ignore all layers included
in Config.Volumes.

In future we should also add some flags or alernative ways of masking
paths.

Signed-off-by: Aleksa Sarai asarai@suse.de

@cyphar cyphar added this to the 0.3.0 milestone Jun 3, 2017
@cyphar
Copy link
Member Author

cyphar commented Jun 3, 2017

@vrothberg PTAL

@cyphar cyphar force-pushed the ignore-volumes-in-snapshot branch 6 times, most recently from f29c820 to b150f72 Compare June 5, 2017 12:46
@vrothberg
Copy link
Contributor

Sorry, I did not forget about this. Hopefully I find time to check this PR next week.

@cyphar
Copy link
Member Author

cyphar commented Jun 25, 2017

This is now actually recommended by opencontainers/image-spec#694 (yay, finally).

@vrothberg
Copy link
Contributor

Awesome! I put checking the code on tomorrow's to-do.

Copy link
Contributor

@vrothberg vrothberg left a comment

Choose a reason for hiding this comment

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

Somehow my guts tell me to invert the functionality and add an --unmask-volumes flag and mask volumes by default. Especially because "If a new image is created from a container based on the image described by this configuration, data in these paths SHOULD NOT be included in the new image."

return func(path string) bool {
// Convert path to relative-to-root.
path = filepath.Clean(path)
path = filepath.Join("/", path)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mean an absolute path? If so, we should use filpath.Abs(path).

Copy link
Member Author

Choose a reason for hiding this comment

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

filepath.Abs can fail, and it also tries to do things we don't want from memory. Effectively what this does in this context is that it makes the path underneath the root. However, I've just realised that it shouldn't be necessary to have a Clean(path) beforehand because the prefix path is / (which is safe against Clean issues).

for _, mask := range masks {
// Mask also needs to be relative-to-root.
mask = filepath.Clean(mask)
mask = filepath.Join("/", mask)
Copy link
Contributor

Choose a reason for hiding this comment

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

Absolute path?

Copy link
Member Author

Choose a reason for hiding this comment

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

See above.

// FilterFunc is a function used when filtering deltas with FilterDeltas.
type FilterFunc func(path string) bool

// isParent returns whether the path a is lexically an ancestor of the path b.
Copy link
Contributor

Choose a reason for hiding this comment

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

That's a very elegant function 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. 😉

bundle-verify "$BUNDLE_A"

# Create files in those volumes.
mkdir -p "$BUNDLE_A/rootfs/some nutty/path name/"
Copy link
Contributor

Choose a reason for hiding this comment

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

I would expect unpack to create volume paths. Is there a specific reason not to? Run-times should be able to deal with both cases?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm. I'm not sure. VOLUME in a Dockerfile creates the directory in the image (from memory) so I'm not sure if it makes sense for us to do that -- what should we do if a non-directory already exists there (for example)? I don't like the idea of erroring out in that case, but ignoring it also seems fishy.

I'll have to think about it some more, but can you open an issue for us to review at a later date?

Copy link
Contributor

Choose a reason for hiding this comment

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

Good idea, let's move to an issue 👍

test/repack.bats Outdated
! [ -e "$BUNDLE_B/rootfs/some nutty/path name" ]
! [ -e "$BUNDLE_B/rootfs/some nutty/path name/ here" ]

# TODO: We need to add some flags to repack to allow users to ignore VOLUME.
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure I understand this comment correctly. What do you mean by "ignore"? In the sense that content will be copied regardless of the path being a volume?

Copy link
Contributor

Choose a reason for hiding this comment

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

There's one hiding at the bottom :)

CHANGELOG.md Outdated
@@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]
### Added
- `umoci repack` now supports `--mask-path` to ignore certain changes in the
rootfs when generating new layers.
Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer it to be more explicit: [...] to ignore changes in specified path of the rootfs when generating new layers.

if ctx.Bool("mask-volumes") {
for v := range config.Volumes {
volumes = append(volumes, v)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to rename volumes to maskedPaths.

test/repack.bats Outdated
[ "$status" -eq 0 ]
image-verify "${IMAGE}"

# Re-extract to verify the volume changes weren't included.
Copy link
Contributor

Choose a reason for hiding this comment

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

...the masked path changes...

test/repack.bats Outdated
# Masked paths must not be included.
! [ -e "$BUNDLE_C/rootfs/volume" ]
! [ -e "$BUNDLE_C/rootfs/volume/test" ]
# But volumes might not be included.
Copy link
Contributor

Choose a reason for hiding this comment

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

might BE included?

Copy link
Member Author

@cyphar cyphar left a comment

Choose a reason for hiding this comment

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

Some responses enclosed.

As for the opt-in security (we already discussed this, I'm just putting it here for posterity):

I agree that opt-in security is bad (and my main argument for proposing adding this language to the spec was security). My main concern was that users like KIWI don't actually want to have this option be the default, and I'm not sure how we should approach changing our API (specifically adding flags that opt-out of new features) for such users.

We need to talk to the KIWI folks about what they want the default to be and come to an agreement on how they would like to be able to interface with us if we change our ABI. This will additionally be very important with the rc5 bump because in future I'm planning on changing how you reference tags (in somewhat minor ways, but I really want --layout to die).

return func(path string) bool {
// Convert path to relative-to-root.
path = filepath.Clean(path)
path = filepath.Join("/", path)
Copy link
Member Author

Choose a reason for hiding this comment

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

filepath.Abs can fail, and it also tries to do things we don't want from memory. Effectively what this does in this context is that it makes the path underneath the root. However, I've just realised that it shouldn't be necessary to have a Clean(path) beforehand because the prefix path is / (which is safe against Clean issues).

// FilterFunc is a function used when filtering deltas with FilterDeltas.
type FilterFunc func(path string) bool

// isParent returns whether the path a is lexically an ancestor of the path b.
Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. 😉

for _, mask := range masks {
// Mask also needs to be relative-to-root.
mask = filepath.Clean(mask)
mask = filepath.Join("/", mask)
Copy link
Member Author

Choose a reason for hiding this comment

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

See above.

bundle-verify "$BUNDLE_A"

# Create files in those volumes.
mkdir -p "$BUNDLE_A/rootfs/some nutty/path name/"
Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm. I'm not sure. VOLUME in a Dockerfile creates the directory in the image (from memory) so I'm not sure if it makes sense for us to do that -- what should we do if a non-directory already exists there (for example)? I don't like the idea of erroring out in that case, but ignoring it also seems fishy.

I'll have to think about it some more, but can you open an issue for us to review at a later date?

@cyphar
Copy link
Member Author

cyphar commented Jul 5, 2017

I'm going to wait on merging this until I speak to @davidcassany about how he feels about --no-mask-volumes and how we're going to handle CLI changes in the future.

This makes it much simpler to create filters for []mtree.InodeDelta
given an arbitrary filter function. This is necessary to implement
volume masking (as well as arbitrary path masking and possibly glob
masking in the future).

Signed-off-by: Aleksa Sarai <asarai@suse.de>
The reason for the split is that some users may wish to mask arbitrary
paths that have not been set with --config.volumes (which therefore
requires --mask-path). We make --no-mask-volumes an opt-out option
(despite the backwards compatibility problem) because it's a security
feature that really shouldn't be opt-in. I don't anticipate this will
break current users of KIWI (and future users will hit this and realise
it's a feature). However, this needs to be toggle-able because:

1. It is a backwards-incompatible change to the command-line API. Since
   KIWI has its own opinions about configuration and its relation to
   file unpacking, so older users of umoci need a way to switch to the
   old semantics.

2. Some users don't want to follow the suggestion of the spec that
   volumes should not be included in layers. While it's not clear when
   this would be a good idea (--no-mask-volumes is a security feature
   against credential exposure), we must retain it as an option. If
   nobody ends up using it we can remove the ability to disable it.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
@cyphar cyphar force-pushed the ignore-volumes-in-snapshot branch from 1ee0585 to f4153fe Compare July 19, 2017 14:46
@cyphar
Copy link
Member Author

cyphar commented Jul 19, 2017

I've rebased this and made it opt-out after discussions with @davidcassany. I agree with him that I severely doubt that any current users will be broken by this and in the future KIWI will have strict requirements on umoci versions.

Signed-off-by: Aleksa Sarai <asarai@suse.de>
Signed-off-by: Aleksa Sarai <asarai@suse.de>
@cyphar cyphar force-pushed the ignore-volumes-in-snapshot branch from f4153fe to 1e52a94 Compare July 19, 2017 15:20
@cyphar
Copy link
Member Author

cyphar commented Jul 19, 2017

LGTM.

@cyphar cyphar merged commit 1e52a94 into master Jul 19, 2017
cyphar added a commit that referenced this pull request Jul 19, 2017
@cyphar cyphar deleted the ignore-volumes-in-snapshot branch July 19, 2017 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants