Search code examples
rubyamazon-web-serviceschef-infrachef-recipe

Using variables in Ruby for Chef cookbook


I have my cookbook which I am using to create an RDS instance on AWS. I did not want to store the AWS credentials in my code so I wrote a small snippet of Ruby code to get the credentials from a file stored on my local machine. Here's the code:

Dir.glob("#{Dir.home}/.aws/config1") do |my_config_file|
   access_key = File.readlines(my_config_file)[0]
   secret_access_key = File.readlines(my_config_file)[1]
   #puts access_key
   #puts "\n"
   #puts secret_access_key
end

    include_recipe "aws-rds"

    aws_rds db_info[:name] do
      # will use the iam role if available
      # optionally place the keys
      # see http://docs.aws.amazon.com/AWSSdkDocsRuby/latest/DeveloperGuide/ruby-dg-roles.html

      aws_access_key        access_key
      aws_secret_access_key secret_access_key
      engine                'postgres'
      db_instance_class     'db.t1.micro'
      region                'us-east-1'
      allocated_storage     5
      master_username       db_info[:username]
      master_user_password  db_info[:password]
    end

When I run my cookbook, I keep getting an error like this:

Recipe Compile Error in C:/Users/amohamme1/.chef/local-mode-cache/cache/cookbooks/amir_rds_test-machines/recipes/up-machines.rb
================================================================================

NoMethodError
-------------
undefined method `access_key' for Chef::Resource::AwsRds

I am new to ruby. I have tried declaring the access_key and secret_access_key variables as global. That did not solve the problem. I'm not sure how I can fix this problem. Any help is appreciated.


Solution

  • The issue is the variables are declared inside a block, variables declared in a block are scoped to that block so when the block ends (the end keyword) the variable disappears. If you want to use the variable inside your resource you should do:

    access_key = nil
    secret_access_key = nil
    
    Dir.glob("#{Dir.home}/.aws/config1") do |my_config_file|
       access_key = File.readlines(my_config_file)[0]
       secret_access_key = File.readlines(my_config_file)[1]
    end
    
    aws_rds db_info[:name] do
      aws_access_key        access_key
      aws_secret_access_key secret_access_key
      engine                'postgres'
      db_instance_class     'db.t1.micro'
      region                'us-east-1'
      allocated_storage     5
      master_username       db_info[:username]
      master_user_password  db_info[:password]
    end
    

    One thing to keep in mind is that this isn't the "Chef way" of storing secrets. Items that we don't want in source control are normally stored in data bags.

    In the case of secrets like access keys, the "Chef way" is to either use encrypted data bags or if you need to be more enterprise then chef vault.