knife-briefcase 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +13 -0
  4. data/CHANGELOG.md +6 -0
  5. data/CONTRIBUTING.md +43 -0
  6. data/Gemfile +13 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +83 -0
  9. data/Thorfile +60 -0
  10. data/knife-briefcase.gemspec +32 -0
  11. data/lib/chef/knife/briefcase_delete.rb +14 -0
  12. data/lib/chef/knife/briefcase_get.rb +34 -0
  13. data/lib/chef/knife/briefcase_list.rb +10 -0
  14. data/lib/chef/knife/briefcase_put.rb +32 -0
  15. data/lib/chef/knife/briefcase_reload.rb +45 -0
  16. data/lib/knife-briefcase.rb +5 -0
  17. data/lib/knife-briefcase/knife.rb +69 -0
  18. data/lib/knife-briefcase/version.rb +3 -0
  19. data/spec/chef/knife/briefcase_delete_spec.rb +44 -0
  20. data/spec/chef/knife/briefcase_get_spec.rb +43 -0
  21. data/spec/chef/knife/briefcase_list_spec.rb +17 -0
  22. data/spec/chef/knife/briefcase_put_spec.rb +60 -0
  23. data/spec/chef/knife/briefcase_reload_spec.rb +32 -0
  24. data/spec/fixtures/.gitignore +1 -0
  25. data/spec/fixtures/briefcase.pem +27 -0
  26. data/spec/fixtures/gnupg.1/.gitignore +1 -0
  27. data/spec/fixtures/gnupg.1/pubring.gpg +0 -0
  28. data/spec/fixtures/gnupg.1/secring.gpg +0 -0
  29. data/spec/fixtures/gnupg.1/trustdb.gpg +0 -0
  30. data/spec/fixtures/gnupg.2/.gitignore +1 -0
  31. data/spec/fixtures/gnupg.2/pubring.gpg +0 -0
  32. data/spec/fixtures/gnupg.2/secring.gpg +0 -0
  33. data/spec/fixtures/gnupg.2/trustdb.gpg +0 -0
  34. data/spec/fixtures/gnupg.without-1/.gitignore +1 -0
  35. data/spec/fixtures/gnupg.without-1/pubring.gpg +0 -0
  36. data/spec/fixtures/gnupg.without-1/secring.gpg +0 -0
  37. data/spec/fixtures/gnupg.without-1/trustdb.gpg +0 -0
  38. data/spec/fixtures/gnupg/.gitignore +1 -0
  39. data/spec/fixtures/gnupg/pubring.gpg +0 -0
  40. data/spec/fixtures/gnupg/secring.gpg +0 -0
  41. data/spec/fixtures/gnupg/trustdb.gpg +0 -0
  42. data/spec/fixtures/knife.rb +4 -0
  43. data/spec/knife-briefcase/version_spec.rb +11 -0
  44. data/spec/knife_helper.rb +140 -0
  45. data/spec/smoke_spec.rb +9 -0
  46. data/spec/spec_helper.rb +62 -0
  47. metadata +271 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MjI5YTE4YzQ3OTk0ZTA2MjA5OGFhMTFkODJmNTAxYzk0ZWUwMTY2MA==
5
+ data.tar.gz: !binary |-
6
+ YTVmMGZiMGRkYTAwYjg1NzBjNzhiZGFhYmFjNmE5ZmE1NDc2ODk2Yw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDRkMmJkMWFlNDFjM2Q3YzcyNGQ5MGUyZDA2MDYxNzU0MDg0ZDVjNDhiNzM1
10
+ YTU2OWRmNDMyMThhOGQzMTgzYTA4NTMzMzE0MTlhOWM4OWJiZDBjNDRjYmUz
11
+ YTg5YjJjZDA0OGQ1NDJjZmUwZjgzYWRhZmM3YTdmZmM2MGE1YWU=
12
+ data.tar.gz: !binary |-
13
+ MDE5Zjk0Y2ZiNWZmMTY4MjNhZGM1NWM0YzI4MjFkY2M4OTdlZjVhZDgwYmEy
14
+ NmY1YWVjYzdlNTBmY2Q2ZmMxM2ZlNDM1MWE5MjQ0MDMyZDYyOGI3MWRiNjYx
15
+ NzdmYjU0NGY3MDZhODY5OGVlZjQ4Yzk2MzRmYTlhODY4ODY1NTI=
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ *~
4
+ .*.swp
5
+ .DS_Store
6
+ /.bundle
7
+ /.config
8
+ /.yardoc
9
+ /Gemfile.lock
10
+ /InstalledFiles
11
+ /coverage
12
+ /doc/public
13
+ /lib/bundler/man
14
+ /pkg
15
+ /spec/reports
16
+ /tmp
17
+ /vendor/cache
@@ -0,0 +1,13 @@
1
+ ---
2
+ bundler_args: --without development_workstation
3
+ script: bundle exec thor spec:ci
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ notifications:
8
+ hipchat:
9
+ secure: ! 'f83Ygzt9/IIABIe7W0lVEifCw7PIbrHiqQt/JTAawb0G10NgG2Svui9+fMj2
10
+
11
+ Byz4WPy0L4wOQ6YS8rV4Tv7tKjioSpUfkXClDlCLG0rFUEh4i/EsWVV+8NJ7
12
+
13
+ 9ju8aksblSo22OaFGd8ufUPYEhMY/05m/wAVAyxtVqZGANXrPYc='
@@ -0,0 +1,6 @@
1
+ # Changes
2
+
3
+ ## 0.0.1
4
+
5
+ * Initial release
6
+ * Created on Monday, 2013-06-17
@@ -0,0 +1,43 @@
1
+ # Contributing
2
+
3
+ ## Developing
4
+
5
+ 1. Fork the repository on GitHub
6
+ 2. Create your feature branch (`git checkout -b feature/awesomeness`)
7
+ 3. Create your changes.
8
+ * Add test cases in `spec/`. It's best if you first write a failing
9
+ test case, commit it, and then fix it in next commit - this makes
10
+ the whole change easier to review.
11
+ * Document your changes.
12
+ 4. Commit your changes (`git commit -am 'Add more awesomeness'`)
13
+ 5. Push to the branch (`git push -u origin feature/awesomeness`)
14
+ 6. Create new Pull Request on GitHub
15
+
16
+ ## Testing
17
+
18
+ ### Install what's needed
19
+
20
+ Make sure you have [http://gembundler.com/](Gem Bundler) version 1.3
21
+ or greater installed. If in doubt, just use [http://rvm.io/](RVM) or
22
+ [http://rbenv.org/](rbenv).
23
+
24
+ $ gem install bundler
25
+
26
+ Clone the project:
27
+
28
+ $ git clone git://github.com/3ofcoins/knife-briefcase.git
29
+
30
+ Then, run:
31
+
32
+ $ cd knife-briefcase
33
+ $ bundle install
34
+
35
+ Bundler will install all the needed gems and their dependencies.
36
+
37
+ ### Running tests
38
+
39
+ $ bundle exec thor spec
40
+
41
+ To generate test coverage report, tell it to Thor
42
+
43
+ $ bundle exec thor spec --coverage
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ # Helpers used with development, but not needed in runtime, build
6
+ # time, or for tests.
7
+ group :development_workstation do
8
+ gem 'awesome_print'
9
+ gem 'pry'
10
+ gem 'pry-debugger'
11
+ gem 'pry-rescue'
12
+ gem 'pry-stack_explorer'
13
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Maciej Pasternacki <maciej@3ofcoins.net>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,83 @@
1
+ # Knife Briefcase
2
+
3
+ This gem is [Knife](http://docs.opscode.com/knife.html) plugin for
4
+ [Opscode Chef](http://www.opscode.com/chef/) that stores GPG-encrypted
5
+ content for people in chef server's data bag.
6
+
7
+ Its intended use is to share infrastructure-related secrets (such as
8
+ encrypted data bag secret files, SSL private keys, passwords, etc.)
9
+ among the infrastructure team.
10
+
11
+ This may or may not work nicely with
12
+ [git-annex](http://git-annex.branchable.com/) via
13
+ [_hook_ special remote](http://git-annex.branchable.com/special_remotes/hook/).
14
+
15
+ ## Installation
16
+
17
+ Add this line to your Chef repository's Gemfile:
18
+
19
+ gem 'knife-briefcase', :git => 'git://github.com/3ofcoins/knife-briefcase/'
20
+
21
+ Or install it yourself:
22
+
23
+ $ gem build knife-briefcase.gemspec
24
+ $ gem install knife-briefcase*.gem
25
+
26
+ ## Usage
27
+
28
+ `knife briefcase put NAME [FILE]` -- encrypts and signs named `FILE`
29
+ or stdin, and saves it in the data bag with ID `NAME`.
30
+
31
+ `knife briefcase get NAME [FILE]` -- gets `NAME` from the data bag,
32
+ checks signature, decrypts, and shows the contents on standard output,
33
+ or saves it to `FILE` if provided.
34
+
35
+ `knife briefcase list` -- lists encrypted items in the data bag.
36
+
37
+ `knife briefcase delete NAME [NAME [...]]` -- deletes listed `NAME`s
38
+ from the data bag.
39
+
40
+ > **TODO: it may be good to refuse to delete files that the user is
41
+ > unable to encrypt.** User is able to delete them anyway, using
42
+ > `knife data bag delete`, but it shouldn't be allowed via `knife
43
+ > briefcase` command.
44
+
45
+ `knife briefcase reload [NAME [NAME [...]]]` -- downloads and decrypts
46
+ listed items, re-encrypts and re-signs them, and saves the
47
+ re-encrypted content back. If no names are provided, all the items are
48
+ re-encrypted. This should be called when briefcase holders list is
49
+ changed, to allow added user to decrypt bag - or to prevent further
50
+ access by removed user.
51
+
52
+ ## Configuration
53
+
54
+ Following `knife.rb` settings are used:
55
+
56
+ - `briefcase_holders` -- array of e-mail addresses that will be GPG
57
+ recipients of the data
58
+ - `briefcase_signers` -- e-mail address (or array of e-mail
59
+ addresses) that will be used to sign encrypted content
60
+ - `briefcase_data_bag` -- name of the data bag that will be used by
61
+ default to hold encrypted content. If not provided, `briefcase`
62
+ data bag will be used. The data bag name can be overriden on
63
+ command line.
64
+
65
+ ### Example configuration
66
+
67
+ ```ruby
68
+ briefcase_signers `git config --get user.email`.strip
69
+ briefcase_holders [
70
+ 'alice@myproject.com',
71
+ 'bob@myproject.com',
72
+ 'claire@myproject.com',
73
+ 'dave@myproject.com',
74
+ 'erin@myproject.com' ]
75
+ ```
76
+
77
+ ## Contributing
78
+
79
+ See the [CONTRIBUTING.md](CONTRIBUTING.md) file
80
+
81
+ ------------------------------------------------------------------------------
82
+
83
+ [![Build Status](https://travis-ci.org/3ofcoins/knife-briefcase.png?branch=master)](https://travis-ci.org/3ofcoins/knife-briefcase)
@@ -0,0 +1,60 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'rubygems'
3
+
4
+ require 'bundler/setup'
5
+
6
+ require 'rake/testtask'
7
+ require 'thor/rake_compat'
8
+
9
+ class Default < Thor
10
+ class Gem < Thor
11
+ namespace :gem
12
+
13
+ include Thor::RakeCompat
14
+ Bundler::GemHelper.install_tasks
15
+
16
+ desc "build", "Build knife-briefcase-#{KnifeBriefcase::VERSION}.gem into the pkg directory"
17
+ def build
18
+ Rake::Task["build"].execute
19
+ end
20
+
21
+ desc "release", "Create tag v#{KnifeBriefcase::VERSION} and build and push knife-briefcase-#{KnifeBriefcase::VERSION}.gem to Rubygems"
22
+ def release
23
+ Rake::Task["release"].execute
24
+ end
25
+
26
+ desc "install", "Build and install knife-briefcase-#{KnifeBriefcase::VERSION}.gem into system gems"
27
+ def install
28
+ Rake::Task["install"].execute
29
+ end
30
+ end
31
+
32
+ class Test < Thor
33
+ namespace :test
34
+ default_command :all
35
+
36
+ include Thor::RakeCompat
37
+
38
+ Rake::TestTask.new :spec do |task|
39
+ task.libs << 'spec'
40
+ task.test_files = FileList['spec/**/*_spec.rb']
41
+ end
42
+
43
+ desc 'spec', 'Run specs'
44
+ def spec
45
+ Rake::Task['spec'].execute
46
+ end
47
+
48
+ desc 'all', 'Run all tests'
49
+ def all
50
+ invoke(:spec)
51
+ end
52
+
53
+ desc 'ci', 'Run all tests for continuous integration'
54
+ def ci
55
+ ENV['CI'] = 'true'
56
+ invoke(:all)
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,32 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'knife-briefcase/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "knife-briefcase"
8
+ spec.version = KnifeBriefcase::VERSION
9
+ spec.authors = ["Maciej Pasternacki"]
10
+ spec.email = ["maciej@pasternacki.net"]
11
+ spec.description = 'Knife plugin to store GPG-encrypted data in Chef data bag'
12
+ spec.summary = spec.description
13
+ spec.homepage = "https://github.com/3ofcoins/knife-briefcase/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "chef"
22
+ spec.add_dependency "gpgme"
23
+ spec.add_dependency "highline"
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "chef-zero"
26
+ spec.add_development_dependency "minitest"
27
+ spec.add_development_dependency "mocha"
28
+ spec.add_development_dependency "ridley"
29
+ spec.add_development_dependency "simplecov"
30
+ spec.add_development_dependency "thor", "~> 0.18.1"
31
+ spec.add_development_dependency "wrong", ">= 0.7.0"
32
+ end
@@ -0,0 +1,14 @@
1
+ require 'knife-briefcase/knife'
2
+
3
+ class Chef::Knife::BriefcaseDelete < Chef::Knife
4
+ include KnifeBriefcase::Knife
5
+ banner "knife briefcase delete NAME [NAME [...]]"
6
+
7
+ def run
8
+ @name_args.each do |item_name|
9
+ delete_object(Chef::DataBagItem, item_name, 'briefcase_item') do
10
+ rest.delete_rest("data/#{data_bag_name}/#{item_name}")
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,34 @@
1
+ require 'knife-briefcase/knife'
2
+
3
+ class Chef::Knife::BriefcaseGet < Chef::Knife
4
+ include KnifeBriefcase::Knife
5
+ banner "knife briefcase get NAME [FILE]"
6
+
7
+ def run
8
+ encrypted = Chef::DataBagItem.load(data_bag_name, @name_args[0]).
9
+ raw_data['content']
10
+
11
+ begin
12
+ crypto.verify(GPGME::Data.from_str(encrypted)) do |sig|
13
+ if sig.valid?
14
+ Chef::Log.info(sig.to_s)
15
+ else
16
+ Chef::Log.error(sig.to_s)
17
+ exit 1 # TODO: --force
18
+ end
19
+ end
20
+ rescue
21
+ Chef::Log.error("Cannot verify signature: #{$!}")
22
+ exit 1
23
+ end
24
+
25
+ if file
26
+ crypto.decrypt(GPGME::Data.from_str(encrypted), :output => File.open(file, 'w+'))
27
+ else
28
+ stdout.write(crypto.decrypt(GPGME::Data.from_str(encrypted)))
29
+ end
30
+ rescue GPGME::Error::DecryptFailed
31
+ Chef::Log.fatal("Decryption failed")
32
+ exit 1
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ require 'knife-briefcase/knife'
2
+
3
+ class Chef::Knife::BriefcaseList < Chef::Knife
4
+ include KnifeBriefcase::Knife
5
+ banner "knife briefcase list"
6
+
7
+ def run
8
+ output(format_list_for_display(Chef::DataBag.load(data_bag_name)))
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ require 'knife-briefcase/knife'
2
+
3
+ class Chef::Knife::BriefcasePut < Chef::Knife
4
+ include KnifeBriefcase::Knife
5
+ banner "knife briefcase put NAME [FILE]"
6
+
7
+ def run
8
+ encrypted = crypto.encrypt( GPGME::Data.from_io(file ? File.open(file) : stdin),
9
+ :recipients => recipients,
10
+ :sign => !!signers,
11
+ :signers => signers,
12
+ :always_trust => true)
13
+
14
+ begin
15
+ rest.post_rest("data", { "name" => data_bag_name })
16
+ ui.info("Created data_bag[#{data_bag_name}]")
17
+ rescue Net::HTTPServerException => e
18
+ raise unless e.to_s =~ /^409/
19
+ ui.info("data_bag[#{data_bag_name}] already exists")
20
+ end
21
+
22
+ item = Chef::DataBagItem.from_hash(
23
+ 'id' => item_name, 'content' => encrypted.to_s )
24
+ item.data_bag(data_bag_name)
25
+ begin
26
+ rest.post_rest("data/#{data_bag_name}", item)
27
+ rescue Net::HTTPServerException => e
28
+ raise unless e.to_s =~ /^409/
29
+ rest.put_rest("data/#{data_bag_name}/#{item_name}", item)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,45 @@
1
+ require 'knife-briefcase/knife'
2
+
3
+ class Chef::Knife::BriefcaseReload < Chef::Knife
4
+ include KnifeBriefcase::Knife
5
+ banner "knife briefcase reload [NAME [NAME [...]]]"
6
+
7
+ def run
8
+ item_names = if @name_args.empty?
9
+ Chef::DataBag.list(data_bag_name).keys
10
+ else
11
+ @name_args
12
+ end
13
+
14
+ item_names.each do |item_name|
15
+ encrypted = Chef::DataBagItem.load(data_bag_name, item_name).raw_data['content']
16
+
17
+ begin
18
+ crypto.verify(GPGME::Data.from_str(encrypted)) do |sig|
19
+ if sig.valid?
20
+ Chef::Log.info(sig.to_s)
21
+ else
22
+ Chef::Log.error(sig.to_s)
23
+ exit 1 # TODO: --force
24
+ end
25
+ end
26
+ rescue
27
+ Chef::Log.error("Cannot verify signature: #{$!}")
28
+ exit 1
29
+ end
30
+
31
+ recrypted = crypto.encrypt(
32
+ crypto.decrypt(GPGME::Data.from_str(encrypted)),
33
+
34
+ :recipients => recipients,
35
+ :sign => !!signers,
36
+ :signers => signers,
37
+ :always_trust => true)
38
+
39
+ item = Chef::DataBagItem.from_hash(
40
+ 'id' => item_name, 'content' => recrypted.to_s )
41
+ item.data_bag(data_bag_name)
42
+ rest.put_rest("data/#{data_bag_name}/#{item_name}", item)
43
+ end
44
+ end
45
+ end