require 'digest/md5' require 'json' use_inline_resources action :create do @run_context.include_recipe 's3_file::dependencies' client = S3FileLib::client download = true # handle key specified without leading slash remote_path = ::File.join('', new_resource.remote_path) # we need credentials to be mutable aws_access_key_id = new_resource.aws_access_key_id aws_secret_access_key = new_resource.aws_secret_access_key token = new_resource.token decryption_key = new_resource.decryption_key # if credentials not set, try instance profile if aws_access_key_id.nil? && aws_secret_access_key.nil? && token.nil? instance_profile_base_url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/' begin instance_profiles = client.get(instance_profile_base_url) rescue client::ResourceNotFound, Errno::ETIMEDOUT # we can either 404 on an EC2 instance, or timeout on non-EC2 raise ArgumentError.new 'No credentials provided and no instance profile on this machine.' end instance_profile_name = instance_profiles.split.first instance_profile = JSON.load(client.get(instance_profile_base_url + instance_profile_name)) aws_access_key_id = instance_profile['AccessKeyId'] aws_secret_access_key = instance_profile['SecretAccessKey'] token = instance_profile['Token'] end if ::File.exists?(new_resource.path) if decryption_key.nil? if new_resource.decrypted_file_checksum.nil? s3_md5 = S3FileLib::get_md5_from_s3(new_resource.bucket, new_resource.s3_url, remote_path, aws_access_key_id, aws_secret_access_key, token, new_resource.region) if S3FileLib::verify_md5_checksum(s3_md5, new_resource.path) Chef::Log.debug 'Skipping download, md5sum of local file matches file in S3.' download = false end #we have a decryption key so we must switch to the sha256 checksum else if S3FileLib::verify_sha256_checksum(new_resource.decrypted_file_checksum, new_resource.path) Chef::Log.debug 'Skipping download, sha256 of local file matches recipe.' download = false end end # since our resource is a decrypted file, we must use the # checksum provided by the resource to compare to the local file else unless new_resource.decrypted_file_checksum.nil? if S3FileLib::verify_sha256_checksum(new_resource.decrypted_file_checksum, new_resource.path) Chef::Log.debug 'Skipping download, sha256 of local file matches recipe.' download = false end end end end if download response = S3FileLib::get_from_s3(new_resource.bucket, new_resource.s3_url, remote_path, aws_access_key_id, aws_secret_access_key, token, new_resource.region) # not simply using the file resource here because we would have to buffer # whole file into memory in order to set content this solves # https://github.com/adamsb6/s3_file/issues/15 unless decryption_key.nil? begin decrypted_file = S3FileLib::aes256_decrypt(decryption_key,response.file.path) rescue OpenSSL::Cipher::CipherError => e Chef::Log.error("Error decrypting #{name}, is decryption key correct?") Chef::Log.error("Error message: #{e.message}") raise e end ::FileUtils.mv(decrypted_file.path, new_resource.path) else ::FileUtils.mv(response.file.path, new_resource.path) end end f = file new_resource.path do action :create owner new_resource.owner || ENV['user'] group new_resource.group || ENV['user'] mode new_resource.mode || '0644' end new_resource.updated_by_last_action(download || f.updated_by_last_action?) end