cfn-language-discussion
cfn-language-discussion copied to clipboard
Transform AWS::LanguageExtensions failed with: Condition layout is incorrect -- But I'm not using Conditions anywhere in the template.
Community Note
- Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
- Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
- If you are interested in working on this issue or have submitted a pull request, please leave a comment
Tell us about the bug
What goes wrong? Please describe the issue in as much detail as possible.
NOTE: This has the same title as 147 and I suppose it may have the same underlying cause, but in 147 there's a workaround in that reordering the creation condition allows him to create the stack. I'm not using conditions. At all. There are no conditions in this template, which means I can't reorder them, which means I have no decent workaround.
The following code:
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::LanguageExtensions'
Description: 'IAM OIDC Provider configuration for kubernetes cluster'
Parameters:
ClusterName:
Type: String
Description: The Cluster Name. Used to uniquely identify created roles.
OpenIdConnectIssuerUrl:
Type: String
Description: The OpenIdConnect issuer URL.
RoleMapDocument:
Type: String
Description: The Document containing the RoleMap, as json string.
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "OpenIdConnect"
Parameters:
- ClusterName
- OpenIdConnectIssuerUrl
- RoleMapDocument
Mappings:
'Fn::Transform':
Name: JMESPath
Parameters:
Path: "@"
Document: !Ref RoleMapDocument
Resources:
OIDCThumbprint:
Type: Custom::OIDCThumbprint
Properties:
ServiceToken: !ImportValue OpenIdConnectThumbprint
OpenIdConnectIssuerUrl: !Ref OpenIdConnectIssuerUrl
OIDCProvider:
Type: AWS::IAM::OIDCProvider
Properties:
ClientIdList:
- sts.amazonaws.com
ThumbprintList:
- !GetAtt OIDCThumbprint.Thumbprint
Url: !Ref OpenIdConnectIssuerUrl
Tags:
- Key: StackName
Value: !Ref AWS::StackName
Fn::ForEach::Role:
- Name
- 'Fn::Transform':
Name: JMESPath
Parameters:
Path: "keys(RoleMap)"
Document: !Ref RoleMapDocument
- '&{Name}':
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Fn::ToJsonString:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Federated: !Ref OIDCProvider
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
'Fn::Transform':
Name: JMESPath
Parameters:
Path: "@"
Document:
Fn::Sub:
- '{ "${Provider}:aud": "sts.amazonaws.com", "${Provider}:sub": { "Fn::FindInMap" : [ "RoleMap", { "Ref" : "Name" }, "sub" ] } }'
- Provider: !Select [ 1, !Split [ "//", !Ref OpenIdConnectIssuerUrl ] ]
Description: !FindInMap [ RoleMap, !Ref Name, Description ]
ManagedPolicyArns: !FindInMap [ RoleMap, !Ref Name, ManagedPolicyArns ]
RoleName: !Sub '${ClusterName}-${Name}'
Path: !Ref Path
Tags:
- Key: StackName
Value: !Ref AWS::StackName
Outputs:
Arn:
Description: Arn for OpenIdConnect Provider
Value: !Ref OIDCProvider
Fn::ForEach::RoleOutput:
- Name
- 'Fn::Transform':
Name: JMESPath
Parameters:
Path: "keys(RoleMap)"
Document: !Ref RoleMapDocument
- '&{Name}':
Description: !FindInMap [ RoleMap, !Ref Name, Description ]
Value:
Ref: !Sub '${Name}'
Gives the following error when deployed via the command line:
Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state: For expression "Status" we matched expected path: "FAILED" Status: FAILED. Reason: Transform AWS::LanguageExtensions failed with: Condition layout is incorrect
Note that the transform JMESPath is a super simple macro that just does a JMESPath search (Path parameter) on a document (Document parameter). The value passed in for RoleMapDocument looks like this:
{"RoleMap":{"ALBControllerRole":{"ManagedPolicyArns":["arn:aws:iam::99999999999:policy/AWSLoadBalancerControllerIAMPolicy"],"sub":"system:serviceaccount:kube-system:aws-load-balancer-controller","Description":"Allows Ingresses to allocate EC2 Load Balancers."},"ExternalDNSRole":{"ManagedPolicyArns":["arn:aws:iam::99999999999:policy/AWSExternalDNSUpdatePolicy"],"sub":"system:serviceaccount:kube-system:external-dns","Description":"Allows the External Dns service to update Route53."}}}
Which, since the search path is identity, produces the following Mappings entry:
RoleMap: ALBControllerRole: ManagedPolicyArns: ['arn:aws:iam::99999999999:policy/AWSLoadBalancerControllerIAMPolicy'] sub: system:serviceaccount:kube-system:aws-load-balancer-controller Description: Allows Ingresses to allocate EC2 Load Balancers. ExternalDNSRole: ManagedPolicyArns: ['arn:aws:iam::99999999999:policy/AWSExternalDNSUpdatePolicy'] sub: system:serviceaccount:kube-system:external-dns Description: Allows the External Dns service to update Route53.
Within the scope of the ForEach:
`
- 'Fn::Transform': Name: JMESPath Parameters: Path: "keys(RoleMap)" Document: !Ref RoleMapDocument `
Produces [ "ALBControllerRole", "ExternalDNSRole" ], which should result in the creation of two resources, and the second call essentially just reconstitutes an object from a string (because I can sub into a key name in an embedded string version of an object but not an object directly.
Expected behavior
Create the stack with the OIDC Provider and two roles configured to allow cluster services to assume them.
Observed behavior
Failed to create the changeset: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state: For expression "Status" we matched expected path: "FAILED" Status: FAILED. Reason: Transform AWS::LanguageExtensions failed with: Condition layout is incorrect
Test cases
Please include a minimal CloudFormation template here that reproduces the issue
I'll see if there's a more minimal repro, perhaps one that allows me to omit the macro, and will update if I can come up with one. Given that the error message is pretty obviously unrelated to whatever the problem is, it may take some time.
Additional context
Anything else we should know?
I found a much, much more concise repro. First: This works fine (simply add this output to any valid stack that uses LanguageExtensions):
Outputs:
Fn::ForEach::DebugOutput:
- Name
- [ A, B ]
- '&{Name}Policies':
Description: Debug.
Value:
Fn::ToJsonString:
Cond_ition: Irrelevant
You get two outputs:
APolicies | {"Cond_ition":"Irrelevant"} | Debug. | -
BPolicies | {"Cond_ition":"Irrelevant"} | Debug. | -
This doesn't work, but gives a different error that my previous repro:
Fn::ForEach::DebugOutput:
- Name
- [ A, B ]
- '&{Name}Policies':
Description: Debug.
Value:
Fn::ToJsonString:
Condition: Irrelevant
Error:
Waiter encountered a terminal failure state: For expression "Status" we matched expected path: "FAILED" Status: FAILED. Reason: Transform AWS::LanguageExtensions failed with: Fn::ToJsonString does not support Condition intrinsic function for resource Fn::ForEach::DebugOutput
This isn't a Condition, though, "Condition" just happens to be the name of a key that's shoved into a Json string for output.