knife-briefcase 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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