{"record":{"id":"ef090d345bdf65ff","repo":"kubernetes/kops","slug":"bastion-supports-topology-private-only","errorCode":null,"errorMessage":"bastion supports --topology='private' only","messagePattern":"bastion supports --topology='private' only","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/new_cluster.go","lineNumber":1392,"sourceCode":"\t\tif opt.IPv6 {\n\t\t\topt.Topology = api.TopologyPrivate\n\t\t} else {\n\t\t\topt.Topology = api.TopologyPublic\n\t\t}\n\t}\n\n\tcluster.Spec.Networking.Topology = &api.TopologySpec{}\n\n\terr := setupDNSTopology(opt, cluster)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tswitch opt.Topology {\n\tcase api.TopologyPublic:\n\n\t\tif opt.Bastion {\n\t\t\treturn nil, fmt.Errorf(\"bastion supports --topology='private' only\")\n\t\t}\n\n\t\tfor i := range cluster.Spec.Networking.Subnets {\n\t\t\tcluster.Spec.Networking.Subnets[i].Type = api.SubnetTypePublic\n\t\t}\n\n\tcase api.TopologyPrivate:\n\t\tif cluster.Spec.Networking.Kubenet != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid networking option %s. Kubenet does not support private topology\", opt.Networking)\n\t\t}\n\n\t\tfor i := range cluster.Spec.Networking.Subnets {\n\t\t\tcluster.Spec.Networking.Subnets[i].Type = api.SubnetTypePrivate\n\t\t}\n\n\t\tvar zoneToSubnetProviderID map[string]string\n\t\tvar err error\n\t\tif len(opt.Zones) > 0 && len(opt.UtilitySubnetIDs) > 0 {","sourceCodeStart":1374,"sourceCodeEnd":1410,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/new_cluster.go#L1374-L1410","documentation":"setupTopology configures public vs private topology. A bastion host exists to reach privately-topologized clusters, so requesting --bastion together with --topology=public is contradictory and rejected.","triggerScenarios":"`kops create cluster --topology public --bastion` (or programmatic NewClusterOptions with Topology=public and Bastion=true) calls setupTopology from NewCluster and fails.","commonSituations":"Leaving --bastion in a script while changing topology to public; misunderstanding that a bastion requires private topology; defaults where Bastion=true remains set from a template.","solutions":["Remove the --bastion flag if you want public topology.","Switch to --topology private if you actually need a bastion.","In Go, set opt.Bastion=false when Topology is api.TopologyPublic."],"exampleFix":"// before\nkops create cluster my.cluster --topology public --bastion\n// after\nkops create cluster my.cluster --topology private --bastion","handlingStrategy":"validation","validationCode":"[ \"$TOPOLOGY\" = \"private\" ] || [ -z \"$BASTION\" ] || { echo \"--bastion requires --topology private\"; exit 1; }","typeGuard":null,"tryCatchPattern":"if err := createCluster(); err != nil && strings.Contains(err.Error(), \"bastion supports\") { /* drop --bastion or switch to private topology */ }","preventionTips":["Remember bastion implies private topology","Set topology and bastion flags together from one variable","Review cluster templates for stale --bastion flags"],"tags":["topology","bastion","cli-flags","cluster-creation"],"backgroundTag":"incompatible-flag-combination","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}