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

Cache all root metadata versions #2767

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from

Conversation

jku
Copy link
Member

@jku jku commented Jan 14, 2025

Making this ready for review based on discussion in community meeting. There's no rush in getting this merged: let's make sure the review / testing is adequate.

Problem

Currently python-tuf clients typically initialize once from the "bootstrap" root (the root metadata shipped with the client software), and subsequent startups will use the cached root as starting point. This is mostly good but there is a downside: if the bootstrap root is more secure than the cache, then we lose some security (as cache could get poisoned between the first cache initialization and the actual use). This situation can arise if the client software (and bootstrap root) is shipped in a Operating System update, container image or e.g. a Debian package: in this case the client cache is writable by user but the bootstrap root and the client software may not be.

Solution

  • Cache all root versions
  • Always initialize the client starting with the secure bootstrap root
  • When loading subsequent root versions, load from local cache and from remote repository

This should give us best of both worlds:

  • client always initializes from most securely stored root
  • client does not download any more data than now
  • client still uses local cache for roots so repository cannot serve obsolete data

The only downside is that client will now verify every root version on startup: I think this perfectly acceptable as client can and should periodically update the bootstrap root as well -- the added computation is not an issue in practice.

Details

The ngclient cache directory looked like this before:

cachedir/
    root.json
    timestamp.json
    snapshot.json
    targets.json
    somedelegatedrole.json

Now it looks like this:

cachedir/
    root.json        #  This is a symlink to "root_history/3.root.json" for compatibility
    timestamp.json
    snapshot.json
    targets.json
    somedelegatedrole.json
    root_history/
        1.root.json
        2.root.json
        3.root.json
  • non-versioned root.json is preserved as symlink so that older python-tuf versions can coexist (and so it's easier to check current state for humans and tests)
  • root_history directory is used to make name clashes impossible (imagine a delegated role named "1.root") : as long as the client is not susceptible to path traversal issues, this should be safe
  • tests have been added to verify that roots are cached, cached roots are used and that poisoned cache is handled correctly (remote metadata is used if cache is not valid)

@jku
Copy link
Member Author

jku commented Jan 17, 2025

I think I'll refactor the large test cleanups to a different PR so this doesn't look so big (it isn't)

@kairoaraujo
Copy link
Contributor

I think I'll refactor the large test cleanups to a different PR so this doesn't look so big (it isn't)

I'm ok with reviewing it if you want to add to this PR (separate commit).

@jku
Copy link
Member Author

jku commented Jan 17, 2025

not planning to add anything: I just meant the test file removals that are already in the PR: "+268 −1,253" looks like a big change but the actual PR is really manageable

@jku jku force-pushed the bootstrap-root-metadata branch from 392623d to 4534bbf Compare January 17, 2025 09:06
@jku jku mentioned this pull request Jan 17, 2025
@jku jku force-pushed the bootstrap-root-metadata branch from 4534bbf to 10703ac Compare January 17, 2025 09:39
@jku
Copy link
Member Author

jku commented Jan 17, 2025

OK:
there is now #2768 that should be handled before this one: this changes this PR into a fairly small one: 235 insertions(+), 89 deletions(-)

@jku jku force-pushed the bootstrap-root-metadata branch from aa66a53 to c145196 Compare January 27, 2025 13:27
jku added 10 commits January 29, 2025 18:43
Application may have a "more secure" data store than the metadata cache
is: Allow application to bootstrap the Updater with this more secure
root. This means the Updater must also cache the subsequent root versions
(and not just the last one).

* Store versioned root metadata in local cache
* maintain a non versioned symlink to last known good root
* When loading root metadata, look in local cache too
* Add a 'bootstrap' argument to Updater: this allows
  initializing the Updater with known good root metadata
  instead of trusting the root.json in cache

Additional changes to current functionality:
* when using bootstrap argument, the initial root is written to cache.
  This write happens every time Updater is initialized with bootstrap
* The "root.json" symlink is recreated at the end of every refresh()

Signed-off-by: Jussi Kukkonen <[email protected]>
Expect (failing) call to open for "root_history/2.root.json" now that
the client stores versioned roots.

Signed-off-by: Jussi Kukkonen <[email protected]>
Even if last root version from remote is not accepted (leading to an
exception in load_root()) we should update the symlink "root.json" in
local cache to point to last good version.

Signed-off-by: Jussi Kukkonen <[email protected]>
Update test_updater_toplevel_update to use bootstrap argument by
default.

This still does not include tests for bootstrap feature specifically
but it should prove nothing has broken when the feature was added.

Signed-off-by: Jussi Kukkonen <[email protected]>
When application initializes an Updater with bootstrap, it should be
considered the trusted version from that point onwards: Update the
symlink "root.json" already here (even if refresh is never called).
n that Updater instance).

Signed-off-by: Jussi Kukkonen <[email protected]>
Signed-off-by: Jussi Kukkonen <[email protected]>
This includes some minor example improvements

Signed-off-by: Jussi Kukkonen <[email protected]>
This is in order to not clash with theupdateframework#2762.

Signed-off-by: Jussi Kukkonen <[email protected]>
@jku jku force-pushed the bootstrap-root-metadata branch from c145196 to d34aad4 Compare January 29, 2025 16:44
@jku
Copy link
Member Author

jku commented Jan 29, 2025

rebased on main to build on top of #2768 to make this PR a reasonable size

@kairoaraujo kairoaraujo self-requested a review February 7, 2025 15:18
@jku jku marked this pull request as ready for review February 7, 2025 15:31
@jku jku requested a review from a team as a code owner February 7, 2025 15:31
Copy link
Contributor

@kairoaraujo kairoaraujo left a comment

Choose a reason for hiding this comment

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

I added a nit comment as I feel that the note could be more explicit.

directory for downloads"""
directory for downloads

NOTE: This is unsafe and for demonstration only: the bootstrap root
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we log a warning to the user here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think that would be helpful:

  • warnings are useful if they allow the user to react somehow. This is not the case here
  • the note is there to prevent someone from copy-pasting example code to a real client that should be shipping an embedded root instead

@jku
Copy link
Member Author

jku commented Feb 11, 2025

Thanks for reviews. I'll let this sit for now as it will clash with #2762 which I was hoping to merge soonish.

@kairoaraujo
Copy link
Contributor

@jku I guess we can rebase it and merge, right?

@jku
Copy link
Member Author

jku commented Feb 14, 2025

uh, kind of but it will still clash with #2773: I think I'd rather resolve after that one

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.

Updater feature request: verify chain of trust from bootstrapped root metadata
3 participants