POST /api/credential-templates accepts any string as provider, stores it, and returns 200. Only two values are ever matched when credentials are resolved, so anything else creates a template that looks correct everywhere in the API and silently injects nothing.
Observed on v4.0.0-rc1 (ghcr.io/f5devcentral), container engine.
What I did
Provisioning a fresh instance, I created the IBM template the obvious way:
POST /api/credential-templates
{"name":"IBM ROKs Testing","provider":"ibmcloud","region":"us-east",
"ibmcloud_api_key":"…","ibmcloud_resource_group":"default"}
201, and it reads back looking entirely healthy:
id=2 name=IBM ROKs Testing provider=ibmcloud region=us-east
ibmcloud_resource_group=default has_ibmcloud_api_key=true
The project shows credential_template_id: 2. Nothing anywhere says it is wrong.
What happens
Credential resolution branches on two literals (credentials_service.py:190,253):
if template.provider == 'aws': ...
if template.provider == 'ibm': ...
"ibmcloud" matches neither, so resolution falls off the end and lands on the global fallback. The worker log is the only place the problem is visible, and even there it reads like information rather than an error:
Using credential template 'IBM ROKs Testing' for project f5e2e-v1-new-connected
Using global credentials from environment (.env) for project f5e2e-v1-new-connected
There is no IBM key in the deployment's .env, so IBMCLOUD_API_KEY is never injected. Every module then runs without it.
How it actually surfaces
Nowhere near the cause. A container module reports:
✓ Applied 9 field(s) from environment: prefix, ibmcloud.region, ibmcloud.resource_group,
cluster.openshift_version, cluster.vpc_cidr, cluster.create, cluster.workers_per_zone,
cluster.public_gateway, resources.transit_gateway.existing
step 'cluster-up' failed (exit 1)
Nine fields where there should be ten — the missing one is the API key, and you only notice by counting. An opentofu module fails as a Terraform provider error:
Resource Manager service: "The BearerToken property is required but was not specified."
Neither message mentions credentials, templates, or providers. I spent a while checking project bindings, module variables, platform_provider, and a PUT of the key onto the module — all dead ends — before reading the resolver.
Setting provider to ibm fixed it immediately: the global-fallback line disappears and the key reaches the container.
Why ibmcloud is the natural thing to write
Every adjacent field on the same object is spelled that way — ibmcloud_api_key, ibmcloud_resource_group, has_ibmcloud_api_key, ibm_cos_instance_name. provider: "ibm" is the odd one out, and nothing at the API layer hints at it.
Suggested fix
Validate provider against the values resolution actually handles — a Literal["aws","ibm",…] on the create/update model, so a wrong value is a 422 at the point of the mistake rather than a Terraform error hours later:
{"detail":[{"loc":["body","provider"],"msg":"must be one of: aws, ibm, gcp, azure"}]}
Accepting "ibmcloud" as an alias for "ibm" would also be defensible given the field naming, but rejecting it is better than storing it.
Worth considering as a second guard: when a project has a credential template whose provider yields no credentials, log that at WARNING rather than falling through to the global path at INFO. "Template found, contributed nothing, falling back" is the sentence that would have saved the investigation.
POST /api/credential-templatesaccepts any string asprovider, stores it, and returns 200. Only two values are ever matched when credentials are resolved, so anything else creates a template that looks correct everywhere in the API and silently injects nothing.Observed on v4.0.0-rc1 (
ghcr.io/f5devcentral), container engine.What I did
Provisioning a fresh instance, I created the IBM template the obvious way:
201, and it reads back looking entirely healthy:The project shows
credential_template_id: 2. Nothing anywhere says it is wrong.What happens
Credential resolution branches on two literals (
credentials_service.py:190,253):"ibmcloud"matches neither, so resolution falls off the end and lands on the global fallback. The worker log is the only place the problem is visible, and even there it reads like information rather than an error:There is no IBM key in the deployment's
.env, soIBMCLOUD_API_KEYis never injected. Every module then runs without it.How it actually surfaces
Nowhere near the cause. A container module reports:
Nine fields where there should be ten — the missing one is the API key, and you only notice by counting. An opentofu module fails as a Terraform provider error:
Neither message mentions credentials, templates, or providers. I spent a while checking project bindings, module variables,
platform_provider, and aPUTof the key onto the module — all dead ends — before reading the resolver.Setting
providertoibmfixed it immediately: the global-fallback line disappears and the key reaches the container.Why
ibmcloudis the natural thing to writeEvery adjacent field on the same object is spelled that way —
ibmcloud_api_key,ibmcloud_resource_group,has_ibmcloud_api_key,ibm_cos_instance_name.provider: "ibm"is the odd one out, and nothing at the API layer hints at it.Suggested fix
Validate
provideragainst the values resolution actually handles — aLiteral["aws","ibm",…]on the create/update model, so a wrong value is a 422 at the point of the mistake rather than a Terraform error hours later:{"detail":[{"loc":["body","provider"],"msg":"must be one of: aws, ibm, gcp, azure"}]}Accepting
"ibmcloud"as an alias for"ibm"would also be defensible given the field naming, but rejecting it is better than storing it.Worth considering as a second guard: when a project has a credential template whose provider yields no credentials, log that at WARNING rather than falling through to the global path at INFO. "Template found, contributed nothing, falling back" is the sentence that would have saved the investigation.