---
title: "Hand bindings to a CD pipeline"
description: "Without MDS access, emit role bindings as a Confluent CLI script, CFK ConfluentRolebinding manifests or MDS curl commands."
url: https://monedula.dev/flock/docs/acl-rbac-converter/how-to/emit-for-a-cd-pipeline/
---
When MDS changes must go through another pipeline, or the tool cannot have MDS credentials, render the plan as an artifact for whoever holds MDS access to apply. `emit` never contacts MDS: it only turns `plan.json` into a file.

## Before you start

- A reviewed `plan.json`. See [Plan and review role bindings](/flock/docs/acl-rbac-converter/how-to/plan-and-review/). Without MDS access, fill in `scopes.yaml` by hand, as [Find the cluster IDs for scopes.yaml](/flock/docs/acl-rbac-converter/how-to/find-cluster-ids/) shows.

## Steps

### 1. Emit the artifact

<Tabs group="emit-format" labels={['Confluent CLI script', 'CFK manifest', 'MDS curl']} label="Format">

```bash
# Shell script of `confluent iam rbac role-binding create ...` commands
monedula-acl-rbac emit --plan runs/.../plan.json --format script --out-dir emit/
```

```bash
# CFK manifest (ConfluentRolebinding CRs for Confluent for Kubernetes)
monedula-acl-rbac emit --plan runs/.../plan.json --format cfk --out-dir emit/
```

```bash
# Curl commands hitting MDS REST
monedula-acl-rbac emit --plan runs/.../plan.json --format mds-curl --out-dir emit/
```

</Tabs>

`emit` writes one file into the `--out-dir` directory: `script.sh`, `cfk.yaml` or `mds-curl.sh`. Without `--out-dir`, it prints to stdout. Bindings that the plan marks `SKIP_EXISTS` are not emitted; the script and curl formats list them as comments.

- **`script`** has one `confluent iam rbac role-binding create` command per binding, with the principal, role, cluster scope and resource, and `--prefix` for prefixed resources.
- **`cfk`** has one `ConfluentRolebinding` resource per binding, named after the binding's ID. `--cfk-namespace` sets the namespace of the resources. For example, from the [cfk-manifests](https://github.com/monedula-dev/monedula-acl-rbac-converter/tree/main/examples/cfk-manifests) example:

  ```yaml
  apiVersion: platform.confluent.io/v1beta1
  kind: ConfluentRolebinding
  metadata:
      name: rb-913955c4d0ce
      namespace: confluent
  spec:
      principal:
          type: user
          name: svc-platform-admin
      role: SystemAdmin
      resourcePatterns:
          - resourceType: Cluster
            name: kafka-cluster
            patternType: LITERAL
      clustersScopeByIds:
          kafkaClusterId: lkc-demo-1
  ---
  ```

- **`mds-curl`** is a bash script with one `curl` `POST` per binding. It reads the MDS address and a bearer token from the environment variables `MDS_URL` and `MDS_TOKEN` when it runs, and stops if either is missing.

The binding IDs come from the plan and stay the same each time you emit it. To keep two otherwise identical bindings apart, for example across tenants, pass `--cfk-name-salt` to `plan`, which mixes the salt into the IDs; the same flag on `emit` is deprecated and has no effect.

### 2. Hand the artifact over

Commit the artifact to your CD repository or attach it to the change request, with `report.txt`, so the reviewers see what each binding replaces. Keep the emitted files there until the migration is stable: you need them to roll back.

### 3. Prepare the rollback

The tool does not delete role bindings. To undo the ones your pipeline applied:

- **`script`**: for each `confluent iam rbac role-binding create` command, run the matching `confluent iam rbac role-binding delete` with the same principal, role and scope arguments. The required flags differ slightly between `create` and `delete` in some Confluent CLI versions, so check `confluent iam rbac role-binding delete --help`.
- **`cfk`**: `kubectl delete -f emit/cfk.yaml` removes the `ConfluentRolebinding` resources that your pipeline created.
- **`mds-curl`**: change each `POST` to a `DELETE` against the same URL.

### 4. Confirm access

`verify` needs MDS, so on this path the tool cannot check the result for you. Confirm access another way, or have someone with MDS credentials run `verify` against the same run directory later; `delete-acls` will not run without that `verify.json`.

## Check it worked

The emitted file exists in `emit/`. For `script` and `mds-curl`, its header counts the bindings, for example `# Bindings: 7 to create, 0 to skip (already exist).`; the numbers match the `[CREATE]` and `[SKIP_EXISTS]` entries in `report.txt`. After your pipeline has applied it, `verify` from a host with MDS access exits 0.

## Related

- [Two paths: with or without MDS](/flock/docs/acl-rbac-converter/concepts/two-paths/) compares this path with applying directly.
- The [emit command reference](/flock/docs/acl-rbac-converter/reference/cli/emit/) lists every flag.
- Runnable version for the `script` format: [text-dump](https://github.com/monedula-dev/monedula-acl-rbac-converter/tree/main/examples/text-dump).