pulumi-cloudflare icon indicating copy to clipboard operation
pulumi-cloudflare copied to clipboard

Cannot create ApiToken after upgrade to 6x

Open johnbaro opened this issue 7 months ago • 6 comments

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).

johnbaro avatar Apr 29 '25 23:04 johnbaro

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 avatar May 01 '25 20:05 t0yv0

@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.

johnbaro avatar May 03 '25 01:05 johnbaro

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

t0yv0 avatar May 05 '25 17:05 t0yv0

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.

johnbaro avatar May 06 '25 10:05 johnbaro

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.

t0yv0 avatar May 06 '25 15:05 t0yv0

Delete and import worked fine, this is all sorted now.

Thanks for your support.

johnbaro avatar May 06 '25 22:05 johnbaro