今日得た知見をすぐにお届け! cloudpackかっぱ (@inokara) です。

はじめに

AWS SDK for JavaScript in Node.js というものがありまして…ということで node.js を使って AWS を操作する知見を得たのでメモります。

参考

準備

オトコなら IAM で通れ

アクセスキーやシークレットアクセスキーをソースコードに直書きするのは出来るだけ避けたいので、オトコなら(オトコに限らず) Amazon EC2 に以下のような IAM role を設定して覚悟を決めましょう。もちろん、 EC2 に限らず、AWS の各種サービスは IAM に対応(対応表)していますので、利用したいサービスが IAM にどの程度対応しているかを確認しておきましょう。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:Describe*",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "elasticloadbalancing:Describe*",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "cloudwatch:ListMetrics",
        "cloudwatch:GetMetricStatistics",
        "cloudwatch:Describe*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "autoscaling:Describe*",
      "Resource": "*"
    }
  ]
}

これは IAM role の AmazonEC2ReadOnlyAccess を設定した際に割当られるロールキャベツです。

node.js をインストール

こちらを参考にさせて頂いてセットアップします。

sudo yum install wget git gcc-c++ openssl-devel
git clone git://github.com/creationix/nvm.git ~/.nvm
source ~/.nvm/nvm.sh
nvm install v0.10.35

nvm を利用して一般ユーザー権限で node.js を利用出来るようにしていますが、聞くところによる nvm と同じような機能を提供する nodebrew というツールもあるようですが、今回はその辺りの比較はしません。すいません。

AWS SDK for JavaScript in Node.js をインストール

AWS SDK for JavaScript in Node.js(だいぶん長いタイトルですが)を以下のようにインストールします。

npm install aws-sdk

上記は npm を利用して AWS SDK for JavaScript in Node.js をインストールしています。もちろん、これも一般ユーザーでインストールしています。

これで準備はオッケーです。

とりあえず Describe Instances

Describe Instances

IAM role にて Describe Instances が利用出来る状態ですのでアクセスキーやシークレットアクセスキーの設定は不要ですが、region の設定は必要になります。また、 CredentialProviderChain を利用することで IAM role を適用した EC2 インスタンスから SDK を利用して AWS のリソースにアクセス出来るようになります。

CredentialProviderChain については…

Creates a credential provider chain that searches for AWS credentials in a list of credential providers specified by the providers property.

上記の通り、AWS の資格情報を検索する為の資格プロバイダチェーンの作成を行うクラスのようですが、このプロバイダと読んでいるのが…

  • IAM RoleのEC2 Instance Profile
  • 環境変数
  • アプリケーションのオプションや設定ファイル
  • ~/.aws/credentials や ~/.aws/config から読み取る

となります。

尚、上記の記事を参考にさせて頂きました。

ということで、以下のようなスクリプトを用意します。

var util = require('util');
var AWS = require('aws-sdk');

var main = function(){
   'use strict';
    var crd = new AWS.CredentialProviderChain();
    var ec2 = new AWS.EC2({
        region:'ap-northeast-1',
        credentialProvider:crd
    });

    console.log(util.inspect(ec2));
    var params = {
      DryRun: false,
      MaxResults: 50,
      Filters: [
        {
           Name: 'instance-state-name',
           Values: ['running'],
        },
      ],
    };
    ec2.describeInstances(params, function(err, data) {
      if (err) console.log('err: ', err, err.stack);
      else     console.log('Instance_ID: ', data.Reservations[0].Instances[0].InstanceId);
    });
};

main();

上記の例では instance-state-namerunning な状態の EC2 インスタンスのインスタンス ID を取得するスクリプトです。

実行

上記のスクリプトを実行すると以下のように出力されます。

{ config:
   { credentials: null,
     credentialProvider: { providers: [Object] },
     region: 'ap-northeast-1',
     logger: null,
     apiVersions: {},
     apiVersion: null,
     endpoint: 'ec2.ap-northeast-1.amazonaws.com',
     httpOptions: { timeout: 120000 },
     maxRetries: undefined,
     maxRedirects: 10,
     paramValidation: true,
     sslEnabled: true,
     s3ForcePathStyle: false,
     s3BucketEndpoint: false,
     computeChecksums: true,
     convertResponseTypes: true,
     dynamoDbCrc32: true,
     systemClockOffset: 0,
     signatureVersion: 'v4' },
  isGlobalEndpoint: false,
  endpoint:
   { protocol: 'https:',
     host: 'ec2.ap-northeast-1.amazonaws.com',
     port: 443,
     hostname: 'ec2.ap-northeast-1.amazonaws.com',
     pathname: '/',
     path: '/',
     href: 'https://ec2.ap-northeast-1.amazonaws.com/' } }
Instance_ID:  i-xxxxxxxx

一応、かろうじて Instance_ID: i-xxxxxxxx が出力されていますね。ちなみに以下のように修正して実行すると…

--- hoge.js     2015-01-14 16:45:41.726450264 +0000
+++ hoge.js2    2015-01-14 16:46:00.566860580 +0000
@@ -24,7 +24,7 @@
     };
     ec2.describeInstances(params, function(err, data) {
       if (err) console.log('err: ', err, err.stack);
-      else     console.log('Instance_ID: ', data.Reservations[0].Instances[0].InstanceId);
+      else     console.log('Instance_ID: ', data.Reservations[0].Instances[0]);
     });
 };

以下のようにインスタンスの各種情報がズラズラと表示されます。

{ config:
   { credentials: null,
     credentialProvider: { providers: [Object] },
     region: 'ap-northeast-1',
     logger: null,
     apiVersions: {},
     apiVersion: null,
     endpoint: 'ec2.ap-northeast-1.amazonaws.com',
     httpOptions: { timeout: 120000 },
     maxRetries: undefined,
     maxRedirects: 10,
     paramValidation: true,
     sslEnabled: true,
     s3ForcePathStyle: false,
     s3BucketEndpoint: false,
     computeChecksums: true,
     convertResponseTypes: true,
     dynamoDbCrc32: true,
     systemClockOffset: 0,
     signatureVersion: 'v4' },
  isGlobalEndpoint: false,
  endpoint:
   { protocol: 'https:',
     host: 'ec2.ap-northeast-1.amazonaws.com',
     port: 443,
     hostname: 'ec2.ap-northeast-1.amazonaws.com',
     pathname: '/',
     path: '/',
     href: 'https://ec2.ap-northeast-1.amazonaws.com/' } }
Instance_ID:  { InstanceId: 'i-xxxxxxx',
  ImageId: 'ami-xxxxxxx',
  State: { Code: 16, Name: 'running' },
  PrivateDnsName: 'ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal',
  PublicDnsName: 'ec2-xxx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com',
  StateTransitionReason: '',
  KeyName: 'ahoahoaho',
  AmiLaunchIndex: 0,
  ProductCodes: [],
  InstanceType: 't2.micro',
  LaunchTime: Wed Jan 14 2015 09:38:40 GMT+0000 (UTC),
  Placement:
   { AvailabilityZone: 'ap-northeast-1a',
     GroupName: '',
     Tenancy: 'default' },
  Monitoring: { State: 'disabled' },
  SubnetId: 'subnet-xxxxxxx',
  VpcId: 'vpc-xxxxxxx',
  PrivateIpAddress: 'xxx.xxx.xxx.xxx',
  PublicIpAddress: 'xxx.xxx.xxx.xxx',
  Architecture: 'x86_64',
  RootDeviceType: 'ebs',
  RootDeviceName: '/dev/xvda',
  BlockDeviceMappings: [ { DeviceName: '/dev/xvda', Ebs: [Object] } ],
  VirtualizationType: 'hvm',
  ClientToken: 'xxxxx1234567890',
  Tags: [ { Key: 'Name', Value: 'kappa-hage-hage' } ],
  SecurityGroups:
   [ { GroupName: 'hage', GroupId: 'sg-12345678' },
     { GroupName: 'zura', GroupId: 'sg-99999999' } ],
  SourceDestCheck: true,
  Hypervisor: 'xen',
  NetworkInterfaces:
   [ { NetworkInterfaceId: 'eni-xxxxxxx',
       SubnetId: 'subnet-xxxxxxx',
       VpcId: 'vpc-xxxxxxx',
       Description: '',
       OwnerId: '123456789012',
       Status: 'in-use',
       MacAddress: '12:34:xx:yy:zz:qq',
       PrivateIpAddress: 'xxx.xxx.xxx.xxx',
       PrivateDnsName: 'ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal',
       SourceDestCheck: true,
       Groups: [Object],
       Attachment: [Object],
       Association: [Object],
       PrivateIpAddresses: [Object] } ],
  IamInstanceProfile:
   { Arn: 'arn:aws:iam::1234567890123:instance-profile/hage-zura-pika',
     Id: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' },
  EbsOptimized: false }

おお、とりあえず describe instances が出来ればこっちのものですね。

今日の知見

以下のような知見を得ました。

  • IAM role が設定された EC2 で AWS SDK for JavaScript in Node.js を動かして AWS のリソースにアクセスする方法
  • AWS SDK for JavaScript in Node.js で describe-instances する為に必要な最低限クラス、メソッドの書き方
  • Credential のプロバイダはざっくり四種類ありますが、オススメはやっぱり IAM role ですたい

ということで、おやすみなさい。

元記事はこちらです。
IAM で適切に権限が設定された EC2 インスタンスで AWS SDK for JavaScript in Node.js を利用して describe-instances とかしてみる