tuftool is a Rust command-line utility for generating and signing TUF repositories.
Make sure you have the following dependencies present on your system before installing tuftool
:
- OpenSSL: install
libssl-dev
on Ubuntu oropenssl-devel
on Fedora.
To install the latest version of tuftool
:
cargo install --force tuftool
By default, cargo installs binaries to ~/.cargo/bin
, so you will need this in your path. See the cargo book for more about installing Rust binary crates.
The following is an example of how you can create and download a TUF repository using tuftool
.
First, create a working directory:
export WRK="${HOME}/tuftool-example"
mkdir -p "${WRK}"
For production you may want to use a service like AWS KMS, but for this example we will create keys locally as files:
# we will store our root.json in $WRK/root
mkdir "${WRK}/root"
# save the path to the root.json we are about to create, we will use it a lot
export ROOT="${WRK}/root/root.json"
# we will store our signing keys in $WRK/keys
mkdir "${WRK}/keys"
# instantiate a new root.json
tuftool root init "${ROOT}"
# set the root file's expiration date
tuftool root expire "${ROOT}" 'in 6 weeks'
# set the signing threshold for each of the standard signing roles. we are saying
# that each of the following roles must have at least 1 valid signature
tuftool root set-threshold "${ROOT}" root 1
tuftool root set-threshold "${ROOT}" snapshot 1
tuftool root set-threshold "${ROOT}" targets 1
tuftool root set-threshold "${ROOT}" timestamp 1
# create an RSA key and store it as a file. this requires openssl on your system
# this command both creates the key and adds it to root.json for the root role
tuftool root gen-rsa-key "${ROOT}" "${WRK}/keys/root.pem" --role root
# for this example we will re-use the same key for the other standard roles
tuftool root add-key "${ROOT}" -k "${WRK}/keys/root.pem" --role snapshot
tuftool root add-key "${ROOT}" -k "${WRK}/keys/root.pem" --role targets
tuftool root add-key "${ROOT}" -k "${WRK}/keys/root.pem" --role timestamp
# sign root.json
tuftool root sign "${ROOT}" -k "${WRK}/keys/root.pem"
Now that we have a root.json file, we can create and sign a TUF repository.
# create a directory to hold the targets that we will sign. we call this the
# 'input' directory because these are the targets that we want to put into
# our TUF repo
mkdir -p "${WRK}/input"
# create the targets that we want in our TUF repo
echo "1" > "${WRK}/input/1.txt"
echo "2" > "${WRK}/input/2.txt"
# create a tuf repo!
tuftool create \
--root "${ROOT}" \
--key "${WRK}/keys/root.pem" \
--add-targets "${WRK}/input" \
--targets-expires 'in 3 weeks' \
--targets-version 1 \
--snapshot-expires 'in 3 weeks' \
--snapshot-version 1 \
--timestamp-expires 'in 1 week' \
--timestamp-version 1 \
--outdir "${WRK}/tuf-repo"
# you can see our signed repository's metadata here:
ls "${WRK}/tuf-repo/metadata"
# and you can see our signed repository's targets here:
ls "${WRK}/tuf-repo/targets"
### Update TUF Repo
# Change one of the target files
echo "1.1" > "${WRK}/input/1.txt"
# update tuf repo!
tuftool update \
--root "${ROOT}" \
--key "${WRK}/keys/root.pem" \
--add-targets "${WRK}/input" \
--targets-expires 'in 3 weeks' \
--targets-version 2 \
--snapshot-expires 'in 3 weeks' \
--snapshot-version 2 \
--timestamp-expires 'in 1 week' \
--timestamp-version 2 \
--outdir "${WRK}/tuf-repo" \
--metadata-url file:///$WRK/tuf-repo/metadata
Now that we have created TUF repo, we can inspect it using download command. Download command is usually used to download a remote repo using HTTP/S url, but for this example we will use a file based url to download from local repo.
# download tuf repo
tuftool download \
--root "${ROOT}" \
-t "file://${WRK}/tuf-repo/targets" \
-m "file://${WRK}/tuf-repo/metadata" \
"${WRK}/tuf-downlaod"
tuftool
respects the HTTPS_PROXY
and NO_PROXY
environment variables.
Unit tests are run in the usual manner: cargo test
.
Integration tests require working AWS credentials and are disabled by default behind a feature named integ
.
To run all tests, including integration tests: cargo test --features 'integ'
or AWS_PROFILE=test-profile cargo test --features 'integ'
with specific profile.