Reputation: 51
I'm trying to create my cognito resources through cloudformation. Below template works just fine;
AWSTemplateFormatVersion: 2010-09-09
Resources:
CognitoAuthRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Federated: cognito-identity.amazonaws.com
Action:
- 'sts:AssumeRoleWithWebIdentity'
Condition:
StringEquals:
'cognito-identity.amazonaws.com:aud':
Ref: CognitoIdentityPool
'ForAnyValue:StringLike':
'cognito-identity.amazonaws.com:amr': authenticated
CognitoUserPool:
Type: 'AWS::Cognito::UserPool'
Properties:
UsernameAttributes:
- email
AutoVerifiedAttributes:
- email
CognitoUserPoolClient:
Type: 'AWS::Cognito::UserPoolClient'
Properties:
UserPoolId:
Ref: CognitoUserPool
ExplicitAuthFlows:
- ADMIN_NO_SRP_AUTH
GenerateSecret: false
CognitoIdentityPool:
Type: 'AWS::Cognito::IdentityPool'
Properties:
AllowUnauthenticatedIdentities: true
CognitoIdentityProviders:
- ClientId:
Ref: CognitoUserPoolClient
ProviderName:
'Fn::GetAtt':
- CognitoUserPool
- ProviderName
CognitoIdentityPoolRoles:
Type: 'AWS::Cognito::IdentityPoolRoleAttachment'
Properties:
IdentityPoolId:
Ref: CognitoIdentityPool
Roles:
authenticated:
'Fn::GetAtt':
- CognitoAuthRole
- Arn
But when I add RoleMappings attribute to CognitoIdentityPoolRoles resource, Cloudformation returns an error and can not create the stack. Modified resource is below;
CognitoIdentityPoolRoles:
Type: 'AWS::Cognito::IdentityPoolRoleAttachment'
Properties:
IdentityPoolId:
Ref: CognitoIdentityPool
Roles:
authenticated:
'Fn::GetAtt':
- CognitoAuthRole
- Arn
RoleMappings:
AmbiguousRoleResolution: Deny
Type: Rules
RulesConfiguration:
Rules:
- Claim: 'custom:role'
MatchType: Equals
Value: viewer
RoleARN:
'Fn::GetAtt':
- CognitoAuthRole
- Arn
- Claim: 'custom:role'
MatchType: Equals
Value: editor
RoleARN:
'Fn::GetAtt':
- CognitoAuthRole
- Arn
As you can see above RoleMappings type is Rules. You could try with Token parameter and the outcome doesn't change.
CognitoIdentityPoolRoles:
Type: 'AWS::Cognito::IdentityPoolRoleAttachment'
Properties:
IdentityPoolId:
Ref: CognitoIdentityPool
Roles:
authenticated:
'Fn::GetAtt':
- CognitoAuthRole
- Arn
RoleMappings:
AmbiguousRoleResolution: Deny
Type: Token
Unfortunately error message doesn't give any clue, I can not make any progress and stuck in this stage.
Status Type Logical ID Status Reason
CREATE_FAILED AWS::Cognito::IdentityPoolRoleAttachment CognitoIdentityPoolRoles Internal Failure
How can I make IdentityPoolRoleAttachment with RoleMappings work?
Upvotes: 4
Views: 1659
Reputation: 94
I've got the same issue, and unfortunately as i could see the RoleMappings are not supported yet into CloudFormation, so we ever will catch this 'Internal Failure'. But there is some workarounds that you can do to solve your problem. In my case I've used the boto3 library to invoke IdentityPool updates inside a Lambda Function and I've used the Severless Framework, but the same purpose could be did with SAM or another CloudFormation stack framework. So, I did these steps using 2 separated stacks:
service: cognito-template
provider:
name: aws
stage: dev
region: us-east-1
stackName: cognito-template-${self:provider.stage}-resources
custom:
system:
name: myapp
cognitoclientname: MyAppClient
resources:
Resources:
# ## ## ## ## ## ## ## ## ## ## ## ## ## Definicao de Usuários Cognito UserPool ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: ${self:custom.system.name}userpool
AdminCreateUserConfig:
AllowAdminCreateUserOnly: True
UnusedAccountValidityDays: 30
EmailVerificationMessage: Clique no link abaixo para verificar seu endereço de e-mail. {####}
EmailVerificationSubject: Seu link de verificação
MfaConfiguration: OFF
Policies:
PasswordPolicy:
MinimumLength: 8
RequireLowercase: false
RequireNumbers: false
RequireSymbols: false
RequireUppercase: false
Schema:
- AttributeDataType: String
DeveloperOnlyAttribute: false
Mutable: true
Name: name
Required: true
- AttributeDataType: String
DeveloperOnlyAttribute: false
Mutable: true
Name: family_name
Required: true
- AttributeDataType: String
DeveloperOnlyAttribute: false
Mutable: true
Name: email
Required: true
- AttributeDataType: String
DeveloperOnlyAttribute: false
Mutable: true
Name: phone_number
Required: true
- AttributeDataType: String
DeveloperOnlyAttribute: false
Mutable: true
Name: gender
Required: true
- AttributeDataType: String
DeveloperOnlyAttribute: false
Mutable: true
Name: permission
Required: false
UsernameAttributes:
- email
- phone_number
# ## ## ## ## ## ## ## ## ## ## ## ## ## Client Cognito ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
AppUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: ${self:custom.system.cognitoclientname}
ExplicitAuthFlows:
- ADMIN_NO_SRP_AUTH
- USER_PASSWORD_AUTH
GenerateSecret: false
RefreshTokenValidity: 1
UserPoolId: !Ref UserPool
# ## ## ## ## ## ## ## ## ## ## ## ## ## Provedor de Identidade Cognito ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
AppIdentityPool:
Type: AWS::Cognito::IdentityPool
Properties:
IdentityPoolName: ${self:custom.system.name}identitypool
AllowUnauthenticatedIdentities: false
CognitoIdentityProviders:
- ClientId: !Ref AppUserPoolClient
ProviderName: !GetAtt UserPool.ProviderName
AppIdentitiesRolesAttachment:
Type: AWS::Cognito::IdentityPoolRoleAttachment
DependsOn:
- AppIdentityPool
- CognitoAuthorizedRole
- CognitoUnAuthorizedRole
Properties:
IdentityPoolId: !Ref AppIdentityPool
Roles:
authenticated: !GetAtt CognitoAuthorizedRole.Arn
unauthenticated: !GetAtt CognitoUnAuthorizedRole.Arn
CognitoAuthorizedRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref AppIdentityPool
"ForAnyValue:StringLike":
"cognito-identity.amazonaws.com:amr": authenticated
Policies:
- PolicyName: "CognitoAuthorizedPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "mobileanalytics:PutEvents"
- "cognito-sync:*"
- "cognito-identity:*"
Resource: "*"
- Effect: "Allow"
Action:
- "lambda:InvokeFunction"
Resource: "*"
CognitoUnAuthorizedRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref AppIdentityPool
"ForAnyValue:StringLike":
"cognito-identity.amazonaws.com:amr": unauthenticated
Policies:
- PolicyName: "CognitoUnauthorizedPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "mobileanalytics:PutEvents"
- "cognito-sync:*"
Resource: "*"
AdministradorRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref AppIdentityPool
"ForAnyValue:StringLike":
"cognito-identity.amazonaws.com:amr": authenticated
Policies:
- PolicyName: "CognitoAdministradorPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "mobileanalytics:PutEvents"
- "cognito-sync:*"
Resource: "*"
GerenciadorRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Federated: "cognito-identity.amazonaws.com"
Action:
- "sts:AssumeRoleWithWebIdentity"
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref AppIdentityPool
"ForAnyValue:StringLike":
"cognito-identity.amazonaws.com:amr": authenticated
Policies:
- PolicyName: "CognitoAdministradorPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "mobileanalytics:PutEvents"
- "cognito-sync:*"
Resource: "*"
- Effect: "Allow"
Action:
- "s3:GetObject"
- "s3:PutObject"
Resource:
- "arn:aws:s3:::${self:custom.system.name}/public/*"
# ## ## ## ## ## ## ## ## ## ## ## ## ## IAM Permission to lambda script execute update into IdentityPoolRoleMappings ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #
MigrationScriptRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- lambda.amazonaws.com
Action:
- "sts:AssumeRole"
Policies:
- PolicyName: "MigrationScriptPolicy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "cognito-idp:*"
- "cognito-identity:*"
- "iam:*"
Resource: "*"
Outputs:
UserPoolId:
Value: !Ref UserPool
Export:
Name: "UserPool::Id"
UserPoolArn:
Value: !GetAtt UserPool.Arn
Export:
Name: "UserPool::Arn"
UserPoolClientId:
Value: !Ref AppUserPoolClient
Export:
Name: "AppUserPoolClient::Id"
AppIdentityPoolId:
Value: !Ref AppIdentityPool
Export:
Name: "AppIdentityPool::Id"
AdministradorRoleArn:
Value: !GetAtt AdministradorRole.Arn
Export:
Name: "AdministradorRole::Arn"
GerenciadorRoleArn:
Value: !GetAtt GerenciadorRole.Arn
Export:
Name: "GerenciadorRole::Arn"
MigrationScriptRoleArn:
Value: !GetAtt MigrationScriptRole.Arn
Export:
Name: "MigrationScriptRole::Arn"
service: cognito-template
provider:
name: aws
stage: dev
region: us-east-1
stackName: cognito-template-${self:provider.stage}-functions
functions:
migration-script:
handler: lambda_function.handler
runtime: python3.6
role:
Fn::ImportValue: !Sub MigrationScriptRole::Arn
environment:
USER_POOL_REGION: us-east-1 # here you can change to you preferred region if you want
USER_POOL_ID:
Fn::ImportValue: !Sub UserPool::Id
USER_POOL_CLIENT_ID:
Fn::ImportValue: !Sub AppUserPoolClient::Id
IDENTITY_POOL_ID:
Fn::ImportValue: !Sub AppIdentityPool::Id
ADMINISTRADOR_ROLE_ARN:
Fn::ImportValue: !Sub AdministradorRole::Arn
GERENCIADOR_ROLE_ARN:
Fn::ImportValue: !Sub GerenciadorRole::Arn
Finally, the code of the lambda function to execute an update via boto3 call, for that, i've used the python3.6, but can use Node(must see the boto3 docs for Node)
import boto3
import os
def handler(event, context):
setup_cognito()
return event
def setup_cognito():
define_cognito_attributes()
create_cognito_identity_roles()
def create_cognito_identity_roles():
user_pool_region = os.environ['USER_POOL_REGION']
user_pool_id = os.environ['USER_POOL_ID']
user_pool_client_id = os.environ['USER_POOL_CLIENT_ID']
identity_pool_id = os.environ['IDENTITY_POOL_ID']
administrador_role = os.environ['ADMINISTRADOR_ROLE_ARN']
gerenciador_role = os.environ['GERENCIADOR_ROLE_ARN']
client_identity = boto3.client('cognito-identity')
client_idp = boto3.client('cognito-idp')
response = client_identity.get_identity_pool_roles(IdentityPoolId=identity_pool_id)
identity_provider = "cognito-idp.{}.amazonaws.com/{}:{}".format(user_pool_region, user_pool_id, user_pool_client_id)
options = {
'IdentityPoolId': response['IdentityPoolId'],
'Roles': response['Roles'],
'RoleMappings': {
identity_provider: {
'Type': 'Rules',
'AmbiguousRoleResolution': 'AuthenticatedRole',
'RulesConfiguration': {
'Rules': [
{
'Claim': 'custom:permission',
'MatchType': 'Equals',
'Value': 'ADMNISTRADOR',
'RoleARN': administrador_role
},
{
'Claim': 'custom:permission',
'MatchType': 'Equals',
'Value': 'GERENCIADOR',
'RoleARN': gerenciador_role
}
]
}
}
}
}
response = client_identity.set_identity_pool_roles(IdentityPoolId=options['IdentityPoolId'], Roles=options['Roles'], RoleMappings=options['RoleMappings'])
def define_cognito_attributes():
user_pool_id = os.environ['USER_POOL_ID']
user_pool_client_id = os.environ['USER_POOL_CLIENT_ID']
client = boto3.client('cognito-idp')
response = client.update_user_pool_client(
UserPoolId=user_pool_id,
ClientId=user_pool_client_id,
WriteAttributes=[
'custom:permission',
'phone_number',
'email',
'name',
'family_name',
'gender'
]
)
After create, the lambda function can be invoked by CLI or WEB 'Test'Button and then your role mappings will be assigned to you IdentityPool as you wish.
Hope it can help you! (Y)
Upvotes: 2