使用IAM授权从Node2访问AWS API Gateway(NodeJS)

时间:2017-03-26 16:59:42

标签: amazon-web-services amazon-ec2 aws-api-gateway amazon-iam

也许我要走到这里的桥梁,但是我得到了什么:

  • AWS API网关方法,其中AWS_IAM已设置为授权。
  • 允许访问该方法的策略。
  • 附有该政策的EC2角色。
  • 以该角色推出的EC2。

我想让我的EC2上的NodeJS程序(或任何语言)能够调用该API而无需在代码中对AccessKey和SecretKey进行硬编码。

我已经使用这种方法来使用aws-sdk在S3上放置/获取记录,并执行其他AWS功能(就像我上面提到的所有步骤一样),但是,调用API网关似乎不在aws- sdk范围。

使用Wreck(我在我的应用程序中使用我的HTTP调用中使用的NPM)调用API并且没有标题导致:

{
  "message": "Missing Authentication Token"
}

那里没什么大不了的。

我遗失了哪些明显的东西?

1 个答案:

答案 0 :(得分:1)

因此,您似乎需要在http://169.254.169.254/latest/meta-data/iam/security-credentials/Role_Name

访问您的EC2

正如here所述。

以下是我的最终代码,包括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());
        }
    });
});