Docker

Warning

There are limitations to scaling this deployment strategy, as all nodes are running in the same host.

This deployment is recommended for Tests, Development, POC and POV.

Note

  • For this deployment RabbitMQ will be used as the message queue/broker.

  • This deployment uses the built-in RSTUF Authentication/Authorization

The All-in-one host deployment Repository Service for TUF (RSTUF) uses Docker Engine and Docker Compose yaml file to deploy RSTUF and all the services as containers.

Note

See the complete Deployment Configuration for in-depth details.

Requirements

Software and tools

  • Docker Engine (with docker-compose)

  • Python >= 3.10

  • pip

Online Key

This deployment requires the Online Key. See the chapter Signing Keys

Skip this section if an online key has already been generated.

RSTUF Command Line Interface (CLI) provides a feature for Key Generation (generate)


This command will generate cryptographic keys using the securesystemslib library. The user is requested to provide:

  1. the key type, from the supported list of encryption algorithms

  2. the key’s filename, whose path will be the current working directory

  3. a password, to encrypt the private key file

After the above procedure, two files, the private and public key (e.g., id_ed25519 and id_ed25519.pub), will be generated in the current working directory.

The generated keys may be used in the Repository Service for TUF Ceremony process, for the online key or the TUF roles’ keys (root, targets, etc. keys).

❯ rstuf key generate

Choose key type [ed25519/ecdsa/rsa] (ed25519): ed25519
Enter the key's filename: (id_ed25519): id_ed25519
Enter password to encrypt private key file 'id_ed25519':
Confirm:

Key Information (info)

Show relevant information about a key.

❯ rstuf key info --help

Usage: rstuf key info [OPTIONS]

Show key information

╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --show-private        Show the private key. WARNING: use private key information carefully.      │
│ --help          -h    Show this message and exit.                                                │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯

Steps

  1. Create a folder local-keyvault and add the online key

$ mkdir local-keyvault
$ cp path/my/online.key local-keyvault/
  1. Prepare the Docker Swarm to store RSTUF credentials:

    • SECRETS_POSTGRES_PASSWORD is the postgres password

    • SECRETS_RSTUF_ADMIN_PASSWORD is the admin, user used to manage the RSTUF API tokens.

    • SECRETS_RSTUF_TOKEN_KEY is the token key used to hash the API tokens.

    • SECRETS_RSTUF_ONLINE_KEY is the online key.

    Initiating the Docker Swarm

    Caution

    Do not use these credentials, as they are provided as example.

    $ docker swarm init
    

    Postgres password

    $ printf "secret-postgres" | docker secret create SECRETS_POSTGRES_PASSWORD -
    

    RSTUF admin password

    $ printf "secret-password" | docker secret create SECRETS_RSTUF_ADMIN_PASSWORD -
    

    RSTUF API token key

    $ printf $(openssl rand -base64 32) | docker secret create SECRETS_RSTUF_TOKEN_KEY -
    

    RSTUF Worker online key password

    $ printf "online.key,strongPass" | docker secret create SECRETS_RSTUF_ONLINE_KEY -
    

    Note

    HTTPS

    Add the Certificate and the Key in the secrets

    $ docker secret create API_KEY /path/to/api.key
    $ docker secret create API_CRT /path/to/api.crt
    
  2. Create a Docker Compose (functional example below)

The general explanation about this Docker Compose yaml file:

  • It uses Docker Volume for the persistent data and Volumes

  • rstuf-api-data: Persist the built-in RSTUF auth data.

  • rstuf-storage: public TUF Metadata. Using RSTUF Worker with LocalKeyVault storage backend.

  • rstuf-redis-data: Persistent Redis data

  • rstuf-pgsql-data: Persistent PostgresSQL data

  • rstuf-mq-data: Persistent RabbitMQ data

  • It uses Docker Secrets to store:

    • SECRETS_POSTGRES_PASSWORD

    • SECRETS_RSTUF_TOKEN_KEY

    • SECRETS_RSTUF_ADMIN_PASSWORD

    • SECRETS_RSTUF_ONLINE_KEY

    Note

    HTTPS

    Uncoment API_KEY and API_CRT in the secrets section (lines 18-22).

  • It uses RabbitMQ as the broker/message queue

  • It uses Redis for the task results and RSTUF configuration.

  • It uses a simple python container as the webserver to expose the public TUF metadata from rstuf-storage

  • It provisions the repository-service-tuf-api configuration as environment variables: - Broker Server: RSTUF_BROKER_SERVER - Redis Server: RSTUF_REDIS_SERVER - Enable the RSTUF Authentication/Authorization: RSTUF_AUTH, SECRETS_RSTUF_TOKEN_KEY, SECRETS_RSTUF_ADMIN_PASSWORD

  • It provisions the repository-service-tuf-worker configuration as environment variables:

    • Storage backend: RSTUF_STORAGE_BACKEND, RSTUF_LOCAL_STORAGE_BACKEND_PATH

    • Key Vault backend: RSTUF_KEYVAULT_BACKEND, RSTUF_LOCAL_KEYVAULT_PATH, RSTUF_LOCAL_KEYVAULT_KEYS

    • Broker Server: RSTUF_BROKER_SERVER

    • Redis Server: RSTUF_REDIS_SERVER

    • SQL (Postgres) Server: RSTUF_SQL_SERVER, RSTUF_SQL_USER, RSTUF_SQL_PASSWORD

    Note

    HTTPS

    • Uncomment repository-service-tuf-api environment SECRETS_RSTUF_SSL_CERT, SECRETS_RSTUF_SSL_KEY for the certificate and key

    • Uncomment the in repository-service-tuf-api secrets section API_CRT, API_KEY

    • (Optionally) Comment port - 80:80

docker-compose.yml

  1version: "3.7"
  2
  3volumes:
  4  rstuf-api-data:
  5  rstuf-mq-data:
  6  rstuf-storage:
  7  rstuf-redis-data:
  8  rstuf-pgsql-data:
  9
 10secrets:
 11  SECRETS_RSTUF_ADMIN_PASSWORD:
 12    external: True
 13  SECRETS_RSTUF_TOKEN_KEY:
 14    external: True
 15  SECRETS_RSTUF_ONLINE_KEY:
 16    external: True
 17  SECRETS_POSTGRES_PASSWORD:
 18    external: True
 19  # HTTPS (SSL)
 20  # API_KEY:
 21  #   external: True
 22  # API_CRT:
 23  #   external: True
 24
 25services:
 26  rabbitmq:
 27    image: rabbitmq:3-management-alpine
 28    volumes:
 29      - "rstuf-mq-data:/var/lib/rabbitmq"
 30    healthcheck:
 31      test: "exit 0"
 32    restart: always
 33    tty: true
 34
 35  redis:
 36    image: redis:4.0
 37    volumes:
 38      - rstuf-redis-data:/data
 39    healthcheck:
 40      test: "exit 0"
 41    restart: always
 42    tty: true
 43
 44  postgres:
 45    image: postgres:15.1
 46    ports:
 47      - "5433:5432"
 48    # DO NOT USE IT IN PRODUCTION. Check the Postgres best practices
 49    environment:
 50      - POSTGRES_PASSWORD=secret
 51    volumes:
 52      - "rstuf-pgsql-data:/var/lib/postgresql/data"
 53    healthcheck:
 54      test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"]
 55      interval: 1s
 56
 57  rstuf-worker:
 58    image: ghcr.io/repository-service-tuf/repository-service-tuf-worker:latest
 59    volumes:
 60      - rstuf-storage:/var/opt/repository-service-tuf/storage
 61      - ./local-keyvault/:/var/opt/repository-service-tuf/keyvault/ # map the path where is your key
 62    environment:
 63      RSTUF_STORAGE_BACKEND: LocalStorage
 64      RSTUF_LOCAL_STORAGE_BACKEND_PATH: /var/opt/repository-service-tuf/storage
 65      RSTUF_KEYVAULT_BACKEND: LocalKeyVault
 66      RSTUF_LOCAL_KEYVAULT_PATH: /var/opt/repository-service-tuf/keyvault
 67      RSTUF_LOCAL_KEYVAULT_KEYS: /run/secrets/SECRETS_RSTUF_ONLINE_KEY
 68      RSTUF_BROKER_SERVER: amqp://guest:guest@rabbitmq:5672
 69      RSTUF_REDIS_SERVER: redis://redis
 70      RSTUF_SQL_SERVER: postgres:5432
 71      RSTUF_SQL_USER: postgres
 72      RSTUF_SQL_PASSWORD: /run/secrets/SECRETS_POSTGRES_PASSWORD
 73    secrets:
 74      - SECRETS_RSTUF_ONLINE_KEY
 75      - SECRETS_POSTGRES_PASSWORD
 76    depends_on:
 77      - postgres
 78      - redis
 79      - rabbitmq
 80    healthcheck:
 81      test: "exit 0"
 82    restart: always
 83    tty: true
 84
 85  web-server:
 86    image: python:3.10-slim-buster
 87    command: python -m http.server -d /www 8080
 88    volumes:
 89      - rstuf-storage:/www
 90    ports:
 91      - "8080:8080"
 92
 93  rstuf-api:
 94    image: ghcr.io/repository-service-tuf/repository-service-tuf-api:latest
 95    volumes:
 96      - rstuf-api-data:/data
 97    ports:
 98      - 80:80
 99      - 443:443
100    environment:
101      RSTUF_BROKER_SERVER: amqp://guest:guest@rabbitmq:5672
102      RSTUF_REDIS_SERVER: redis://redis
103      RSTUF_AUTH: "true"
104      SECRETS_RSTUF_TOKEN_KEY: /run/secrets/SECRETS_RSTUF_TOKEN_KEY
105      SECRETS_RSTUF_ADMIN_PASSWORD: /run/secrets/SECRETS_RSTUF_ADMIN_PASSWORD
106      # HTTP (SSL)
107      # SECRETS_RSTUF_SSL_CERT: /run/secrets/API_CRT
108      # SECRETS_RSTUF_SSL_KEY: /run/secrets/API_KEY
109    secrets:
110      - SECRETS_RSTUF_ADMIN_PASSWORD
111      - SECRETS_RSTUF_TOKEN_KEY
112      # HTTPS (SSL)
113      # - API_CRT
114      # - API_KEY
115    depends_on:
116      - rstuf-worker
  1. Run using Docker stack

    $ docker stack deploy -c docker-compose.yml rstuf
    Ignoring unsupported options: restart
    
    Creating network rstuf_default
    Creating service rstuf_redis
    Creating service rstuf_postgres
    Creating service rstuf_rstuf-worker
    Creating service rstuf_web-server
    Creating service rstuf_rstuf-api
    Creating service rstuf_rabbitmq
    
  1. Check if all services are running and health

$ docker ps -a
CONTAINER ID   IMAGE                                                                 COMMAND                  CREATED              STATUS                        PORTS                                                                  NAMES
f3eb8e38c244   postgres:15.1                                                         "docker-entrypoint.s…"   59 seconds ago       Up 58 seconds (healthy)       5432/tcp                                                               rstuf_postgres.1.n9bculkxiikst502oneq2y1tl
00831512a35d   redis:4.0                                                             "docker-entrypoint.s…"   About a minute ago   Up About a minute (healthy)   6379/tcp                                                               rstuf_redis.1.gy8owq16qa0fbgyklr6ji1hyy
75be8062673e   rabbitmq:3-management-alpine                                          "docker-entrypoint.s…"   About a minute ago   Up About a minute (healthy)   4369/tcp, 5671-5672/tcp, 15671-15672/tcp, 15691-15692/tcp, 25672/tcp   rstuf_rabbitmq.1.rw9xdy0bc2n2vszayz8z6onij
a15dc8f6f3c9   ghcr.io/repository-service-tuf/repository-service-tuf-api:latest      "bash entrypoint.sh"     About a minute ago   Up About a minute                                                                                    rstuf_rstuf-api.1.o8zmoccz2n4vnxemczlrrg3o9
40d410b9c6ff   python:3.10-slim-buster                                               "python -m http.serv…"   About a minute ago   Up About a minute                                                                                    rstuf_web-server.1.s29tparemtrj5tut6l41in8ah
5762860c1ccc   ghcr.io/repository-service-tuf/repository-service-tuf-worker:latest   "bash entrypoint.sh"     About a minute ago   Up About a minute (healthy)                                                                          rstuf_rstuf-worker.1.aq20wunul0z9lla0nkpo303zn

Verify rstuf_rstuf-worker logs

docker service logs rstuf_rstuf-worker --raw
  1. RSTUF Ceremony and Bootstrap

Repository Service for TUF (RSTUF) has two specific processes as part of the initial setup: Ceremony and Bootstrap.

Note

  • The setup and configuration requirements:

    • Set of root key(s) and online key for signing

    • RSTUF service deployed

Note

  • It is a one-time process to setup the RSTUF service. If this process is completed during the deployment do not run it again.

RSTUF Command Line Interface provides a guided process for the Ceremony and Bootstrap.

To make this process easier, the Repository Service for TUF CLI provides an interactive guided process to perform the Ceremony.

Note

Required RSTUF CLI installed (See Installation)

❯ rstuf admin ceremony -h

A video demonstrating this process is available.

The Ceremony defines the RSTUF settings/configuration and generates the initial signed TUF root metadata.

It does not activate the RSTUF service. It generates the required JSON payload to bootstrap the RSTUF service.

The Ceremony can be done Connected as a specific step or Disconnected, combined with Bootstrap.

This process generates the initial metadata and defines some settings of the TUF service.

See settings details
  • Root metadata expiration policy

    Defines how long this metadata is valid, for example, 365 days (year). This metadata is invalid when it expires.

  • Root number of keys

    It is the total number of root keys (offline keys) used by the TUF Root metadata. The number of keys implies that the number of identities is the TUF Metadata’s top-level administrator.

    Note

    • Updating the Root metadata with new expiration, changing/updating keys or the number of keys, threshold, or rotating a new online key and sign requires following the Metadata Update process.

    Note

    RSTUF requires all Root key(s) during the Ceremony.

    Note

    RSTUF requires at least the threshold number of Root key(s) for Metadata Update.

  • Root key threshold

    The minimum number of keys required to update and sign the TUF Root metadata.

  • Targets, BINS, Snapshot, and Timestamp metadata expiration policy

    Defines how long this metadata is valid. The metadata is invalid when it expires.

  • Targets number of delegated hash bin roles

    The target metadata file might contain a large number of artifacts. The target role delegates trust to the hash bin roles to reduce the metadata overhead for clients.

  • Targets base URL

    The base URL path for downloading all artifacts. Example: https://www.example.com/download/

  • Signing

    This process will also require the Online Key and Root Key(s) (offline) for signing the initial root TUF metadata.

The settings are guided during Ceremony.

The disconnected Ceremony will only generate the required JSON payload (payload.json) file. The Bootstrap requires the payload.

Note

The payload (payload.json) contains only public data, it does not contain private keys.

This process is appropriate when performing the Ceremony on a disconnected computer to RSTUF API to perform the Bootstrap later as a separate step.

❯ rstuf admin ceremony

The connected Ceremony generates the JSON payload file and run the Bootstrap request to RSTUF API.

This process is appropriate when performing the Ceremony on a computer connected to RSTUF API. It does not require a Bootstrap step.

❯ rstuf admin ceremony -b

Note

if using authentication/authorization the login is required

❯ rstuf admin login
❯ rstuf admin ceremony -b

If a Ceremony Connected is complete, skip this, as the RSTUF service is ready.

If a Ceremony Disconnected is complete, it requires running the Bootstrap from a computer connected to the RSTUF API.

❯ rstuf admin ceremony -b -u

Uninstall All-in-one

Remove the Stack

$ docker stack rm rstuf
Removing service rstuf_rstuf-worker
Removing service rstuf_rstuf-api
Removing service rstuf_rabbitmq
Removing service rstuf_redis
Removing service rstuf_web-server
Removing network rstuf_default

Remove all data

$ docker volume rm rstuf_repository-service-tuf-worker-data \
  rstuf_rstuf-storage \
  rstuf_rstuf-keystorage \
  rstuf_rstuf-redis-data \
  rstuf_rstuf-api-data \
  rstuf_rstuf-mq-data