Kubernetes

Multiple RSTUF API instances/replicas can be deployed in a distributed environment to support multiple requests.

This example uses Kubernetes

Note

This deployment guide does not show the Kubernetes cluster configuration. It requires a Kubernetes cluster running with kubectl configured.

Note

For this deployment Redis is used as the message queue/broker.

Warning

This deployment does not have Authentication/Authorization for the API.

This API is fully accessible for unauthorized users. Consider using an API Authentication/Authorization service.

Note

See the complete Deployment Configuration for in-depth details.

Requirements

Software and tools

  • Kubernetes Cluster

  • kubectl

  • Python >= 3.10

  • pip

Online Key

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

Skip if the online key has 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:

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.                                                │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯

Secrets

Caution

Do not use this credential, it is just an example.

onlinekey secret

Generating the secrets for RSTUF Online Key

  1. Get the key content and encode it to base 64

 base64 -i tests/files/key_storage/online.key
YWI2ODU0YzE5MjlmNjYxNTc4MTBhNDBjMjQ1ZGU0NGJAQEBAMTAwMDAwQEBAQGUxZTk4MzMyZTZiYmNkM2M2ZjdmMGFiZjczNTdmNDNmZGJhN2QwMTRkYzYwMDk2YzNkODRkZjIyYTc3NDUwYmVAQEBANDgxNWEzNTgxZTBmNGM3MDU2OThmZTczMmE2ZWEwNDRAQEBAMmJmYjEwMmNjZTg4OWE0ZWRmZDA0YjU0NGQ1MTE2M2FjNGU0NTY4OWU3NmU3ZTdlZTNmMDQ3ZmE0MTQwM2ZiNmViYzI3MDdjMjM3NzgyNjJkNTQwMGU3YWZlYmQ4MWQ0NmE2OWEwZGUwOWZmNjk0N2Y0YzlkY2QzMzkwODlhYTkyNDA0NTI2M2ZjODg0Yzg1MDFiN2NjYjU5MDZjZTMzYjcyY2JkMDc1NWYwYjhhMzVlYzc1M2E1MDAyMmNkM2RkZDU5MjcxMGQyNjlhYjk0ZjMzOTBhYjVmOWZjNTRlOGUzZGJmMzBjMGUxNjNmYmRhYWQ3NzViMjE4MzdmMzcwODdkNDAxN2NhYjA2YjU1NjI1NmE5ODQwNjBmYmEwMWQ5ZDQ0MjdiNzQ1OTZiODQ5N2RmYjM3ZWRiMTUwZmE2OThkMmNiNzVmYWVkYjhiNTFiZmRjZjUwZDNhM2JlNDM3MThkM2FkM2E1YTU5MTNlY2YyNTA4NzUzYTAxOGVlM2Y5NTI0MmRhNjhjMmMyZjYxNDlmZGJkMmU4OGQ1OTBmYmY0N2YzYTE0MWJhMDVkMjRhYTA1MDg1Mjg3NDMwZDg0MmQwZmI3NmE0YzBjNjgxN2ZkNmVjYjM1NGM1YmNmZWUyYTk4NTRhNTc4NTMwYTI4ZDkxMDE4MzYxMmZhYzBiMjkwMmM1ZGNmODI3ZTA0YTkwODIwYmRhNGYyNWJkMjYzMWQ2ODlmYWYwMWM4MTMzNWI2OGMzYjkwMjEzYjlhMDRjNWFjZGM5OTdmNTA1YmJkNDA5NzZiNTU2Y2NhNmEzYjU0ZjI3MGE3ZWI2YjBkOWI2ZjE5YmUyOWQ2YWI4ZDRhMzFhZWRmYmI3MmE0YzhjZDk2Y2ExY2JmZmU5MDExOGJh
  1. Create a base 64 entry for the secrets. See LocalKeyVault in RSTUF_KEYVAULT_BACKEND

 echo -n "base64|YWI2ODU0YzE5MjlmNjYxNTc4MTBhNDBjMjQ1ZGU0NGJAQEBAMTAwMDAwQEBAQGUxZTk4MzMyZTZiYmNkM2M2ZjdmMGFiZjczNTdmNDNmZGJhN2QwMTRkYzYwMDk2YzNkODRkZjIyYTc3NDUwYmVAQEBANDgxNWEzNTgxZTBmNGM3MDU2OThmZTczMmE2ZWEwNDRAQEBAMmJmYjEwMmNjZTg4OWE0ZWRmZDA0YjU0NGQ1MTE2M2FjNGU0NTY4OWU3NmU3ZTdlZTNmMDQ3ZmE0MTQwM2ZiNmViYzI3MDdjMjM3NzgyNjJkNTQwMGU3YWZlYmQ4MWQ0NmE2OWEwZGUwOWZmNjk0N2Y0YzlkY2QzMzkwODlhYTkyNDA0NTI2M2ZjODg0Yzg1MDFiN2NjYjU5MDZjZTMzYjcyY2JkMDc1NWYwYjhhMzVlYzc1M2E1MDAyMmNkM2RkZDU5MjcxMGQyNjlhYjk0ZjMzOTBhYjVmOWZjNTRlOGUzZGJmMzBjMGUxNjNmYmRhYWQ3NzViMjE4MzdmMzcwODdkNDAxN2NhYjA2YjU1NjI1NmE5ODQwNjBmYmEwMWQ5ZDQ0MjdiNzQ1OTZiODQ5N2RmYjM3ZWRiMTUwZmE2OThkMmNiNzVmYWVkYjhiNTFiZmRjZjUwZDNhM2JlNDM3MThkM2FkM2E1YTU5MTNlY2YyNTA4NzUzYTAxOGVlM2Y5NTI0MmRhNjhjMmMyZjYxNDlmZGJkMmU4OGQ1OTBmYmY0N2YzYTE0MWJhMDVkMjRhYTA1MDg1Mjg3NDMwZDg0MmQwZmI3NmE0YzBjNjgxN2ZkNmVjYjM1NGM1YmNmZWUyYTk4NTRhNTc4NTMwYTI4ZDkxMDE4MzYxMmZhYzBiMjkwMmM1ZGNmODI3ZTA0YTkwODIwYmRhNGYyNWJkMjYzMWQ2ODlmYWYwMWM4MTMzNWI2OGMzYjkwMjEzYjlhMDRjNWFjZGM5OTdmNTA1YmJkNDA5NzZiNTU2Y2NhNmEzYjU0ZjI3MGE3ZWI2YjBkOWI2ZjE5YmUyOWQ2YWI4ZDRhMzFhZWRmYmI3MmE0YzhjZDk2Y2ExY2JmZmU5MDExOGJh,strongPassword" | base64
YmFzZTY0fFlXSTJPRFUwWXpFNU1qbG1Oall4TlRjNE1UQmhOREJqTWpRMVpHVTBOR0pBUUVCQU1UQXdNREF3UUVCQVFHVXhaVGs0TXpNeVpUWmlZbU5rTTJNMlpqZG1NR0ZpWmpjek5UZG1ORE5tWkdKaE4yUXdNVFJrWXpZd01EazJZek5rT0RSa1pqSXlZVGMzTkRVd1ltVkFRRUJBTkRneE5XRXpOVGd4WlRCbU5HTTNNRFUyT1RobVpUY3pNbUUyWldFd05EUkFRRUJBTW1KbVlqRXdNbU5qWlRnNE9XRTBaV1JtWkRBMFlqVTBOR1ExTVRFMk0yRmpOR1UwTlRZNE9XVTNObVUzWlRkbFpUTm1NRFEzWm1FME1UUXdNMlppTm1WaVl6STNNRGRqTWpNM056Z3lOakprTlRRd01HVTNZV1psWW1RNE1XUTBObUUyT1dFd1pHVXdPV1ptTmprME4yWTBZemxrWTJRek16a3dPRGxoWVRreU5EQTBOVEkyTTJaak9EZzBZemcxTURGaU4yTmpZalU1TURaalpUTXpZamN5WTJKa01EYzFOV1l3WWpoaE16VmxZemMxTTJFMU1EQXlNbU5rTTJSa1pEVTVNamN4TUdReU5qbGhZamswWmpNek9UQmhZalZtT1daak5UUmxPR1V6WkdKbU16QmpNR1V4TmpObVltUmhZV1EzTnpWaU1qRTRNemRtTXpjd09EZGtOREF4TjJOaFlqQTJZalUxTmpJMU5tRTVPRFF3TmpCbVltRXdNV1E1WkRRME1qZGlOelExT1RaaU9EUTVOMlJtWWpNM1pXUmlNVFV3Wm1FMk9UaGtNbU5pTnpWbVlXVmtZamhpTlRGaVptUmpaalV3WkROaE0ySmxORE0zTVRoa00yRmtNMkUxWVRVNU1UTmxZMll5TlRBNE56VXpZVEF4T0dWbE0yWTVOVEkwTW1SaE5qaGpNbU15WmpZeE5EbG1aR0prTW1VNE9HUTFPVEJtWW1ZME4yWXpZVEUwTVdKaE1EVmtNalJoWVRBMU1EZzFNamczTkRNd1pEZzBNbVF3Wm1JM05tRTBZekJqTmpneE4yWmtObVZqWWpNMU5HTTFZbU5tWldVeVlUazROVFJoTlRjNE5UTXdZVEk0WkRreE1ERTRNell4TW1aaFl6QmlNamt3TW1NMVpHTm1PREkzWlRBMFlUa3dPREl3WW1SaE5HWXlOV0prTWpZek1XUTJPRGxtWVdZd01XTTRNVE16TldJMk9HTXpZamt3TWpFellqbGhNRFJqTldGalpHTTVPVGRtTlRBMVltSmtOREE1TnpaaU5UVTJZMk5oTm1FellqVTBaakkzTUdFM1pXSTJZakJrT1dJMlpqRTVZbVV5T1dRMllXSTRaRFJoTXpGaFpXUm1ZbUkzTW1FMFl6aGpaRGsyWTJFeFkySm1abVU1TURFeE9HSmgsc3Ryb25nUGFzc3dvcmQ=

postgrespassword secret

Generating the secrets for Postgres password

 echo -n "PostgreSQLstrongPassword" | base64
UG9zdGdyZVNRTHN0cm9uZ1Bhc3N3b3Jk

Secrets example

k8s/secrets.yml

 1##########################################
 2# SECRETS
 3##########################################
 4# RSTUF online key password
 5apiVersion: v1
 6kind: Secret
 7metadata:
 8  name: onlinekey
 9type: Opaque
10data:
11  keys: YmFzZTY0fFlXSTJPRFUwWXpFNU1qbG1Oall4TlRjNE1UQmhOREJqTWpRMVpHVTBOR0pBUUVCQU1UQXdNREF3UUVCQVFHVXhaVGs0TXpNeVpUWmlZbU5rTTJNMlpqZG1NR0ZpWmpjek5UZG1ORE5tWkdKaE4yUXdNVFJrWXpZd01EazJZek5rT0RSa1pqSXlZVGMzTkRVd1ltVkFRRUJBTkRneE5XRXpOVGd4WlRCbU5HTTNNRFUyT1RobVpUY3pNbUUyWldFd05EUkFRRUJBTW1KbVlqRXdNbU5qWlRnNE9XRTBaV1JtWkRBMFlqVTBOR1ExTVRFMk0yRmpOR1UwTlRZNE9XVTNObVUzWlRkbFpUTm1NRFEzWm1FME1UUXdNMlppTm1WaVl6STNNRGRqTWpNM056Z3lOakprTlRRd01HVTNZV1psWW1RNE1XUTBObUUyT1dFd1pHVXdPV1ptTmprME4yWTBZemxrWTJRek16a3dPRGxoWVRreU5EQTBOVEkyTTJaak9EZzBZemcxTURGaU4yTmpZalU1TURaalpUTXpZamN5WTJKa01EYzFOV1l3WWpoaE16VmxZemMxTTJFMU1EQXlNbU5rTTJSa1pEVTVNamN4TUdReU5qbGhZamswWmpNek9UQmhZalZtT1daak5UUmxPR1V6WkdKbU16QmpNR1V4TmpObVltUmhZV1EzTnpWaU1qRTRNemRtTXpjd09EZGtOREF4TjJOaFlqQTJZalUxTmpJMU5tRTVPRFF3TmpCbVltRXdNV1E1WkRRME1qZGlOelExT1RaaU9EUTVOMlJtWWpNM1pXUmlNVFV3Wm1FMk9UaGtNbU5pTnpWbVlXVmtZamhpTlRGaVptUmpaalV3WkROaE0ySmxORE0zTVRoa00yRmtNMkUxWVRVNU1UTmxZMll5TlRBNE56VXpZVEF4T0dWbE0yWTVOVEkwTW1SaE5qaGpNbU15WmpZeE5EbG1aR0prTW1VNE9HUTFPVEJtWW1ZME4yWXpZVEUwTVdKaE1EVmtNalJoWVRBMU1EZzFNamczTkRNd1pEZzBNbVF3Wm1JM05tRTBZekJqTmpneE4yWmtObVZqWWpNMU5HTTFZbU5tWldVeVlUazROVFJoTlRjNE5UTXdZVEk0WkRreE1ERTRNell4TW1aaFl6QmlNamt3TW1NMVpHTm1PREkzWlRBMFlUa3dPREl3WW1SaE5HWXlOV0prTWpZek1XUTJPRGxtWVdZd01XTTRNVE16TldJMk9HTXpZamt3TWpFellqbGhNRFJqTldGalpHTTVPVGRtTlRBMVltSmtOREE1TnpaaU5UVTJZMk5oTm1FellqVTBaakkzTUdFM1pXSTJZakJrT1dJMlpqRTVZbVV5T1dRMllXSTRaRFJoTXpGaFpXUm1ZbUkzTW1FMFl6aGpaRGsyWTJFeFkySm1abVU1TURFeE9HSmgsc3Ryb25nUGFzc3dvcmQ=
12---
13# POSTGRES password
14apiVersion: v1
15kind: Secret
16metadata:
17  name: postgrespassword
18data:
19  password: UG9zdGdyZVNRTHN0cm9uZ1Bhc3N3b3Jk

Applying secrets

 kubectl apply -f secrets.yml
secret/onlinekey created
secret/postgrespassword created

❯ kubectl get secrets
NAME                  TYPE                                  DATA   AGE
default-token-dqt9k   kubernetes.io/service-account-token   3      22d
onlinekey             Opaque                                1      2s
postgrespassword      Opaque                                1      2s

Volumes

The following volumes will be defined:

rstuf-storage persistent volume

RSTUF Workers will use the Storage Backend Service type as LocalStorage which requires a LocalStorage [Optional]

  • RSTUF Workers will use the RSTUF_STORAGE_BACKEND_PATH as this volume

  • WebServer will use the same volume the HTTP root document (htdocs) to expose the TUF Metadata at http://webserver/

rstuf-keystorage persistent volume

RSTUF Workers will use the Key Vault Backend Service type as LocalKeyVault which requires a LocalKeyVault [Optional]

  • RSTUF Workers will use the RSTUF_KEYVAULT_BACKEND_PATH as this volume

  • The online keys will be uploaded to this volume

redis-data persistent volume

Redis persistent data volume

postgres-data persistent volume

Postgres persistent data volume

Volumes example

 1##########################################
 2# VOLUMES
 3##########################################
 4# RSTUF Storage (backend storage)
 5apiVersion: v1
 6kind: PersistentVolumeClaim
 7metadata:
 8  labels:
 9    io.kompose.service: rstuf-storage
10  name: rstuf-storage
11spec:
12  accessModes:
13    - ReadWriteOnce
14  resources:
15    requests:
16      storage: 100Mi
17status: {}
18---
19# RSTUF KeyVault (backend keyvault)
20apiVersion: v1
21kind: PersistentVolumeClaim
22metadata:
23  labels:
24    io.kompose.service: rstuf-keystorage
25  name: rstuf-keystorage
26spec:
27  accessModes:
28    - ReadWriteOnce
29  resources:
30    requests:
31      storage: 100Mi
32status: {}
33---
34# Redis persistent data volume
35apiVersion: v1
36kind: PersistentVolumeClaim
37metadata:
38  labels:
39    io.kompose.service: redis-data
40  name: redis-data
41spec:
42  accessModes:
43    - ReadWriteOnce
44  resources:
45    requests:
46      storage: 100Mi
47status: {}
48---
49# Postgres persistent data volume
50apiVersion: v1
51kind: PersistentVolumeClaim
52metadata:
53  labels:
54    io.kompose.service: postgres-data
55  name: postgres-data
56spec:
57  accessModes:
58    - ReadWriteOnce
59  resources:
60    requests:
61      storage: 250Mi
62status: {}

Applying Volumes

 kubectl apply -f volumes.yml
persistentvolumeclaim/rstuf-storage created
persistentvolumeclaim/rstuf-keystorage created
persistentvolumeclaim/redis-data created
persistentvolumeclaim/postgres-data created

❯ kubectl get pv
NAME                   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                     REASON   AGE
pvc-5184d98009604a73   10Gi       RWO            Retain           Bound    default/redis-data                  7s
pvc-70548101b01f440e   10Gi       RWO            Retain           Bound    default/rstuf-keystorage            9s
pvc-79aff76456bd433f   10Gi       RWO            Retain           Bound    default/rstuf-storage               9s
pvc-c3ee2645d4114816   10Gi       RWO            Retain           Bound    default/postgres-data               8s

Services

redis service

  • Exposes the port 6379 in the deployment network

postgres service

  • Exposes the port 5432 in the deployment network

web-metadata

  • Exposes the port 80 externally, using a load balancer

rstuf-api

  • Exposes the port 80 externally, using a load balancer

Services example

 1##########################################
 2# SERVICES
 3##########################################
 4
 5# Redis service
 6apiVersion: v1
 7kind: Service
 8metadata:
 9  labels:
10    io.kompose.service: redis
11  name: redis
12spec:
13  ports:
14    - name: "6379"
15      port: 6379
16      targetPort: 6379
17  selector:
18    io.kompose.service: redis
19status:
20  loadBalancer: {}
21---
22# Postgres service
23apiVersion: v1
24kind: Service
25metadata:
26  labels:
27    io.kompose.service: postgres
28  name: postgres
29spec:
30  ports:
31    - name: "5432"
32      port: 5432
33      targetPort: 5432
34  selector:
35    io.kompose.service: postgres
36status:
37  loadBalancer: {}
38---
39# http service (exposing TUF metadata plublic)
40apiVersion: v1
41kind: Service
42metadata:
43  labels:
44    io.kompose.service: web-metadata
45  name: web-metadata
46spec:
47  type: LoadBalancer
48  ports:
49    - name: "http"
50      port: 80
51      targetPort: 80
52  selector:
53    io.kompose.service: web-metadata
54---
55# RSTUF API service
56apiVersion: v1
57kind: Service
58metadata:
59  labels:
60    io.kompose.service: rstuf-api
61  name: rstuf-api
62spec:
63  type: LoadBalancer
64  ports:
65    - name: "http"
66      port: 80
67      targetPort: 80
68  selector:
69    io.kompose.service: rstuf-api
70# RSTUF Worker is not a service, only a consumer backend

Applying services

 kubectl apply -f services.yml
service/redis created
service/postgres created
service/web-metadata created
service/rstuf-api created

❯ kubectl get services
NAME           TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)        AGE
kubernetes     ClusterIP      10.128.0.1       <none>            443/TCP        32d
postgres       ClusterIP      10.128.54.79     <none>            5432/TCP       30s
redis          ClusterIP      10.128.202.49    <none>            6379/TCP       30s
rstuf-api      LoadBalancer   10.128.44.53     <PUBLIC_IP>       80:30158/TCP   30s
web-metadata   LoadBalancer   10.128.135.249   <PUBLIC_IP>       80:32744/TCP   30s

Deployment

The following deployment will be applied:

redis deployment

postgres deployment

  • Postgres will use the postgres-data persistent volume mounted on /var/lib/postgresql/data/rstuf

  • Postgres will use environment variable POSTGRES_PASSWORD set as the secrets postgrespassword

web-metadata deployment

web-metadata is the Web Server is Apache which exposes the TUF Metadata

rstuf-api deployment

  • RSTUF API will use environment variables RSTUF_BROKER_SERVER and RSTUF_REDIS_SERVER as redis deployment address (redis://redis).

  • RSTUF API container will use port 80 to serve the API (internally)

rstuf-worker deployment

  • RSTUF Worker will use:

    • rstuf-keystorage persistent volume mounted on /var/opt/repository-service-tuf/keystorage

    • rstuf-storage persistent volume mounted on /var/opt/repository-service-tuf/storage

    • environment variables RSTUF_BROKER_SERVER and RSTUF_REDIS_SERVER as redis deployment (redis://redis).

    • environment variables RSTUF_SQL_SERVER as the postgres deployment (postgres:5432), RSTUF_SQL_USER as postgres, and RSTUF_SQL_PASSWORD as the postgrespassword secret.

    • environment variable RSTUF_KEYVAULT_BACKEND as LocalKeyVault

    • environment variable RSTUF_LOCAL_KEYVAULT_PATH as /var/opt/repository-service-tuf/keystorage

    • environment variable RSTUF_LOCAL_KEYVAULT_KEYS as onlinekey secret

    • environment variable RSTUF_STORAGE_BACKEND as LocalStorage

    • environment variable RSTUF_LOCAL_STORAGE_BACKEND_PATH as /var/opt/repository-service-tuf/storage

Deployment example

  1##########################################
  2# DEPLOYMENT
  3##########################################
  4
  5# Redis deployment
  6apiVersion: apps/v1
  7kind: Deployment
  8metadata:
  9  labels:
 10    io.kompose.service: redis
 11  name: redis
 12spec:
 13  replicas: 1
 14  selector:
 15    matchLabels:
 16      io.kompose.service: redis
 17  strategy:
 18    type: Recreate
 19  template:
 20    metadata:
 21      labels:
 22        io.kompose.service: redis
 23    spec:
 24      containers:
 25        - image: redis:4.0
 26          livenessProbe:
 27            exec:
 28              command:
 29              - redis-cli
 30              - ping
 31          name: redis
 32          ports:
 33            - containerPort: 6379
 34          resources: {}
 35          tty: true
 36          volumeMounts:
 37            - mountPath: /data
 38              name: redis-data
 39      restartPolicy: Always
 40      volumes:
 41        - name: redis-data
 42          persistentVolumeClaim:
 43            claimName: redis-data
 44status: {}
 45---
 46# Postgres Deployment
 47apiVersion: apps/v1
 48kind: Deployment
 49metadata:
 50  labels:
 51    io.kompose.service: postgres
 52  name: postgres
 53spec:
 54  replicas: 1
 55  selector:
 56    matchLabels:
 57      io.kompose.service: postgres
 58  strategy:
 59    type: Recreate
 60  template:
 61    metadata:
 62      labels:
 63        io.kompose.service: postgres
 64    spec:
 65      containers:
 66        - env:
 67            - name: POSTGRES_PASSWORD
 68              valueFrom:
 69                secretKeyRef:
 70                  name: postgrespassword
 71                  key: password
 72            - name: PGDATA
 73              value: /var/lib/postgresql/data/rstuf
 74          image: postgres:15.1
 75          livenessProbe:
 76            exec:
 77              command:
 78                - pg_isready
 79                - -U
 80                - postgres
 81                - -d
 82                - postgres
 83          name: postgres
 84          resources: {}
 85          tty: true
 86          volumeMounts:
 87            - mountPath: /var/lib/postgresql/data
 88              name: postgres-data
 89      restartPolicy: Always
 90      volumes:
 91        - name: postgres-data
 92          persistentVolumeClaim:
 93            claimName: postgres-data
 94status: {}
 95---
 96# http deployment (Web Server to expose metadata public)
 97apiVersion: apps/v1
 98kind: Deployment
 99metadata:
100  name: web-metadata
101  labels:
102    io.kompose.service: web-metadata
103spec:
104  replicas: 1
105  selector:
106    matchLabels:
107      io.kompose.service: web-metadata
108  template:
109    metadata:
110      labels:
111        io.kompose.service: web-metadata
112    spec:
113      containers:
114        - name: web-metadata
115          image: httpd
116          ports:
117            - containerPort: 80
118          resources: {}
119          volumeMounts:
120            - mountPath: /usr/local/apache2/htdocs
121              name: rstuf-storage
122      restartPolicy: Always
123      volumes:
124        - name: rstuf-storage
125          persistentVolumeClaim:
126            claimName: rstuf-storage
127---
128# RSTUF Worker deployment
129apiVersion: apps/v1
130kind: Deployment
131metadata:
132  labels:
133    io.kompose.service: rstuf-worker
134  name: rstuf-worker
135spec:
136  replicas: 5
137  selector:
138    matchLabels:
139      io.kompose.service: rstuf-worker
140  strategy:
141    type: Recreate
142  template:
143    metadata:
144      labels:
145        io.kompose.service: rstuf-worker
146    spec:
147      containers:
148        - env:
149            - name: RSTUF_BROKER_SERVER
150              value: redis://redis
151            - name: RSTUF_REDIS_SERVER
152              value: redis://redis
153            - name: RSTUF_SQL_SERVER
154              value: postgres:5433
155            - name: RSTUF_SQL_USER
156              value: postgres
157            - name: RSTUF_SQL_PASSWORD
158              valueFrom:
159                secretKeyRef:
160                  name: postgrespassword
161                  key: password
162            - name: RSTUF_KEYVAULT_BACKEND
163              value: LocalKeyVault
164            - name: RSTUF_LOCAL_KEYVAULT_PATH
165              value: /var/opt/repository-service-tuf/keystorage/
166            - name: RSTUF_LOCAL_KEYVAULT_KEYS
167              valueFrom:
168                secretKeyRef:
169                  name: onlinekey
170                  key: keys
171            - name: RSTUF_STORAGE_BACKEND
172              value: LocalStorage
173            - name: RSTUF_LOCAL_STORAGE_BACKEND_PATH
174              value: /var/opt/repository-service-tuf/storage
175          image: ghcr.io/repository-service-tuf/repository-service-tuf-worker:latest
176          name: rstuf-worker
177          resources: {}
178          tty: true
179          volumeMounts:
180            - name: onlinekey
181              mountPath: "/run/secrets/onlinekey"
182              readOnly: true
183            - name: postgrespassword
184              mountPath: "/run/secrets/postgrespassword"
185              readOnly: true
186            - mountPath: /var/opt/repository-service-tuf/storage
187              name: rstuf-storage
188            - mountPath: /var/opt/repository-service-tuf/keystorage
189              name: rstuf-keystorage
190      restartPolicy: Always
191      volumes:
192        - name: rstuf-storage
193          persistentVolumeClaim:
194            claimName: rstuf-storage
195        - name: rstuf-keystorage
196          persistentVolumeClaim:
197            claimName: rstuf-keystorage
198        - name: onlinekey
199          secret:
200            secretName: onlinekey
201        - name: postgrespassword
202          secret:
203            secretName: postgrespassword
204status: {}
205---
206# RSTUF API deployment
207apiVersion: apps/v1
208kind: Deployment
209metadata:
210  labels:
211    io.kompose.service: rstuf-api
212  name: rstuf-api
213spec:
214  replicas: 1
215  selector:
216    matchLabels:
217      io.kompose.service: rstuf-api
218  strategy:
219    type: Recreate
220  template:
221    metadata:
222      labels:
223        io.kompose.service: rstuf-api
224    spec:
225      containers:
226        - env:
227            - name: RSTUF_BROKER_SERVER
228              value: redis://redis
229            - name: RSTUF_REDIS_SERVER
230              value: redis://redis
231          image: ghcr.io/repository-service-tuf/repository-service-tuf-api:latest
232          name: rstuf-api
233          ports:
234            - containerPort: 80
235          resources: {}
236      volumes:
237      restartPolicy: Always
238status: {}

Applying deployment

 kubectl apply -f deployment.yml
deployment.apps/redis created
deployment.apps/postgres created
deployment.apps/web-metadata created
deployment.apps/rstuf-worker created
deployment.apps/rstuf-api created

❯ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
postgres-64866cf7f9-p4clt       1/1     Running   0          4m12s
redis-6f6fbbd9ff-ckrrt          1/1     Running   0          4m12s
rstuf-api-7cd78b65f7-sn56n      1/1     Running   0          4m12s
rstuf-worker-5b89554c95-xrlgb   1/1     Running   0          4m12s
web-metadata-75f59886f-h274h    1/1     Running   0          4m12s

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