Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Abusing Databags for Fun and Profit

Abusing Databags for Fun and Profit

Databags are a handy dandy way of storing state. This session looks at ways of generating, manipulating and using databags to do update and synchronisation of configuration and requirements across multiple nodes in an environment. This talk covers building tools to interact with databags, creating databags within recipes, and cover real world use cases.

Thom May

May 25, 2012
Tweet

More Decks by Thom May

Other Decks in Technology

Transcript

  1. require 'net/ldap' l = Net::LDAP.new(host: "x.y") l.bind l.search(filter: ...) do

    |u| homedir = u[:homedirectory].first directory homedir do owner u[:uidNumber].first.to_i group gid mode "0750" recursive true end end Friday, 25 May 12
  2. default[:app][:db1][:host] = "" default[:app][:db1][:user] = "" default[:app][:db1][:pass] = "" default[:app][:db1][:db]

    = "db1" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" attributes/default.rb Friday, 25 May 12
  3. default[:app][:db1][:host] = "" default[:app][:db1][:user] = "" default[:app][:db1][:pass] = "" default[:app][:db1][:db]

    = "db1" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:user] = "appro" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" attributes/default.rb Friday, 25 May 12
  4. default[:app][:db1][:host] = "" default[:app][:db1][:user] = "" default[:app][:db1][:pass] = "" default[:app][:db1][:db]

    = "db1" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:user] = "appro" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" attributes/default.rb production role Friday, 25 May 12
  5. default[:app][:db1][:host] = "" default[:app][:db1][:user] = "" default[:app][:db1][:pass] = "" default[:app][:db1][:db]

    = "db1" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:user] = "appro" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:host] = "x.x.x" default[:app][:db1][:pass] = "2342" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" attributes/default.rb production role Friday, 25 May 12
  6. default[:app][:db1][:host] = "" default[:app][:db1][:user] = "" default[:app][:db1][:pass] = "" default[:app][:db1][:db]

    = "db1" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:user] = "appro" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:host] = "x.x.x" default[:app][:db1][:pass] = "2342" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" attributes/default.rb production role cluster role Friday, 25 May 12
  7. default[:app][:db1][:host] = "" default[:app][:db1][:user] = "" default[:app][:db1][:pass] = "" default[:app][:db1][:db]

    = "db1" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:user] = "appro" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" default[:app][:db1][:host] = "x.x.x" default[:app][:db1][:pass] = "2342" default[:app][:db2][:host] = "x.x.x" default[:app][:db2][:user] = "db2" default[:app][:db2][:pass] = "2342" default[:app][:db2][:db] = "db2" set[:app][:version] = "1.2.3" attributes/default.rb production role cluster role Friday, 25 May 12
  8. Enter Data Bags Friday, 25 May 12 First release in

    chef 0.8. really low key announcement: “allow you to store arbitrary data within the Chef Server, and have it fully indexed for Search”
  9. { "level": 6, "id": "some-test-node", "volumes": { "sdg": "/dev/xvdg", "sdh":

    "/dev/xvdh", "sdi": "/dev/xvdi", "sdj": "/dev/xvdj", "sdk": "/dev/xvdk", "sdl": "/dev/xvdl", "sdm": "/dev/xvdm", "sdn": "/dev/xvdn", }, "mount": "/srv/", "volsize": 250 } Friday, 25 May 12
  10. ebs = data_bag_item("ebs", node.hostname) xvds = [] ebs["volumes"].each_pair do |vol,

    real| xvds << real aws_ebs_volume "srv_volume_#{vol}" do aws_access_key node.aws.access_key aws_secret_access_key node.aws.secret_key size ebs["volsize"] device "/dev/#{vol}" action [:create, :attach] end end Friday, 25 May 12
  11. ebs = data_bag_item("ebs", node.hostname) xvds = [] ebs["volumes"].each_pair do |vol,

    real| xvds << real aws_ebs_volume "srv_volume_#{vol}" do aws_access_key node.aws.access_key aws_secret_access_key node.aws.secret_key size ebs["volsize"] device "/dev/#{vol}" action [:create, :attach] end end Friday, 25 May 12
  12. db = search(:databases, "id:#{dbname}").first if db template "#{base_dir}/shared/config/database.yml" do cookbook

    "baton" owner site variables({name: db["id"], pass: db[chef_environment]["pass"]}) end end 16:21 ~ knife search databases “id:test” 1 items found chef_type: data_bag_item data_bag: databases id: test creator: Thom May development: pass: foobar Friday, 25 May 12
  13. data_bag(:ftpusers).each do |v| user = data_bag_item(:ftpusers, v) user user["id"] do

    password user["password"] shell "/bin/sh" group "metrics" home "/home/#{user["id"]}" supports :manage_home => true action [:create,:manage,:modify] end end Friday, 25 May 12
  14. Security risks Friday, 25 May 12 Altering data bags from

    the node when using the Open Source chef-server requires giving the node's API client admin privileges. In most cases, this is not advisable
  15. Security risks Race-y Friday, 25 May 12 There’s no guarantee

    in the API that you’re the only thing writing.
  16. def lock(name) begin item = data_bag_item("locks", name) raise "Lock found"

    if item rescue Net::HTTPServerException => e raise e unless e.response_code == "404" end item = Chef::DataBagItem.new item.data_bag "locks" item.raw_data = { "id" => name, "holder" => node.fqdn } item.save end def unlock(name) begin item = data_bag_item("locks", name) rescue Net::HTTPServerException => e raise e unless e.response_code == "404" end item.destroy end Friday, 25 May 12
  17. def generate_id Chef::Log.info "Percona server-id: #{node.percona.server_id}" begin item = data_bag_item(

    "percona", "server-id" ) id = item['last-used'] + 1 rescue Net::HTTPServerException => e id = 1 raise e unless e.response.code == "404" end item = Chef::DataBagItem.new item.data_bag "percona" item.raw_data = { "id" => "server-id", "last-used" => id } item.save node.set.percona.server_id = id node.save end generate_id if node.percona.server_id == 0 Friday, 25 May 12
  18. uri = URI.parse(conf["chef_url"]) Spice.setup do |s| s.host = uri.host s.port

    = uri.port.to_s s.url_path = uri.path s.scheme = uri.scheme s.client_name = conf["client_name"] s.key_file = conf["key_file"] end Spice.connect! Spice::DataBag.show(:name => conf["db_name"]).keys.each do |k| item = Spice::DataBag.show_item(:name => conf["db_name"], :id => k) end Friday, 25 May 12
  19. 11:13 ~ % knife data bag show databases app1 app2

    auth refinery surechem_curi website Friday, 25 May 12