---
title: "Apply role bindings to MDS"
description: "Create the planned role bindings in Confluent MDS: authentication, TLS, dry runs, confirmation and the per-run lock."
url: https://monedula.dev/flock/docs/acl-rbac-converter/how-to/apply-to-mds/
---

`apply` creates the role bindings of a [reviewed plan](/flock/docs/acl-rbac-converter/how-to/plan-and-review/) in the Confluent Metadata Service (MDS). It is the only command that changes external state itself, and it never deletes ACLs.

## Before you start

- The MDS URL and credentials for a principal that may create role bindings: a token, or a user name and a password file.
- If MDS uses a private certificate authority, its CA bundle in PEM format.

## Steps

### 1. Choose how to authenticate

`apply` accepts three kinds of MDS credentials:

<Tabs group="apply-auth" labels={['Token file', 'User and password', 'Interactive login']} label="Authentication">

```bash
monedula-acl-rbac apply \
  --plan runs/2026-05-21T10-00-00Z/plan.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token \
  --confirm
```

```bash
monedula-acl-rbac apply \
  --plan runs/2026-05-21T10-00-00Z/plan.json \
  --mds-url https://mds.example.com \
  --mds-user admin \
  --mds-password-file ~/.confluent/mds-password \
  --confirm
```

```bash
monedula-acl-rbac auth login --mds-url https://mds.example.com
# Prompts for username + password, exchanges for a token, writes the cache file.

monedula-acl-rbac apply --plan ... --mds-url https://mds.example.com --confirm
# Subsequent calls pick up the cached token automatically.
```

</Tabs>

- **Token file**: a pre-fetched bearer token, the recommended choice for CI/CD. To fetch one yourself, for example when a vault manages your MDS credentials, exchange a user name and password for it:

  ```bash
  curl -u USER:PASS https://mds.example.com/security/1.0/authenticate \
    | jq -r .auth_token > ~/.confluent/token
  chmod 0600 ~/.confluent/token
  ```

  `confluent iam mds login` produces compatible tokens too.
- **User and password**: the tool exchanges them for a token and keeps it in memory. Add `--cache-token` to store it for later commands.
- **Interactive login**: `auth login` prompts for the user name and password, and caches the token for the MDS URL and your operating-system user.

When you give more than one, a token file wins over a user name and password, which win over a cached token. Cached tokens live in your user configuration directory, with mode 0600 on Linux and macOS: `~/.config/monedula-acl-rbac/tokens/` on Linux (under `$XDG_CONFIG_HOME` when it is set), `~/Library/Application Support/monedula-acl-rbac/tokens/` on macOS and `%AppData%\monedula-acl-rbac\tokens\` on Windows. Environment variables such as `MONEDULA_ACL_RBAC_MDS_URL` can set the MDS flags; the [CLI overview](/flock/docs/acl-rbac-converter/reference/cli/) lists them.

### 2. Set up TLS to MDS

For an MDS with a private CA, pass the CA bundle and, for mutual TLS, a client certificate and key:

```bash
monedula-acl-rbac apply \
  --plan ... \
  --mds-url https://mds.example.com \
  --mds-ca-cert /etc/ssl/corp-ca.pem \
  --mds-client-cert /etc/ssl/client.pem \
  --mds-client-key /etc/ssl/client-key.pem \
  --mds-token-file ~/.confluent/token \
  --confirm
```

`--mds-insecure-skip-verify` skips certificate verification for development clusters and prints a warning on every run; never use it in production.

### 3. Preview with a dry run

```bash
monedula-acl-rbac apply \
  --plan runs/2026-05-21T10-00-00Z/plan.json \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token \
  --dry-run
```

The dry run reads MDS to find the bindings that already exist, but makes no writes. It records every call it would make, with the request body, in `would-apply.log` in the run directory. Read that log before you continue.

### 4. Apply

Run the same command with `--confirm` instead of `--dry-run`, as in step 1; the two flags cannot be combined. Without `--confirm`, `apply` asks you to type `yes`, and outside a terminal it refuses ([Safety guarantees](/flock/docs/acl-rbac-converter/concepts/safety-guarantees/#nothing-changes-without-confirmation)).

`apply` creates each binding that does not exist yet, writing every MDS call and its result to `apply.log` in the run directory. Bindings that already exist are skipped, so running `apply` again after a failure picks up where it stopped. Flags worth knowing:

- `--apply-parallelism N`: concurrent MDS writes, 4 by default.
- `--mds-max-retries N`: retries of transient MDS failures, such as HTTP 5xx and 429 responses or a reset connection, with exponential backoff capped at 5 seconds per attempt. A 429 response's `Retry-After` is honored up to 60 seconds. The default is 3; 0 turns retries off.
- `--format json`: a structured summary on stdout with a result per binding and the counts of created, skipped and failed bindings, described by [apply-summary.v1.json](/flock/docs/acl-rbac-converter/reference/formats/apply-summary-v1/).
- `--progress`: per-binding progress on stderr, on by default when stderr is a terminal.

## The run-directory lock

While `apply` runs, including a dry run, it holds a lock file, `.lock`, in the run directory, and a second run against that directory refuses to start. A lock left behind by a run that died is cleared with `--force-unlock`, as [Recover from a failed run](/flock/docs/acl-rbac-converter/how-to/recover-from-a-failed-run/) describes. A dry run ignores `--force-unlock`: a stale lock that stops `apply --dry-run` is cleared only by a real `apply --confirm --force-unlock`.

## Check it worked

`apply` exits 0 when every binding was created or already existed. `apply.log` has a `CREATE` or `SKIP` line for every binding and no `FAIL` line. To see what MDS now holds for a principal:

```bash
monedula-acl-rbac mds list-bindings \
  --mds-url https://mds.example.com \
  --mds-token-file ~/.confluent/token \
  --principal-filter User:alice
```

`mds list-bindings` takes the same MDS flags as `apply`. Whether the bindings grant the access is what [Verify effective access](/flock/docs/acl-rbac-converter/how-to/verify-effective-access/), the next step, checks.

## Related

- The [apply command reference](/flock/docs/acl-rbac-converter/reference/cli/apply/) lists every flag and exit code.
- Runnable version: [live-mds-migration](https://github.com/monedula-dev/monedula-acl-rbac-converter/tree/main/examples/live-mds-migration), which applies a plan to a real MDS in Docker.