Accessing AWS API Gateway from an EC2 using IAM authorization (NodeJS)

浪子不回头ぞ 提交于 2019-12-13 12:35:06

问题


Perhaps I'm going a bridge to far here but heres what I got:

  • An AWS API Gateway Method that has AWS_IAM set for Authorization.
  • A Policy that allows access to that Method.
  • An EC2 Role that has that policy attached to it.
  • An EC2 Launched with that Role.

I would like to have my NodeJS program (or any language for that matter) on that EC2 to be able to call that API without hardcoding an AccessKey and SecretKey in the code.

I have used this approach to use the aws-sdk to put/get records on S3, and do other AWS functionality (like all the steps I mentioned above), However, invoking an API Gateway seems to be outside the aws-sdk scope.

Calling the API with Wreck (the NPM I use from my HTTP calls in my app) and no headers results in:

{
  "message": "Missing Authentication Token"
}

Not a big shock there.

Anything obvious I am missing?


回答1:


So it appears you need to access your EC2 at http://169.254.169.254/latest/meta-data/iam/security-credentials/Role_Name

As explained here.

Here is my final code including Signing AWS Requests with Signature Version 4:

var Moment = require('moment');
var Wreck = require('wreck');
var Crypto = require('crypto');

function getSignatureKey(key, dateStamp, regionName, serviceName) {
    var kDate = Crypto.createHmac('sha256', 'AWS4' + key).update(dateStamp,'utf8').digest();
    var kRegion = Crypto.createHmac('sha256', kDate).update(regionName, 'utf8').digest();
    var kService = Crypto.createHmac('sha256', kRegion).update(serviceName, 'utf8').digest();
    var kSigning = Crypto.createHmac('sha256', kService).update('aws4_request', 'utf8').digest();
    return kSigning;
}

var assumed_role = 'MY_ROLE';
Wreck.get('http://169.254.169.254/latest/meta-data/iam/security-credentials/' + assumed_role, function(err, res, payload) {
    var payload_obj = JSON.parse(payload.toString());
    var access_key = payload_obj.AccessKeyId;
    var secret_key = payload_obj.SecretAccessKey;
    var token = payload_obj.Token;

    var payload = {}
    payload.email = 'devin.stewart@example.com';
    payload.first_name = 'Devin';
    payload.last_name = 'Stewart';
    payload.full_name = 'Devin Stewart';

    var request_parameters = JSON.stringify(payload);

    var method = 'POST';
    var api_id = 'MY_API_ID'
    var service = 'execute-api';
    var region = 'us-east-1';
    var api_path = '/production/people';
    var host = api_id + '.' + service + '.' + region + '.amazonaws.com';
    var endpoint = 'https://' + host + api_path;
    var content_type = 'application/json';

    var t = Moment.utc()
    var amz_date = t.format('YYYYMMDD[T]HHmmss[Z]');
    var date_stamp = t.format('YYYYMMDD'); // Date w/o time, used in credential scope

    var canonical_querystring = '';
    var canonical_headers = 'content-type:' + content_type + '\n' + 'host:' + host + '\n' + 'x-amz-date:' + amz_date + '\n' + 'x-amz-security-token:' + token + '\n';
    var signed_headers = 'content-type;host;x-amz-date;x-amz-security-token';
    var payload_hash = Crypto.createHash('sha256').update(request_parameters).digest('hex');
    var canonical_request = method + '\n' + api_path + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash;

    var algorithm = 'AWS4-HMAC-SHA256';
    var credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request';
    var string_to_sign = algorithm + '\n' +  amz_date + '\n' +  credential_scope + '\n' +  Crypto.createHash('sha256').update(canonical_request).digest('hex');

    var signing_key = getSignatureKey(secret_key, date_stamp, region, service);
    var signature = Crypto.createHmac('sha256', signing_key).update(string_to_sign, 'utf8').digest('hex');

    authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' +  'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature;
    var headers = { 
        'Content-Type':content_type,
        'X-Amz-Date':amz_date,
        'X-Amz-Security-Token':token,
        'Authorization':authorization_header
    };

    var options = {headers: headers, payload: request_parameters};
    Wreck.post(endpoint, options, function (err, res, payload) {
        if (err) {
            console.log(err.data.payload.toString());
        } else {
            console.log(payload.toString());
        }
    });
});


来源:https://stackoverflow.com/questions/43031759/accessing-aws-api-gateway-from-an-ec2-using-iam-authorization-nodejs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!