Open Tedsterh opened 2 years ago
Can you please post the full error message you get from the lambda?
When I create a lambda using Amplify, it automatically gets given a policy called amplify-lambda-execution-policy
which allows it access to all Query endpoints, so I don't see how the countTraits
would be excluded from this.
I just get an unauthorised message
{
path: [Array],
data: null,
errorType: 'Unauthorized',
errorInfo: null,
locations: [Array],
message: 'Not Authorized to access countTrait on type Query'
}
The auth rules for the model
type Trait @model @searchable @count
@auth(rules: [
{allow: owner, ownerField: "userID", operations: [read]},
{allow: private, provider: iam},
{allow: public, operations: [read], provider: apiKey},
{allow: groups, groups: ["User"], operations: [read]},
{allow: groups, groups: ["Admin"]},
]) {}
{
"Fn::Join": [
"",
[
"arn:aws:appsync:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":apis/",
{
"Ref": "apianimalGraphQLAPIIdOutput"
},
"/types/Query/*"
]
]
}
It has all the right permissions in its policy
Hi, can you please use code blocks with the correct (graphql
) syntax highlighting please? https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks
Can you also post the lambda role document, by finding the lambda function in the console, opening "Configuration", then "Permissions", then "View role document"
Sorry just gone back and edited those Heres the Statements from the role document
"statements": [
{
"action": "appsync:GraphQL",
"effect": "Allow",
"resource": "arn:aws:appsync:us-east-2:<APP-ID>:apis/<API-ID>/types/Query/*",
"service": "appsync",
"source": {
"index": "0",
"policyName": "amplify-lambda-execution-policy",
"policyType": "inline"
}
},
{
"action": "appsync:GraphQL",
"effect": "Allow",
"resource": "arn:aws:appsync:us-east-2:<APP-ID>:apis/<API-ID>/types/Mutation/*",
"service": "appsync",
"source": {
"index": "0",
"policyName": "amplify-lambda-execution-policy",
"policyType": "inline"
}
}
]
I'm a bit stumped by this, actually. Because this part of the docs suggests that it's the lambda role policy that grants it access to the API, and we can see from what you've posted that it should have access to all Query
types.
Maybe consider asking on one of the Amplify forums and if you find anything I can try to fix it here.
Yes it's very bizarre, I shall open a ticket with them. It's weird because it also doesn't let me me call it with the API key either, only a user pool token
I have the same problem with my queries that have lambda functions attached using the @function
Oh, if the API key isn't working either than that's a bit less surprising. Can you see if the cognito pool has any policies that might explain why it works properly?
How can I check what permissions a user from a userPool might have? Theres nothing in its CloudFormation about the api
Try opening the AppSync API in the console and clicking Settings
It looks like it defaults to allow?
That might relate to it. Can you also show me the AppSync resolver for your working (e.g. listTrait
) queries? They should be in your Amplify app: amplify/backend/api/<resource_name>/build/resolvers
It looks like there is 4 different resolvers for the listTrait
Query.listTraits.auth.1.req.vtl
Query.listTraits.postAuth.1.req.vtl
Query.listTraits.req.vtl
Query.listTraits.res.vtl
The auth ones are of interest to me.
Okay so in the auth.1
## [Start] Authorization Steps. **
$util.qr($ctx.stash.put("hasAuth", true))
#set( $isAuthorized = false )
#set( $primaryFieldMap = {} )
#if( $util.authType() == "API Key Authorization" )
#set( $isAuthorized = true )
#end
#if( $util.authType() == "IAM Authorization" )
#set( $adminRoles = ["us-east-2_<KEY>_Full-access/CognitoIdentityCredentials","us-east-2_<KEY>_Manage-only/CognitoIdentityCredentials","thenftproject24bf3d5f24bf3d5fPostConfirmation-dev"] )
#foreach( $adminRole in $adminRoles )
#if( $ctx.identity.userArn.contains($adminRole) && $ctx.identity.userArn != $ctx.stash.authRole && $ctx.identity.userArn != $ctx.stash.unauthRole )
#return($util.toJson({}))
#end
#end
#if( !$isAuthorized )
#if( ($ctx.identity.userArn == $ctx.stash.authRole) || ($ctx.identity.cognitoIdentityPoolId == "us-east-2:<POOL_ID>" && $ctx.identity.cognitoIdentityAuthType == "authenticated") )
#set( $isAuthorized = true )
#end
#end
#end
#if( $util.authType() == "User Pool Authorization" )
#if( !$isAuthorized )
#set( $staticGroupRoles = [{"claim":"cognito:groups","entity":"User"},{"claim":"cognito:groups","entity":"Admin"}] )
#foreach( $groupRole in $staticGroupRoles )
#set( $groupsInToken = $util.defaultIfNull($ctx.identity.claims.get($groupRole.claim), []) )
#if( $groupsInToken.contains($groupRole.entity) )
#set( $isAuthorized = true )
#break
#end
#end
#end
#if( !$isAuthorized )
#set( $authFilter = [] )
#set( $role0 = $util.defaultIfNull($ctx.identity.claims.get("username"), $util.defaultIfNull($ctx.identity.claims.get("cognito:username"), "___xamznone____")) )
#if( $role0 != "___xamznone____" )
$util.qr($authFilter.add({"userID": { "eq": $role0 }}))
#end
#if( !$authFilter.isEmpty() )
$util.qr($ctx.stash.put("authFilter", { "or": $authFilter }))
#end
#end
#end
#if( !$isAuthorized && $util.isNull($ctx.stash.authFilter) )
$util.unauthorized()
#end
$util.toJson({"version":"2018-05-29","payload":{}})
## [End] Authorization Steps. **
The postAuth.1
## [Start] Sandbox Mode Disabled. **
#if( !$ctx.stash.get("hasAuth") )
$util.unauthorized()
#end
$util.toJson({})
## [End] Sandbox Mode Disabled. **
Okay, then I guess it must be the authorization resolver that is telling your lambda it isn't authorized. But I'm surprised it's doing that, because my resolver never calls $util.unauthorized()
Are your resolvers built in the build folder as well? I can't seem to find them in there
I guess they aren't (which might suggest they aren't hooking into the same process that handles auth). But you can see them in the AppSync console anyway.
In the count resolver on AppSync it doesn't have anything for apiKey
#set( $isAuthorized = false )
#if( $util.authType() == "API Key Authorization" )
#end
and with the one that list traits
#if( $util.authType() == "API Key Authorization" )
#set( $isAuthorized = true )
#end
And for the IAM on it is slightly different than the list one
#if( $util.authType() == "IAM Authorization" )
#set( $adminRoles = ["us-east-2_<KEY>_Full-access/CognitoIdentityCredentials","us-east-2_<KEY>_Manage-only/CognitoIdentityCredentials","thenftproject24bf3d5f24bf3d5fPostConfirmation-dev] )
#foreach( $adminRole in $adminRoles )
#if( $ctx.identity.userArn.contains($adminRole) && $ctx.identity.userArn != $ctx.stash.authRole && $ctx.identity.userArn != $ctx.stash.unauthRole )
#return($context.source.traitCount)
#end
#end
$util.unauthorized()
#end
which has got this
#if( $util.authType() == "IAM Authorization" )
#set( $adminRoles = ["us-east-2_<KEY>_Full-access/CognitoIdentityCredentials","us-east-2_<KEY>_Manage-only/CognitoIdentityCredentials","thenftproject24bf3d5f24bf3d5fPostConfirmation-dev"] )
#foreach( $adminRole in $adminRoles )
#if( $ctx.identity.userArn.contains($adminRole) && $ctx.identity.userArn != $ctx.stash.authRole && $ctx.identity.userArn != $ctx.stash.unauthRole )
#return($util.toJson({}))
#end
#end
#if( !$isAuthorized )
#if( ($ctx.identity.userArn == $ctx.stash.authRole) || ($ctx.identity.cognitoIdentityPoolId == "us-east-2:<POOL_ID>" && $ctx.identity.cognitoIdentityAuthType == "authenticated") )
#set( $isAuthorized = true )
#end
#end
#end
Okay well it looks like both of them just call unauthorized()
no matter what, which explains why this is happening. I wasn't aware that AppSync
did this, because those above resolvers were not written by me, they must be auto generated. And also it seems they don't get generated unless you have auth enabled, so I didn't even know they existed.
Ah no worries, is there a way to overwrite those resolvers? Is this something that can be done?
In theory it should be fixable. I think what's happened is that the @auth
directive generates its own resolvers, but it's not propertly doing it for my custom resolver. So I have to work out why.
The function directive made by amplify uses this to handle the auth
// Create the GraphQL resolvers.
const resolverId = ResolverResourceIDs.ResolverResourceID(config.resolverTypeName, config.resolverFieldName);
let resolver = createdResources.get(resolverId);
const requestTemplate: Array<Expression> = [
qref(`$ctx.stash.put("typeName", "${config.resolverTypeName}")`),
qref(`$ctx.stash.put("fieldName", "${config.resolverFieldName}")`),
];
const authModes = [context.authConfig.defaultAuthentication, ...(context.authConfig.additionalAuthenticationProviders || [])].map(
mode => mode?.authenticationType,
);
if (authModes.includes(AuthorizationType.IAM)) {
const authRoleParameter = (context.stackManager.getParameter(IAM_AUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString;
const unauthRoleParameter = (context.stackManager.getParameter(IAM_UNAUTH_ROLE_PARAMETER) as cdk.CfnParameter).valueAsString;
requestTemplate.push(
qref(
`$ctx.stash.put("authRole", "arn:aws:sts::${
cdk.Stack.of(context.stackManager.rootStack).account
}:assumed-role/${authRoleParameter}/CognitoIdentityCredentials")`,
),
qref(
`$ctx.stash.put("unauthRole", "arn:aws:sts::${
cdk.Stack.of(context.stackManager.rootStack).account
}:assumed-role/${unauthRoleParameter}/CognitoIdentityCredentials")`,
),
);
}
requestTemplate.push(obj({}));
Would this be able to be used in the resolver so we can use this is a lambda?
Hmm, this is part of it, but not all of it, I think.
Hi, sorry its me again,
So I am able to call
searchTraits
andlistTraits
from inside the function but I cannot callcountTraits
, I am also unable to use the an apiKey to call the count even though my model has the correct auth on it.I have tried to remove permissions and add them again, but no luck.