Redpanda Cloud API: BYOC Clusters
BYOC (Bring Your Own Cloud) lets you run Redpanda in your own AWS, GCP, or Azure account: Redpanda manages the control plane and agent lifecycle, while your VPC, IAM roles, and storage buckets stay under your cloud account. You pay cloud infrastructure costs directly. This is the primary alternative to Serverless, which runs entirely in Redpanda's account.
The provisioning workflow has three phases: (1) create a Network resource that registers your VPC/VNet with Redpanda, (2) create a Cluster resource of TYPE_BYOC referencing that network, and (3) run rpk cloud byoc apply --redpanda-id <id> to execute the Terraform that installs the agent in your cloud account.
Both the Network and Cluster create calls return an Operation object — poll GET /v1/operations/{id} until state is STATE_COMPLETED before proceeding.
Quickstart
# 1. Get an OAuth2 bearer token (client credentials flow)
TOKEN=$(curl -s -X POST "https://auth.prd.cloud.redpanda.com/oauth/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=${CLIENT_ID}" \
-d "client_secret=${CLIENT_SECRET}" \
-d "audience=cloudv2-production.redpanda.cloud" \
| jq -r '.access_token')
BASE="https://api.redpanda.com"
# 2. Create (or identify) a Resource Group
curl -s -X POST "${BASE}/v1/resource-groups" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"resource_group": {"name": "my-byoc-rg"}}' | jq .
RG_ID="<resource_group_id from response>"
# 3. Create a Network (AWS example — Redpanda-managed VPC, CIDR-based)
NET_OP=$(curl -s -X POST "${BASE}/v1/networks" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"network\": {
\"name\": \"my-byoc-network\",
\"resource_group_id\": \"${RG_ID}\",
\"cloud_provider\": \"CLOUD_PROVIDER_AWS\",
\"region\": \"us-east-1\",
\"cidr_block\": \"10.0.0.0/20\",
\"cluster_type\": \"TYPE_BYOC\"
}
}" | jq .)
NET_OP_ID=$(echo "${NET_OP}" | jq -r '.operation.id')
# 4. Poll the network operation until STATE_COMPLETED
until [ "$(curl -s "${BASE}/v1/operations/${NET_OP_ID}" \
-H "Authorization: Bearer ${TOKEN}" | jq -r '.operation.state')" = "STATE_COMPLETED" ]; do
echo "Waiting for network…"; sleep 10
done
NET_ID=$(curl -s "${BASE}/v1/networks?filter.name_contains=my-byoc-network" \
-H "Authorization: Bearer ${TOKEN}" | jq -r '.networks[0].id')
# 5. Create the BYOC cluster
CLUSTER_OP=$(curl -s -X POST "${BASE}/v1/clusters" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{
\"cluster\": {
\"name\": \"my-byoc-cluster\",
\"resource_group_id\": \"${RG_ID}\",
\"type\": \"TYPE_BYOC\",
\"cloud_provider\": \"CLOUD_PROVIDER_AWS\",
\"region\": \"us-east-1\",
\"zones\": [\"use1-az1\", \"use1-az2\", \"use1-az3\"],
\"throughput_tier\": \"tier-1-aws-v2-arm\",
\"network_id\": \"${NET_ID}\",
\"connection_type\": \"CONNECTION_TYPE_PUBLIC\"
}
}" | jq .)
# connection_type is the legacy single-topology selector and is deprecated. For a cluster that
# serves a public AND a private listener per service, send per-service "connections" instead —
# see "Cluster Connectivity" below.
# Note: tier names are version-dependent. Authoritative list:
# GET /v1/regions/CLOUD_PROVIDER_AWS (or CLOUD_PROVIDER_GCP/CLOUD_PROVIDER_AZURE; cloud_provider is a path segment)
# or see https://docs.redpanda.com/redpanda-cloud/reference/tiers/byoc-tiers/
# Real AWS examples: tier-1-aws-v2-arm, tier-1-aws-v2-x86, tier-1-aws-v3-arm
# Real GCP examples: tier-1-gcp-v2-x86, tier-1-gcp-um4g
CLUSTER_OP_ID=$(echo "${CLUSTER_OP}" | jq -r '.operation.id')
# Poll until cluster_id is available in operation metadata (may not be populated on first poll)
until CLUSTER_ID=$(curl -s "${BASE}/v1/operations/${CLUSTER_OP_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
| jq -r '.operation.metadata.cluster_id // .operation.resource_id // empty'); \
[ -n "${CLUSTER_ID}" ]; do
echo "Waiting for cluster ID…"; sleep 5
done
# 6. Poll until CREATING_AGENT state — the control plane is waiting for the agent
until [ "$(curl -s "${BASE}/v1/clusters/${CLUSTER_ID}" \
-H "Authorization: Bearer ${TOKEN}" | jq -r '.cluster.state')" = "STATE_CREATING_AGENT" ]; do
echo "Waiting for cluster to reach CREATING_AGENT…"; sleep 15
done
# 7. Run the rpk byoc agent (install + apply)
rpk cloud byoc install --redpanda-id "${CLUSTER_ID}" \
-X cloud.client_id="${CLIENT_ID}" \
-X cloud.client_secret="${CLIENT_SECRET}"
# AWS provider — runs Terraform in your account
rpk cloud byoc aws apply --redpanda-id "${CLUSTER_ID}" \
-X cloud.client_id="${CLIENT_ID}" \
-X cloud.client_secret="${CLIENT_SECRET}"
# 8. Poll until STATE_READY
until [ "$(curl -s "${BASE}/v1/clusters/${CLUSTER_ID}" \
-H "Authorization: Bearer ${TOKEN}" | jq -r '.cluster.state')" = "STATE_READY" ]; do
echo "Waiting for cluster to be ready…"; sleep 30
done
echo "Cluster is READY"
BYOC vs Serverless
| Dimension |
BYOC |
Serverless |
| Infra ownership |
Customer VPC / account |
Redpanda's account |
| Cloud bill |
Customer pays AWS/GCP/Azure directly |
Redpanda charges per usage |
| Network isolation |
Fully isolated VPC |
Shared multi-tenant |
| Agent required |
Yes — rpk cloud byoc apply |
No |
| Cluster type |
TYPE_BYOC |
N/A (separate ServerlessCluster resource) |
| Network resource |
Required |
Not required |
| Customer-managed IAM |
Optional (customer_managed_resources) |
Not supported |
| Throughput tiers |
Dedicated tiers |
Serverless tiers |
Control Plane API Overview
Base URL: https://api.redpanda.com
Auth: Bearer token obtained via OAuth2 client credentials. Set Authorization: Bearer <token> on every request.
Protocol: ConnectRPC (also accepts standard HTTP/JSON via the REST gateway).
All mutating operations (CreateNetwork, CreateCluster, DeleteCluster, DeleteNetwork) return an Operation object with a 20-character ID. Poll GET /v1/operations/{id} to track progress.
| Resource |
Endpoints |
| Networks |
POST /v1/networks, GET /v1/networks/{id}, GET /v1/networks, PATCH /v1/networks/{id}?update_mask=..., DELETE /v1/networks/{id} |
| Clusters |
POST /v1/clusters, GET /v1/clusters/{id}, GET /v1/clusters, PATCH /v1/clusters/{id}?update_mask=..., DELETE /v1/clusters/{id} |
| Network Peerings |
POST /v1/network/{network_id}/network-peerings, GET/DELETE /v1/network/{network_id}/network-peerings/{id}, GET /v1/network/{network_id}/network-peerings |
| Cloud Provider Access (PREVIEW) |
GET /v1/cloud-provider-accesses/prerequisites, POST /v1/cloud-provider-accesses, GET/DELETE /v1/cloud-provider-accesses/{id}, GET /v1/cloud-provider-accesses |
| Shadow Links |
POST /v1/shadow-links, GET/DELETE /v1/shadow-links/{id}, GET /v1/shadow-links, PATCH /v1/shadow-links/{id}?update_mask=... |
| Operations |
GET /v1/operations/{id}, GET /v1/operations |
| Scheduled Operations (PREVIEW) |
GET /v1/scheduled-operations (list only) |
| Resource Groups |
POST /v1/resource-groups, GET /v1/resource-groups/{id}, GET /v1/resource-groups |
| Regions |
GET /v1/regions/{cloud_provider}, GET /v1/regions/{cloud_provider}/{name} |
Cluster Connectivity: connection_type vs connections
connection_type (CONNECTION_TYPE_PUBLIC / CONNECTION_TYPE_PRIVATE) makes the whole cluster
public or private and is deprecated. It is superseded by a per-service connections list on
kafka_api, http_proxy, and schema_registry — dual listener mode, which serves a public and
a private listener at the same time, each with its own server-assigned endpoint and its own
SASL/SCRAM or mTLS auth:
"kafka_api": {"connections": [
{"type": "CONNECTION_TYPE_PUBLIC", "auth": {"mode": "AUTH_MODE_SASL"}},
{"type": "CONNECTION_TYPE_PRIVATE", "auth": {"mode": "AUTH_MODE_SASL"}}
]}
Decision rules:
- Want one connectivity mode for the whole cluster and nothing else?
connection_type still works.
- Need in-VPC clients on a private listener while external clients stay public? Use
connections
— set them on all three services with the same topology, and omit connection_type and
the per-service sasl block (the API rejects either alongside connections).
- Dual listener mode is beta, AWS only, and enabled per organization; Azure is rejected
outright, and the fields are not in the published API reference yet. It cannot be configured in
the Cloud UI.
- Read endpoints from
connections[].endpoint in GET /v1/clusters/{id}, not from the deprecated
seed_brokers/url fields.
- Migrating public-only ↔ dual is self-service (with the
controlplane_cluster_migrate_connectivity
permission) — except on BYOVPC clusters, which always keep a private connection: every BYOVPC
migration to or from dual listener mode goes through Redpanda Support. Anything that moves any
cluster between private-only and publicly reachable also goes through Support.
- Once a service uses
connections, its legacy sasl/mtls update path is closed — the API
rejects such a PATCH and tells you to use connections. Change auth via connections[].auth.mode.
Full rules, examples, and migration semantics: Clusters and Agent.
Cluster State Machine
BYOC clusters move through these states (grounded in cluster.proto):
STATE_CREATING_AGENT → STATE_CREATING → STATE_READY
↗
STATE_UPGRADING ──────────────────────
STATE_DELETING_AGENT → STATE_DELETING → (deleted)
STATE_FAILED
STATE_SUSPENDED
The cluster enters STATE_CREATING_AGENT after the API accepts the create request. This is when you must run rpk cloud byoc apply to install the agent Terraform. Once the agent completes provisioning, the cluster transitions to STATE_CREATING, then STATE_READY.
rpk cloud byoc Commands
# Install the byoc plugin (pinned to the cluster's required version)
rpk cloud byoc install --redpanda-id <cluster-id>
# Apply (provision) agent infra — cloud-provider subcommand is required.
# GCP also requires --project-id; Azure also requires --subscription-id.
rpk cloud byoc aws apply --redpanda-id <cluster-id>
rpk cloud byoc gcp apply --redpanda-id <cluster-id> --project-id <gcp-project-id>
rpk cloud byoc azure apply --redpanda-id <cluster-id> --subscription-id <azure-sub-id>
# Destroy agent infra (same per-provider account flags as apply)
rpk cloud byoc aws destroy --redpanda-id <cluster-id>
rpk cloud byoc gcp destroy --redpanda-id <cluster-id> --project-id <gcp-project-id>
rpk cloud byoc azure destroy --redpanda-id <cluster-id> --subscription-id <azure-sub-id>
# Validate prerequisites without a cluster ID (uses latest plugin version)
rpk cloud byoc aws validate
rpk cloud byoc gcp validate
# Note: only aws/gcp validate are confirmed; azure validate is not separately attested.
# Uninstall the local plugin binary
rpk cloud byoc uninstall
The --redpanda-id flag is required for apply and destroy. The plugin is automatically pinned to the version the control plane specifies for the given cluster ID. Set RPK_CLOUD_SKIP_VERSION_CHECK=1 to use the currently installed plugin binary as-is (dev/CI use only).
Authentication for rpk cloud byoc uses the same client credentials as rpk cloud login:
# Via -X flags (not persisted)
rpk cloud byoc aws apply --redpanda-id <id> \
-X cloud.client_id=<id> \
-X cloud.client_secret=<secret>
# Via environment variables
export RPK_CLOUD_CLIENT_ID=<id>
export RPK_CLOUD_CLIENT_SECRET=<secret>
rpk cloud byoc aws apply --redpanda-id <id>
Enterprise Features on BYOC
Redpanda Cloud BYOC is a managed deployment of Redpanda Enterprise Edition — the enterprise license is included in your Cloud subscription, so you never apply a license key. Every enterprise differentiator is available; you turn it on through cluster config and topic properties, not a license workflow.
Two surfaces:
- Cluster-config properties (e.g.
iceberg_enabled, audit_enabled, partition_autobalancing_mode, default_leaders_preference, enable_schema_id_validation) — set via the Control Plane API under cluster_configuration.custom_properties at POST /v1/clusters (create) or PATCH /v1/clusters/{id}?update_mask=cluster_configuration.custom_properties (update), or via rpk cluster config set on the data plane. Integer values must be strings in custom_properties.
- Topic properties (e.g.
redpanda.iceberg.mode, redpanda.remote.write, redpanda.cloud_topic.enabled, redpanda.leaders.preference) — set with rpk topic create -c ... / rpk topic alter-config on the data plane after the cluster is STATE_READY.
# Enable an enterprise cluster property after the cluster exists.
# update_mask is a REQUIRED query parameter (comma-separated snake_case field paths —
# the API uses proto field names); the JSON body IS the ClusterUpdate object directly
# (no "cluster" wrapper, no update_mask in body).
curl -s -X PATCH "${BASE}/v1/clusters/${CLUSTER_ID}?update_mask=cluster_configuration.custom_properties" \
-H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" \
-d '{"cluster_configuration":{"custom_properties":{"iceberg_enabled":"true"}}}' | jq '.operation.id'
Key features and their nested keys (full detail in Enterprise Features):
| Feature |
Where |
Primary keys |
| Tiered Storage (always on) |
topic + cluster |
redpanda.remote.write/read/delete/recovery, redpanda.storage.mode, redpanda.storage.mode.impl (tiered_v1/tiered_v2, read-only after create); cluster default_redpanda_storage_mode_tiered_impl |
| Cloud Topics |
topic |
redpanda.cloud_topic.enabled, redpanda.storage.mode=cloud |
| Iceberg Topics |
cluster + topic |
iceberg_enabled, iceberg_default_catalog_namespace; redpanda.iceberg.mode/delete/invalid.record.action/partition.spec/target.lag.ms |
| Continuous Data Balancing |
cluster |
partition_autobalancing_mode=continuous, partition_autobalancing_max_disk_usage_percent, partition_autobalancing_node_availability_timeout_sec, partition_autobalancing_node_autodecommission_timeout_sec, core_balancing_continuous |
| Shadow Linking (DR) |
rpk + control plane |
rpk shadow config generate --for-cloud / create / status / failover; schema_registry_sync_options selects shadow_schema_registry_topic or shadow_schema_registry_api (HTTP-API mode, incl. Confluent Schema Registry sources) |
| Remote Read Replicas |
topic + cluster |
redpanda.remote.readreplica, cloud_storage_enable_remote_read |
| Audit Logging |
cluster |
audit_enabled, audit_log_num_partitions, audit_enabled_event_types, audit_excluded_topics/principals, audit_queue_drain_interval_ms |
| RBAC / GBAC |
rpk / ACLs |
rpk security role ...; Group: principals |
| OIDC / OAuthBearer / Kerberos |
cluster |
sasl_mechanisms (OAUTHBEARER, GSSAPI), http_authentication (OIDC) |
| Schema ID Validation |
cluster + topic |
enable_schema_id_validation; redpanda.{key,value}.schema.id.validation, redpanda.{key,value}.subject.name.strategy |
| Leadership Pinning |
cluster + topic |
default_leaders_preference, redpanda.leaders.preference (none / racks: / ordered_racks:) |
| FIPS |
provisioning |
request a FIPS-enabled cluster (fips_mode) |
Reference Directory
- BYOC Model and Auth: What BYOC is vs Serverless, OAuth2 client-credentials flow, and the end-to-end provisioning sequence.
- Networks: Creating the Network resource per cloud provider — AWS (VPC/subnet/IAM ARNs), GCP (network name, project, GCS bucket), Azure (VNet, subnets, resource groups). Plus VPC/VNet peering (NetworkPeeringService), Cloud Provider Access cross-account AWS provisioning (PREVIEW), and private connectivity / centralized egress (AWS PrivateLink incl. cross-region, GCP PSC, Azure Private Link, Transit Gateway egress). Field-level reference grounded in network.proto, network_peering.proto, cloud_provider_access.proto, and common.proto.
- Clusters and Agent: ClusterCreate fields for BYOC (TYPE_BYOC, network_id, throughput_tier, customer_managed_resources, zones, cloud_provider_tags), dual listener mode (per-service
connections, endpoints, and migration semantics), the cluster PATCH/update_mask form, Operation lifecycle, Scheduled Operations (PREVIEW), control-plane Shadow Linking (ShadowLinkService, including the two Schema Registry replication modes and Confluent Schema Registry migration), and the full rpk cloud byoc install/apply/destroy/validate flow.
- Enterprise Features: Enabling Redpanda Enterprise differentiators on a BYOC cluster (license included with the Cloud subscription) via
cluster_configuration.custom_properties and topic properties — Tiered Storage, Cloud Topics, Iceberg Topics, Continuous Data Balancing, Shadow Linking DR, Remote Read Replicas, Audit Logging, RBAC/GBAC, OIDC/OAuthBearer/Kerberos, FIPS, Server-Side Schema ID Validation, and Leadership Pinning — with their nested config keys and license-expiration behavior, grounded in the licensing overview and per-feature docs.
1---2name: cloud-byoc-23description: Provisions and manages Redpanda Cloud BYOC (Bring Your Own Cloud) clusters via the Control Plane API (api.redpanda.com) and the `rpk cloud byoc` plugin, where your VPC, IAM roles, and storage stay in your own AWS, GCP, or Azure account. Use when creating or tearing down BYOC clusters and Networks; wiring customer-managed IAM roles, buckets, or subnets into a cluster; setting up private connectivity (AWS PrivateLink, GCP Private Service Connect, Azure Private Link, VPC peering, or Transit Gateway egress); configuring dual listener mode (a public and a private listener per service); registering cross-account AWS access; managing Shadow Link cross-cluster DR; running `rpk cloud byoc apply`; or enabling Enterprise features (Tiered Storage, Cloud Topics, Iceberg Topics, Continuous Data Balancing, RBAC, and more) on a BYOC cluster. For Serverless clusters, see `/redpanda:cloud-serverless`; for fully Redpanda-managed Dedicated clusters, see `/redpanda:cloud-dedicated`.4---56# Redpanda Cloud API: BYOC Clusters78BYOC (Bring Your Own Cloud) lets you run Redpanda in your own AWS, GCP, or Azure account: Redpanda manages the control plane and agent lifecycle, while your VPC, IAM roles, and storage buckets stay under your cloud account. You pay cloud infrastructure costs directly. This is the primary alternative to Serverless, which runs entirely in Redpanda's account.910The provisioning workflow has three phases: (1) create a **Network** resource that registers your VPC/VNet with Redpanda, (2) create a **Cluster** resource of `TYPE_BYOC` referencing that network, and (3) run `rpk cloud byoc apply --redpanda-id <id>` to execute the Terraform that installs the agent in your cloud account.1112Both the Network and Cluster create calls return an `Operation` object — poll `GET /v1/operations/{id}` until `state` is `STATE_COMPLETED` before proceeding.1314## Quickstart1516```bash17# 1. Get an OAuth2 bearer token (client credentials flow)18TOKEN=$(curl -s -X POST "https://auth.prd.cloud.redpanda.com/oauth/token" \19 -H "Content-Type: application/x-www-form-urlencoded" \20 -d "grant_type=client_credentials" \21 -d "client_id=${CLIENT_ID}" \22 -d "client_secret=${CLIENT_SECRET}" \23 -d "audience=cloudv2-production.redpanda.cloud" \24 | jq -r '.access_token')2526BASE="https://api.redpanda.com"2728# 2. Create (or identify) a Resource Group29curl -s -X POST "${BASE}/v1/resource-groups" \30 -H "Authorization: Bearer ${TOKEN}" \31 -H "Content-Type: application/json" \32 -d '{"resource_group": {"name": "my-byoc-rg"}}' | jq .3334RG_ID="<resource_group_id from response>"3536# 3. Create a Network (AWS example — Redpanda-managed VPC, CIDR-based)37NET_OP=$(curl -s -X POST "${BASE}/v1/networks" \38 -H "Authorization: Bearer ${TOKEN}" \39 -H "Content-Type: application/json" \40 -d "{41 \"network\": {42 \"name\": \"my-byoc-network\",43 \"resource_group_id\": \"${RG_ID}\",44 \"cloud_provider\": \"CLOUD_PROVIDER_AWS\",45 \"region\": \"us-east-1\",46 \"cidr_block\": \"10.0.0.0/20\",47 \"cluster_type\": \"TYPE_BYOC\"48 }49 }" | jq .)5051NET_OP_ID=$(echo "${NET_OP}" | jq -r '.operation.id')5253# 4. Poll the network operation until STATE_COMPLETED54until [ "$(curl -s "${BASE}/v1/operations/${NET_OP_ID}" \55 -H "Authorization: Bearer ${TOKEN}" | jq -r '.operation.state')" = "STATE_COMPLETED" ]; do56 echo "Waiting for network…"; sleep 1057done5859NET_ID=$(curl -s "${BASE}/v1/networks?filter.name_contains=my-byoc-network" \60 -H "Authorization: Bearer ${TOKEN}" | jq -r '.networks[0].id')6162# 5. Create the BYOC cluster63CLUSTER_OP=$(curl -s -X POST "${BASE}/v1/clusters" \64 -H "Authorization: Bearer ${TOKEN}" \65 -H "Content-Type: application/json" \66 -d "{67 \"cluster\": {68 \"name\": \"my-byoc-cluster\",69 \"resource_group_id\": \"${RG_ID}\",70 \"type\": \"TYPE_BYOC\",71 \"cloud_provider\": \"CLOUD_PROVIDER_AWS\",72 \"region\": \"us-east-1\",73 \"zones\": [\"use1-az1\", \"use1-az2\", \"use1-az3\"],74 \"throughput_tier\": \"tier-1-aws-v2-arm\",75 \"network_id\": \"${NET_ID}\",76 \"connection_type\": \"CONNECTION_TYPE_PUBLIC\"77 }78 }" | jq .)7980# connection_type is the legacy single-topology selector and is deprecated. For a cluster that81# serves a public AND a private listener per service, send per-service "connections" instead —82# see "Cluster Connectivity" below.8384# Note: tier names are version-dependent. Authoritative list:85# GET /v1/regions/CLOUD_PROVIDER_AWS (or CLOUD_PROVIDER_GCP/CLOUD_PROVIDER_AZURE; cloud_provider is a path segment)86# or see https://docs.redpanda.com/redpanda-cloud/reference/tiers/byoc-tiers/87# Real AWS examples: tier-1-aws-v2-arm, tier-1-aws-v2-x86, tier-1-aws-v3-arm88# Real GCP examples: tier-1-gcp-v2-x86, tier-1-gcp-um4g8990CLUSTER_OP_ID=$(echo "${CLUSTER_OP}" | jq -r '.operation.id')9192# Poll until cluster_id is available in operation metadata (may not be populated on first poll)93until CLUSTER_ID=$(curl -s "${BASE}/v1/operations/${CLUSTER_OP_ID}" \94 -H "Authorization: Bearer ${TOKEN}" \95 | jq -r '.operation.metadata.cluster_id // .operation.resource_id // empty'); \96 [ -n "${CLUSTER_ID}" ]; do97 echo "Waiting for cluster ID…"; sleep 598done99100# 6. Poll until CREATING_AGENT state — the control plane is waiting for the agent101until [ "$(curl -s "${BASE}/v1/clusters/${CLUSTER_ID}" \102 -H "Authorization: Bearer ${TOKEN}" | jq -r '.cluster.state')" = "STATE_CREATING_AGENT" ]; do103 echo "Waiting for cluster to reach CREATING_AGENT…"; sleep 15104done105106# 7. Run the rpk byoc agent (install + apply)107rpk cloud byoc install --redpanda-id "${CLUSTER_ID}" \108 -X cloud.client_id="${CLIENT_ID}" \109 -X cloud.client_secret="${CLIENT_SECRET}"110111# AWS provider — runs Terraform in your account112rpk cloud byoc aws apply --redpanda-id "${CLUSTER_ID}" \113 -X cloud.client_id="${CLIENT_ID}" \114 -X cloud.client_secret="${CLIENT_SECRET}"115116# 8. Poll until STATE_READY117until [ "$(curl -s "${BASE}/v1/clusters/${CLUSTER_ID}" \118 -H "Authorization: Bearer ${TOKEN}" | jq -r '.cluster.state')" = "STATE_READY" ]; do119 echo "Waiting for cluster to be ready…"; sleep 30120done121122echo "Cluster is READY"123```124125## BYOC vs Serverless126127| Dimension | BYOC | Serverless |128|---|---|---|129| Infra ownership | Customer VPC / account | Redpanda's account |130| Cloud bill | Customer pays AWS/GCP/Azure directly | Redpanda charges per usage |131| Network isolation | Fully isolated VPC | Shared multi-tenant |132| Agent required | Yes — `rpk cloud byoc apply` | No |133| Cluster type | `TYPE_BYOC` | N/A (separate `ServerlessCluster` resource) |134| Network resource | Required | Not required |135| Customer-managed IAM | Optional (`customer_managed_resources`) | Not supported |136| Throughput tiers | Dedicated tiers | Serverless tiers |137138## Control Plane API Overview139140**Base URL:** `https://api.redpanda.com`141142**Auth:** Bearer token obtained via OAuth2 client credentials. Set `Authorization: Bearer <token>` on every request.143144**Protocol:** ConnectRPC (also accepts standard HTTP/JSON via the REST gateway).145146All mutating operations (CreateNetwork, CreateCluster, DeleteCluster, DeleteNetwork) return an `Operation` object with a 20-character ID. Poll `GET /v1/operations/{id}` to track progress.147148| Resource | Endpoints |149|---|---|150| Networks | `POST /v1/networks`, `GET /v1/networks/{id}`, `GET /v1/networks`, `PATCH /v1/networks/{id}?update_mask=...`, `DELETE /v1/networks/{id}` |151| Clusters | `POST /v1/clusters`, `GET /v1/clusters/{id}`, `GET /v1/clusters`, `PATCH /v1/clusters/{id}?update_mask=...`, `DELETE /v1/clusters/{id}` |152| Network Peerings | `POST /v1/network/{network_id}/network-peerings`, `GET`/`DELETE /v1/network/{network_id}/network-peerings/{id}`, `GET /v1/network/{network_id}/network-peerings` |153| Cloud Provider Access (PREVIEW) | `GET /v1/cloud-provider-accesses/prerequisites`, `POST /v1/cloud-provider-accesses`, `GET`/`DELETE /v1/cloud-provider-accesses/{id}`, `GET /v1/cloud-provider-accesses` |154| Shadow Links | `POST /v1/shadow-links`, `GET`/`DELETE /v1/shadow-links/{id}`, `GET /v1/shadow-links`, `PATCH /v1/shadow-links/{id}?update_mask=...` |155| Operations | `GET /v1/operations/{id}`, `GET /v1/operations` |156| Scheduled Operations (PREVIEW) | `GET /v1/scheduled-operations` (list only) |157| Resource Groups | `POST /v1/resource-groups`, `GET /v1/resource-groups/{id}`, `GET /v1/resource-groups` |158| Regions | `GET /v1/regions/{cloud_provider}`, `GET /v1/regions/{cloud_provider}/{name}` |159160## Cluster Connectivity: `connection_type` vs `connections`161162`connection_type` (`CONNECTION_TYPE_PUBLIC` / `CONNECTION_TYPE_PRIVATE`) makes the whole cluster163public or private and is **deprecated**. It is superseded by a per-service `connections` list on164`kafka_api`, `http_proxy`, and `schema_registry` — **dual listener mode**, which serves a public and165a private listener at the same time, each with its own server-assigned endpoint and its own166SASL/SCRAM or mTLS auth:167168```json169"kafka_api": {"connections": [170 {"type": "CONNECTION_TYPE_PUBLIC", "auth": {"mode": "AUTH_MODE_SASL"}},171 {"type": "CONNECTION_TYPE_PRIVATE", "auth": {"mode": "AUTH_MODE_SASL"}}172]}173```174175Decision rules:176177- Want one connectivity mode for the whole cluster and nothing else? `connection_type` still works.178- Need in-VPC clients on a private listener while external clients stay public? Use `connections`179 — set them on **all three** services with the **same** topology, and omit `connection_type` and180 the per-service `sasl` block (the API rejects either alongside `connections`).181- Dual listener mode is **beta, AWS only, and enabled per organization**; Azure is rejected182 outright, and the fields are not in the published API reference yet. It cannot be configured in183 the Cloud UI.184- Read endpoints from `connections[].endpoint` in `GET /v1/clusters/{id}`, not from the deprecated185 `seed_brokers`/`url` fields.186- Migrating public-only ↔ dual is self-service (with the `controlplane_cluster_migrate_connectivity`187 permission) — **except on BYOVPC clusters**, which always keep a private connection: every BYOVPC188 migration to or from dual listener mode goes through Redpanda Support. Anything that moves any189 cluster between private-only and publicly reachable also goes through Support.190- Once a service uses `connections`, its legacy `sasl`/`mtls` update path is closed — the API191 rejects such a PATCH and tells you to use `connections`. Change auth via `connections[].auth.mode`.192193Full rules, examples, and migration semantics: [Clusters and Agent](references/clusters-and-agent.md#dual-listener-mode-public--private-listeners-per-service-beta-aws).194195## Cluster State Machine196197BYOC clusters move through these states (grounded in `cluster.proto`):198199```200STATE_CREATING_AGENT → STATE_CREATING → STATE_READY201 ↗202STATE_UPGRADING ──────────────────────203STATE_DELETING_AGENT → STATE_DELETING → (deleted)204STATE_FAILED205STATE_SUSPENDED206```207208The cluster enters `STATE_CREATING_AGENT` after the API accepts the create request. This is when you must run `rpk cloud byoc apply` to install the agent Terraform. Once the agent completes provisioning, the cluster transitions to `STATE_CREATING`, then `STATE_READY`.209210## rpk cloud byoc Commands211212```bash213# Install the byoc plugin (pinned to the cluster's required version)214rpk cloud byoc install --redpanda-id <cluster-id>215216# Apply (provision) agent infra — cloud-provider subcommand is required.217# GCP also requires --project-id; Azure also requires --subscription-id.218rpk cloud byoc aws apply --redpanda-id <cluster-id>219rpk cloud byoc gcp apply --redpanda-id <cluster-id> --project-id <gcp-project-id>220rpk cloud byoc azure apply --redpanda-id <cluster-id> --subscription-id <azure-sub-id>221222# Destroy agent infra (same per-provider account flags as apply)223rpk cloud byoc aws destroy --redpanda-id <cluster-id>224rpk cloud byoc gcp destroy --redpanda-id <cluster-id> --project-id <gcp-project-id>225rpk cloud byoc azure destroy --redpanda-id <cluster-id> --subscription-id <azure-sub-id>226227# Validate prerequisites without a cluster ID (uses latest plugin version)228rpk cloud byoc aws validate229rpk cloud byoc gcp validate230# Note: only aws/gcp validate are confirmed; azure validate is not separately attested.231232# Uninstall the local plugin binary233rpk cloud byoc uninstall234```235236The `--redpanda-id` flag is required for `apply` and `destroy`. The plugin is automatically pinned to the version the control plane specifies for the given cluster ID. Set `RPK_CLOUD_SKIP_VERSION_CHECK=1` to use the currently installed plugin binary as-is (dev/CI use only).237238Authentication for `rpk cloud byoc` uses the same client credentials as `rpk cloud login`:239240```bash241# Via -X flags (not persisted)242rpk cloud byoc aws apply --redpanda-id <id> \243 -X cloud.client_id=<id> \244 -X cloud.client_secret=<secret>245246# Via environment variables247export RPK_CLOUD_CLIENT_ID=<id>248export RPK_CLOUD_CLIENT_SECRET=<secret>249rpk cloud byoc aws apply --redpanda-id <id>250```251252## Enterprise Features on BYOC253254Redpanda Cloud BYOC is a managed deployment of **Redpanda Enterprise Edition** — the enterprise license is included in your Cloud subscription, so you never apply a license key. Every enterprise differentiator is available; you turn it on through cluster config and topic properties, not a license workflow.255256Two surfaces:2572581. **Cluster-config properties** (e.g. `iceberg_enabled`, `audit_enabled`, `partition_autobalancing_mode`, `default_leaders_preference`, `enable_schema_id_validation`) — set via the Control Plane API under `cluster_configuration.custom_properties` at `POST /v1/clusters` (create) or `PATCH /v1/clusters/{id}?update_mask=cluster_configuration.custom_properties` (update), or via `rpk cluster config set` on the data plane. Integer values must be strings in `custom_properties`.2592. **Topic properties** (e.g. `redpanda.iceberg.mode`, `redpanda.remote.write`, `redpanda.cloud_topic.enabled`, `redpanda.leaders.preference`) — set with `rpk topic create -c ...` / `rpk topic alter-config` on the data plane after the cluster is `STATE_READY`.260261```bash262# Enable an enterprise cluster property after the cluster exists.263# update_mask is a REQUIRED query parameter (comma-separated snake_case field paths —264# the API uses proto field names); the JSON body IS the ClusterUpdate object directly265# (no "cluster" wrapper, no update_mask in body).266curl -s -X PATCH "${BASE}/v1/clusters/${CLUSTER_ID}?update_mask=cluster_configuration.custom_properties" \267 -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" \268 -d '{"cluster_configuration":{"custom_properties":{"iceberg_enabled":"true"}}}' | jq '.operation.id'269```270271Key features and their nested keys (full detail in [Enterprise Features](references/enterprise-features.md)):272273| Feature | Where | Primary keys |274|---|---|---|275| Tiered Storage (always on) | topic + cluster | `redpanda.remote.write/read/delete/recovery`, `redpanda.storage.mode`, `redpanda.storage.mode.impl` (`tiered_v1`/`tiered_v2`, read-only after create); cluster `default_redpanda_storage_mode_tiered_impl` |276| Cloud Topics | topic | `redpanda.cloud_topic.enabled`, `redpanda.storage.mode=cloud` |277| Iceberg Topics | cluster + topic | `iceberg_enabled`, `iceberg_default_catalog_namespace`; `redpanda.iceberg.mode/delete/invalid.record.action/partition.spec/target.lag.ms` |278| Continuous Data Balancing | cluster | `partition_autobalancing_mode=continuous`, `partition_autobalancing_max_disk_usage_percent`, `partition_autobalancing_node_availability_timeout_sec`, `partition_autobalancing_node_autodecommission_timeout_sec`, `core_balancing_continuous` |279| Shadow Linking (DR) | rpk + control plane | `rpk shadow config generate --for-cloud` / `create` / `status` / `failover`; `schema_registry_sync_options` selects `shadow_schema_registry_topic` or `shadow_schema_registry_api` (HTTP-API mode, incl. Confluent Schema Registry sources) |280| Remote Read Replicas | topic + cluster | `redpanda.remote.readreplica`, `cloud_storage_enable_remote_read` |281| Audit Logging | cluster | `audit_enabled`, `audit_log_num_partitions`, `audit_enabled_event_types`, `audit_excluded_topics/principals`, `audit_queue_drain_interval_ms` |282| RBAC / GBAC | rpk / ACLs | `rpk security role ...`; `Group:` principals |283| OIDC / OAuthBearer / Kerberos | cluster | `sasl_mechanisms` (`OAUTHBEARER`, `GSSAPI`), `http_authentication` (`OIDC`) |284| Schema ID Validation | cluster + topic | `enable_schema_id_validation`; `redpanda.{key,value}.schema.id.validation`, `redpanda.{key,value}.subject.name.strategy` |285| Leadership Pinning | cluster + topic | `default_leaders_preference`, `redpanda.leaders.preference` (`none` / `racks:` / `ordered_racks:`) |286| FIPS | provisioning | request a FIPS-enabled cluster (`fips_mode`) |287288## Reference Directory289290- [BYOC Model and Auth](references/byoc-model-and-auth.md): What BYOC is vs Serverless, OAuth2 client-credentials flow, and the end-to-end provisioning sequence.291- [Networks](references/networks.md): Creating the Network resource per cloud provider — AWS (VPC/subnet/IAM ARNs), GCP (network name, project, GCS bucket), Azure (VNet, subnets, resource groups). Plus VPC/VNet peering (NetworkPeeringService), Cloud Provider Access cross-account AWS provisioning (PREVIEW), and private connectivity / centralized egress (AWS PrivateLink incl. cross-region, GCP PSC, Azure Private Link, Transit Gateway egress). Field-level reference grounded in network.proto, network_peering.proto, cloud_provider_access.proto, and common.proto.292- [Clusters and Agent](references/clusters-and-agent.md): ClusterCreate fields for BYOC (TYPE_BYOC, network_id, throughput_tier, customer_managed_resources, zones, cloud_provider_tags), dual listener mode (per-service `connections`, endpoints, and migration semantics), the cluster PATCH/update_mask form, Operation lifecycle, Scheduled Operations (PREVIEW), control-plane Shadow Linking (ShadowLinkService, including the two Schema Registry replication modes and Confluent Schema Registry migration), and the full rpk cloud byoc install/apply/destroy/validate flow.293- [Enterprise Features](references/enterprise-features.md): Enabling Redpanda Enterprise differentiators on a BYOC cluster (license included with the Cloud subscription) via `cluster_configuration.custom_properties` and topic properties — Tiered Storage, Cloud Topics, Iceberg Topics, Continuous Data Balancing, Shadow Linking DR, Remote Read Replicas, Audit Logging, RBAC/GBAC, OIDC/OAuthBearer/Kerberos, FIPS, Server-Side Schema ID Validation, and Leadership Pinning — with their nested config keys and license-expiration behavior, grounded in the licensing overview and per-feature docs.