Reputation: 1319
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.
Upvotes: 1
Views: 428
Reputation: 6120
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.
Upvotes: 3
Reputation: 1072
I think you're a bit off in the weeds with your approach here.
Consider creating AWS infrastructure pieces such as RDS using the AWS CloudFormation service. Chef is better suited at running on a VM (e.g. EC2 instance) and provisioning your software stack.
For example, use cloud formation to create your EC2 instance. Use chef to install software components on it, such as the JDK, Tomcat, etc.
As the comments you've included indicate, an IAM instance profile would be the preferred way to handle authentication/authorization when using this cookbook. With your current solution, you could consider storing these variables in an encrypted data bag.
I suspect your error has to do with the convergence/execution phases of chef. As a fail safe, you could pass these in via knife/chef-solo when you execute the cookbook via json attributes.
knife .... --json-attributes '{"myCompany":{"aws":{"access_key":"...", "secret_key":"..."}}}'
Your recipe would then become
include_recipe "aws-rds"
aws_rds db_info[:name] do
aws_access_key node[:myCompany][:aws][:access_key]
aws_secret_access_key node[:myCompany][:aws][:secret_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
Upvotes: 1