Open skryshi opened 2 years ago
hi @skryshi - thanks for the issue! The IAM-based "@auth" rules are scoped down to only match the auth/unauth roles that Amplify generate. This exact-match allows us to perform field-level authorization based on IAM.
The AppSync console will use the IAM user that your AWS Account is signed in as and therefore won't match the auth/unauth role. To work around this, we provide a mechanism called "AdminRoles" but these have special access privileges that are scoped based on their IAM policy, not @auth
rule. I just added some more documentation to make this clearer https://github.com/aws-amplify/docs/pull/3828/files
@renebrandel I am having this issue also.
I have a schema like:
type IncidentNote
@model(timestamps: { createdAt: "createdAt" })
@key(
name: "notesByIncident"
fields: ["incidentId", "createdAt"]
queryField: "notesByIncident"
)
@auth(
rules: [
{
allow: owner
ownerField: "monitoringCenterId"
operations: [read, create]
identityClaim: "custom:monitoringCenterId"
}
{ allow: private, provider: iam, operations: [create] }
]
) {
id: ID!
incidentId: ID!
note: String!
monitoringCenterId: ID!
modifiedBy: String!
writtenBy: String
createdAt: AWSDateTime!
shareExternal: Boolean
}
Prior to upgrading to 7.5.2 I was able to create entities using the AWSAppSyncClient
with auth type AWS_IAM
, no I am not.
@localsecurity-emily which IAM role are you using to sign the requests?
How would I check that? I should have mentioned it's only an issue when I am mocking amplify locally. Prior to the upgrade I didn't have any issue, now I can't make requests using the IAM credentials, I just end up with:
Error: GraphQL error: undefined
InvalidClientTokenId: The security token included in the request is invalid.
The client is initialized as:
graphqlClient = new appsync.AWSAppSyncClient({
url: process.env.API_LOCALSECURITYGRAPHQL_GRAPHQLAPIENDPOINTOUTPUT,
region: process.env.AWS_REGION,
auth: {
type: "AWS_IAM",
credentials: {
accessKeyId: "fake",
secretAccessKey: "fake",
},
},
disableOffline: true,
});
process.env.API_LOCALSECURITYGRAPHQL_GRAPHQLAPIENDPOINTOUTPUT = http://192.168.0.244:20002/graphql
process.env.AWS_REGION = us-fake-1
@renebrandel Thank you, that worked.
@localsecurity-emily - I see. I've renamed the task to make it clearer for the engineering team to pick it up.
+1 on this one, I've got the same issue - not being able to use IAM authorization when mocking locally, both lambda and the local graphiQL interface since upgrading Amplify CLI version. I back-tracked, and it seems to stop working for me from CLI version 6.4.0 (did a big upgrade from an earlier version).
For local graphiQL, I'm getting the following back
{
"data": {
"getUser": null
},
"errors": [
{}
]
}
Hosted AppSync GraphiQL interface didn't work for me until I added the console role to the 'custom-roles.json' file like @renebrandel mentioned (not an ideal solution imo, but it worked). Could it be that this is also related to an issue with the role-names which are now used for authorization? I.e. no local roles defined during mocking?
The mock server now supports IAM, and when the request is signed with AccessKey ASIAVJKIAM-AuthRole
, the request gets authrole
and any other AccessKey is treated as user with UnAuth role. This change was released in Amplify CLI v7.6.3
Thanks @yuth!
Can confirm that it works for me now by changing the following:
Lambda
const AWS = require('aws-sdk')
const AWSAppSyncClient = require('aws-appsync').default;
require('cross-fetch/polyfill');
const mockCredentials = {
"accessKeyId": "ASIAVJKIAM-AuthRole",
"secretAccessKey": "fake"
}
const credentials = AWS.config.credentials || mockCredentials
exports.appsync = new AWSAppSyncClient({
url: process.env.API_<APINAME>_GRAPHQLAPIENDPOINTOUTPUT,
region: process.env.REGION,
auth: {
type: 'AWS_IAM',
credentials: credentials,
},
disableOffline: true,
});
And local graphiQL by setting role to Auth in Update auth:
@yuth @renebrandel thank you so much for your work on this bug :) I have two related questions, I hope it's appropriate to add them here:
The mock server now supports IAM, and when the request is signed with AccessKey ASIAVJKIAM-AuthRole, the request gets authrole and any other AccessKey is treated as user with UnAuth role.
AWS documentation now discusses special 'adminRoles' (thanks @renebrandel for adding that documentation!). Is there any way to mock these roles? I have a setup where a lambda function calls my api and is granted access via adminRole logic. I can get this to run locally in a very hacky way: 1) I mock the signer credentials with the ASIAVJKIAM-AuthRole key and 2) I have to update my schema with an @auth([{allow:private, provider:iam}]) annotation. I need 2) because my mock environment is using a non-adminRole to grant this permission. But 2) is super undesirable because if it is accidentally submitted it opens my entire schema to my users. Is there any way to mock this lamda as running as an adminRole and have the mock api recognize it? Even a hack like "keys like ASIAVJKIAM-mock-\<roleName> are treated as associated with that roleName" would be helpful.
The example above uses appsync.AWSAppSyncClient with configured credentials... does that work for issuing actual data get/create/etc requests to GraphQL, or is that client just meant for configuring AppSync? I ask because I could not find a "send graphql query" function in that module's documentation, and the amplify docs use AWS.Signers.v4 directly. It would be great if I'm just missing something in the docs and this client can be used to correctly sign everything :)
@eettaa what auth do you have in your schema for non mock version where you're using a non-admin role
@yuth I use cognito pools-based auth for most of my schema. Something like
type TestInt @model @auth(rules: [{allow: owner}]) {
id: ID!
num: Int!
owner: String!
}
The case I'm discussing above is that I also have a lambda function that I want to be able to update TestInt. So I run amplify update function > [lambda name] > (add api access)
... This then results in adminRoles being added to the auth checks in the compiled VTL resolvers. But while running mock it appears impossible for the lambda function to actually impersonate its prod auth role.
+1 having the same problem. Used to work on previous transformer, but on v2 it stopped working, and I'm now unable to access my graphql apis through my lambda on my mock server. Literally having to code in the dark and push it to test in the cloud, which makes development really really slow.
if there was a way to sign the request with the auth role so we could "simulate" the cloud, that would be a step forward. Keep to know how you "hack it" so you could get it running, because that would at least help me to test it locally.
The example above uses appsync.AWSAppSyncClient with configured credentials... does that work for issuing actual data get/create/etc requests to GraphQL, or is that client just meant for configuring AppSync? I ask because I could not find a "send graphql query" function in that module's documentation, and the amplify docs use AWS.Signers.v4 directly. It would be great if I'm just missing something in the docs and this client can be used to correctly sign everything :)
@eettaa Yes, this is used to do mutations / queries to GraphQL. The client will automatically sign the request. To give an example of how I used it:
const appsync = require('./graphql-client').appsync;
const gql = require('graphql-tag');
const getUserQuery = gql`
query GetEmployee($id: ID!) {
getEmployee(id: $id) {
id
email
managerId
createdAt
updatedAt
owner
manager {
id
email
}
}
}
`;
exports.getEmployeeById = async (id) => {
return appsync
.query({
query: getUserQuery,
fetchPolicy: 'no-cache',
variables: {
id: id,
},
})
.then((res) => res)
.catch((err) => err);
};
And then just run await getEmployeeById(dataSubjectId);
in your lambda function
You can do the same with .mutation
@rafaelfaria have you tried my example above? I fixed this by using a specific set of mock credentials, which signs the request made by the graphQL client (in mock) as if it was done by an authenticated role.
const mockCredentials = {
"accessKeyId": "ASIAVJKIAM-AuthRole",
"secretAccessKey": "fake"
}
@lbrinker-1 I tried this and it worked 🎉
const mockCredentials = {
"accessKeyId": "ASIAVJKIAM-AuthRole",
"secretAccessKey": "fake"
}
const credentials = endpoint === "localhost" ? mockCredentials : AWS.config.credentials
const signer = new AWS.Signers.V4(req, 'appsync', true);
signer.addAuthorization(credentials, AWS.util.date.getDate());
Thanks @lbrinker-1 for discussion on the AppSync client, I'll try it out. From above:
AWS documentation now discusses special 'adminRoles' (thanks @renebrandel for adding that documentation!). Is there any way to mock these roles?
@yuth @renebrandel as I believe they are the Amplify folks on the thread- any guidance on that kind of IAM mocking?
So, I end up back to this post :).
From one side with the help of this discussion, I managed to fix the issue I was having trying to access Queries and Mutations from my lambda.
However, I have recently updated to the latest version (7.6.21 ) and now, I keep getting Unauthorised, even though my schema worked before and seems to be correct (see below).
In the mock amplify console, I am able to query my data using the IAM - Auth, however, when I use it on my website, I can't test it locally, doesn't matter what I do, still comes back as Unauthorized.
I have tried adding a user with Administrator policy attached to it, to the custom-roles.json
and adding this file to the root of the API. Despite being able to see the user I added in the resolvers, I still keep getting Unauthorised. I really don't know what to try anymore.
Any help would be appreciated.
My resolver has the "rafael-iam", the user I created with Admin policy attached to it.
my custom-roles.json
looks like:
{
"adminRoleNames": ["rafael-iam"]
}
and I can see it applying it on the resolvers
#set( $adminRoles = ["us-east-1_PFGnwOWuc_Full-access/CognitoIdentityCredentials","us-east-1_PFGnwOWuc_Manage-only/CognitoIdentityCredentials","lambdaNewsFeed-dev","rafael-iam"] )
This is my schema (used to work before). I have some one-to-many logic going on.
type Event @model
@auth(
rules: [
{ allow: private, operations: [read], provider: iam },
{ allow: groups, groups: ["Admin"] }
]
)
{
id: ID!
title: String!
image: String
description: String
tokenAddress: String @index(name: "byEvent")
token: Token @belongsTo(fields: ["tokenAddress"])
}
on my code, I call the get method as
const { data } = (await API.graphql({
query: getEvent,
variables: { id: eventId },
authMode: GRAPHQL_AUTH_MODE.AWS_IAM,
})) as GetEventResult;
Looking forward to see if there is any ideas to try.
@rafaelfaria can you try to stop the mock, delete the amplify/backend/api/
I've had this a couple of times in the past where I was getting a random unauthorised, and that fixed it for me. Didn't have the time to dive deep into the root cause, but might be worth trying that?
Hi @lbrinker-1 ,
That has happened to me before, so I have tried that a few times.
I kid you not, I think I have tried everything. My latest attempt is to literally delete amplify and redo everything again, which is not ideal but I am desperate. This used to work and now it just doesn't. I can't test anything that needs IAM.
So I rebuild the whole amplify project using the latest version (7.6.21). Still having problems :/. Then I did with (7.6.13) because this is the last one I remember updating, that would still work. However, no luck there either.
Any reason why custom-roles.json wouldn't work?
I am literally out of ideas :/
@rafaelfaria Sorry, I missed your comment. Have you managed to fix your issue, or are you still encountering it?
@lbrinker-1 Im facing this issue but actually in AppSync console
@Enzaik do you mean the local or remote GraphiQL interface? If it's remote - make sure to follow the steps that Rene mentioned above, where you add the appropriate IAM role/user to custom-roles.json
. (documentation: https://docs.amplify.aws/cli/graphql/authorization-rules/#use-iam-authorization-within-the-appsync-console). If it's local, make sure to update the auth in the GraphiQL interface to use the 'Auth' role.
@LaurensBrinker in remote GraphiQL playground. And I did create custom-roles.json
, with no success. Please let me know if a new issue needs to be open
@LaurensBrinker still happening. Can't really test my application by mocking it, I have to develop and push it every single time. Works fine when it's in my dev environment.
I haven't updated to the latest version (8) yet. Not sure if there is any fix there, but will try next.
Hi there - just stumbled across this issue. My backend contains a few different lambdas that access AppSync directly by using the "admin roles" functionality mentioned above. This all works well when deployed. However, I get unauthorised when trying to hit the amplify mock APIs locally. After a bit of digging I'm pretty sure it is because my models intentionally do not contain { allow: private, provider: iam }
, as doing so would allow authenticated users access to my API models, which I definitely do not want. I can get things to work by using the ASIAVJKIAM-AuthRole
access key but only if I also add { allow: private, provider: iam }
to my models, which is undesirable.
The ideal solution would be to be able to specify a custom user ARN for accessing the mock APIs locally, which would enable me to fake my local requests as one of my allowed admin user ARNs
Any help / assistance appreciated
After a bit of digging I'm pretty sure it is because my models intentionally do not contain { allow: private, provider: iam }, as doing so would allow authenticated users access to my API models, which I definitely do not want.
@jleskovar "Authenticated Users" in what sense? I'm using the same { allow: private, provider: iam }
to give full access to my Lambda function, but I use {allow: owner}
, which is setup to use Cognito as authentication type, to use only allow Cognito users access to their own items. Or e.g. {allow: private, provider: userPools, operations: [read]}
to allow authenticated users Read access.
@Enzaik / @jleskovar I'm not quite sure tbh, I think it might be best to create a separate issue, link this one, and dive deeper into the steps required to replicate. And then someone from the Amplify team can have a deeper look.
This is an issue for us as well. Tried the mock credentials. mock API_KEY works but our schema authorization bars us from using it.
I'm also trying to get the local ( mocked ) version of the API to work. using
type Team @model @auth(rules : [{ allow: private, provider: iam}]) {
id: ID!
name: String!
description: String
}
Not sure how to inject the mock auth based on the discussion above, at least through any of the exposed Amplify APIs.
@rafaelfaria and @abstractalchemist I was able to test my lambda locally by creating an accessKey in IAM for my authorized user in custom-rules.json. With that in my request I put:
credentials = {
accessKeyId: "USER_ACCESS_KEY_ID",
secretAccessKey: "USER_SECRET_ACCESS_KEY,
}
Was the custom-role mock issue solved somehow - I think this will be a much better solution.
Hi there - just stumbled across this issue. My backend contains a few different lambdas that access AppSync directly by using the "admin roles" functionality mentioned above. This all works well when deployed. However, I get unauthorised when trying to hit the amplify mock APIs locally. After a bit of digging I'm pretty sure it is because my models intentionally do not contain
{ allow: private, provider: iam }
, as doing so would allow authenticated users access to my API models, which I definitely do not want. I can get things to work by using theASIAVJKIAM-AuthRole
access key but only if I also add{ allow: private, provider: iam }
to my models, which is undesirable.The ideal solution would be to be able to specify a custom user ARN for accessing the mock APIs locally, which would enable me to fake my local requests as one of my allowed admin user ARNs
Any help / assistance appreciated
Before opening, please confirm:
How did you install the Amplify CLI?
npm
If applicable, what version of Node.js are you using?
v16.6.1
Amplify CLI Version
7.5.2
What operating system are you using?
Mac
Amplify Categories
api
Amplify Commands
Not applicable
Describe the bug
Queries and mutations with IAM @auth are failing with
Not Authorized to access
exception.I created a fresh project to test out the new Amplify release 7.5.2. Used this graphQL model:
Using AWS AppSync console, run this query:
When I run this query as a UserPool user, I get back some data. When I run this query as IAM, I get this exception:
As a sanity check, I have verified that IAM should have full access to queries:
The above unauthorized exception also happens for IAM
createTest()
mutation. (And might also happen for other mutations and subscriptions, I haven't tested everything).Expected behavior
IAM queries and mutations succeed, returning either some date or null if there is no data.
Reproduction steps
amplify init
amplify add auth
amplify add api
amplify push
GraphQL schema(s)
Log output
Additional information
No response