Skip to content

Latest commit

 

History

History

playground

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

⚠️ Note

repository-playground (the CI-based implementation) has moved to a separate project https://github.com/theupdateframework/tuf-on-ci

CI-based TUF implementation

This is a TUF implementation that operates on Continuous Integration platform. Supported features include:

  • Threshold signing with offline keys, guided by CI
  • Automated online signing
  • Streamlined, opinionated user experience
  • No custom code required

The optimal use case (at least to begin with) is TUF repositories with a low to moderate frequency of change, both for target files and keys.

This is a Work-In-Progress: any code should be seen as experimental for now. See example for an instance running repository-playground.

Documentation

Setup

Current signing requirements are:

  • A HW key with PIV support (such as a newer Yubikey)
  • Python 3.11 or higher

Setup signer

  1. Create a PIV signing key on your HW key if you don't have one. For Yubikey owners the easiest tool is Yubikey manager:Yubikey manager UI

    yubico-piv-tool can also do it (just copy-paste the public key and certificate when requested):

    yubico-piv-tool -a generate -a verify-pin -a selfsign -a import-certificate -s 9c -k -A ECCP256 -S '/CN=piv_auth/OU=example/O=example.com/'
  2. Install a PKCS#11 module. Playground has been tested with the Yubico implementation, Debian users can install it with

    $ apt install ykcs11

    macOS users can install with

    $ brew install yubico-piv-tool
  3. install playground-sign

    $ pip install git+https://[email protected]/jku/repository-playground#subdirectory=playground/signer

Configure signer

Whenever you run signing tools, you need a configuration file .playground-sign.ini in the root dir of the git repository that contains the metadata:

[settings]
# Path to PKCS#11 module
pykcs11lib = /usr/lib/x86_64-linux-gnu/libykcs11.so
# GitHub username
user-name = @my-github-username

# Git remotes to pull and push from
pull-remote = origin
push-remote = origin

A provided script exists that can generate one.

Setup a new Playground repository

  1. Fork the template.
  2. To enable repository publishing, set Settings->Pages->Source to Github Actions

Using a KMS

Currently Azure and Google cloud KMS are supported. If you intend to use a Cloud KMS for online signing (instead of the default "ambient Sigstore signing"), there are a couple of extra steps:

  1. Make sure Cloud KMS allows this repository OIDC identity to sign with a KMS key.
    1. For GCP, define your authentication details as repository variables in Settings->Secrets and variables->Actions->Variables. Examples:
      GCP_WORKLOAD_IDENTITY_PROVIDER: projects/843741030650/locations/global/workloadIdentityPools/git-repo-demo/providers/git-repo-demo
      GCP_SERVICE_ACCOUNT: [email protected]
      
    2. For Azure, AZURE_CLIENT_ID, AZURE_TENANT_ID and AZURE_SUBSCRIPTION_ID must be set. Then an extra step in the workflow must be inserted like this:
      jobs:
        snapshot:
        runs-on: ubuntu-latest
      
          permissions:
            id-token: 'write' # for OIDC identity access
            contents: 'write' # for committing snapshot/timestamp changes
          ...
          steps:
            - name: Login to Azure
              uses: azure/login@v1
              with:
                client-id: ${{ secrets.AZURE_CLIENT_ID }}
                tenant-id: ${{ secrets.AZURE_TENANT_ID }}
                subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
            - id: snapshot
              uses: jku/repository-playground/playground/actions/snapshot@main
        ...
        deploy:
      
  2. (only needed for initial repository creation) Prepar local environment for accessing the cloud KMS.
    1. For GCP use gcloud and authenticate in the environment where you plan to run playground-delegate tool (you will need roles/cloudkms.publicKeyViewer permission)

    2. For Azure use az login and authenticate against the environment where the key vault exists. You will need to the role "Key Vault Crypto User").

Operation

Both tools (playground-delegate and playground-sign) take one required argument, the signing event name (it is used as a git branch name). Typically the signing event exists and you know its name but in some cases (delegation, target modification) you can choose a name for a new signing event: anything starting with "sign/" is fine.

The tools will fetch the current signing event content from a matching branch in pull-remote. After signing or delegation changes, the tools will push the changes to matching branch on push-remote.

Notes on remotes configured in .playground-sign.ini:

  • pull-remote should always be the actual TUF repository
  • If you have permissions to push to the TUF repository, you can set push-remote to same value
  • Otherwise you can set push-remote to your fork: in this case after running the tools, you should make a PR from your fork to the signing event branch on the TUF repository

Initial signing event

  1. Run delegate tool to create initial metadata
    $ playground-delegate <event-name>
  2. Respond to the prompts

Add a delegation or modify an existing one

  1. Run delegate tool when you want to modify a roles delegation
    $ playground-delegate <event-name> <role>
  2. Respond to the prompts

Modify target files

Make target file changes in the signing event git branch using tools and review processes of your choice.

$ git fetch origin
$ git switch -C sign/my-target-changes origin/main
$ echo "test content" > targets/file.txt
$ git commit -m "Add a target file" -- targets/file.txt
$ git push origin sign/my-target-changes

This starts a signing event (or updates an existing signing event).

Sign changes made by others

Signing should be done when the signing event (GitHub issue) asks for it:

  1. Run signer tool in the signing event branch
    $ playground-sign <event-name>
  2. Respond to the prompts

Components

Repository template

Status: Implemented in the playground-template project. Workflows include

  • signing-event
  • snapshot
  • version-bumps

See here.

Repository actions

Status:

  • actions/signing-event: functionality is there but output is a work in progress, and various checks are still unimplemented
  • actions/snapshot: Implemented
  • actions/online-version-bump: Implemented
  • actions/offline-version-bump: Implemented

Various parts are still very experimental

  • loads of content safety checks are missing
  • output of the signing event is a work in progress
  • failures in the actions are not visible to user
  • testing is still completely manual

See repo/, See actions/

signing tool

Status:

  • playground-delegate mostly implemented
  • playground-sign mostly implemented, although output is a work in progress

See signer/

Client

client/ contains a simple downloader client. It can securely lookup and download artifacts from the repository. There is nothing specific to this repository implementation in the client implementation: any other client could be used.

TODO: Client is currently not up-to-date WRT repository implementation.

Examples

Initialize a new repository

  1. Instantiate template
  2. Enable publishing to GitHub Pages: Settings > Pages > Source: GitHub Actions
  3. Install the signer tools as described here on your local computer
  4. Clone the instantiated repository
  5. Prepate the configuration file (.playground-sign.ini)
  6. Run playground-delegate <event-name>
  7. Follow the instructions to configure the root, after this is done a new branch with <event-name> is pushed to origin
  8. Once the new metadata is pushed, reivew the change and merge into main
  9. Once merged to main snapshot and timestamp workflows will run and publish the root for consumption

Adding a new signer

Adding a new root signer is done via the playground-sign command.

$ playground-delegate sign/add-fakeuser-2

Remote branch not found: branching off from main
Enter name of role to modify: root
Modifying delegation for root

Configuring role root
 1. Configure signers: [@-fakeuser-1], requiring 1 signatures
 2. Configure expiry: Role expires in 365 days, re-signing starts 60 days before expiry
Please choose an option or press enter to continue: 1
Please enter list of root signers [@-fakeuser-1]: @-fakeuser-1,@-fakeuser-2
Please enter root threshold [1]:
 1. Configure signers: [@-fakeuser-1, @-fakeuser-2], requiring 1 signatures
 2. Configure expiry: Role expires in 365 days, re-signing starts 60 days before expiry
Please choose an option or press enter to continue:
...

Once finished the changes are pushed to the branch <event-name> which in the above example is sign/add-fakueuser-2.

By naming the event with sign/<event-name> automation will pick up this branch and run the signing automation that creates issues with the current signing state and tags each signer on what's expected to do. This always provides a clear state of the situation.

To accept the invitation and become a signer, the invitee runs playground-sign <event-name> and provides information on what key to use. After completion the updated metadata will be pushed to origin. Currently the invitee must execute playground-sign <event-name> twice, the first run will only add the key to the metadata, the second invocation will actually sign the metadata. This will be changed in a future release.

When adding or changing root signer, remember that a quorum of current key-holders must sign the updated root metadata for it to be valid.

Removing a signer

To remove a signer, follow the steps when adding a signer. When configuring the desired role, add a new list of signers where the desired users are not present. After this a new signing event happens and so all kept signers must resign the metadata.

Adding targets

Create a new branch, and give it a descriptive name, then add the targets and push the branch to origin

$ git checkout -b sign/add-targets
$ mkdir targets
$ echo file1 > targets/file1.txt
$ echo file2 > targets/file2.txt

The branch can now be pushed to origin and an issue will be created that tracks the changes and the required signaturesby the correct key holders.

Run the playground-sign <event-name> command to sign the metadata and push the branch to origin, once pushed, and signed by all key holders create a PR and merge. The snapshot workflow will then run an publish the repository for consumption.

Debug tools

The same tool (playground-status) that runs during the automation can be run locally too to inspect the current status of a branch (signing event).

To install the repository tools, run pip install from the playground/repo directory where the pyproject.toml file exists:

$ pip install -e .

As an example, this would be the output when an open invitation exists for a new user to become a root key holder:

$ playground-status
### Current signing event state
Event [sign/add-fakeuser-1](../compare/sign/add-fakeuser-1)
#### :x: root
root delegations have open invites (@-fakeuser-2).
Invitees can accept the invitations by running `playground-sign add-fakeuser-2`
$