Providers
How a workstation is placed on a backend: automatic placement, the lima, GCP, Azure and AWS providers, and their config knobs.
A provider is the backend that actually runs a Workstation: a local VM (lima on macOS, qemu on Linux) or a cloud VM (GCP, Azure, AWS). You rarely name one directly: you state requirements and let automatic placement (capability discovery) decide where the workstation runs.
Choosing a provider
- Automatic placement (default). Omit any provider hint and the scheduler
places the workstation on a backend that satisfies its
spec.requirements. - Pin a provider.
spec.provider: gcp(or--provider gcponcreate workstation) is shorthand for adding aprovider:gcprequirement.
rl workstation create my-box # discovery picks a backend
rl workstation create my-box --provider gcp # pin GCPThe selected backend is reported at status.provider.
Per-provider machine tuning goes in spec.providerConfig, an opaque block read
from the Workstation spec only (it is not merged from config layers). Its shape is
provider-specific, described below.
An unsupported OS fails loudly, and says what is supported
distribution + version pairs, given per
provider below. Naming a pair a provider does not carry — or leaving distribution
or version out on a cloud provider — fails the workstation with a message on
status.message that lists the supported pairs, rather than silently booting some
default image. The same applies when you ask for an architecture an image has no
build for (an Arm machine type with an amd64-only image, say).lima (local, macOS)
Lima is the local provider on macOS (qemu is the Linux equivalent). It runs a local
Linux VM under the platform hypervisor and needs limactl on PATH, bundled with
the macOS native app. The in-VM agent is downloaded over HTTP
at boot, like every provider; nothing is copied in over a mount.
providerConfig knobs (all optional, an empty config is sized to the host: all
CPUs, half its RAM, half its free disk):
| Key | Type | Description |
|---|---|---|
cpus | int | vCPU count. Default: all host CPUs. |
memory | int | RAM in GiB. Default: half host RAM. |
disk | int | Boot disk in GiB. Default: half host free disk. |
arch | string | Guest architecture. Default: the host architecture. |
apiVersion: workstations.ringleader.dev/v1
kind: Workstation
metadata:
name: local-box
namespace: local
spec:
provider: lima
providerConfig:
cpus: 4
memory: 8
disk: 60GCP (cloud)
The GCP provider creates a Compute Engine VM. It authenticates through a CloudIdentity in the workstation’s namespace, which brokers the short-lived credentials — via per-organization federation, an impersonation chain, or the control plane’s own default identity. Set that up first; see the CloudIdentity reference for the credential paths, and cloud onboarding for what to configure in your account.
Machine and disk knobs live under providerConfig.gcp:
| Key | Type | Description |
|---|---|---|
project | string | Required. GCP project ID. Usually forced by the CloudIdentity’s overrideProviderConfig. |
zone | string | Required. e.g. us-central1-a. Usually forced by the CloudIdentity. |
machineType | string | Machine type. Default e2-medium; e.g. n2-standard-4. Arm families (t2a, c4a, n4a, …) require an arm64 image. |
diskGiB | int | Boot disk size (grows in place on increase). Default ~40 GiB. |
diskType | string | e.g. pd-balanced (default), pd-ssd; hyperdisk-only families default to hyperdisk-balanced. A family/type mismatch fails loudly. |
network | string | VPC network name. Default default. |
subnetwork | string | Subnetwork name, or a full self-link. Required if network is a custom-mode VPC. |
networkTags | []string | GCE network tags (firewall targeting). |
assignPublicIp | bool | Give the VM an external IP. Default true. |
enableNestedVirtualization | bool | Enable nested virtualization on the VM. Default false. |
labels | map | GCE instance labels. |
metadata | map | Extra GCE instance metadata. |
The OS image is the ordinary config-layer image field (distribution + version) —
debian 12/13, or ubuntu 22.04/24.04/26.04, each resolved to the matching
Google-published image family for the machine type’s architecture:
apiVersion: workstations.ringleader.dev/v1
kind: Workstation
metadata:
name: cloud-box
namespace: dev
labels:
cloud: gcp
spec:
provider: gcp
image:
distribution: debian
version: "13"
providerConfig:
gcp:
machineType: e2-standard-4
diskGiB: 100project and zone are typically supplied by the CloudIdentity’s
overrideProviderConfig, so the workstation only needs machineType.
Authorized keys, not instance metadata
authorized_keys on every provider. GCP does not
write ssh-keys instance metadata. SSH access is driven entirely by ownership and
Grants.Reachability
A GCP workstation gets an external IP by default. It is still not reachable
until a firewall rule allows TCP 22 — a custom VPC has none, and GCP denies ingress
by default. rl shell dials the workstation directly on port 22; there is no bastion and no
tunnel, so a workstation with egress but no inbound rule finishes setting up, reports Ready, and
cannot be opened. See
reaching your workstations.
Use networkTags to match the firewall rule your onboarding created, and
assignPublicIp: false for a workstation with no public IP that you reach privately.
Azure (cloud)
The Azure provider creates a VM in one resource group, authenticating through a
CloudIdentity exactly as GCP does. Ringleader synthesizes the per-VM NIC in the
subnet you give it (and tears it down with the VM), so subnetId is required unless
you supply a pre-existing NIC.
| Key | Type | Description |
|---|---|---|
subscriptionId | string | Required. The subscription the VM runs in. |
resourceGroup | string | Required. The resource group (your cost/RBAC boundary). |
location | string | Required. e.g. eastus. Immutable. |
subnetId | string | The full ARM subnet resource id. Ringleader creates a per-VM NIC in it, and tears it down with the VM. |
networkInterfaceId | string | Attach a pre-existing NIC instead. Ringleader never deletes a NIC it did not create. |
publicIp | bool | Attach a Standard public IP. Default false — a workstation without one needs a NAT gateway for egress, or it never finishes setting up. |
size | string | The VM size, e.g. Standard_D4s_v5. |
osDiskGiB | int | OS disk size. |
osDiskType | string | OS disk storage type. |
osDiskCaching | string | OS disk caching mode. |
ephemeralOsDisk | bool | Use an ephemeral OS disk. |
securityType | string | Defaults to Standard, which nested virtualization requires (and which needs a subscription feature registered — see onboarding). |
adminUsername | string | The bootstrap admin user Azure creates on the VM. |
tags | map | Azure resource tags. |
spec:
provider: azure
providerConfig:
azure:
subscriptionId: 22222222-2222-2222-2222-222222222222
resourceGroup: ringleader-workstations
location: eastus
subnetId: /subscriptions/…/virtualNetworks/ringleader-vnet/subnets/workstations
publicIp: true
size: Standard_D4s_v5The OS image is the ordinary config-layer image field (distribution + version) —
debian 12/13, or ubuntu 22.04/24.04/26.04, each resolved to the matching
marketplace image for the size’s architecture.
Placement is typically supplied by the CloudIdentity’s defaultProviderConfig, so a
workstation names only what it wants to differ.
AWS (cloud)
The AWS provider creates an EC2 instance, authenticating through a CloudIdentity exactly as GCP and Azure do. Set that up first; see onboarding AWS for the IAM role and trust to create in your account, and the CloudIdentity reference for the credential path.
| Key | Type | Description |
|---|---|---|
region | string | Required. The region the instance runs in. Immutable. |
instanceType | string | e.g. m6i.xlarge. Default t3.medium. Must be x86-64 — the image alias table resolves x86-64 AMIs. |
subnetId | string | The subnet the instance is placed in (also fixes the availability zone and VPC). |
securityGroupIds | list | Security groups attached to the instance. |
assignPublicIp | bool | Attach a public IP. Default true. A workstation without one needs a NAT gateway for egress, or it never finishes setting up. |
rootVolumeGiB | int | Root volume size. Default ~40 GiB. |
rootVolumeType | string | Root volume type. Default gp3. |
rootDeviceName | string | Root device name, if the AMI’s differs from the default. |
nestedVirtualization | bool | Request an instance configuration that supports nested virtualization. |
iamInstanceProfile | string | An instance profile to attach, so software on the workstation has its own AWS identity. The AWS analogue of the GCP runtime service account (Ringleader attaches, but does not create, the profile). |
tags | map | EC2 resource tags. |
The OS image is the ordinary config-layer image field (distribution + version),
resolved to a vendor-published public AMI: debian 12/13, ubuntu
22.04/24.04/26.04, or amazonlinux 2023. The AMI is resolved at launch, so
you always get the latest patched image for the release you named rather than a
pinned snapshot.
spec:
provider: aws
image:
distribution: ubuntu
version: "24.04"
providerConfig:
aws:
region: us-east-1
instanceType: m6i.xlarge
subnetId: subnet-0abc123
securityGroupIds: [sg-0abc123]
assignPublicIp: truePlacement is typically supplied by the CloudIdentity’s defaultProviderConfig, so a
workstation names only what it wants to differ.
Reachability
An AWS workstation gets a public IP by default, so the internet gateway alone
gives it egress. It is still not reachable until a security-group rule allows TCP 22.
rl shell dials the workstation directly on port 22; there is no bastion and no tunnel, so a
workstation with egress but no inbound rule finishes setting up, reports Ready, and cannot be opened.
Use assignPublicIp: false for a private workstation reached over VPN or peering, with a NAT
gateway for its egress. See
reaching your workstations.
See also
- CloudIdentity: how the control plane authenticates to a cloud provider and injects provider-config defaults and overrides.
- Workstation:
requirements,provider, andproviderConfig.