stackit object-storage credentials create has been observed to panic in some CLI versions — create S3-compatible keys in the portal if needed.
Bootstrap object visibility
A wide-open bucket policy makes bootstrap.ign (cluster secrets) world-readable. Tighten to source IPs or VPC egress only; remove or restrict policy after bootstrap.
apiVersion:v1baseDomain:openshift.runs.onstackit.cloudcompute:-name:workerarchitecture:amd64hyperthreading:Enabledplatform:{}replicas:3controlPlane:architecture:amd64hyperthreading:Enabledname:masterplatform:{}replicas:3metadata:name:cluster-anetworking:clusterNetwork:-cidr:10.128.0.0/14hostPrefix:23machineNetwork:-cidr:10.0.0.0/24serviceNetwork:-172.30.0.0/16type:OVNKubernetesplatform:none:{}pullSecret:|REPLACE WITH YOUR PULL SECRETsshKey:|REPLACE SSH KEY HERE from ~/.ssh/ocp-on-stackit.pub
Per-node Butane in this repo: bootstrap merges the object-store URL of bootstrap.ign; control plane nodes merge conf/master.ign, workers merge conf/worker.ign (paths relative to butane -d .).
{"listeners":[{"displayName":"api","port":6443,"protocol":"PROTOCOL_TCP","targetPool":"api"},{"displayName":"machine-config-server","port":22623,"protocol":"PROTOCOL_TCP","targetPool":"machine-config-server"}],"name":"lb-int","networks":[{"networkId":"<REPLACE WITH NETWORK_ID>","role":"ROLE_LISTENERS_AND_TARGETS"}],"options":{"accessControl":{"allowedSourceRanges":["10.0.0.0/24"]},"ephemeralAddress":false,"privateNetworkOnly":true},"planId":"p10","targetPools":[{"name":"api","targetPort":6443,"targets":[{"displayName":"bootstrap","ip":"REPLACE WITH IP OF BOOTSTRAP NODE"},{"displayName":"control-plane-0","ip":"REPLACE WITH IP OF CONTROL PLANE 0 NODE"},{"displayName":"control-plane-1","ip":"REPLACE WITH IP OF CONTROL PLANE 1 NODE"},{"displayName":"control-plane-2","ip":"REPLACE WITH IP OF CONTROL PLANE 2 NODE"}]},{"name":"machine-config-server","targetPort":22623,"targets":[{"displayName":"bootstrap","ip":"REPLACE with IP"},{"displayName":"control-plane-0","ip":"REPLACE WITH IP OF CONTROL PLANE 0 NODE"},{"displayName":"control-plane-1","ip":"REPLACE WITH IP OF CONTROL PLANE 1 NODE"},{"displayName":"control-plane-2","ip":"REPLACE WITH IP OF CONTROL PLANE 2 NODE"}]}]}
Adjust stackit-lb-int.json
Fill target pools with control plane node IPs (API + MCS). Create LB:
stackitpublic-ipcreate
# attach to external LB / listener as required by STACKIT networking modelstackitdnsrecord-setcreate--zone-id<ZONE_ID>--nameapi.cluster-a--record<PUBLIC_IP>--ttl60stackitdnsrecord-setcreate--zone-id<ZONE_ID>--name'*.apps.cluster-a'--record<PUBLIC_IP>--ttl60
{"externalAddress":"<REPLACE WITH EXTERNAL IP ADDRESS>","listeners":[{"displayName":"api","port":6443,"protocol":"PROTOCOL_TCP","targetPool":"api"},{"displayName":"ingress-http","port":80,"protocol":"PROTOCOL_TCP","targetPool":"ingress-http"},{"displayName":"ingress-https","port":443,"protocol":"PROTOCOL_TCP","targetPool":"ingress-https"}],"name":"lb-ext","networks":[{"networkId":"<REPLACE WITH NETWORK_ID>","role":"ROLE_LISTENERS_AND_TARGETS"}],"options":{"ephemeralAddress":false,"privateNetworkOnly":false},"planId":"p10","targetPools":[{"name":"api","targetPort":6443,"targets":[{"displayName":"bootstrap","ip":"REPLACE WITH IP OF BOOTSTRAP NODE"},{"displayName":"control-plane-0","ip":"REPLACE WITH IP OF CONTROL PLANE 0 NODE"},{"displayName":"control-plane-1","ip":"REPLACE WITH IP OF CONTROL PLANE 1 NODE"},{"displayName":"control-plane-2","ip":"REPLACE WITH IP OF CONTROL PLANE 2 NODE"}]},{"name":"ingress-http","targetPort":80,"targets":[{"displayName":"worker-0","ip":"REPLACE WITH IP OF WORKER 0 NODE"},{"displayName":"worker-1","ip":"REPLACE WITH IP OF WORKER 1 NODE"},{"displayName":"worker-2","ip":"REPLACE WITH IP OF WORKER 2 NODE"}]},{"name":"ingress-https","targetPort":443,"targets":[{"displayName":"worker-0","ip":"REPLACE WITH IP OF WORKER 0 NODE"},{"displayName":"worker-1","ip":"REPLACE WITH IP OF WORKER 1 NODE"},{"displayName":"worker-2","ip":"REPLACE WITH IP OF WORKER 2 NODE"}]}]}
Adjust stackit-lb-ext.json
Adjust listeners and backends (API → masters; 80/443 → workers or ingress nodes), then: