Skip to content
Config Reference

Config Reference

Podplane uses JSONC (JSON with comments) configuration files to store cluster and OIDC server settings. These files are generated interactively by podplane cluster create and podplane oidc create.

podplane.cluster.jsonc

This file is the user-facing projection of cluster configuration. It is created in the current directory by podplane cluster create and is required by many CLI commands such as podplane login and podplane install.

New cluster configs include a relative $schema reference to ./podplane.cluster.schema.json. Podplane writes that schema file next to the config so editors such as VS Code can provide offline validation, completion, and hover documentation in shared infrastructure repositories. The source schema is checked into the Podplane repository at schemas/podplane.cluster.schema.json.

Example

{
  "$schema": "./podplane.cluster.schema.json",
  "cluster": {
    "id": "internaltools-production",
    "name": "Internal Tools (Production)",
    "oidc": {
      "issuer_url": "https://auth.example.com"
    },
    "acme": {
      "server": "https://acme-v02.api.letsencrypt.org/directory",
      "email": "[email protected]"
    },
    "domains": [
      {
        "zone": "internaltools.example.com",
        "provider": {
          "kind": "aws-route53",
          "account": "123456789012",
          "profile": "default",
          "region": "us-east-1",
          "hosted_zone_id": "Z0123456789"
        }
      }
    ],
    "pools": {
      "control-plane": {
        "arch": "arm64",
        "instance_type": "t4g.medium",
        "size": 1
      },
      "ingress": {
        "arch": "arm64",
        "instance_type": "t4g.medium",
        "size": 1
      }
    },
    "providers": [
      {
        "kind": "aws",
        "region": "us-east-1",
        "account": "123456789012",
        "profile": "default",
        "tags": {
          "podplane:environment": "production",
          "podplane:managed-by": "podplane"
        },
        "vpc": {
          "v4cidr": "172.18.0.0/16",
          "v6cidr": "auto"
        },
        "zones": {
          "us-east-1a": [
            { "v4cidr": "172.18.10.0/28", "v6cidr": "auto", "services": ["nat", "nlb"], "public": true },
            { "v4cidr": "172.18.20.0/28", "v6cidr": "auto", "services": ["nstance"] },
            { "v4cidr": "172.18.1.0/24", "v6cidr": "auto", "pool": "control-plane" },
            { "v4cidr": "172.18.3.0/24", "v6cidr": "auto", "pool": "ingress" }
          ],
          "us-east-1b": [
            { "v4cidr": "172.18.11.0/28", "v6cidr": "auto", "services": ["nat", "nlb"], "public": true },
            { "v4cidr": "172.18.21.0/28", "v6cidr": "auto", "services": ["nstance"] },
            { "v4cidr": "172.18.2.0/24", "v6cidr": "auto", "pool": "control-plane" },
            { "v4cidr": "172.18.4.0/24", "v6cidr": "auto", "pool": "ingress" }
          ]
        },
        "load_balancers": {
          "main": {
            "public": true,
            "subnets": "public",
            "listeners": [
              { "port": 443, "pool": "ingress" }
            ]
          },
          "kubernetes-api": {
            "public": true,
            "subnets": "public",
            "listeners": [
              { "port": 6443, "pool": "control-plane" }
            ]
          }
        },
        "buckets": ["uploads", "assets"],
        "roles": {
          "app-storage": {
            "buckets": ["uploads", "assets"]
          },
          "analytics": {
            "buckets": ["uploads"],
            "permissions": "read-only"
          }
        }
      }
    ],
    "kubernetes": {
      "api_hostname": "k8s.example.com",
      "api_load_balancer": "kubernetes-api",
      "cluster_cidr": ["100.64.0.0/10", "fd64::/48"],
      "service_cidr": ["198.18.0.0/15", "fdc6::/108"]
    },
    "registry": {
      "hostname": "registry.example.com",
      "ingress": { "enabled": false }
    },
    "seed": {
      "name": "recommended",
      "version": "v1.2.3-1"
    },
    "components": {
      "registry": {
        "mirror": {
          "enabled": true,
          "prefix": "mirror"
        }
      },
      "source": {
        "url": "https://github.com/podplane/components.git",
        "ref": {
          "semver": "^1.2.3"
        }
      }
    }
  }
}

Fields

For the operational impact of changing cluster fields after initial deployment, including which changes are updated live (through an Nstance-pushed mutable.env file) and which changes cause Nstance to rotate Nstance-managed VMs, see Change Impact: VMConfig Live Updates vs VM Rotation.

FieldDescription
cluster.idCluster identifier - lowercase alphanumeric and hypens, max 32 characters. Auto-generated from name by the CLI, used as a prefix for cloud resources and maps to Nstance cluster_id.
cluster.nameCluster name, used as a human-readable identifier
cluster.oidc.issuer_urlOIDC issuer URL for cluster authentication (e.g. https://auth.example.com)
cluster.oidc.client_idOIDC client ID (defaults to cluster.id if not specified)
cluster.oidc.username_claimToken claim used as the username (default: email)
cluster.oidc.groups_claimToken claim used for group membership (default: groups)
cluster.oidc.signing_algsAllowed OIDC signing algorithms. Passed to kube-apiserver at runtime; vmconfig defaults to ["RS256"] when omitted.
cluster.acme.serverOptional ACME directory override. Defaults to the Let’s Encrypt production directory.
cluster.acme.emailACME account email address for expiry and account notices. Configuring it enables ACME for domains using a supported DNS provider; currently only AWS Route53 is enabled. Omit cluster.acme to use self-signed ingress certificates.
cluster.domains[]Array of domain configurations. The first domain is used as the default for ingress routing.
cluster.domains[].zoneExact ingress apex (e.g. staging.example.com); Podplane creates apex and wildcard DNS records.
cluster.domains[].load_balancerNamed provider load balancer targeted by the apex and wildcard records. Defaults to main.
cluster.domains[].providerOptional DNS provider. Omit it for manual DNS management.
cluster.domains[].provider.kindDNS provider: aws-route53, cloudflare, google-cloud-dns, or local. Cluster Terraform generation currently supports aws-route53.
cluster.domains[].provider.regionAWS Route53 region for DNS-01. If omitted, Podplane can infer it when exactly one matching AWS provider exists.
cluster.domains[].provider.hosted_zone_idOptional explicit Route53 hosted zone ID. Use it to disambiguate or pin the exact hosted zone; otherwise, generated Terraform looks up the public hosted zone by domain name.
cluster.domains[].provider.secret_provider_class_nameExisting Secrets Store CSI SecretProviderClass to mount so external secret material can be synced before cert-manager uses it.
cluster.domains[].provider.secret_nameKubernetes Secret name containing DNS provider credentials. Used by DNS providers that authenticate with Kubernetes Secrets.
cluster.domains[].provider.secret_keyKey inside secret_name. Defaults to api-token for Cloudflare and service-account.json for Google Cloud DNS.
cluster.domains[].provider.projectGoogle Cloud project ID for Cloud DNS.
cluster.domains[].provider.hosted_zone_nameGoogle Cloud DNS managed zone name for the domain (optional).
cluster.pools.<name>.archCPU architecture for the pool’s nodes. amd64 or arm64
cluster.pools.<name>.instance_typeCloud provider instance type (e.g. t4g.medium for AWS, n2-standard-2 for Google Cloud)
cluster.pools.<name>.sizeMinimum number of instances in the pool
cluster.pools.<name>.disk_sizeRoot volume size in GB (default: 100)
cluster.providers[]Array of cloud provider configurations (supports multi-cloud). The available fields vary by kind - the fields below apply to aws and google.
cluster.providers[].kindCloud provider - aws, google, or proxmox
cluster.providers[].regionProvider region (e.g. us-east-1 for AWS, us-central1 for Google Cloud)
cluster.providers[].accountAWS account ID (AWS only)
cluster.providers[].profileAWS CLI profile name (AWS only)
cluster.providers[].projectGoogle Cloud project ID (Google Cloud only)
cluster.providers[].tagsKey-value map of tags to apply to all cloud resources created by this provider (e.g. {"podplane:environment": "production"})
cluster.providers[].vpc.idID of an existing VPC to use (alternative to creating a new one with v4cidr)
cluster.providers[].vpc.v4cidrIPv4 CIDR block for creating a new VPC (or specify an id to use existing)
cluster.providers[].vpc.v6cidrIPv6 CIDR for the VPC - "auto" for provider-assigned or an explicit CIDR (optional, for dual-stack)
cluster.providers[].zones.<zone>[]Array of subnet definitions for this zone. Each entry has either pool (for node subnets) or services (for infrastructure subnets).
cluster.providers[].zones.<zone>[].poolName of the pool this subnet belongs to (mutually exclusive with services)
cluster.providers[].zones.<zone>[].servicesInfrastructure services this subnet hosts - nstance, nat, and/or nlb (array, mutually exclusive with pool)
cluster.providers[].zones.<zone>[].publicWhether the subnet is public - has a route to an internet gateway (default: false)
cluster.providers[].zones.<zone>[].idID of an existing subnet to use (alternative to creating a new one with v4cidr)
cluster.providers[].zones.<zone>[].v4cidrIPv4 CIDR block for creating a new subnet (or specify an id to use existing)
cluster.providers[].zones.<zone>[].v6cidrIPv6 CIDR for the subnet - "auto" for provider-assigned or an explicit CIDR (optional, for dual-stack)
cluster.providers[].load_balancers.<name>.publicWhether the named load balancer is internet-facing.
cluster.providers[].load_balancers.<name>.subnetsSubnet role in which the load balancer is placed, such as public or a pool name.
cluster.providers[].load_balancers.<name>.listeners[]Explicit listeners exposed by the load balancer. Domains require 443 -> 443; a managed Kubernetes API requires api_port -> 6443 targeting the control-plane pool.
cluster.providers[].load_balancers.<name>.listeners[].portExternal listener port.
cluster.providers[].load_balancers.<name>.listeners[].target_portPort on target VMs. Defaults to the external port.
cluster.providers[].load_balancers.<name>.listeners[].poolPool whose VMs are registered with this listener’s target group.
cluster.providers[].bucketsArray of app-accessible object storage bucket names. Cloud bucket names are derived as {cluster.id}-{name}.
cluster.providers[].roles.<name>.bucketsArray of bucket names this role can access
cluster.providers[].roles.<name>.permissionsResource access level - read-write or read-only (default: read-write)
cluster.kubernetes.api_hostnameRequired Kubernetes API hostname used by kubeconfig and the API server certificate.
cluster.kubernetes.api_portExternal Kubernetes API port. Defaults to 6443; the target port remains 6443.
cluster.kubernetes.api_load_balancerOptional named provider load balancer. Omit it to manage API connectivity and DNS outside Podplane.
cluster.secrets.default_providerDefault secrets provider name used by podplane secret and templates when --provider is omitted.
cluster.secrets.providersNamed secrets providers. Only provider-selection metadata belongs here; credentials are configured on the operator deployment.
cluster.secrets.providers.<name>.kindSecrets provider kind, such as aws, gcp, or openbao.
cluster.secrets.providers.<name>.key_prefixOptional backend key prefix for this provider. Defaults to cluster.id; set it only when clusters should intentionally share a provider backend prefix.
cluster.secrets.providers.<name>.object_typeAWS Secrets Store CSI object type, such as secretsmanager or ssmparameter.
cluster.secrets.providers.<name>.addressVault/OpenBao server address used by the operator and rendered into generated SecretProviderClass objects.
cluster.secrets.providers.<name>.mount_pathVault/OpenBao KV-v2 mount name. Defaults to secret.
cluster.secrets.providers.<name>.ca_certOptional PEM CA bundle for a Vault/OpenBao endpoint served by a private CA. Local fakevault config sets this automatically.
cluster.secrets.providers.<name>.auth_pathVault/OpenBao Kubernetes/JWT auth mount path used by the operator. Defaults to auth/kubernetes.
cluster.secrets.providers.<name>.operator_roleVault/OpenBao role used by the operator service account. Defaults to podplane-operator. Workload CSI reads use the binding/service account role separately.
cluster.kubernetes.cluster_cidrCIDR ranges for Pod IPs, joined with commas for kube-controller-manager --cluster-cidr
cluster.kubernetes.service_cidrCIDR ranges for Service ClusterIPs, joined with commas for kube-apiserver --service-cluster-ip-range
cluster.registry.hostnameCluster registry hostname used by node-local Zot, podplane push, and optional Docker-push-compatible ingress.
cluster.registry.ingress.enabledEnables optional Docker-push-compatible registry ingress/token-service routing. Disabled by default; podplane push does not require ingress.
cluster.seed.namePodplane seed file to use when creating the Netsy bootstrap file - recommended, minimal, or none. Leave cluster.seed as an empty object to seed no platform-components state, leaving a bare cluster that must be bootstrapped manually.
cluster.seed.versionPodplane seeds release version used for the selected seed file, e.g. v1.2.3-1. Generated configs pin this to the known available seed version. Omit inside an empty cluster.seed object.
cluster.seed.digestExpected SHA-512 digest of the selected seed snapshot. Generated configs pin this from the seeds manifest; seed resolution verifies the downloaded file before interpolation.
cluster.components.registry.mirror.enabledRender platform component image references through the configured registry mirror. Local clusters enable this automatically so seeded components pull from the VM-hosted registry backed by the local dependency cache.
cluster.components.registry.mirror.hostnameAdvanced shared-mirror hostname override. Defaults to cluster.registry.hostname.
cluster.components.registry.mirror.prefixAdvanced mirror path-prefix override. Defaults to mirror; /mirror/ cleans to mirror, and / or an empty string means no prefix.
cluster.components.source.urlGit repository URL used by platform-components as the source for component Helm charts. Defaults to the published Podplane components repository when omitted.
cluster.components.source.ref.branchGit branch to use for component Helm charts.
cluster.components.source.ref.tagGit tag to use for component Helm charts. Mutually exclusive with other source.ref selectors.
cluster.components.source.ref.semverGit semver range to use for component Helm charts. Mutually exclusive with other source.ref selectors.
cluster.components.source.ref.commitGit commit to use for component Helm charts. Mutually exclusive with other source.ref selectors.
cluster.components.source.secretRef.nameOptional Flux Git credentials Secret name in the platform-components namespace. Use this for private/enterprise components repos; Podplane wires the reference but does not create the Secret.

Validation rules:

  • cluster.id must be lowercase alphanumeric with hyphens only, no leading/trailing/consecutive hyphens, max 32 characters.
  • vpc.id and vpc.v4cidr/vpc.v6cidr are mutually exclusive - specify an existing VPC ID or CIDRs to create a new VPC, not both.
  • Subnet id and v4cidr/v6cidr are mutually exclusive - specify an existing subnet ID or CIDRs to create a new subnet, not both.
  • Each subnet must have exactly one of pool or services - not both.
  • Subnets with nat or nlb in services must be public: true.
  • Role buckets entries must reference bucket names declared in the same provider’s buckets array.

podplane.oidc.jsonc

This file stores configuration for an Easy OIDC server deployment. It is created in the current directory by podplane oidc create and is required by podplane oidc delete.

New OIDC configs include a relative $schema reference to ./podplane.oidc.schema.json. Podplane writes that schema file next to the config so editors such as VS Code can provide offline validation, completion, and hover documentation in shared infrastructure repositories. The source schema is checked into the Podplane repository at schemas/podplane.oidc.schema.json.

Example

{
  "$schema": "./podplane.oidc.schema.json",
  "oidc": {
    "provider": {
      "kind": "aws",
      "region": "us-east-1",
      "account": "123456789012",
      "profile": "default"
    },
    "hostname": "auth.example.com",
    "domain": {
      "zone": "example.com",
      "provider": {
        "kind": "aws"
      }
    },
    "connector": {
      "kind": "google",
      "client_secret_arn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:easy-oidc-connector-secret"
    },
    "signing_key_secret_arn": "arn:aws:secretsmanager:us-east-1:123456789012:secret:easy-oidc-signing-key",
    "default_redirect_uris": ["http://localhost:8000"],
    "clients": {
      "kubelogin-prod": {
        "groups_override": "prod-groups"
      },
      "kubelogin-dev": {}
    },
    "groups_overrides": {
      "prod-groups": {
        "[email protected]": ["prod-admins", "devs"]
      }
    }
  }
}

Fields

FieldDescription
oidc.provider.kindCloud provider - aws (Google Cloud and Azure are planned)
oidc.provider.regionProvider region to deploy into (e.g. us-east-1)
oidc.provider.accountProvider account identifier (e.g. AWS account ID)
oidc.provider.profileProvider credentials profile (e.g. AWS CLI profile name)
oidc.hostnameThe hostname for the OIDC server (e.g. auth.example.com)
oidc.domain.zoneDomain zone for the hostname (e.g. example.com)
oidc.domain.provider.kindDomain DNS provider - aws, cloudflare, or google
oidc.connector.kindUpstream OAuth provider - google or github
oidc.connector.client_secret_arnARN of the AWS Secrets Manager secret containing the OAuth client ID and secret
oidc.signing_key_secret_arnARN of the AWS Secrets Manager secret containing the OIDC signing key
oidc.default_redirect_urisDefault redirect URIs applied to clients that don’t specify their own
oidc.clients.<name>Map of OIDC client configurations
oidc.clients.<name>.groups_overrideName of a groups override to apply to the specified client (optional)
oidc.groups_overrides.<name>Static group mappings, where each key is an email and the value is an array of group names

File Location

By default, the CLI looks for config files in the current working directory. You can specify an alternate path using the -f flag:

podplane login -f ./my-cluster/podplane.cluster.jsonc
podplane oidc delete -f ./auth-server/podplane.oidc.jsonc

See CLI Overview for recommended directory structure.