Skip to content

Commit

Permalink
Merge pull request #209 from chef/SPOOL-118/user-org-scoped-keys-support
Browse files Browse the repository at this point in the history
Chef Server 12.5 Support
  • Loading branch information
tylercloke committed Apr 21, 2016
2 parents c68b52e + c4d46fc commit c98d4fb
Show file tree
Hide file tree
Showing 18 changed files with 785 additions and 246 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ branches:
- master
rvm:
- "1.9.3-p551"
- "2.0.0-p647"
- "2.1.6"
- "2.2.2"
install: bundle install --binstubs --without changelog
Expand Down
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,69 @@ This plugin is distributed as a Ruby Gem. To install it, run:
Depending on your system's configuration, you may need to run this command
with root privileges.

## DEVELOPMENT:

### Git Hooks

There is a git pre-commit hook to help you keep your chefstyle up to date.
If you wish to use it, simply:

```
mv hooks/pre-commit .git/hooks/
chmod +x .git/hooks/pre-commit
```

### Running Your Changes

To run your changes locally:

```
bundle install
bundle exec knife vault
```

### Testing

#### Rspec Tests

There are some unit tests that can be run with:

```
bundle exec rspec spec/
```

#### Cucumber Testing

There are cucumber tests. Run the whole suite with:

```
bundle exec rake features
```

If you get any failures, you can run the specific feature that failed with:

```
bundle exec cucumber features/<failed>.feature
```

If you want to test things out directly, after a failure you can go into the test
directory and try out the commands that failed:

```
cd tmp/aruba
bundle exec knife <your command that failed from test with -c knife.rb>
```

Optionally add `-VV` to the above to get a full stacktrace.

### Rubocop Errors

If you are seeing rubocop errors in travis for your pull request, run:

`bundle exec chefstyle -a`

This will fix up your rubocop errors automatically, and warn you about any it can't.

## KNIFE COMMANDS:

See KNIFE_EXAMPLES.md for examples of commands
Expand Down
9 changes: 6 additions & 3 deletions chef-vault.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ Gem::Specification.new do |s|
s.add_development_dependency "aruba", "~> 0.6"
s.add_development_dependency "simplecov", "~> 0.9"
s.add_development_dependency "simplecov-console", "~> 0.2"
s.add_development_dependency "rubocop", "~> 0.30"
# Chef 12 and higher pull in Ohai 8, which needs Ruby v2
# so only in the case of a CI build on ruby v1, we constrain
# chef to 11 or lower so that we can maintain CI test coverage
# of older versions
if ENV.key?("TRAVIS_BUILD") && RUBY_VERSION =~ /^1/
s.add_development_dependency "chef", "~> 11.18"
else
s.add_development_dependency "chef", ">= 0.10.10"
elsif ENV.key?("TRAVIS_BUILD") && RUBY_VERSION == "2.1.6"
# Test version of Chef with Chef Zero before
# /orgs/org/users/user/keys endpoint was added.
s.add_development_dependency "chef", "12.8.1"
else # Test most current version of Chef on 2.2.2
s.add_development_dependency "chef"
end
end
2 changes: 1 addition & 1 deletion features/vault_create.feature
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,4 @@ Feature: knife vault create
Given a local mode chef repo with nodes 'one,two'
And I create a vault item 'test/item' containing the JSON '{"foo": "bar"}' encrypted for 'one,two,three' with 'alice' as admin
Then the exit status should not be 0
And the output should contain "FATAL: Could not find alice in users or clients!"
And the output should contain "FATAL: Could not find default key for alice in users or clients!"
43 changes: 43 additions & 0 deletions hooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env ruby
output = `bundle exec chefstyle -a`
if !$?.success?
puts "pre-commit hook: Tried to run `bundle exec chefstyle -a` to autocleanup errors, but it failed with output:"
puts output
end

detected = /(\d+) offenses detected/.match(output)
corrected = /(\d+) offenses corrected/.match(output)

# no errors detected by chefstyle
exit 0 if detected.nil?

# chefstyle found errors
if !detected.nil?
# get the first result from the capture group that isn't the whole capture
num_detected = detected.to_a[1].to_i
num_corrected = if corrected.nil?
0
else
corrected.to_a[1].to_i
end
if num_detected == num_corrected
puts <<EOF
pre-commit hook: Ran `bundle exec chefstyle -a` to autocleanup errors if any existed and
#{num_detected} were detected, but all were cleaned up. `git add` all files that were
autoupdated and try commiting again. New git status:
EOF
puts `git status`
else
puts <<EOF
pre-commit hook: Ran `bundle exec chefstyle -a` to autocleanup errors if any existed and
#{num_detected} were detected, but #{num_detected - num_corrected} could not be cleaned up
automatically. Run:
bundle exec chefstyle -a
to see remaining errors to clean up by hand, add all updated files, and try commiting again.
EOF
end
exit 1
end
4 changes: 2 additions & 2 deletions lib/chef-vault.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
require "chef-vault/item_keys"
require "chef-vault/user"
require "chef-vault/certificate"
require "chef-vault/chef_patch/api_client"
require "chef-vault/chef_patch/user"
require "chef-vault/chef_api"
require "chef-vault/chef_key"

class ChefVault
attr_accessor :vault
Expand Down
39 changes: 39 additions & 0 deletions lib/chef-vault/chef_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Author:: Tyler Cloke <[email protected]>
# Copyright:: Copyright 2016, Chef Software, Inc.
# License:: Apache License, Version 2.0

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "chef/server_api"

class ChefVault
class ChefApi

def rest_v0
@rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "0" })
end

def rest_v1
@rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_root], { :api_version => "1" })
end

def org_scoped_rest_v0
@org_scoped_rest_v0 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "0" })
end

def org_scoped_rest_v1
@org_scoped_rest_v1 ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { :api_version => "1" })
end

end
end
149 changes: 149 additions & 0 deletions lib/chef-vault/chef_key.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Author:: Tyler Cloke <[email protected]>
# Copyright:: Copyright 2016, Chef Software, Inc.
# License:: Apache License, Version 2.0

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "json"

class ChefVault
class ChefKey

attr_accessor :key_string
attr_reader :actor_type
attr_reader :actor_name

def initialize(actor_type, actor_name)
if actor_type != "clients" && actor_type != "admins"
raise "You must pass either 'clients' or 'admins' as the first argument to ChefVault::ChefKey.new."
end
@actor_type = actor_type
@actor_name = actor_name
end

def key
@key ||= is_admin? ? get_admin_key : get_client_key
end

def get_admin_key
# chef vault currently only supports using the default key
get_key("users")
rescue Net::HTTPServerException => http_error
# if we failed to find an admin key, attempt to load a client key by the same name
case http_error.response.code
when "403"
print_forbidden_error
raise http_error
when "404"
begin
$stdout.puts "WARNING: The default key for #{actor_name} not found in users, trying client keys."
get_key("clients")
rescue Net::HTTPServerException => http_error
case http_error.response.code
when "404"
raise ChefVault::Exceptions::AdminNotFound,
"FATAL: Could not find default key for #{actor_name} in users or clients!"
when "403"
print_forbidden_error
raise http_error
else
raise http_error
end
end
else
raise http_error
end
end

def get_client_key
begin
get_key("clients")
rescue Net::HTTPServerException => http_error
if http_error.response.code == "403"
print_forbidden_error
raise http_error
elsif http_error.response.code == "404"
raise ChefVault::Exceptions::ClientNotFound,
"#{actor_name} is not a valid chef client and/or node"
else
raise http_error
end
end
end

def is_client?
actor_type == "clients"
end

def is_admin?
actor_type == "admins"
end

# @private

def api
@api ||= ChefVault::ChefApi.new
end

# Use API V0 to load the public_key directly from the user object
# using the chef-client code.
def chef_api_client
@chef_api_client ||= begin
require "chef/api_client"
Chef::ApiClient
end
end

# Similar thing as above but for client.
def chef_user
@chef_user ||= begin
require "chef/user"
Chef::User
end
end

def get_key(request_actor_type)
api.org_scoped_rest_v1.get("#{request_actor_type}/#{actor_name}/keys/default")["public_key"]
# If the keys endpoint doesn't exist, try getting it directly from the V0 chef object.
rescue Net::HTTPServerException => http_error
raise http_error unless http_error.response.code == "404"
if request_actor_type == "clients"
chef_api_client.load(actor_name).public_key
else
chef_user.load(actor_name).public_key
end
end

def print_forbidden_error
$stdout.puts <<EOF
ERROR: You received a 403 FORBIDDEN while requesting an #{actor_type} key for #{actor_name}.
If you are on Chef Server < 12.5:
Clients do not have access to all public keys within their org.
Either upgrade to Chef Server >= 12.5 or make this request using a user.
If you are on Chef Server == 12.5.0
All clients and users have access to the public keys endpoint. Getting
this error on 12.5.0 is unexpected regardless of what your
public_key_read_access_group contains.
If you are on Chef Server > 12.5.1
Has your public_key_read_access_group been modified? This group controls
read access on public keys within your org. It defaults to the users
and client groups, so all org actors should have permission unless
the defaults have been changed.
EOF
end
end
end
45 changes: 0 additions & 45 deletions lib/chef-vault/chef_patch/api_client.rb

This file was deleted.

Loading

0 comments on commit c98d4fb

Please sign in to comment.