pulumi / pulumi-aws-native

AWS Native Provider for Pulumi
Apache License 2.0
94 stars 17 forks source link

Impossible to create an access policy (for a sitewise's portal) with pulumi #581

Open befou opened 2 years ago

befou commented 2 years ago

What happened?

Everytime I try to create an access policy with pulumi, I have this error : "creating resource: operation error CloudControl: CreateResource, https response error StatusCode: 400, RequestID: efbf5dec-5d82-4937-999b-79ef4d6b638a, api error ValidationException: Model validation failed (#/AccessPolicyResource/Portal: extraneous key [Id] is not permitted

/AccessPolicyIdentity/IamUser: extraneous key [Arn] is not permitted)".

Steps to reproduce

            user, err := iam.LookupUser(ctx, &iam.LookupUserArgs{
        UserName: "your_user_name@example.fr",
    }, nil)
    if err != nil {
        return err
    }

    //Here we create the sensor's access policy
    _, err = iotsitewise.NewAccessPolicy(ctx , "pulumi_sensor_access_policy", &iotsitewise.AccessPolicyArgs{
        AccessPolicyIdentity: &iotsitewise.AccessPolicyIdentityArgs{
            IamUser: &iotsitewise.AccessPolicyIamUserArgs{
                Arn: pulumi.String(user.Arn),
            },
        },
        AccessPolicyResource: &iotsitewise.AccessPolicyResourceArgs{
            Portal:  &iotsitewise.AccessPolicyPortalArgs{
                Id: pulumi_sensor_portal.PortalId,
            },
        },
        AccessPolicyPermission: pulumi.String("ADMINISTRATOR"),
    })
    if err != nil {
        return err
    }

Expected Behavior

The access policy is created and a new administrator is created in the portal.

Actual Behavior

"creating resource: operation error CloudControl: CreateResource, https response error StatusCode: 400, RequestID: efbf5dec-5d82-4937-999b-79ef4d6b638a, api error ValidationException: Model validation failed (#/AccessPolicyResource/Portal: extraneous key [Id] is not permitted

/AccessPolicyIdentity/IamUser: extraneous key [Arn] is not permitted)".

Versions used

CLI
Version 3.36.0 Go Version go1.17.12 Go Compiler gc

Plugins NAME VERSION aws 5.9.2 aws 4.38.1 aws-native 0.19.0 go unknown

Host
OS ubuntu Version 21.10 Arch x86_64

This project is written in go: executable='/usr/bin/go' version='1.17 linux/amd64'

Current Stack: dev

TYPE URN pulumi:pulumi:Stack urn:pulumi:dev::poc_project::pulumi:pulumi:Stack::poc_project-dev pulumi:providers:aws urn:pulumi:dev::poc_project::pulumi:providers:aws::default aws:iam/role:Role urn:pulumi:dev::poc_project::aws:iam/role:Role::befou_pulumi_sitewise_data_role aws:iam/role:Role urn:pulumi:dev::poc_project::aws:iam/role:Role::befou_pulumi_portal_role aws:iam/role:Role urn:pulumi:dev::poc_project::aws:iam/role:Role::befou_pulumi_access_role pulumi:providers:aws-native urn:pulumi:dev::poc_project::pulumi:providers:aws-native::default aws:iam/rolePolicy:RolePolicy urn:pulumi:dev::poc_project::aws:iam/rolePolicy:RolePolicy::befou_pulumi_policy_data aws-native:iotsitewise:AssetModel urn:pulumi:dev::poc_project::aws-native:iotsitewise:AssetModel::pulumi_befou_sensor_model aws-native:iot:TopicRule urn:pulumi:dev::poc_project::aws-native:iot:TopicRule::befou_pulumi_sitewise_horizontal_rule aws-native:iot:TopicRule urn:pulumi:dev::poc_project::aws-native:iot:TopicRule::befou_pulumi_sitewise_motor_rule aws-native:iot:TopicRule urn:pulumi:dev::poc_project::aws-native:iot:TopicRule::befou_pulumi_sitewise_white_rule aws-native:iot:TopicRule urn:pulumi:dev::poc_project::aws-native:iot:TopicRule::befou_pulumi_sitewise_vertical_rule aws-native:iot:TopicRule urn:pulumi:dev::poc_project::aws-native:iot:TopicRule::befou_pulumi_sitewise_endless_rule aws-native:iot:TopicRule urn:pulumi:dev::poc_project::aws-native:iot:TopicRule::befou_pulumi_sitewise_orange_rule aws:iam/rolePolicy:RolePolicy urn:pulumi:dev::poc_project::aws:iam/rolePolicy:RolePolicy::befou_pulumi_policy_portal aws:iam/rolePolicy:RolePolicy urn:pulumi:dev::poc_project::aws:iam/rolePolicy:RolePolicy::befou_pulumi_access_policy aws-native:iotsitewise:Portal urn:pulumi:dev::poc_project::aws-native:iotsitewise:Portal::pulumi_befou_sensor_portal aws-native:iotsitewise:Asset urn:pulumi:dev::poc_project::aws-native:iotsitewise:Asset::pulumi_befou_sensor_asset aws-native:iotsitewise:Project urn:pulumi:dev::poc_project::aws-native:iotsitewise:Project::pulumi_befou_sensor_project aws-native:iotsitewise:Dashboard urn:pulumi:dev::poc_project::aws-native:iotsitewise:Dashboard::pulumi_befou_sensor_dashboard

Found no pending operations associated with dev

Backend
Name pulumi.com URL https://app.pulumi.com/benjamin.foucher User benjamin.foucher Organizations benjamin.foucher

Dependencies: NAME VERSION github.com/pulumi/pulumi-aws/sdk/v5 v5.9.2 github.com/pulumi/pulumi/sdk/v3 v3.35.3

Pulumi locates its logs in /tmp by default

Additional context

I tried a lot of things but nothing worked.

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

viveklak commented 2 years ago

I am fairly certain this is because of a validation failure in the CFN provisioner used by cloudcontrol API. Would you be able to provide a minimal repro (apologies I am not familiar with the sitewise service)?

befou commented 2 years ago

Hi, thank you for the answer. Here is a repro for the failure :

package main

import (
    "github.com/pulumi/pulumi-aws-native/sdk/go/aws/iotsitewise"
    "github.com/pulumi/pulumi-aws/sdk/v4/go/aws/iam"
    "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    "log"
    "io/ioutil"
)

func main() {
    pulumi.Run(func(ctx *pulumi.Context) error {
        //here we get the json file of the role for Sitewise portal 
        jsonPortalRole, err := ioutil.ReadFile("./Ressources/SitewisePortalRole.json")
        if err != nil {
            log.Fatal(err)
        }
        portalRoleJson := string(jsonPortalRole)

        //here we create a role for the sensor's portal
        portalRole, err := iam.NewRole(ctx, "pulumi_portal_role", &iam.RoleArgs{
            Name:             pulumi.String("pulumi_portal_role"),
            AssumeRolePolicy: pulumi.Any(portalRoleJson),
        })
        if err != nil {
            return err
        }

        //here we get the json file of the role for the portal access
        jsonAccessRole, err := ioutil.ReadFile("./Ressources/SitewiseAccessRole.json")
        if err != nil {
            log.Fatal(err)
        }
        accessRoleJson := string(jsonAccessRole)

        //here we create a role for the sensor's portal
        accessRole, err := iam.NewRole(ctx, "pulumi_access_role", &iam.RoleArgs{
            Name:             pulumi.String("pulumi_access_role"),
            AssumeRolePolicy: pulumi.Any(accessRoleJson),
        })
        if err != nil {
            return err
        }

        //Here we create the sensor's portal
        pulumi_sensor_portal, err := iotsitewise.NewPortal(ctx , "pulumi_sensor_portal", &iotsitewise.PortalArgs{
            PortalContactEmail: pulumi.String("benjamin.foucher@smile.fr"),
            RoleArn: portalRole.Arn,
            PortalName: pulumi.String("befou_sensor_portal"),
            PortalDescription: pulumi.String("A portal created with pulumi"),
            PortalAuthMode: pulumi.String("IAM"),
            Alarms: &iotsitewise.AlarmsPropertiesArgs{
                AlarmRoleArn: accessRole.Arn,
            },
        })
        if err != nil {
            return err
        }

        user, err := iam.LookupUser(ctx, &iam.LookupUserArgs{
            UserName: "benjamin.foucher@smile.fr",
        }, nil)
        if err != nil {
            return err
        }

        //Here we create the sensor's access policy
        _, err = iotsitewise.NewAccessPolicy(ctx , "pulumi_access_policy", &iotsitewise.AccessPolicyArgs{
            AccessPolicyIdentity: &iotsitewise.AccessPolicyIdentityArgs{
                IamUser: &iotsitewise.AccessPolicyIamUserArgs{
                    Arn: pulumi.String(user.Arn),
                },
            },
            AccessPolicyResource: &iotsitewise.AccessPolicyResourceArgs{
                Portal:  &iotsitewise.AccessPolicyPortalArgs{
                    Id: pulumi_sensor_portal.PortalId,
                },
            },
            AccessPolicyPermission: pulumi.String("ADMINISTRATOR"),
        })
        if err != nil {
            return err
        }
        return nil
    })
}

The json file SitewisePortalRole.json : { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "monitor.iotsitewise.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }

The json file SitewiseAccessRole.json : { "Version": "2008-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "iotevents.amazonaws.com", "iot.amazonaws.com" ] }, "Action": "sts:AssumeRole" } ] }

gbegher commented 10 months ago

Any update on this? I just ran into the same error using the typescript library @pulumi/aws-native.

This seems to be the reason:

Here's my typescript code (irrelevant parts omitted)

const accessPolicy = new iotsitewise.AccessPolicy("access-policy", {
    accessPolicyPermission: "ADMINISTRATOR",
    accessPolicyIdentity: {
      iamRole: {
        arn: ..., // should NOT be capitalized
      },
    },
    accessPolicyResource: {
      portal: {
        id: ..., // should NOT be capitalized
      },
    },
  })

Here's what the Cloudformation docs say:

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotsitewise-accesspolicy-portal.html https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-iotsitewise-accesspolicy-iamrole.html

corymhall commented 1 week ago

Looking into this today it looks like this is due to those fields (id, arn, etc) not following the standard CFN format of having the first letter capitalized. There is an existing utility IrreversibleNames where we can store the name that won't be converted. We currently don't have a way of manually specifying values here, which we should add for cases like this.