この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
node.jsを用いて、CloudSearch用いる例としては弊社k.ootakiの記事を参照ください。
node.jsでCloudSearchを動かしてみる | Developers.IO
上記の方法では、認証情報(accessKey/secretAccessKey)をconfig.jsonに記載していますが、 EC2上で動かす際は、それらの情報はIAM Role側に持たせることで、認証情報を記述することなく動かすことが可能です。
システムでIAM Roleを用いて動かすといった話は以下の都元の記事を参照ください。
IAMによるAWS権限管理運用ベストプラクティス (2) | Developers.IO
検証を行った環境は以下になります。
- Amazon Linux AMI 2014.09.1 (HVM)
- node.js v0.10.32
- aws-sdk version 2.0.30
ES2上で動かない!?
私の上記のブログを読んだ理解では、IAMRoleを用いて動かすには以下のコードで動くものと想像していました。
sample.js
var AWS = require('aws-sdk');
var config = require('config');
var cloudSearch = new AWS.CloudSearchDomain({
endpoint: config.endpoint,
region:config.region
});
var params = {
query: '角川'
};
cloudSearch.search(params, function (err, data) {
if (err) {
console.log('error', err);
}
if (data) {
if (data.hits.found > 0) {
console.log(data.hits.hit[0]);
} else {
console.log('not found');
}
}
});
割り当てたIAM Roleは以下のようになります。
IAM Role
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"cloudsearch:*"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
上記のコードをIAM Roleを設定したES2で動かそうとすると以下のようになります。
$ node ./sample.js
User: anonymous is not authorized to perform
このコードを動かしてみると、User: anonymous is not authorized to performといったエラーが出てしまいます。
要はCredentialがセットされていないようなので、セットしようとおもいます。
クレデンシャルを探せ!
AccessKey/secretAccessKeyをセットすれば動きはしますが、 ベストプラクティスである”APIキーをシステム内にハードコーディングしない”に反してしまうことになります。
上記の例ではCloudSearchDomainのイニシャライズ時にendpointのみを渡していますが、 その際にパラメータとしてクレデンシャルを渡すことができそうです。
File: README — AWS SDK for JavaScript
以下がそのパラメータ候補になります。
- credentials (AWS.Credentials) — the AWS credentials to sign requests with. You can either specify this object, or specify the accessKeyId and secretAccessKey options directly.
- credentialProvider (AWS.CredentialProviderChain) — the provider chain used to resolve credentials if no static credentials property is set.
credentialProviderをセットしてみる。
ベストプラクティスでも紹介されていた、credentialProviderをセットする方法を試してみたいと思います。
sample2.js
var AWS = require('aws-sdk');
var config = require('config');
var chain = new AWS.CredentialProviderChain();
var cloudSearch = new AWS.CloudSearchDomain({
endpoint: config.endpoint,
region:config.region,
credentialProvider:chain
});
var params = {
query: '角川'
};
cloudSearch.search(params, function (err, data) {
if (err) {
console.log('error', err);
}
if (data) {
if (data.hits.found > 0) {
console.log(data.hits.hit[0]);
} else {
console.log('not found');
}
}
});
上記の方法でAWS S3クラス等では、credentialを取得しAPIを実行することができるのですが、 なぜかCloudSearchDomainはだめで結果は最初とかわりません。
Credentinalの情報を取得してセットする。
直接Credential情報をセットすれば動くことはわかっているので、CredentilProviderChainから取得しそれをセットします。
sample3.js
var AWS = require('aws-sdk');
var config = require('config');
var chain = new AWS.CredentialProviderChain();
chain.resolve(function(err, cre) {
var cloudSearch = new AWS.CloudSearchDomain({
endpoint: config.endpoint,
credentials: cre,
region: config.region
});
var params = {
query: '角川'
};
cloudSearch.search(params, function(err, data) {
if (err) {
console.log('error', err);
}
if (data) {
if (data.hits.found > 0) {
console.log(data.hits.hit[0]);
} else {
console.log('not found');
}
});
});
});
上記のコードを動かすことで、ようやくCloudSearchにアクセスすることができました。
$ $ node sample3.js
{ id: '5',
fields: { title: [ '新世紀エヴァンゲリオン(13) (角川コミックス・エース)' ] } }
まとめ
ほかの言語で検証していないので、上記の現象がnode.jsのみにおけるものなのか、 それとも他の開発言語でも該当するのかは不明です。
なお、AWS.CloudSearchクラスはIAM Roleが適用されているEC2インスタンス上から node.jsのSDKからAPIを呼ぶことが可能でした。