Code Monkey home page Code Monkey logo

repository-playground's Introduction

Repository Playground

This is a place to develop workflows and Best Practices for community artifact repositories (like PyPI or npm). To accomplish that we intend to implement a community repository of our own: A service that works like "real" artifact repositories like PyPI but is able to experiment more freely.

Current active milestone for the project is to implement a TUF repository on a CI system but this goal will evolve over time.

If you'd like to reach out, you can file an issue in this project or come and say hi on slack. Any mail sent to jkukkonen at google.com will also be read, sooner or later.

Why build this?

Community repositories have two goals that conflict with each other:

  • The projects are conservative for good reasons: They are crucial parts of a vast number of supply chains, and value stability very highly. "Prototyping" is not something they are generally interested in.
  • On the other hand, many of their workflows and processes were designed in a more innocent time. Updating those workflows to match modern security requirements may require changes that are not mere bug fixes: prototyping and path finding are required to find optimal solutions.

Repository playground is a place to do some of the prototyping and path finding that is required to build modern and secure Community repositories.

Why start with TUF and trust delegation?

We're hoping Repository playground is used to solve other security problems that are shared by Community repositories, but have decided to start by tackling the problem of "trust delegation with cryptographic signatures" because of two reasons:

  • The security improvement is significant: Most importantly TUF can ensure that a compromise of the repository infrastructure does not lead to end-user device compromise
  • Implementing TUF in this context is not trivial: Without a concentrated effort this is unlikely to happen in the repository projects themselves

More details in documentation:

repository-playground's People

Contributors

jku avatar joshuagl avatar kommendorkapten avatar lukpueh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

repository-playground's Issues

git-repo: support adding targets

There is currently no way to add/remove actual target files.

Plan:

  • content in targets/ defines the targetfiles we want in the metadata. if you want to add a file, add it to the targets directory and run playground-sign
  • No arguments should be needed: the tool can see what the changes are make the metadata changes
  • delegation paths are enforced, so a path targets/abc/file.txt should be added to role abc metadata.

git-repo: decide on support for multiple keys

I'm adding support on securesystemslib for identifying the HW keys: secure-systems-lab/securesystemslib#526

I want to start using that in some sense

  • I think limiting it to one HW key per repository per user is fine
  • Signer can recognise the correct HW key
  • the signer can store the key details (URI) in .playground-sign.ini

There is an edge case: if you are a signer but have lost your local repository, you've then also lost your URI... So there should be a way to (practically automatically) import a key as the signing key without explicitly adding new signing keys to metadata

git-repo: Implement cron triggered action

We should have an action running frequently (much more frequently than minimum signing period) on cron that:

  • checks each roles expiry / signing periods
  • for online roles: if update is needed,
    • bump version & sign,
    • push to main, fast-forward deploy to main (this triggers deployment)
  • for offline roles: if update is needed
    • bump version,
    • push to signing branch (this triggers signing event)

README: Improve elevator pitch

It'll take a bit of time before we have an implementation to demo. We should make sure our first page documentation makes a good pitch even in the mean time:

  • should be aimed at people who understand the problem space (community repositories)
  • should explain the problem, and how we plan to solve it in a couple of paragraphs
  • should include a few pointers to further docs

git-repo: refactor offline-bump output

Currently playground-offline-bump outputs the created signing event names, and the action uses that list to dispatch the events

This is prone to break if tool stdout contains anything extra (like debug output). Should refactor maybe so that the event names are written to a file (which the action does anyway) and stdout can be used for other useful things.

milestone: Minimal uploads

This should be an API that repository admins (with private keys) can use to upload new versions of metadata.

  • check that everything that was modified is correctly signed + possibly other validity checks (e.g. versions in metadata match what was expected)
  • persist new metadata changes to storage
  • this can then trigger e.g. timestamp: #19

Currently playground has no server component: the admins upload metadata by pushing changes to the underlying git repository.

Some notes:

  • likely makes sense to accept the binaries (targets) in the upload API as well?
  • I wonder if it would make sense to require uploader to send the signatures and the canonical form of signed via the API? this way repository would never need to parse large amounts of unsigned data
    (as an example, use DSSE as the transport format instead of using tuf metadata)

git-repo: repository should check for delegation and targetpath compliance

targetpaths and delegations should be strictly controlled: repository and signer should both refuse metadata where these rules are not followed

  • only toplevel targets can delegate: other targets roles cannot
  • only path delegations
  • valid delegation paths are ["<delegatedrole>/*"]
  • targetpaths must match glob "<delegatedrole>/*" (or as a special case "*" for targets)

support "sigstore key" for maintainer signing as well

Online roles already work with sigstore signing. Would be nice to support them for maintainer (offline) signing as well

This requires:

  • support in the UI: must be able to choose hw key or sigstore key
    • this means we need to somehow get issuer and identity (for SigstoreSigner.import_())
    • as version 1, could ask user to input identity, and then ask to select issuer from list
  • the signer uri could be stored in application config -- but does not have to since there is nothing that we can't recreate
  • anything else?

try to remove signing-event argument

Having to input SIGNING-EVENT is annoying. There are multiple ways to make SIGNING-EVENT an optional argument

  • playground-sign could
    • check which roles user is a singer for
    • use the GitHub API to find out if any signing events for these roles are open (this requires something like labeling GitHub issues by role or something)
  • playground-delegate, when used to start a new signing event, could just make up a signing event with f"{rolename}-v{version}"

This would still leave a few cases unsolved so signing-event should still be somehow user changeable:

  • playground-sign would not notice invites
  • using playground-delegate to add changes to an existing signing event

File remaining design/prototype/implementation issues

Filing issues for everything feels like a daunting task so I'm writing things down here to start with:

  • define TUF metadata layout #4
  • publish metadata (at least initially) #5
  • Implement downloader client -- can be done as soon as there's working metadata
  • prototype repository library as documented in https://github.com/theupdateframework/python-tuf/blob/develop/docs/repository-library-design.md -- probably at least partly in this repo, partly in python-tuf
  • prototype developer tooling: this should be something like a downloader client (in that it uses trusted metadata from the remote repository) but it should also be able to work with not-completely-trusted data: targets files that are not yet fully signed and are not yet part of the snapshot -- this could mean a modified version of ngclient._internal.trusted_metadata_set ?
  • Design/prototype timestamp/snapshot functionality using the repository library: this should be fairly easy, there's a really rough example in https://github.com/jku/tuf-demo github actions (but I don't want to implement this in github: I want an "actual server")
  • document the "developer API" -- how are changes to metadata actually submitted to the repository: complete metadata files, just the changes, or something else?
  • document how developer key management works -- meaning updates to projects keys, adding new projects (delegations), removing projects. This has all kinds of funky interactions with TUF (as keys are defined in delegating metadata)
  • design multisig workflow: How are partially signed changes made available to other developers? It think this almost works by allowing "unfinished" (partially signed) new versions of metadata to exist in the live metadata repository... but this might have unintended consequences (like partially signed root files that could be downloaded by clients?)
  • implement the developer API serverside
  • implement developer signing tool that uses the API
  • maybe implement online metadata visualization (web page per metadata file that allows browsing the metadata -- what is delegated to who)

refactor snapshot

this is part of #31: move code from bash steps in snapshot action to python code toe enable testing

The new python playground-snapshot command should do roughly what currently happens in the action:

  • run playground-snapshot
  • if snapshot was created
    • git commit
    • git push main
    • run playground-publish

git-repo: signer should be able to describe the changes in the signing event

This applies to repository as well, but signer tool should be able to handle at least 95% of signing events and fully describe the changes that it requests signatures for. Examples:

  • Target file abc/file.txt was added
  • @jku was added to role root signers. Current signers are ...

In addition to this, the signer should verify (without describing) some changes:

  • version changes in ways we expect
  • new expiry date is within expected expiry-period

milestone: timestamp

We want Timestamping repository side functionality.

This requires:

  • basic "admin metadata upload" playground functionality (so service knows when timestamping is needed)
  • TUF repository implementation with timestamp functionality (see below)
  • a service running in cloud: runs timestamp on valid uploads and at scheduled times
  • key storage so service has access to the timestamp key

TUF repository implementation refers to something like https://github.com/theupdateframework/python-tuf/blob/develop/docs/adr/0010-repository-library-design.md (see also theupdateframework/python-tuf#1136). I think it's reasonable to try to get a minimal implementation into python-tuf -- but if that does not work out, https://github.com/vmware-labs/repository-editor-for-tuf/ has shown that it can be done outside of python-tuf.

signer: Redesign target file management

The target file adding/removal/modification was working for a short while... but then git-integration was added to signer tool (so the tool does fetch/commit/push). And now it just can't work the same way -- it's likely broken for all but the simplest file adding case.

The old design was this:

  • no "UI": the new state of targets was the actual files in targets/ directory when the too was executed
  • to affect a change you would just modify the target file in targets/, and run playground-sign without any args

This cannot work anymore as the tool now does a git fetch to begin with -- so the "new state of targets/ directory" is not really a thing anymore.

I think there needs to be actual UI -- like "add <filename>", "remove <filename>". Then the code doesn't need to scan the targets directory to find those changed files (the signing event status finding code probably still needs to scan but now it can do so between two points in git history).

git-repo: "playground-status" cannot check for some issues currently

the design currently expects the GH action to call PlaygroundRepository.status(rolename) for each modified role:
this is useful but not sufficient.

Some cases this does not cover (there are probably more):

  • removed delegated roles
  • target files in targets/ changing without the metadata changing EDIT: DONE

I think maybe there needs to be a generic status check for the whole repository? If there is, then the role-specific one may be unneeded.

setup metadata publishing

once #4 is handled we should start publishing metadata, even if it's manually built (as having metadata enables client development and makes it easier to reason about workflows): the real pipeline will likely involve a separate cloud service but MVP could be just GitHub Pages (like I've done with https://jku.github.io/tuf-demo/). I think we want the metadata working storage to be git for easy debugging -- we can start by storing it in this repository but in reality possibly want it in a separate one.

define TUF metadata layout

  • docs/TUF-CLIENT-DESIGN.md talks about some constraints the client puts on the metadata structure (or the way targets delegations must work).
  • PEP-480 defines a metadata structure that is likely quite close to what we want (although I'm not sure if supporting the "unclaimed" delegation makes sense here)...
  • ... but at least the issue of developer key changes likely requires some modifications to PEP-480

We might not have all the information we need to create a final metadata structure but I think we should still go ahead and build one: It would be good to have actual metadata in a repository ASAP.

Implement "Milestone: Minimal TUF"

This is based on roadmap in #15

First playground version should be the most minimal TUF setup possible:

  • just two keys ("root" and "repository admin" keys)
  • Effectively no timestamp or snapshot
  • content is delivered to repository admin via unspecified means
  • repository admin generates metadata for the content locally using vaguely specified means (https://github.com/vmware-labs/repository-editor-for-tuf + manual editing as needed)
  • metadata is stored in git and automatically published to client HTTP endpoint from there
  • there is a downloader client with comparable features to baseline client

The repository (metadata) architecture should be documented, and the security properties explained.

git-repo: Make sure failures are visible

I'm not sure what the correct way to implement this is but: failures in automation should be really visible. We can't allow signers not being notified of expiry because of a bug -- all workflow failures should lead to an issue being filed or something like it

git-repo: Add safety checks for root_history

When there are changes in root_history in a signing event, both signer and repo should verify that those changes are reasonable:

  • existing files are not changed
  • the added file matches the added root.json and the version in filename matches version in file

git-repo: Create playground-bump-online/playground-bump-offline commands

This is part of #31: Refactor and merge current commands version bump commands to two that handle git commits and (behind a flag maybe) git pushes. The currently exposed commands can likely be removed from the CLI.

online-version-bump action

This could be a single command "playground-bump-online" which does the same thing as current steps:

  • run playground-bump-expiring snapshot
  • if snapshot was not created
    • run playground-bump-expiring timestamp
  • else
    • run playground-timestamp
  • if snapshot or timestamp was created
    • git add
    • git commit
    • git push main
    • TODO: this should trigger publish just like snapshot does

offline-version-bump action

This could be handled by a command playground-bump-offline:

  • for each offline role
    • run playground-bump-expiring ROLE
    • if new version was created
      • TODO git add
      • git commit
      • git push HEAD:$EVENT

git-repo: configuration for online signing

Currently the assumption is that new repositories edit .github/workflows/snapshot.yml and add their gcp auth details there.

I think it would make more sense if

  • there is a .playground.ini configuration file where these are stored
  • this file is used by snapshot.yml
  • user is expected to fill the file contents (?) when creating the repository -- or maybe there is a way to tie this to the key management UI?

This should be more compatible with other online signing systems as well

tests: add test for online sigstore signing

When running on GitHub Actions, instead of "LOCAL_TESTING_KEY" we can use the default empty key input in e2e.sh:signer_init() to get sigstore signing for the online key

The tricky thing here is that this can only work on "push" triggers, not on "pull_request" trigger (because the OIDC identity won't be available in PRs)

git-repo: Implement snapshot update

Merging signing event branches into main should trigger:

  • snapshot+timestamp update, merging to main
  • fast-forwarding deploy branch to main (this triggers deployment)

git-repo: actions should not do checkout themselves

I originally made the actions handle checkout (to make the actual workflow simpler) but that may be a mistake.
An example of this is how the gcloud auth token gets overwritten by the "internal" checkout...

Should add the the checkout to the template workflows, and remove them from the actions

git-repo: Cache roles

Current implementation reads roles from disk several times during a single run. The roles should be cached but this should be done carefully: it's really easy to open a role and accidentally tweak some values. This is not critical now as that role typically isn't written to disk or used for anything else. If the roles are cached and reused, this changes completely

Possible design:

  • repo.open(role)
    • if role is not in cache
      • load the role from disk, add to cache
    • return a deepcopy of role from cache
  • repo.close(role, metadata)
    • stores on disk
    • replaces role in cache

Create a "git-based repository design"

I've been looking at other uses cases (non-package repo cases) and there is one the clearly stands out: the git+CI based repo with low change frequency and low number of keyholders. There are implementations already (see sigstore) and I believe this would be an attractive TUF use case for many others too if we manage to productize it.

The potential issue here is that the reliance on git+CI (the appealing feature of this repo type) likely does not mesh well with the end goal of building designs for package repositories. That said, it is clearly a quick path towards a working repository, which might make it worth it anyway...

I'm undecided if this use case is a good fit for this project or not: I like the idea though so I will keep researching this.

refactor signing-event

This is part of #31: Should try simplifying signing-event so that there is less GitHub Action and more python code, making the code easier to test

This one is trickier than snapshot and version-bump refactors: maybe the playground-status should handle the git merge-base call and the checkout of the "known good" original commit...

git-repo: Add git network support back to signer

The plan in #31 includes making both repository tools and signer integrate with git enough that

  • GH actions become simpler in "production"
  • the tools can be run in a local git repo for testing purposes
  • signer hopefully becomes easier to use

currently signer flow is

  1. get signing event branch (either create or pull from remote)
  2. run playground-sign
  3. git add & git commit
  4. git push to remote (that may or may not be same as the pull-remote)

I'd like this to be embedded in playground-sign:

  • "push-remote" and "pull-remote" need to be configured in .playground-sign.ini
  • signing-event (branch) name is either given as CLI arg (in this case fetch from remote, use a temp local branch)., Otherwise maybe we can make up the name?
    • it would be cool if playground-sign could figure out any currently open signing-events without a name...
  • git commit we can handle
  • git push to signing-event branch on push-remote -- this needs to be togglable with --push like in the repo tools

git-repo: Add action to validate signing-event PRs

This should use the same validation code that the signing event uses to produce a check for the PR
Validate that:

  • metadata is valid TUF metadata, correctly signed
  • the repository is historically coherent (version numbers etc)
  • metadata follows the playground rules (approved delegations, contains the custom fields we expect)
  • targets changes and metadata changes match

reconsider signing tool layout

Current signing tools are:

  • playground-sign
    • signing others changes
    • making target file changes
  • playground-delegate
    • changing delegations (and role itself, see x-playground-expiry-period)
    • initializing the repository

This split makes some sense but isn't obviously the only one that makes sense:

  • everything would fit into a single tool just fine... but it could be more confusing
  • having target file changes in playground-sign does ruin its simplicity a bit... could have a separate playground-target for uploading new files, and then playground-sign would really only sign other peoples changes, and do nothing else
  • Another aspect that may separate different functionalities is the level of git integration:
    • earlier in development, git commit and push were not handled at all
    • currently all commands will commit and push
    • this makes quite a lot of sense for e.g. pure signing, but it's less clear if this is the right choice for e.g. making delegation changes?
    • see also #64

git-repo: add tuf-client-like security features to both signer and repo

Example: if the repository is compromised and the whole metadata is replaced with something not signed by correct keys, the signer should refuse to operate (because it keeps a client-like metadata cache and the "update" from cached state fails). This could even be implemented as a fairly normal TUF client (just one that fetches metadata from the git tree)

git-repo: re-consider PR creation

Currently singing-event creates a PR when threshold is reached. This is nice but requires user to Allow GitHub Actions to create and approve pull requests in settings.

The features is maybe not worth that annoyance: The signing event could just provide a link in a signing event comment to create the PR instead.

git-repo: Find and fix issue with public key adding

  • In a test run of playground-delegate root
  • a new signer was added as root signer
  • configured user-name was the signer that was added

for some reason the tool did not ask to insert the HW key (to add the public key to role). This should have happened in delegate.py:_update_offline_role()

Some user stories could be more TUF-agnostic

Maybe this does not make a big difference, but I think the user stories would be stronger if they weren't motivated by a TUF setup. E.g. all the "downloader user" stories work well regardless of TUF being used or not.

The following user stories, otoh, feel like jumping ahead a bit:

  • “Modify top level metadata” (repo admin)
  • “Modify top level keys” (repo admin)
  • “Modify keys/threshold for a project” (project admin)

I suggest to first list the genuine desires/tasks related to each user category (e.g. repo admin wants to authorize project maintainer to sign artifacts for a project), and only in a later step describe how this is realized in a TUF setup (e.g. add keys in top-level metadata).

git-repo: handle delegation changes that lead to unsigned roles

if e.g. targets key is changed (or threshold raised), this currently does not automatically lead to targets re-signing.

Something (either the playground-delegate that modifies root, or the signing-event GH action itself) should trigger signing for targets in the same event, I think. It probably makes sense for playground-delegate to do it (since it may actually be able to sign for targets itself right away)

So offline solution: When a delegation (or just one of the public key contents of the delegation) in a delegator is modified, playground-delegate should create a new version of the delegated metadata. The idea is that the delegated metadata should be signed in the same signing event where the delegation changes: this way we never end up with repository versions where metadata is just incorrectly signed

should we implement a baseline repository (a non-tuf version)?

This came up in a discussion: It could be useful to have a "baseline repository", a repository implementation that doesn't include the improvements like TUF: this would allow demonstrating the advantages but also would make the scope of required workflow changes clear.

There are some problems with this:

  • we likely won't have the resources to host and maintain multiple public services (let's say a plain repo, TUF with repository signing, TUF with developer signing)
  • We know that TUF with developer signing means significant workflow changes when compared to current repository operations. In the worst case that could mean we would implement completely different systems (like a web UI for the plain repo and then local developer tool for the TUF developer signing case)
  • relying on TUF also lets us sidestep some things like "repository accounts" (as PKI covers identities in this case). A plain repo does not have that builtin... so every "write" action like upload would have to be somehow authenticated

That said, maybe there is something to this idea: maybe we could implement at least the repository API for the plain case first, and maybe even a downloader and developer tool (that would handle things that twine and the web UI currently handle for PyPI). Then as the next step we could add TUF in to the mix. The biggest problem there is developer authentication for the plain repo -- I don't think we want to spend time implementing that, and would have to hand wave that somehow -- maybe just use a static secret to represent a "token" from a unimplemented authentication method

git-repo: consider checks for PRs from signing event to main

This is where we should find any issues that should prevent merging the changes The issue here is:

  • signing event should be producing good data ... so maybe we just reproduce the same signing event checks here?
  • the repository is not fully complete at this point unless we run snapshot on the PR already (note that snapshot requires online signing permissions)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.