Experiencing a weird issue regarding permissions, ...
# help
d
Experiencing a weird issue regarding permissions, I have 4 different stacks giving permissions to a lambda function the ability to read dynamo streams and to send messages to a SQS DLQ. The function find:
Copy code
lambda.Function.fromFunctionAttributes(
            this,
            "EventsPublisherFunction",
            {
                functionArn: ssm.StringParameter.valueForStringParameter(
                    this,
                    RESONANCE_EVENTS_PUBLISHER_FUNCTION_ARN_SSM_PARAM
                ),
                role: iam.Role.fromRoleArn(
                    this,
                    "EventsPublisherFunctionRole",
                    ssm.StringParameter.valueForStringParameter(
                        this,
                        RESONANCE_EVENTS_PUBLISHER_FUNCTION_ROLE_ARN_SSM_PARAM
                    )
                ),
            }
        );
A sample grant:
Copy code
distributionDynamoDlq.grantSendMessages(this.eventsPublisherFunction);
        this.distributionDynamoTable.grantStreamRead(
            this.eventsPublisherFunction
        );
The issue is that only the LAST stack deployed sticks, as in it overwrites the other stacks permissions, and only grants
eventsPublisherFunction
its resources. Is this expected behavior?
t
hm this isn't what I would expect
d
me neither...quite surprised...
I really dont want to have to centralize this logic if I dont have to
t
I'm not sure why this isn't working, perhaps something to do with the imported function? Could you test by doing the same thing on a function you create inside one of your stacks?
d
well, since the behavior is between two stacks, I cant create the function in both...
t
I meant creating a function in one then passing it around vs using an imported function
d
oh, like an export...right...
t
I generally only need to use the static
fromXXX
functions when I have resources created outside of CDK that I need to deal with
d
I actually exclusively use SSM params (and from...) over Cfn exports for flexibility reasons.
it would be difficult for me to accomplish this testing case, as all of the stacks are in different apps, but I think your inclination is the right one, its something with the import.
actually, maybe one would work.
this behavior happens for both when the function is imported via
props
or if via
fromFunctionAttributes
.
re-testing to be sure
incorrect, this WORKS via props and only occurs when using
fromFunctionAttributes
.
Quote from the CDK slack:
I think you're fundamentally breaking one of the tenants of CF and role management, tbh. Each one of your 4 stacks is told 'I get to control permissions' because you import the role and then assign permissions to it. None of the 4 stacks understands that the other 3 exist, and therefore they overwrite the previous changes, because it was told "I get to control this role", but that's not really what you are trying to do. You are trying to have each stack control part of the role. And that's not going to be easy with CFN and the CDK.
So, you could centralize this and keep everything pretty 'stock' in your CDK and CFN. Or, you can write some custom code (behind a CustomResource) that would add to the policy, rather than replace.
honestly had no idea this was an anti-pattern
t
hm I also don't perceive it that way. I think of it as a single role and each stack is adding policies
d
agreed, but evidently
grant
!==
add
the quote is from Matthew Bonig, the owner of CDK.dev , so it would be hard to find a more authoritative source.
actually, I have a new issue then... if I am supposed to give permissions in the lambda's owner stack, how do I add the eventSourceMapping in the dynamoTable stack (which requires the permission), while still maintaining least permissions?
I guess I have to flip the mapping too...
all feels wrong, but I think its because you wouldnt go this direction in code design...
f
@Derek Kershner just gave this a try on my end, I think the issue is that each of the 4 stacks are creating an IAM policy with the same name 
EventsPublisherFunctionRolePolicy531F5E73
, and the last deployed stack overrides it
Instead, use a different ID for the imported IAM Role, ie.
${id}
is stack id
Copy code
iam.Role.fromRoleArn(
  this,
  `${id}-EventsPublisherFunctionRole`,
  ...
)
d
oooh, nice, I think I like this idea better than centralizing. Good to have options, thanks @Frank.