【AWS SDK for Ruby】認証情報の設定時にちょっとハマった

記事タイトルとURLをコピーする

概要

AWS SDK for Rubyを用いたプログラムでAWSの認証情報を利用には、環境変数に設定する方法や、共有認証情報(~/.aws)を設定する方法や、IAMロールを利用する方法等様々あります。

また、コードに記述する方法として、 Aws.config を使用する方法や、クライアントオブジェクト内で設定する方法もあります。

docs.aws.amazon.com

今回、クライアントオブジェクト内で設定する方法について少しハマった点があったので、共有します。

前提

  • 確認Version
    • aws-sdk (3.0.1)
    • Ruby 2.7.2

以下サンプルコードは Aws::STS::Client を例に記載します。

docs.aws.amazon.com

クライアントオブジェクト内で設定する方法

以下のようにクライアントオブジェクトを作成する際に、キーがシンボルの認証情報を記載したハッシュオブジェクトをコンストラクタに渡すことで、認証情報を設定できます。 access_key_idsecret_access_key だけでなく、AssumeRoleを用いた一時的な認証情報の設定等も可能です。詳しくは上記リンクのドキュメントを参照ください。

sts = Aws::STS::Client.new(
  access_key_id: 'your_access_key_id',
  secret_access_key: 'your_secret_access_key'
)

ハマったところ

さて、もし上記ハッシュオブジェクトのキーを誤って文字列で指定してしまったらどうなるでしょうか。

credential = {
  'access_key_id': 'your_access_key_id',
  'secret_access_key': 'your_secret_access_key'
}
sts = Aws::STS::Client.new(credential)

実はこの状態で実行してもエラーにはなりません。この場合は、ここで設定している認証情報は利用せず、環境変数等で設定している認証情報が利用されます(そのような認証情報が設定されていない場合は、API実行時にエラーになります)。

では、もし以下のようにキーに指定する文字列の内容も誤っていたらどうなるでしょうか。

credential = {
  'hoge_access_key_id': 'your_access_key_id',
  'hoge_secret_access_key': 'your_secret_access_key'
}
sts = Aws::STS::Client.new(credential)

実は、この場合は、以下のようなエラーになります。

invalid configuration option `"hoge_access_key_id"' (ArgumentError)

どちらも認証情報の読み込みには失敗しているわけですが、なぜこのような違いが生じるのか、少しコードを探ってみました。

SDK内部を覗いてみた

クライアントオブジェクト生成時に指定する認証情報のハッシュオブジェクトの形式(キー)をチェックする処理の部分を探ってみると、以下の部分でチェックを行っていました。 この struct はクライアントオブジェクトのオプションで許容するキーと同じ値をキーに持つ構造体クラスのオブジェクトです。 opt は認証情報のハッシュオブジェクトで指定されたキー値の1つです。

begin
  struct[opt] = value
rescue NameError
  msg = "invalid configuration option `#{opt.inspect}'"
  raise ArgumentError, msg
end

https://github.com/aws/aws-sdk-ruby/blob/a8332558e8c8a4889dfce17dd54742172500dffb/gems/aws-sdk-core/lib/seahorse/client/configuration.rb#L164-L169

struct は以下のメソッドで定義されます。 @defaults はクライアントオブジェクト生成時にオプションの許容するキーがシンボルで格納された配列のオブジェクトです。

def empty_struct
   Struct.new(*@defaults.keys.sort).new
end

https://github.com/aws/aws-sdk-ruby/blob/a8332558e8c8a4889dfce17dd54742172500dffb/gems/aws-sdk-core/lib/seahorse/client/configuration.rb#L158-L160

さて、Rubyの構造体クラスは定義されているキーを文字列で指定しても、シンボルで指定してもどちらでも値を取り出すことができます。 ただし、存在しないキーの値の場合は、NameErrorが発生します。

Struct.new("Job", :id, :name)

job = Struct::Job.new(1, "test")

p job["id"] # => 1
p job[:id] # => 1
p job["id_hoge"] # => NameError

[PARAM] member: Symbol, String でメンバの名前を指定します。 [EXCEPTION] NameError: member が String, Symbol で存在しないメンバを指定した場合に発生します。 class Struct (Ruby 3.0.0 リファレンスマニュアル)

つまり、上述のチェック処理の部分においては、Rubyの構造体クラスの仕様から、SDKの仕様としてはシンボルでキーを指定するところを文字列で指定したとしてもエラーにはならなかったようです。しかし、SDKの仕様通りの形式では無かったために、最終的には認証情報の登録に失敗する、ということのようです。

おわりに

以上になります。AWSの認証情報は様々な形で定義できるので、気をつけていきたいと思います。

くればやし (記事一覧)