LoginSignup
30
16

More than 3 years have passed since last update.

[aws]IAM Roleで権限設定している場合のcredentialの渡し方

Last updated at Posted at 2019-08-26

IAM Roleで権限設定している場合のcredentialの渡し方

アプリケーションからAWSのリソースにアクセスする場合、何かしらのIAMユーザを作って、 AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY を発行して、環境変数などにセットして

Aws::S3::Client.new(
  region: 'ap-northeast-1',
  access_key_id: ENV['AWS_ACCESS_KEY_ID'],
  secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
)
=> #<Aws::S3::Client>

でアクセスすること、多いですよね。

でも、EC2インスタンスや、ECSのタスクに Roleを設定してそちらで権限管理すると、credentialをアプリケーション側で管理しなくてもよくてより管理しやすくなってよいのですが、その場合のアプリケーションからのクレデンシャルの渡し方があまり分からなかったので調べました。

carrierwaveの場合

carrierwaveの場合は、gem側で用意されていて、通常のAWS_ACCESS_KEY_IDなどを渡す代わりに、

config/initializer/carrierwave.rb
CarrierWave.configure do |config|
  config.fog_credentials = {
      provider: 'AWS',
      region: 'ap-northeast-1',
      use_iam_profile: true
  }
end

と、 use_iam_profile:true を渡せば、carrirwaveの中(から呼ばれている aws-fog というgem)でよしなにやってくれます

Shrineの場合

carrierwaveと似たような画像アップロードのgemでShrineというのがありますが、こちらの場合は、S3を使う場合、

s3.rb

class Shrine
  module Storage
    class S3
      # ... 略 ...
      def initialize(bucket:, client: nil, prefix: nil, upload_options: {}, multipart_threshold: {}, signer: nil, public: nil, **s3_options)
        raise ArgumentError, "the :bucket option is nil" unless bucket

        @client = client || Aws::S3::Client.new(**s3_options) # <= これ

と、aws-sdkに、直接アプリからの設定を渡していました。

この場合どうするんだろう?というのが分からずに色々調べた結果になります。

結果

最終的にはすごく単純で、 ec2や、ecsコンテナに、iam roleが設定された場合、特定のurlにリクエストを送るとクレデンシャルが取得できるAPIがつかえるようになるので、そこから持ってきた内容を設定するだけということでした。

インスタンスメタデータとユーザーデータ

これを実装しているのが、 carrierwaveでみた、 aws-fog

と、 use_iam_profile:true を渡せば、carrirwaveの中(から呼ばれている aws-fog というgem)でよしなにやってくれます

の部分です。

で、Shrineで、この処理実装しないといけないのかーとおもっていたら、aws-sdkにこれらの処理をやってくれる処理があってそれを使うとすごく楽です。

最終的には下記のようにしました。
ECSの場合、 Aws::ECSCredentials
EC2の場合、 Aws::InstanceProfileCredential
が使えます。これらを credentials というkeyでsdkにわたすと、いろいろ取得してくれてよしなにcredentialを作ってくれます。

config/initializer/shrine.rb
require 'shrine'
require 'shrine/storage/s3'

s3_options = {
  region: 'ap-northeast-1',
  bucket: 'some_bucket_name'
}

# AWS_CONTAINER_CREDENTIALS_RELATIVE_URI が定義されている場合
# Role設定されたECSで動いているので、ECSの方、そうでなければ、EC2用のInstanceProfileの方を使う。
if ENV["AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"]
  s3_options = s3_options.merge(credentials: Aws::ECSCredentials.new)
else
  s3_options = s3_options.merge(credentials: Aws::InstanceProfileCredentials.new)
end

Shrine.storages = {
  cache: Shrine::Storage::S3.new(prefix: 'prefix', **s3_options),
  ...  ...
}

結果的には非常に簡単だったのですが、これらに気づくまで結構時間がかかったので、メモとして残しておきます。

30
16
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
16