pulumi-cloudflare
pulumi-cloudflare copied to clipboard
Cannot create ApiToken after upgrade to 6x
Describe what happened
Creating an ApiToken was working in 5.49.1 but breaks after upgrading to 6.1.2 with the message below.
error: cloudflare:index/apiToken:ApiToken resource 's3-presigned-url' has a problem: Invalid Configuration for Read-Only Attribute. Cannot set value for this attribute as the provider has marked it as read-only. Remove the configuration line setting the value.
Refer to the provider documentation or contact the provider developers for additional information about configurable and read-only attributes that are supported.. Examine values at 's3-presigned-url.policies[0].permissionGroups[0].name'.
Sample program
5x working program
const permissionGroups = await cloudflare.getApiTokenPermissionGroups({provider: cloudflareProvider});
const r2ReadGroup = permissionGroups.r2["Workers R2 Storage Bucket Item Read"];
const s3PresignedUrlToken = new cloudflare.ApiToken("s3-presigned-url",
{
name: pulumi.interpolate`${namePrefixLower}-s3-presigned-url-${out.values!.resources_suffix}`,
expiresOn: '2035-12-31T00:00:00Z',
policies: [{
permissionGroups: [r2ReadGroup],
resources: filesBucket.name.apply(name => ({[`com.cloudflare.edge.r2.bucket.${conf.cloudflare_account_id}_default_${name}`]: "*"})),
}],
}, {provider: cloudflareProvider});
6x refactor
const permissionGroupsList = await cloudflare.getApiTokenPermissionGroupsList({}, {provider: cloudflareProvider});
const r2ReadGroup = permissionGroupsList.results.find(g=> g.name =="Workers R2 Storage Bucket Item Read")!;
const s3PresignedUrlToken = new cloudflare.ApiToken("s3-presigned-url",
{
name: pulumi.interpolate`${namePrefixLower}-s3-presigned-url-${out.values!.resources_suffix}`,
expiresOn: '2035-12-31T00:00:00Z',
policies: [{
permissionGroups: [r2ReadGroup], // <<== Offending line
effect: "allow",
resources: filesBucket.name.apply(name => ({[`com.cloudflare.edge.r2.bucket.${conf.cloudflare_account_id}_default_${name}`]: "*"})),
}],
}, {provider: cloudflareProvider});
It's hard to tell from the docs what exactly the problem may be as the name attribute is not called out as readonly
Log output
No response
Affected Resource(s)
No response
Output of pulumi about
CLI
Version 3.157.0
Go Version go1.24.1
Go Compiler gc
Plugins KIND NAME VERSION resource aws 6.78.0 resource awsx 2.21.1 resource cloudflare 6.1.2 resource cloudflare 5.49.1 resource docker 4.6.1 resource docker 3.6.1 resource docker-build 0.0.8 language nodejs 3.157.0 resource random 4.18.1 resource random 4.18.0 resource std 2.2.0
Host OS Microsoft Windows 11 Pro Version 10.0.26100 Build 26100 Arch x86_64
This project is written in nodejs: executable='C:\Program Files\nodejs\node.exe' version='v22.14.0'
Additional context
No response
Contributing
Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).
Thanks for filing this @johnbaro my team will pick up to try to root cause.
Looks like you are setting https://github.com/pulumi/pulumi-cloudflare/blob/895770afc6f30bd9dceee5297f75b57bc57901ee/sdk/nodejs/types/input.ts#L3196 but the provider rejects it.
The provider models it as Computed which is the cause of the problem:
https://github.com/cloudflare/terraform-provider-cloudflare/blob/72a74193561eaaf004a9aa21499c44ca729e8bd3/internal/services/api_token/schema.go#L70
Looks like there is a bug in pulumi-terraform-bridge that should not have exposed it, possibly duplicative of https://github.com/pulumi/pulumi-terraform-bridge/issues/2893
Once we fix the problem though the compiler will force some code updates on your program that you can attempt fixing now before Pulumi ships the update.
permissionGroups: [r2ReadGroup], // <<== Offending line
The id attribute is required and meta is optional. Possibly something like this could work?
permissionGroups: [{id: r2ReadGroup.id, meta: r2ReadGroup.meta}], // <<== Offending line
@t0yv0, thanks for the reply.
That workaround results in more errors unfortunately.
Changing it as per permissionGroups: [{id: r2ReadGroup.id}]
results in
error: objectEncoder failed on property "policies": encList failed while encoding element 0 ({map[effect:{allow} permissionGroups:{[{6a018a9f2fc74eb6b293b0c548f38b39}]} resources:{map[com.cloudflare.edge.r2.bucket.[REDACTED]:{*}]}]}): objectEncoder failed on property "permission_groups": encList failed while encoding element 0 ({6a018a9f2fc74eb6b293b0c548f38b39}): Expected an Object PropertyValue, found string ("{6a018a9f2fc74eb6b293b0c548f38b39}")
Looking at verbose logs, this comes through:
I0503 11:06:56.075745 77424 rpc.go:292] Unmarshaling property for RPC[Provider[cloudflare, 0xc001e0e370].Invoke(cloudflare:index/getApiTokenPermissionGroupsList:getApiTokenPermissionGroupsList).returns]: id={6a018a9f2fc74eb6b293b0c548f38b39}
I0503 11:06:56.075745 77424 rpc.go:292] Unmarshaling property for RPC[Provider[cloudflare, 0xc001e0e370].Invoke(cloudflare:index/getApiTokenPermissionGroupsList:getApiTokenPermissionGroupsList).returns]: name={Workers R2 Storage Bucket Item Read}
I0503 11:06:56.075745 77424 rpc.go:292] Unmarshaling property for RPC[Provider[cloudflare, 0xc001e0e370].Invoke(cloudflare:index/getApiTokenPermissionGroupsList:getApiTokenPermissionGroupsList).returns]: scopes={[{com.cloudflare.edge.r2.bucket}]}
It looks like the result of getApiTokenPermissionGroupsList is unmarshaling the id as an object (id={6a018a9f2fc74eb6b293b0c548f38b39}) instead of a string (id=6a018a9f2fc74eb6b293b0c548f38b39`), although the message seems to state the opposite.
I've spent some time here trying to repro, unfortunately it looks like our test CloudFlare account does not have R2 buckets enabled so I could not readily test with that, so I cooked up a program that uses zones instead. This provisions without error for me purely on V6 (pulumi up to create), note it still has this:
permissionGroups: [{id: r2ReadGroup.id}], // <<== Offending line
import * as pulumi from "@pulumi/pulumi";
import * as cloudflare from "@pulumi/cloudflare";
import * as random from "@pulumi/random";
const config = new pulumi.Config();
const accountId = config.require("accountId");
const permissionGroupsList = cloudflare.getApiTokenPermissionGroupsListOutput({}, {});
const r2ReadGroup = permissionGroupsList.apply(g => g.results.find(r => r.name == "Zone WAF Write")!);
const randomStr = new random.RandomString("random", {
length: 8,
overrideSpecial: "-",
special: true,
upper: false,
});
const zone = new cloudflare.Zone("my-zone", {
name: randomStr.result.apply(r => `ts-test-cloudflare-${r}-zone.com`),
account: {id: accountId},
});
new cloudflare.ApiToken(
"s3-presigned-url",
{
name: `t0yv0-test-1160-token`,
expiresOn: '2035-12-31T00:00:00Z',
policies: [{
permissionGroups: [{id: r2ReadGroup.id}], // <<== Offending line
effect: "allow",
resources: zone.id.apply(id => {
const x: {[key: string]: string} = {};
x["com.cloudflare.api.account.zone.*"] = "*";
return x;
}),
}],
});
CLI
Version 3.167.0
Go Version go1.24.2
Go Compiler gc
Plugins
KIND NAME VERSION
resource cloudflare 6.1.2
language nodejs 3.167.0
resource random 4.18.2
Host
OS darwin
Version 14.6.1
Arch arm64
This project is written in nodejs: executable='/run/current-system/sw/bin/node' version='v20.19.0'
Current Stack: anton-pulumi-corp/cloudflare-1160/dev
TYPE URN
pulumi:pulumi:Stack urn:pulumi:dev::cloudflare-1160::pulumi:pulumi:Stack::cloudflare-1160-dev
pulumi:providers:cloudflare urn:pulumi:dev::cloudflare-1160::pulumi:providers:cloudflare::default_6_1_2
pulumi:providers:random urn:pulumi:dev::cloudflare-1160::pulumi:providers:random::default_4_18_2
random:index/randomString:RandomString urn:pulumi:dev::cloudflare-1160::random:index/randomString:RandomString::random
cloudflare:index/zone:Zone urn:pulumi:dev::cloudflare-1160::cloudflare:index/zone:Zone::my-zone
cloudflare:index/apiToken:ApiToken urn:pulumi:dev::cloudflare-1160::cloudflare:index/apiToken:ApiToken::s3-presigned-url
Found no pending operations associated with dev
Backend
Name pulumi.com
URL https://app.pulumi.com/anton-pulumi-corp
User anton-pulumi-corp
Organizations anton-pulumi-corp, moolumi, demo, pulumi
Token type personal
Dependencies:
NAME VERSION
typescript 5.8.3
@pulumi/cloudflare 6.1.2
@pulumi/pulumi 3.167.0
@pulumi/random 4.18.2
@types/node 18.19.87
Pulumi locates its logs in /var/folders/gd/3ncjb1lj5ljgk8xl5ssn_gvc0000gn/T/com.apple.shortcuts.mac-helper// by default
That works for me too, digging further, it's the existing resources from the old provider I believe.
This is the old resource
{
"__defaults": [],
"expiresOn": "2035-12-31T00:00:00Z",
"name": "xxx-ssz0ooff",
"policies": [
{
"__defaults": [
"effect"
],
"effect": "allow",
"permissionGroups": [
"6a018a9f2fc74eb6b293b0c548f38b39"
],
"resources": {
"com.cloudflare.edge.r2.bucket.xxx-files-bucket-dev-ssz0ooff": "*"
}
}
]
}
vs the new
{
"expiresOn": "2035-12-31T00:00:00Z",
"name": "t0yv0-test-1160-token",
"policies": [
{
"effect": "allow",
"permissionGroups": [
{
"id": "fb6778dc191143babbfaa57993f1d275"
}
],
"resources": {
"com.cloudflare.api.account.zone.*": "*"
}
}
]
}
I can't find a migration guide for this upgrade, there is one for terraform
I'll remove the token from state then import it again with the new provider and see if that fixes it.
I've checked on this with the team, indeed it looks like we are lacking a migration guide at this point but there're some short notes in the release notes https://github.com/pulumi/pulumi-cloudflare/releases/tag/v6.0.0
import is a good fallback! Let us know if that gets you unstuck here.
It looks like you are correct in your analysis, ApiToken.policies.permissionGroups needs a state migration for the old state to be re-shaped to be seamlessly understood for the new schema. Ideally this would have been a migration on the upstream provider but we can consider adding some code on Pulumi side if the problem affects a lot of users.
Delete and import worked fine, this is all sorted now.
Thanks for your support.