Prerequisites
Required tools, accounts, and access credentials
This page lists every tool, account, and credential you need before you can call the Trilio Share Protection (Abacá) API or deploy any part of the control plane. Satisfying these prerequisites up front prevents the most common setup failures — missing services, wrong versions, or credentials that lack the exact permissions Abacá expects. The requirements are split into three groups: the OpenStack services that must be running in your environment, the S3 bucket you will register as a backup target, and the client-side tooling you need on your workstation.
OpenStack environment
Your target OpenStack cluster must be running the following services at the versions shown:
| Service | Minimum version | Why Abacá needs it |
|---|---|---|
| Keystone | OpenStack ≥ 2023.1 (Antelope) / RHOSO 18 | Authenticates every API call; issues the Keystone trust that lets the conductor act on your behalf |
| Barbican | Same release as Keystone | Stores your S3 credentials and Kopia repository password as tenant-owned secrets; Abacá never holds these values itself |
| Manila | Same release | The source of the file shares you want to protect |
| MariaDB | ≥ 10.x (Kolla 2024.2+) | Abacá's bookkeeping database (schema: abaca) |
| RabbitMQ | Same release as OpenStack | Conductor RPC transport (vhost: /abaca, topic: abaca-conductor) |
| Nova + Neutron | Same release | Required only when using the AttachToShareNetwork network attachment strategy (DHSS=true shares); not required for StaticReachability |
The Kolla-Ansible globals must include enable_barbican: "yes". For DHSS=true share protection, you also need enable_manila: "yes" with an appropriately configured backend.
API access
Before calling the Abacá API you will need:
- Network access to the Abacá service endpoint — the
abaca-apicontainer listens on port 9797 on the controller host (e.g.http://<controller>:9797). The endpoint is also registered in the Keystone service catalog under the service nameshare-protection. Confirm reachability with a quick health check:curl -sf http://<controller>:9797/healthcheck - An authentication token — see Authentication. All API calls require a valid Keystone token in the
X-Auth-Tokenheader. - An HTTP client —
curl, Postman, or a language-specific SDK such as thepython-abacaclientlibrary.
S3 backup target bucket
Every backup target requires a dedicated S3-compatible bucket that satisfies all of the following before enrollment:
- Dedicated bucket — the bucket must not be shared with other application data.
- Versioning enabled — required for object lock.
- Object lock enabled at creation time — object lock cannot be added to an existing bucket; the bucket must be recreated if it was created without it.
- No lifecycle expiration rules — expiration rules will silently delete backup objects and corrupt the Kopia repository.
Abacá runs automated preflight conformance checks (reachability, read/write round-trip, addressing mode, object-lock detection, lifecycle-rule scan, and bucket-contents inspection) during the enrollment process and refuses to accept a bucket that fails any check.
Supported S3-compatible providers: AWS S3, MinIO, Ceph RGW, ODF, Wasabi.
S3 credentials in Barbican
You must store your S3 access key and secret key as separate secrets in Barbican before calling the target registration endpoint. Abacá accepts only Barbican secret href references — it will never accept raw credential values in an API request body. Your Barbican tenant user needs the creator role (the default Kolla policy requires it for POST /v1/secrets).
Workstation tooling
| Tool | Version | Required for |
|---|---|---|
| Python | ≥ 3.11 (3.12 recommended) | python-abacaclient SDK and openstack CLI |
python-abacaclient | GA release | openstack share protection … CLI commands and Python SDK calls |
openstackclient | Any version compatible with your OpenStack release | CLI access to Keystone, Manila, Barbican |
| Docker or Podman | Any recent stable | Local dev stack via Docker Compose only; not required for production |
libguestfs-tools + qemu-utils | Any recent stable | Building the worker VM Glance image; build-worker-image.sh installs these on first run |
Control plane (operators only)
If you are deploying the Abacá control plane rather than just consuming the API, you additionally need:
- OpenShift ≥ 4.12 for the production control-plane deployment.
- A RHEL worker VM image with Kopia ≥ 0.23.1 baked in, uploaded to Glance as
abaca-worker-<KOPIA_VERSION>. This image must have theabaca-worker-agentbaked in (abaca_worker_agent_baked=1). Seedeploy/kolla/build-worker-image.sh. - An admin openrc for the target cluster, sourced in your shell. All deploy scripts require it.
- ~5 GB free disk space on the controller (Docker images + Kolla logs).
- SSH access from your workstation to the controller as a user with
sudo. The scripts default to userpureuser; override withABACA_SSH_USER/ABACA_SUDO_PASSWORD.
These steps bring up the Abacá control plane on a Kolla-Ansible OpenStack cluster and verify that it is ready to accept API calls. If you are only consuming an already-running API, skip to step 6 (verify the endpoint) and step 7 (install the client).
Step 1 — Source your admin openrc
All bootstrap scripts require an OpenStack admin credential. Source it once in the shell you will use for the remaining steps:
source cluster1-openrc.sh
Step 2 — Run the one-shot installer
From the repository root, run the installer. It executes steps 01–08 in order and is fully idempotent — safe to re-run:
bash deploy/kolla/install.sh
The installer performs these steps internally:
| Step | What it does |
|---|---|
| 01-identity | Creates the abaca Keystone service user (roles: service, admin) and a dedicated abaca worker project |
| 02-catalog | Registers the share-protection service in the Keystone catalog with public, internal, and admin endpoints on port 9797 |
| 03-database | Creates the abaca MariaDB database and user with a fresh random password; writes credentials to cluster1-abaca-secrets.env |
| 04-messaging | Creates the /abaca RabbitMQ vhost and user with a fresh random password; writes credentials to cluster1-abaca-secrets.env |
| 05-build | Syncs source to the controller and builds the abaca_api and abaca_conductor container images locally |
| 06-config | Renders /etc/kolla/abaca-api/abaca.conf and /etc/kolla/abaca-conductor/abaca.conf |
| 07-deploy | Runs database migrations (db_sync), starts or restarts the containers, and waits for /healthcheck to return 200 |
| 08-dashboard | Installs the abaca-dashboard Horizon plugin into the running horizon container |
To re-run only specific steps (for example, a fast dev loop that just rebuilds and restarts containers):
bash deploy/kolla/install.sh \
--skip-identity --skip-catalog --skip-db --skip-mq \
--skip-config --skip-dashboard
Step 3 — Bootstrap the workstation-side Python venv (if needed)
If you do not already have openstackclient on your PATH, bootstrap the local venv:
bash deploy/cluster1/bootstrap.sh
This installs openstackclient, python-manilaclient, and python-abacaclient into deploy/cluster1/.venv.
Step 4 — Build the worker VM Glance image
Abacá dispatches backup and restore work to short-lived worker VMs. Build the worker image (first run downloads ~700 MB):
bash deploy/kolla/build-worker-image.sh
The image is uploaded to Glance as abaca-worker-<KOPIA_VERSION> (currently Kopia 0.23.1). To force a rebuild:
bash deploy/kolla/build-worker-image.sh --force
Step 5 — Boot a worker VM
You need at least one active worker VM before tenants can enroll a backup target. Read the transport URL from the controller and boot a worker:
export ABACA_TRANSPORT_URL=$(ssh <controller> \
"sudo grep '^transport_url' /etc/kolla/abaca-conductor/abaca.conf" \
| cut -d' ' -f3)
OS_CLOUD=abaca-service abaca-dev worker-boot \
--network dr-net --key-name abaca-worker
Confirm the worker registered and is active:
openstack --os-cloud abaca-service share protection worker list
You should see one row with state=active and a last_heartbeat_at timestamp less than one minute old.
Step 6 — Verify the API endpoint
Confirm the abaca-api container is healthy:
curl -sf http://<controller>:9797/healthcheck
A 200 OK response confirms the control plane is up and accepting requests.
Step 7 — Install the Python client
Install python-abacaclient into your working Python environment (≥ 3.11):
pip install python-abacaclient
Verify the OpenStack CLI plugin loaded correctly:
openstack share protection --help
Step 8 — (Optional) Set up a local dev S3 backend with MinIO
For local end-to-end testing without an external S3 provider, deploy MinIO on the controller:
bash deploy/kolla/minio.sh
This creates two buckets on the controller at port 9000: abaca-demo-plain (no versioning) and abaca-demo-locked (versioning + COMPLIANCE object lock with a 1-day default retention).
Step 9 — (Optional) Generate clouds.yaml
Generate a workstation-side ~/.config/openstack/clouds.yaml with three named clouds (abaca-admin, abaca-service, abaca-tenant) from the openrc files:
bash deploy/kolla/clouds-yaml.sh
Use OS_CLOUD=abaca-tenant when running tenant-side operations such as target enrollment.
Abacá's runtime configuration lives in /etc/kolla/abaca-api/abaca.conf and /etc/kolla/abaca-conductor/abaca.conf on the controller. Both files are rendered by deploy/kolla/06-config.sh from your cluster1-abaca-secrets.env file. After editing a config file, restart the affected container for the change to take effect:
docker restart abaca_api abaca_conductor
Key configuration options
[kopia] executor
| Value | Default | When to use |
|---|---|---|
worker_rpc | Yes | Production. Every Kopia command is dispatched to a fleet-picked worker VM over RabbitMQ. The conductor never holds tenant S3 credentials or the repository password. |
ephemeral_container | No | Dev/local stack only (deploy/docker-compose.dev.yml). Runs Kopia in a short-lived local container. Logs a startup WARNING. Not for production. |
The production installer (deploy/kolla/06-config.sh) always sets executor = worker_rpc.
[kopia] subprocess_timeout
The maximum number of seconds the conductor waits for a Kopia subprocess (on the worker or in a container) to complete before killing it and raising KopiaTimeout. A timeout maps the job to operator_action_required in error_category. Tune this if your shares are very large or your S3 endpoint is slow.
[enrollment] dispatch
| Value | Default | Effect |
|---|---|---|
rpc | Yes | The API casts the job to the conductor via oslo.messaging on the abaca-conductor topic. job.executed_by is stamped conductor:<hostname>. |
inline | No | Unit-test harness only. The API drives the state machine on its own thread. Starting with dispatch=inline while api.noauth=False is refused at startup. |
[api] noauth
When False (the default and only production-safe value), every inbound request must carry a valid Keystone token. Setting noauth=True disables authentication entirely; this is only used in isolated unit-test harnesses and is refused in combination with dispatch=inline as described above.
S3 bucket least-privilege policy
When you create your S3 bucket, attach a bucket policy that grants Abacá exactly the actions it needs and nothing more. Replace TENANT-ABACA-BUCKET with your actual bucket name:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AbacaObjectDataPlane",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": "arn:aws:s3:::TENANT-ABACA-BUCKET/*"
},
{
"Sid": "AbacaBucketControlPlane",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:ListBucketVersions",
"s3:GetBucketVersioning",
"s3:GetBucketObjectLockConfiguration",
"s3:GetObjectLegalHold",
"s3:PutObjectLegalHold",
"s3:GetObjectRetention",
"s3:PutObjectRetention"
],
"Resource": "arn:aws:s3:::TENANT-ABACA-BUCKET"
}
]
}
Do not grant s3:CreateBucket, s3:PutLifecycleConfiguration, s3:PutBucketVersioning, or any wildcard s3:*. Bucket creation and object-lock enablement are one-time manual actions, not runtime Abacá privileges.
On non-AWS providers (MinIO, Ceph RGW, ODF, Wasabi), map the equivalent actions; the intent — object read/write/delete plus versioning and object-lock introspection, scoped to a single bucket — is what matters.
FIPS mode
FIPS mode is a supported, validated production configuration. When FIPS mode is enabled, Abacá configures Kopia to use only FIPS-approved algorithms (AES256-GCM-HMAC-SHA256 encryption, HMAC-SHA256-128 block hash, pbkdf2 key derivation) and runs worker VMs in RHEL FIPS mode. If the pinned Kopia binary does not support --key-derivation-algorithm (Kopia < 0.14 or a stripped build), the conductor records fips_kdf_gap: true on the target's capabilities and falls back to scrypt, which is not FIPS-140 compliant. The fix is to rebuild the worker image with Kopia ≥ 0.23.1 and re-enroll the target.
Environment variables for deploy scripts
The deploy scripts read the following environment variables (override as needed; do not hardcode passwords):
| Variable | Default | Purpose |
|---|---|---|
ABACA_SSH_USER | pureuser | SSH user on the controller |
ABACA_SUDO_PASSWORD | pureuser | sudo password for that user |
ABACA_TARGET_HOST | controller hostname | Host where containers run |
ABACA_PUBLIC_URL | http://<VIP>:9797 | Public Keystone endpoint URL |
ABACA_INTERNAL_URL | http://<VIP>:9797 | Internal Keystone endpoint URL |
ABACA_ADMIN_URL | http://<VIP>:9797 | Admin Keystone endpoint URL |
Generated passwords (for the abaca database user and the /abaca RabbitMQ user) are written to cluster1-abaca-secrets.env at the repository root (mode 0600, gitignored) by steps 03 and 04 of the installer.
Authenticating
All API calls require a Keystone token obtained from your OpenStack identity endpoint. Include it in every request as the X-Auth-Token header:
# Obtain a token
export OS_TOKEN=$(openstack --os-cloud abaca-tenant token issue -f value -c id)
# Use it in a request
curl -sS http://<controller>:9797/v1/targets \
-H "X-Auth-Token: ${OS_TOKEN}"
Tokens are short-lived. If you receive a 401 Unauthorized, request a new token and retry.
Storing S3 credentials in Barbican
Before registering a backup target, store your S3 access key and secret key as separate Barbican secrets. Abacá only accepts Barbican href references — never raw values:
# Store the access key
openstack --os-cloud abaca-tenant secret store \
--name abaca-s3-access-key \
--secret-type opaque \
--payload "<YOUR_ACCESS_KEY>"
# Store the secret key
openstack --os-cloud abaca-tenant secret store \
--name abaca-s3-secret-key \
--secret-type opaque \
--payload "<YOUR_SECRET_KEY>"
Note the secret_href returned for each. You will pass these hrefs when creating a backup target.
Registering a backup target
Use the python-abacaclient CLI to register a backup target. This triggers enrollment — Abacá runs preflight conformance checks against your bucket and initializes the Kopia repository:
export OS_CLOUD=abaca-tenant
openstack share protection target create \
--name my-backup-target \
--endpoint https://s3.example.com \
--bucket my-abaca-bucket \
--region us-east-1 \
--access-key-ref <access_key_secret_href> \
--secret-key-ref <secret_key_secret_href>
The API responds with 202 Accepted and returns both the target record and a job ID. Enrollment is asynchronous; poll the job until it reaches a terminal state:
openstack share protection job show <job_id>
The job moves through these states: queued → provisioning_network → provisioning_source → connecting_repository → transferring → finalizing → releasing → available (or error). When the job reaches available, the target is ready.
Creating a protection policy
A protection policy binds a share to a target and defines the backup schedule and retention rules:
openstack share protection policy create \
--name daily-policy \
--share-id <manila_share_id> \
--target-id <target_id> \
--schedule "0 2 * * *" \
--retention-daily 7 \
--retention-weekly 4 \
--retention-monthly 12
Once attached, backups run automatically according to the cron schedule.
Running an on-demand backup
To trigger a backup immediately, outside of the policy schedule:
openstack share protection backup create \
--policy-id <policy_id>
This also returns 202 Accepted with a job ID. Poll the job to follow progress.
Restoring a share from backup
To restore a backup to a new share (the default):
openstack share protection restore create \
--backup-id <backup_id>
To restore to a specific sub-path or single file, or back onto the original share, pass the appropriate options. Refer to openstack share protection restore create --help for the full option list.
Using the abaca-dev CLI for enrollment (developer workflow)
For the full enrollment flow in a development environment, use abaca-dev enroll. This handles storing credentials in Barbican, creating the Keystone trust, and calling the API in one step:
export OS_CLOUD=abaca-tenant
abaca-dev enroll \
--target-name demo \
--bucket abaca-demo-locked \
--access-key <mc-user> \
--secret-key <mc-pass>
The command prints the target and job IDs. Use openstack share protection job show <job_id> to poll until available.
Checking the API health endpoint
The /healthcheck endpoint requires no authentication and is useful for monitoring and readiness probes:
curl -sf http://<controller>:9797/healthcheck
Example 1 — Verify the control plane is reachable
Before any authenticated call, confirm the API is up:
curl -sf http://<controller>:9797/healthcheck
Expected output:
OK
A non-200 response means the abaca_api container is not running or the port is not reachable from your network. Check docker logs abaca_api on the controller.
Example 2 — Obtain a Keystone token and list backup targets
export OS_TOKEN=$(openstack --os-cloud abaca-tenant token issue -f value -c id)
curl -sS http://<controller>:9797/v1/targets \
-H "X-Auth-Token: ${OS_TOKEN}" | python3 -m json.tool
Expected output (empty tenant):
{
"targets": []
}
Example 3 — Store S3 credentials in Barbican and register a backup target
export OS_CLOUD=abaca-tenant
# 1. Store credentials
ACCESS_HREF=$(openstack secret store \
--name abaca-s3-access-key \
--secret-type opaque \
--payload "AKIAIOSFODNN7EXAMPLE" \
-f value -c "Secret href")
SECRET_HREF=$(openstack secret store \
--name abaca-s3-secret-key \
--secret-type opaque \
--payload "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" \
-f value -c "Secret href")
# 2. Register the target (triggers enrollment)
openstack share protection target create \
--name my-backup-target \
--endpoint https://s3.us-east-1.amazonaws.com \
--bucket my-abaca-bucket \
--region us-east-1 \
--access-key-ref "${ACCESS_HREF}" \
--secret-key-ref "${SECRET_HREF}"
Expected output (abbreviated):
{
"target": {
"id": "a1b2c3d4-...",
"name": "my-backup-target",
"status": "enrolling"
},
"job": {
"id": "e5f6a7b8-...",
"type": "target_enroll",
"state": "queued"
}
}
Example 4 — Poll a job until it reaches a terminal state
JOB_ID="e5f6a7b8-..."
while true; do
STATE=$(openstack --os-cloud abaca-tenant share protection job show "${JOB_ID}" \
-f value -c state)
echo "$(date -u +%H:%M:%S) state=${STATE}"
case "${STATE}" in
available|error) break ;;
esac
sleep 5
done
Expected output (successful enrollment):
10:01:03 state=queued
10:01:08 state=provisioning_network
10:01:13 state=connecting_repository
10:01:23 state=transferring
10:01:35 state=finalizing
10:01:38 state=releasing
10:01:40 state=available
If the final state is error, retrieve the error_category and error_message fields from the job to determine who needs to act:
openstack --os-cloud abaca-tenant share protection job show "${JOB_ID}"
Example 5 — Create a protection policy and trigger an on-demand backup
export OS_CLOUD=abaca-tenant
# Create the policy (runs daily at 02:00 UTC)
POLICY_ID=$(openstack share protection policy create \
--name daily-policy \
--share-id "<manila_share_id>" \
--target-id "a1b2c3d4-..." \
--schedule "0 2 * * *" \
--retention-daily 7 \
--retention-weekly 4 \
--retention-monthly 12 \
-f value -c id)
echo "Policy created: ${POLICY_ID}"
# Trigger an immediate backup
openstack share protection backup create --policy-id "${POLICY_ID}"
Expected output:
{
"backup": {
"id": "c9d0e1f2-...",
"status": "creating"
},
"job": {
"id": "a3b4c5d6-...",
"type": "backup",
"state": "queued"
}
}
Example 6 — List active workers (operators)
curl -sS http://<controller>:9797/v1/admin/workers \
-H "X-Auth-Token: ${OS_TOKEN}" | python3 -m json.tool
Expected output:
{
"workers": [
{
"id": "f7e8d9c0-...",
"state": "active",
"last_heartbeat_at": "2024-11-01T10:01:55Z",
"capacity_slots": 4,
"running_jobs": 0
}
]
}
Use the following pattern to diagnose failures: check the job's state, error_category, and error_message first, then look at container logs on the controller.
# Check job details
openstack --os-cloud abaca-tenant share protection job show <job_id>
# Check container logs
docker logs abaca_api # on the controller
docker logs abaca_conductor # on the controller
Symptom: curl http://<controller>:9797/healthcheck returns 502 or 500.
Likely cause: The abaca_api or abaca_conductor container failed to start, usually because a database migration failed, the RabbitMQ vhost is missing, or there is a config file syntax error.
Fix:
- Check
docker logs abaca_apianddocker logs abaca_conductorfor error messages. - Re-run the database migration:
bash deploy/kolla/install.sh --skip-identity --skip-catalog --skip-mq --skip-build --skip-dashboard(this re-runs step 07 which callsdb_sync). - Verify the RabbitMQ vhost exists:
bash deploy/kolla/04-messaging.sh. - Check for config syntax errors by reviewing
/etc/kolla/abaca-api/abaca.confand/etc/kolla/abaca-conductor/abaca.confon the controller.
Symptom: Enrollment job reaches error with error_category: tenant_action_required.
Likely cause: Your S3 bucket fails a preflight conformance check. Common sub-causes:
- Bucket has lifecycle expiration rules.
- Bucket is not dedicated (contains foreign objects).
- Barbican secret hrefs are invalid or the Keystone trust does not grant access to them.
- S3 credentials cannot reach the bucket endpoint.
Fix:
- Read
error_messageon the job for the specific check that failed. - For expiration rules: delete or disable all lifecycle expiration rules on the bucket, then re-enroll.
- For a mixed-use bucket: use a dedicated bucket; create a new one if necessary. Remember that object lock must be enabled at bucket creation time and cannot be added later.
- For credential issues: verify the Barbican secrets are accessible with your tenant token (
openstack --os-cloud abaca-tenant secret get <href>) and that the Keystone trust was created with the correct role scoping.
Symptom: Enrollment job reaches error with error_category: operator_action_required.
Likely cause: Infrastructure problem — the conductor cannot reach the S3 endpoint from the worker's network, a Kopia subprocess timed out, or Barbican is unavailable.
Fix:
- Verify the worker VM can reach the S3 endpoint and the controller's RabbitMQ port (5672).
- If egress is blocked on your hypervisor, set up host-NAT egress:
TENANT_NET_NAME=dr-net bash deploy/kolla/setup-host-nat-egress.sh. - Check
[kopia] subprocess_timeout— increase it for large shares or slow S3 endpoints. - Check Barbican availability:
openstack --os-cloud abaca-tenant secret list.
Symptom: Worker VM boots but never appears in openstack share protection worker list (or state stays provisioning).
Likely cause: The worker agent cannot connect to RabbitMQ, or the transport URL in the worker image does not match the conductor's.
Fix:
- SSH into the worker VM and check:
journalctl -u abaca-worker-agent. - Compare
/etc/abaca/abaca.confon the worker VM with/etc/kolla/abaca-conductor/abaca.confon the controller — thetransport_urlvalues must match. - Confirm the worker VM can reach the controller on port 5672:
nc -zv <controller> 5672. - If the Glance image predates the R2 worker-agent bake, rebuild it:
bash deploy/kolla/build-worker-image.sh --force.
Symptom: 401 Unauthorized on every API call.
Likely cause: Your Keystone token has expired, or you are sending the token in the wrong header.
Fix:
- Request a new token:
export OS_TOKEN=$(openstack --os-cloud abaca-tenant token issue -f value -c id). - Confirm you are passing it as
X-Auth-Token: ${OS_TOKEN}, notAuthorization: Bearer. - Verify the
share-protectionservice endpoint is registered correctly:openstack endpoint list --service share-protection.
Symptom: A config change to /etc/kolla/abaca-api/abaca.conf or /etc/kolla/abaca-conductor/abaca.conf has no effect.
Likely cause: The config file is bind-mounted read-only into the container; the container must be restarted to pick up changes.
Fix:
docker restart abaca_api abaca_conductor
Symptom: Horizon Share Protection panels are missing after running 08-dashboard.sh.
Likely cause: The abaca-dashboard Horizon plugin installation is ephemeral. Running kolla-ansible reconfigure horizon or rebuilding the Horizon image reverts it.
Fix: Re-run the dashboard installer:
bash deploy/kolla/08-dashboard.sh
Note: a durable installation path (custom abaca-horizon image) is tracked in the project backlog. Treat this as a known limitation and re-run the script after any Horizon reconfigure.
Symptom: target.capabilities shows fips_kdf_gap: true after enrollment.
Likely cause: The Kopia binary baked into the worker image does not support --key-derivation-algorithm (Kopia < 0.14 or a stripped build). The repository was created with scrypt instead of pbkdf2, which is not FIPS-140 compliant.
Fix: Rebuild the worker image to include Kopia ≥ 0.23.1, then re-enroll the target so the new repository uses pbkdf2:
bash deploy/kolla/build-worker-image.sh --force
After the new image is in Glance, delete the affected target and re-enroll it.