简体   繁体   English

为什么 aws-sdk-ruby 在初始化时连接到“169.254.169.254”?

[英]Why is aws-sdk-ruby connecting to '169.254.169.254' on initialization?

I installed the gem webmock , which blocks external connections during the test suite.我安装了 gem webmock ,它在测试套件期间阻止外部连接。 After I installed it, I got an unexpected result when running the test suite.我安装后,在运行测试套件时得到了一个意想不到的结果。

I'm somewhat confused why the aws-sdk needs to connect to 169.254.169.254 on initialization?我有点困惑为什么 aws-sdk 需要在初始化时连接到169.254.169.254

rspec spec/models/concerns/posconcern_spec.rb
[Coveralls] Set up the SimpleCov formatter.
[Coveralls] Using SimpleCov's 'rails' settings.

An error occurred while loading ./spec/models/concerns/posconcern_spec.rb.
Failure/Error: require File.expand_path('../../config/environment', __FILE__)

WebMock::NetConnectNotAllowedError:
  Real HTTP connections are disabled. Unregistered request: GET http://169.254.169.254/latest/meta-data/iam/security-credentials/ with headers {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}

  You can stub this request with the following snippet:

  stub_request(:get, "http://169.254.169.254/latest/meta-data/iam/security-credentials/").
    with(headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=>'Ruby'}).
    to_return(status: 200, body: "", headers: {})

  ============================================================
# /home/andey/.rvm/gems/ruby-2.3.4/gems/webmock-3.1.0/lib/webmock/http_lib_adapters/net_http.rb:114:in `request'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:109:in `http_get'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:90:in `block (2 levels) in get_credentials'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:105:in `open_connection'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:88:in `block in get_credentials'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:121:in `retry_errors'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:87:in `get_credentials'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:73:in `block in refresh'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:121:in `retry_errors'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:72:in `refresh'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/refreshing_credentials.rb:20:in `initialize'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/instance_profile_credentials.rb:51:in `initialize'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/credential_provider_chain.rb:90:in `new'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/credential_provider_chain.rb:90:in `instance_profile_credentials'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/credential_provider_chain.rb:12:in `block in resolve'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/credential_provider_chain.rb:11:in `each'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/credential_provider_chain.rb:11:in `resolve'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/aws-sdk-core/plugins/request_signer.rb:37:in `block in <class:RequestSigner>'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:70:in `call'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:205:in `block in resolve_defaults'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:57:in `each'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:57:in `each'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:204:in `resolve_defaults'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:200:in `value_at'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:189:in `block in resolve'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:189:in `resolve'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:177:in `apply_defaults'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/configuration.rb:150:in `build!'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/base.rb:68:in `build_config'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/base.rb:19:in `initialize'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/aws-sdk-core-2.10.52/lib/seahorse/client/base.rb:105:in `new'
# ./config/initializers/aws.rb:1:in `<top (required)>'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/activesupport-4.2.9/lib/active_support/dependencies.rb:268:in `load'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/activesupport-4.2.9/lib/active_support/dependencies.rb:268:in `block in load'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/activesupport-4.2.9/lib/active_support/dependencies.rb:240:in `load_dependency'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/activesupport-4.2.9/lib/active_support/dependencies.rb:268:in `load'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/engine.rb:652:in `block in load_config_initializer'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/activesupport-4.2.9/lib/active_support/notifications.rb:166:in `instrument'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/engine.rb:651:in `load_config_initializer'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/engine.rb:616:in `block (2 levels) in <class:Engine>'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/engine.rb:615:in `each'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/engine.rb:615:in `block in <class:Engine>'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/initializable.rb:30:in `instance_exec'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/initializable.rb:30:in `run'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/initializable.rb:55:in `block in run_initializers'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/initializable.rb:44:in `each'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/initializable.rb:44:in `tsort_each_child'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/initializable.rb:54:in `run_initializers'
# /home/andey/.rvm/gems/ruby-2.3.4/gems/railties-4.2.9/lib/rails/application.rb:352:in `initialize!'
# ./config/environment.rb:5:in `<top (required)>'
# ./spec/rails_helper.rb:3:in `require'
# ./spec/rails_helper.rb:3:in `<top (required)>'
# ./spec/models/concerns/posconcern_spec.rb:1:in `require'
# ./spec/models/concerns/posconcern_spec.rb:1:in `<top (required)>'

Relevant link to repo:回购相关链接:

https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/instance_profile_credentials.rb#L45 https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/instance_profile_credentials.rb#L45

It is trying to connect to the AWS metadata server to get the AWS credentials.它正在尝试连接到 AWS 元数据服务器以获取 AWS 凭证。 All AWS servers should be able to connect to the internal metadata server.所有 AWS 服务器都应该能够连接到内部元数据服务器。

I installed the gem webmock, which blocks external connections during the test suite我安装了 gem webmock,它在测试套件期间阻止了外部连接

How are you blocking it?你是怎么屏蔽的? Firewall?防火墙? Add a rule to allow traffic to 169.254.169.254 or stub it.添加规则以允许流量到169.254.169.254或存根。

The script is trying to connect to AWS services.该脚本正在尝试连接到 AWS 服务。 For that it needs credentials which can be provided in many ways.为此,它需要可以通过多种方式提供的凭据。 One way is to use AWS IAM role and fetch the credentials dynamically from the metadata server (169.254.169.254).一种方法是使用 AWS IAM 角色并从元数据服务器 (169.254.169.254) 动态获取凭证。 Your script is connecting to 169.254.169.254 to fetch the credentials.您的脚本正在连接到169.254.169.254以获取凭据。 It can be used to connect to AWS services later.它可用于稍后连接到 AWS 服务。

This is a follow up to @helloV 's answer.这是@helloV 回答的后续。

Full documentation on完整的文档

http://169.254.169.254/latest/meta-data/iam/security-credentials/

An application on the instance retrieves the security credentials provided by the role from the instance metadata item iam/security-credentials/role-name.实例上的应用程序从实例元数据项 iam/security-credentials/role-name 中检索角色提供的安全凭证。 The application is granted the permissions for the actions and resources that you've defined for the role through the security credentials associated with the role.通过与角色关联的安全凭证,应用程序被授予您为角色定义的操作和资源的权限。 These security credentials are temporary and we rotate them automatically.这些安全凭证是临时的,我们会自动轮换它们。 We make new credentials available at least five minutes prior to the expiration of the old credentials.我们会在旧凭据到期前至少五分钟提供新凭据。

http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#instance-metadata-security-credentials

Had a tough time researching on how to stub it.很难研究如何存根。 Will share my findings here hope it'll help other people.将在这里分享我的发现希望它会帮助其他人。

Since AWS uses service name to fetch credentials for multiple services such as S3, any IAM Role, SQS etc. But when dealing with IAM roles AWS hits http://169.254.169.254/latest/meta-data/iam/security-credentials/ which return the role name attached onto the machine and using the response of the same it hits the curl http://169.254.169.254/latest/meta-data/iam/security-credentials/# {role}.由于 AWS 使用服务名称来获取 S3、任何 IAM 角色、SQS 等多种服务的凭证。但是在处理 IAM 角色时,AWS 会访问http://169.254.169.254/latest/meta-data/iam/security-credentials/它返回附加到机器上的角色名称并使用相同的响应它点击 curl http://169.254.169.254/latest/meta-data/iam/security-credentials/# {role}。 So we need to stub both of the curls in order to successfully mock the IAM role.所以我们需要存根两个 curl 才能成功模拟 IAM 角色。 Below is the code for the same.下面是相同的代码。

def self.auth(params = {})
  status = params[:status].presence || 200
  url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/'
  WebMock.stub_request(:get, url)
      .with({headers: request_headers}.compact)
      .to_return(status: status, body: 'SampleRole', headers: {})
end

def self.role_auth(role = 'SampleRole')
  url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/#{role}"
  WebMock.stub_request(:get, url)
      .with({headers: request_headers}.compact)
      .to_return(status: 200, body: sample_response, headers: {})
end

private

def self.request_headers
  {
      'Accept': '*/*',
      'Accept-Encoding': 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
      'User-Agent': 'aws-sdk-ruby3/3.21.2'
  }.with_indifferent_access
end

def self.sample_response
  {
      Code: 'Success',
      LastUpdated: '2020-05-08T05:55:23Z',
      Type: 'AWS-HMAC',
      AccessKeyId: Faker::Lorem.characters(10),
      SecretAccessKey: Faker::Lorem.characters(20),
      Token: Faker::Lorem.characters(60),
      Expiration: '2020-05-08T12:00:45Z'
  }.to_json
end

So whenver any rspec uses InstanceCredentials provider you need to stub both of the above defined requests in before block of each of the rspec.因此,每当任何 rspec 使用 InstanceCredentials 提供程序时,您都需要在每个 rspec 的 before 块中存根上述两个定义的请求。

Example:示例:

before do
 ApiStub::IamCred.auth
 ApiStub::IamCred.role_auth
end

Hope it helps.希望它有帮助。 Happy Coding快乐编码

There are some good answers in this thread on how to stub this.在这个线程中有一些关于如何存根的很好的答案。 Another alternative (a better one?) is to eliminate the need for thE SDK to check for credentials from the instance meta data service.另一种选择(更好的选择?)是消除 SDK 检查来自实例元数据服务的凭据的需要。 You can do this by providing credentials.您可以通过提供凭据来执行此操作。 These can be fake.这些可能是假的。 A simple way to do this would be to provide credential via the ENV (eg ENV['AWS_ACCESS_TOKEN'] and ENV['SECRET_ACCESS_TOKEN']).一个简单的方法是通过 ENV 提供凭证(例如 ENV['AWS_ACCESS_TOKEN'] 和 ENV['SECRET_ACCESS_TOKEN'])。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM