Mark Reed
Mark Reed

Reputation: 95315

How to get a role's name/ARN into its own AssumeRole policy?

I've got a CloudFormation stack that creates several IAM roles. I have the somewhat unusual-sounding requirement to include a statement in the role's AssumeRole policy preventing the role from assuming itself. The role names are constructed using Fn::Join with the value of a parameter, so in order to reproduce the role name and construct its ARN in the policy statement, I have to duplicate that expression.

Is there any way to cache the result of the expression so that I don't have to repeat it? There are several of these roles and each one has the same issue. Can I define a parameter whose default value includes the value of another parameter and reference that? Or can I use Fn:GetAtt inside the definition of a resource to access other attributes of the resource being defined (such as its name)?

If not, is there another solution besides repeating the name-construction expressions? This is something I would put in the locals block in Terraform...

Since this wound up not being possible, I ran this shell one-liner to update each role after creation, to prevent it from assuming itself:

aws iam update-assume-role-policy \
  --role-name "$role" \
  --policy-document file://<(
      aws iam get-role --role-name "$role" |
       jq '.Role | .Arn as $arn | .AssumeRolePolicyDocument | 
           .Statement+=[{"Effect": "Deny", 
                         "Action": "sts:AssumeRole", 
                         "Principal": { "AWS": $arn }}]')

Upvotes: 1

Views: 1668

Answers (1)

Marcin
Marcin

Reputation: 238537

Is there any way to cache the result of the expression so that I don't have to repeat it?

Sadly, there is no such way in plain CloudFormation.

Can I define a parameter whose default value includes the value of another parameter and reference that?

Unfortunately, parameters can't refer other parameters.

Or can I use Fn:GetAtt inside the definition of a resource to access other attributes of the resource being defined (such as its name)?

You can't get any return values of a resource before it is fully constructed.

Having sad that, if you know the role name up-front, you could construct its ARN yourself. Role ARNs have known format. However, you want be able to use it as a Principal in the same role, as principles must be valid. Thus, you can't use ARN of a role as a principle before it actually exists.

If you want to add ARN of a role to be its own Principal, you would have to construct a custom resource in CloudFormation. Thus, you first create your role normally, and then use the custom resource (in a form of lambda function) to update it's Principal element.

Also since you have to duplicate a lot of elements in your templates, a general solution to this is by means of CloudFormation macros.

Either way, it seems to me that because your requirements regarding templates are not normally supported out of the box, you will have to develop some custom resources and/or macros to fully satisfy them. With custom resources and macros you can basically achieve what ever you want, but it will require extra development.

Upvotes: 1

Related Questions