amplify-category-api icon indicating copy to clipboard operation
amplify-category-api copied to clipboard

{ errorType: 'UnauthorizedException', message: 'Permission denied' } when calling mutation from GitHub action

Open duckbytes opened this issue 1 year ago β€’ 4 comments

How did you install the Amplify CLI?

No response

If applicable, what version of Node.js are you using?

16

Amplify CLI Version

12.10.1

What operating system are you using?

linux

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

No manual changes made

Describe the bug

I have a mutation query in my schema:

registerTenant(name: String, emailAddress: String, tenantName: String): Tenant @function(name: "plateletAddNewTenant-${env}") @auth(rules: [{allow: private, provider: iam}])

that I want to be able to call from a GitHub action. So far I've been able to set up permissions that allow the IAM account to call that mutation, but I'm getting this error:

{ errorType: 'UnauthorizedException', message: 'Permission denied' }

This is the policy I'm using for AppSync:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "appsync:GraphQL"
            ],
            "Resource": [
                "arn:aws:appsync:*:<id>:apis/*/types/Query/fields/getTenantByTenantName",
                "arn:aws:appsync:*:<id>:apis/*/types/Mutation/resolvers/registerTenant"
            ]
        }
    ]
}

It seems like it can call the getTenantByTenantName query fine, but gets that error on the registerTenant call.

in amplify/backend/api/platelet/custom-roles.json I have the following (with my proper id):

{
    "adminRoleNames": [
        "arn:aws:iam::<id>:user/test-test.bloodbikes.cloud"
    ]
}

I use this on another API I have and get no issue when making calls to it using IAM.

I tested running the action with a full admin access policy attached to the IAM user but it was still denied, so it seems like the API is returning that permission denied error rather than it being a problem with the policy.

It's strange that no error is returned when using getTenantByTenantName, which is just a queryField added to an index, but the registerTenant which is a custom function throws that error.

type Tenant
@auth(rules: [
{allow: private, operations: [read]},
{allow: private, provider: iam, operations: [read]},
])
@model {
  id: ID!
  name: String! @index(name: "byTenantName", queryField: "getTenantByTenantName")
  referenceIdentifier: String!
  admin: User! @hasOne
}

Expected behavior

I expect the query to complete without a permission denied error.

Reproduction steps

  1. Add a custom mutation to type Mutation with lambda function.
  2. Create access keys and set IAM policy to allow running that mutation.
  3. Set up GitHub action that calls the mutation.

This is the code I use in the GitHub action:

import * as core from "@actions/core";
import { Sha256 } from "@aws-crypto/sha256-js";
import { SignatureV4 } from "@aws-sdk/signature-v4";
import { HttpRequest } from "@aws-sdk/protocol-http";
import fetch, { Request } from "node-fetch";
import {
  RegisterTenantMutationVariables,
  GetTenantByTenantNameQueryVariables,
} from "./API";
import { registerTenant } from "./graphql/mutations";
import { getTenantByTenantName } from "./graphql/queries";

const request = async (queryDetails: { variables: any; query: string }) => {
  const apiURL = core.getInput("tenantApiUrl");
  const region = core.getInput("awsRegion");
  const accessKeyId = core.getInput("awsAccessKeyId");
  const secretAccessKey = core.getInput("awsSecretAccessKey");
  console.log("apiURL", apiURL);
  console.log("region", region);
  console.log("queryDetails", queryDetails);

  const endpoint = new URL(apiURL);
  const credentials = {
    accessKeyId,
    secretAccessKey,
  };
  const signer = new SignatureV4({
    credentials,
    region,
    service: "appsync",
    sha256: Sha256,
  });

  const requestToBeSigned = new HttpRequest({
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      host: endpoint.host,
    },
    hostname: endpoint.host,
    body: JSON.stringify(queryDetails),
    path: endpoint.pathname,
  });

  const signed = await signer.sign(requestToBeSigned);
  const request = new Request(endpoint, signed);
  return await fetch(request);
};

const errorCheck = (body: any) => {
  if (body?.errors) {
    console.error(body?.errors);
    throw new Error(body?.errors[0].message);
  }
};

export const registerTenantQuery = async (
  input: RegisterTenantMutationVariables
) => {
  const response = await request({
    variables: input,
    query: registerTenant,
  });
  const body = await response.json();
  errorCheck(body);
  return body?.data?.registerTenant;
};

export const getTenantByName = async (
  variables: GetTenantByTenantNameQueryVariables
) => {
  const response = await request({
    variables,
    query: getTenantByTenantName,
  });
  const body = await response.json();
  errorCheck(body);

  console.log("aaaa: ", body?.data?.getTenantByTenantName?.items);
  return body?.data?.getTenantByTenantName?.items[0] || null;
};

Project Identifier

f97b80f7ee5ceef2a72f107f35e6d453

Log output

# Put your logs below this line


Additional information

No response

Before submitting, please confirm:

  • [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
  • [X] I have removed any sensitive information from my code snippets and submission.

duckbytes avatar Apr 15 '24 08:04 duckbytes

HeyπŸ‘‹ thanks for raising this! I'm going to transfer this over to our API repository for better assistance πŸ™‚

ykethan avatar Apr 15 '24 15:04 ykethan

Why are you defining a separate policy when you define the Auth rules with the Auth directive @auth in the mutation declaration?

biller-aivy avatar Apr 18 '24 19:04 biller-aivy

@biller-aivy the policy is for my IAM user that I use with GitHub actions. I want to be able to call that mutation from that user.

If I don't add any policy, I get a different kind of unauthorized error.

duckbytes avatar Apr 18 '24 20:04 duckbytes

Hi @duckbytes,

I see you're declaring your IAM policy resource with resolvers in the registerTenant clause:

"arn:aws:appsync:*:<id>:apis/*/types/Mutation/resolvers/registerTenant"

I believe that should be fields:

"arn:aws:appsync:*:<id>:apis/*/types/Mutation/fields/registerTenant"

Please see AWS AppSync documentation for supported resource types.

Hope this helps.

palpatim avatar May 09 '24 21:05 palpatim

hi @palpatim

I gave it a try with this policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "appsync:GraphQL"
            ],
            "Resource": [
                "arn:aws:appsync:*:<id>:apis/*/types/Query/fields/getTenantByTenantName/*",
                "arn:aws:appsync:*:<id>:apis/*/types/Mutation/fields/registerTenant/*",
                "arn:aws:appsync:*:<id>:apis/*/types/Query/fields/getTenantByTenantName",
                "arn:aws:appsync:*:<id>:apis/*/types/Mutation/fields/registerTenant"
            ]
        }
    ]
}

but I get the same permission denied error:

message: 'Not Authorized to access getTenantByTenantName on type Query'

The error is actually on the query and not the registerTenant mutation. I haven't been able to try if registerTenant works yet.

duckbytes avatar May 27 '24 19:05 duckbytes

Hi @duckbytes, you've mentioned earlier that:

It's strange that no error is returned when using getTenantByTenantName, which is just a queryField added to an index, but the registerTenant which is a custom function throws that error.

And from the latest error message you've shared i.e Not Authorized to access getTenantByTenantName on type Query this seems to now be broken after adding those additional policies? I don't see anything in those policies that could've caused this. Can you clarify which of the query or mutation is not working?

phani-srikar avatar Jul 13 '24 04:07 phani-srikar

Hey πŸ‘‹ , This issue is being closed due to inactivity. If you are still experiencing the same problem and need further assistance, please feel free to leave a comment. This will enable us to reopen the issue and provide you with the necessary support.

AnilMaktala avatar Jul 26 '24 14:07 AnilMaktala

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.

github-actions[bot] avatar Jul 29 '24 13:07 github-actions[bot]