How to use Appsync Http Resolver with AWS services which expected post but without an request body?

0

How to use Appsync Http Resolver with AWS services which expected post but without an request body?

I try to make a request to this endpoint: https://docs.aws.amazon.com/codeartifact/latest/APIReference/API_ListPackages.html

Appsync Setup

Http datasource endpoint: https://codeartifact.eu-central-1.amazonaws.com/

I use following http resolver:

function request(ctx) {
  return {
    method: "POST",
    params: {
      query: {
        "domain": "<redacted>",
        "domain-owner": "<redacted>",
        "repository": "<redacted>"
      },
    },
    resourcePath: "/v1/packages",
  };
}

function response(ctx) {
  return [ctx.result.body];
}

export {
  request,
  response
};

Then I get following error message:

The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.

JS script

So I tried to create a js script to send such a request:

When I set applyChecksum to false, the request works.

When I set the applyChecksum to true, the request fails with the same error message above.

import {SignatureV4} from "@smithy/signature-v4";
import {Sha256} from "@aws-crypto/sha256-js";
import {defaultProvider} from "@aws-sdk/credential-provider-node";

const signatureV4 = new SignatureV4({
  service: "codeartifact",
  applyChecksum: false,                //if set to true, the reuqest fails
  region: "eu-central-1",
  credentials: defaultProvider(),
  sha256: Sha256
});


const url = new URL("https://codeartifact.eu-central-1.amazonaws.com/v1/packages")

const signedRequest = await signatureV4.sign({
  method: "POST",
  protocol: url.protocol,
  hostname: url.hostname,
  path: url.pathname,
  headers: {
    host: url.host
  },
  query: {
    'domain': "<redacted>",
    'domain-owner': "<redacted>",
    'repository': "<redacted>",
  }
});

edit:

cdk

this.graphqlApi = new GraphqlApi(this, 'AppSyncApi', {
...
})

const codeArtifactHttpDataSource = this.graphqlApi.addHttpDataSource('CodeArtifactHttpDataSource', `https://codeartifact.eu-central-1.amazonaws.com/`, {
  authorizationConfig: {
    signingRegion: 'eu-central-1',
    signingServiceName: 'codeartifact',
  },
});

codeArtifactHttpDataSource.grantPrincipal.addToPrincipalPolicy(new PolicyStatement({
  actions: ['codeartifact:DescribePackageVersion',
    'codeartifact:DescribeRepository',
    'codeartifact:GetPackageVersionReadme',
    'codeartifact:GetRepositoryEndpoint',
    'codeartifact:ListPackages',
    'codeartifact:ListPackageVersions',
    'codeartifact:ListPackageVersionAssets',
    'codeartifact:ListPackageVersionDependencies',
    'codeartifact:ReadFromRepository',
    'codeartifact:GetAuthorizationToken'],
  resources: ['*'],
}));

const appsyncFunction = new AppsyncFunction(this, 'AppsyncFunction', {
  api: this.graphqlApi ,
  dataSource: codeArtifactHttpDataSource,
  name: 'js_function',
  code: Code.fromAsset(path.join(__dirname, '<path-to-js>')),
  runtime: FunctionRuntime.JS_1_0_0,
});

new Resolver(this, 'Resolver', {
  api: this.graphqlApi,
  pipelineConfig: [appsyncFunction],
  typeName: 'Query',
  fieldName: '<fieldname>',
  runtime: FunctionRuntime.JS_1_0_0,
  code: Code.fromInline(`
    // The before step
    export function request(ctx) {
      return {}
    }
    // The after step
    export function response(ctx) {
      return ctx.prev.result
    }`)
});
  • Is it the case that you're receiving this error even after setting up the role and HTTP data source, and if so could you provide the details of the http configuration file used?

  • @jthwaits i added the cdk part, with signing part. We use this with kms signing services to sigin jwts, which works great.

2 Answers
0
Accepted Answer

I had to set the content type to application/x-amz-json-1.1 and the body to {} to create a valid signature.

Fixed http resolver

function request(ctx) {
  return {
    method: "POST",
    params: {
      query: {
        "domain": "<redacted>",
        "domain-owner": "<redacted>",
        "repository": "<redacted>"
      },
    },
    resourcePath: "/v1/packages",
    headers: {
      // I had to set this Content-Type to get the SignatureV4 to work.
      "Content-Type": "application/x-amz-json-1.1"
    },
    // I had to set this body to get the SignatureV4 to work.
    body: "{}"
  };
}
Stefan
answered 3 months ago
0

With AWS AppSync, when invoking AWS services with HTTP resolvers there are two additional components required: an IAM role with permissions to call the service APIs, and signing configuration in the data source. Details for configuring these can be found here: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-http-resolvers-js.html#invoking-aws-services-js.

AWS
answered 6 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions