• Home

  • Custom Ecommerce
  • Application Development
  • Database Consulting
  • Cloud Hosting
  • Systems Integration
  • Legacy Business Systems
  • Security & Compliance
  • GIS

  • Expertise

  • About Us
  • Our Team
  • Clients
  • Blog
  • Careers

  • CasePointer

  • VisionPort

  • Contact
  • Our Blog

    Ongoing observations by End Point Dev people

    Deploying password files with Chef

    Matt Vollrath

    By Matt Vollrath
    April 3, 2013

    Today I worked on a Chef recipe that needed to deploy an rsync password file from an encrypted data bag. Obtaining the password from the data bag in the recipe is well documented, but I knew that great care should be taken when writing the file. There are a plethora of ways to write strings to files in Chef, but many have potential vulnerabilities when dealing with secrets. Caveats:

    • The details of execute resources may be gleaned from globally-visible areas of proc.
    • The contents of a template may be echoed to the chef client.log or stored in cache, stacktrace or backup areas.
    • Some chef resources which write to files can be made to dump the diff or contents to stdout when run with verbosity.

    With tremendous help from Jay Feldblum in freenode#chef, we came up with a safe, optimized solution to deploy the password from a series of ruby blocks:

    pw_path = Pathname("/path/to/pwd/file")
    pw_path_uid = 0
    pw_path_gid = 0
    pw = Chef::EncryptedDataBagItem.load("bag", "item")['password']
    
    ruby_block "#{pw_path}-touch" do
      block   { FileUtils.touch pw_path } # so that we can chown & chmod it before writing the pw to it
      not_if  { pw_path.file? }
    end
    
    ruby_block "#{pw_path}-chown" do
      block   { FileUtils.chown pw_path_uid, pw_path_gid, pw_path }
      not_if  { s = pw_path.stat ; s.uid == pw_path_uid && s.gid == pw_path_gid }
    end
    
    ruby_block "#{pw_path}-chmod" do
      block   { FileUtils.chmod 0600, pw_path }
      not_if  { s = pw_path.stat ; "%o" % s.mode == "100600" }
    end
    
    ruby_block "#{pw_path}-content" do
      block   { pw_path.open("w") {|f| f.write pw} }
      not_if  { pw_path.read == pw } # NOTE: a secure compare method might make this even better
    end
    

    Further reading:

    automation chef devops hosting


    Comments