Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lambda function generated execution role IAM understanding #1298

Closed
unknown1337 opened this issue Feb 24, 2023 · 8 comments
Closed

Lambda function generated execution role IAM understanding #1298

unknown1337 opened this issue Feb 24, 2023 · 8 comments
Assignees
Labels
question Further information is requested

Comments

@unknown1337
Copy link

unknown1337 commented Feb 24, 2023

Amplify CLI Version

10.7.2

Question

Goal: enable a lambda function to mutation a graphql schema Company

Method 1, NOK:

  • amplify add function test (incl resource access permissions->api allow)
  • graphql schema 1:
  @model
  @auth(rules: [{ allow: owner }]) {
  id: ID!
  name: String!
  owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
} 
  • amplify mock function test

Result NOK: "Not Authorized to access listCompanies on type Model"

Method 2, OK, but not understood & documentation mismatch?

  • amplify add function test (incl resource access permissions->api allow)
  • graphql schema 1:
  @model
  @auth(rules: [{ allow: owner,**{ provider: iam, allow: private }** }]) {
  id: ID!
  name: String!
  owner: String @auth(rules: [{ allow: owner, operations: [read, delete] }])
}
  • amplify mock function test

Result OK: 'list of companies'

Questions

  1. When the amplify CLI generates the IAM policies for the lambda execution policies, is it still required to add { provider: iam, allow: private } in the @auth gql scheme? According my tests, yes, but this is contradicting the documentation "...these functions have special access privileges that are scoped based on their IAM policy instead of any particular @auth rule."
  2. What is meant with The function can only be added when the GraphQL API with IAM authorization exists."". Does this imply that when running the amplify add api IAM needs to be selected as Auth mechanism?
  3. in order to mock the function, am I correct that my IAM USER selected when running amplify init is 'used'? Thus I have to add the correct policies to that IAM user to allow GQL permissions? For now I added administrator access (not really the least priviledge WoW).
  4. if I only allow regular users (=app visitors) to register through cognito, is there than a risk that they are allowed to update the resource company due to { provider: iam, allow: private } (private = any signed-in user has access.) IFF possible some context (or suggested reading material) would help me understand and learn.
  5. update: after some more testing I got again the error when running amplify mock function: Not Authorized to access listCompanies on type ModelCompanyConnection. I have no clue what could be wrong as the model contains { provider: iam, allow: private } & my local IAM user (local-aws-info.json) has the AdministratorAccess policy assigned. Any tips?

THANKS A LOT!

@unknown1337 unknown1337 added pending-triage question Further information is requested labels Feb 24, 2023
@josefaidt
Copy link
Contributor

Hey @unknown1337 👋 thanks for raising this!

When the amplify CLI generates the IAM policies for the lambda execution policies, is it still required to add { provider: iam, allow: private } in the @auth gql scheme? According my tests, yes, but this is contradicting the documentation "...these functions have special access privileges that are scoped based on their IAM policy instead of any particular @auth rule."

Yes, granting your Lambda access to your GraphQL API through the amplify add/update function flow will generate the necessary IAM policy for your Function, however the schema will need to include the private IAM auth rule on the models you wish to interact with via IAM.

What is meant with The function can only be added when the GraphQL API with IAM authorization exists."". Does this imply that when running the amplify add api IAM needs to be selected as Auth mechanism?

Correct, yes, IAM will need to be selected as an auth mechanism

in order to mock the function, am I correct that my IAM USER selected when running amplify init is 'used'? Thus I have to add the correct policies to that IAM user to allow GQL permissions? For now I added administrator access (not really the least priviledge WoW).

I do not believe IAM is authorized in amplify mock function, however the policies will be generated automatically for you in the Function's CloudFormation template.

if I only allow regular users (=app visitors) to register through cognito, is there than a risk that they are allowed to update the resource company due to { provider: iam, allow: private } (private = any signed-in user has access.) IFF possible some context (or suggested reading material) would help me understand and learn.

Although the shorthand auth rule syntax can be a bit confusing, the allow: private rule will use Cognito by default unless we specify provider: iam. Specifying the following auth rules will ensure the model's records are only accessible by their respective owners and private IAM calls

{ allow: owner }
{ allow: private, provider: iam }

This can even be scoped down to ensure private IAM calls will only be able to "read" records

{ allow: owner }
{ allow: private, provider: iam, operations: [read] }

update: after some more testing I got again the error when running amplify mock function: Not Authorized to access listCompanies on type ModelCompanyConnection. I have no clue what could be wrong as the model contains { provider: iam, allow: private } & my local IAM user (local-aws-info.json) has the AdministratorAccess policy assigned. Any tips?

Were the resources pushed prior to running amplify mock api?

@unknown1337
Copy link
Author

unknown1337 commented Feb 24, 2023

WOW, thanks for the response. Gained some great insights already :)

Yes, granting your Lambda access to your GraphQL API through the amplify add/update function flow will generate the necessary IAM policy for your Function, however the schema will need to include the private IAM auth rule on the models you wish to interact with via IAM.

  1. am I correct that generating a function without configuring Do you want to access other resources in this project from your Lambda function? Yes that the IAM role that is generated for the function does not allow access to my graphql api yet?
  2. When do I need to allow api access to the function using the CLI? And do I need to add a @Auth directive with IAM to the corresponding model?
    a) if I use an unsigned request with (how is this an IAM request?) And do I need to add a @Auth directive with IAM to the corresponding model?
 const options = {
    method: 'POST',
    headers: {
      'x-api-key': GRAPHQL_API_KEY
    },
    body: JSON.stringify({ query, variables })
  };

b) if I sign my request (this I assume is an IAM request as the default provider will provide temporary IAM auth credentials?) And do I need to add a @Auth directive with IAM to the corresponding model?

  const signer = new SignatureV4({
**    credentials: defaultProvider(),**
    region: AWS_REGION,
    service: 'appsync',
    sha256: Sha256
  });

I do not believe IAM is authorized in amplify mock function, however the policies will be generated automatically for you in the Function's CloudFormation template.

Thanks, I will try to see if I can find this in the cloudformation code

Specifying the following auth rules will ensure the model's records are only accessible by their respective owners and private IAM calls

  1. Could you elaborate a bit on the definition of a private IAM call and the difference between executing a cognito userpool call? please see 2a and 2b

Were the resources pushed prior to running amplify mock api?

Yes, thanks, but it was already pushed. I managed to get it working :) by adding

{
  "adminRoleNames": ["amplify-CR"]
}

Thanks :)

@unknown1337
Copy link
Author

@josefaidt , could you maybe help me a bit further, I REALLY value your feedback. Thanks!

@josefaidt
Copy link
Contributor

Hey 👋 apologies for the delay!

am I correct that generating a function without configuring Do you want to access other resources in this project from your Lambda function? Yes that the IAM role that is generated for the function does not allow access to my graphql api yet?

Correct, you can inspect the generated IAM policy in the Function's CloudFormation template, however it will not be created until you push.

When do I need to allow api access to the function using the CLI? And do I need to add a @Auth directive with IAM to the corresponding model?

If you want to interact with the GraphQL API in that function. For instance, if you have a PostConfirmation Cognito Trigger that creates a UserProfile record after a user confirms signup.

Could you elaborate a bit on the definition of a private IAM call and the difference between executing a cognito userpool call? please see 2a and 2b

Private IAM will call using the role's credentials, where calling via Cognito User Pool (from a Lambda) will require you to pass the user's JWT. In the case of a PostConfirmation trigger you can call the GraphQL API on the user's behalf by constructing and passing their ID token -- if you are using owner auth you will not need to construct the owner argument as the user's sub::username. Both are achievable with either auth mechanism.

@unknown1337
Copy link
Author

unknown1337 commented Mar 17, 2023

Thanks a lot @josefaidt , most of it is clear!

in the case of a PostConfirmation trigger you can call the GraphQL API on the user's behalf by constructing and passing their ID token

Where will the token be verified (if e.g. the claims were not altered by the user? I think answer 2a and b are correct?)

  1. the lambda function receives a verified token thus I can check the claims directly and perform a dynamodb insert using the function's IAM role.
  2. the lambda function receives an UNverified token, so I either:
    a) need to verify the token (how to get the publicKey? shouldnt this be a secret key?)
 const result = await jwt.verify(authorizationToken, publicKey);
const   isAuthorized = result && result.fooClaim && result.fooClaim=== 'bar'

b) or needs to call the graphql api as that api will perform the authorization (correct alternative?)

Thanks!

@josefaidt
Copy link
Contributor

Hey @unknown1337 apologies for the delay!

Where will the token be verified

In the Company model's auth resolver. However you can instead use allow: private, provider: iam and pass the model's owner information manually using the convention <sub>::<username>

or needs to call the graphql api as that api will perform the authorization (correct alternative?)

Yes, calls directly to your GraphQL API will perform the authorization, and enables streaming the mutations in the event you have subscriptions running.

If you are looking to insert data directly to the underlying Company DynamoDB table you can do so by passing the required information including the owner value (if "owner" auth is used)

@unknown1337
Copy link
Author

Thanks, so does this imply that the tokens passed to a lambda function are 'never' checked for validity. This implies that I

  1. have to check the token & claim validity in that lambda function if I perform direct dynamodb table mutations
  2. I dont need to check token & claim validity if I call the Gql api endpoint from that lambda function (as the gql resolver will then check validity).

correct?

Copy link

github-actions bot commented Apr 4, 2024

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants