# Author:: Tyler Cloke # 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 Actor attr_accessor :key_string attr_reader :type attr_reader :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::Actor.new." end @type = actor_type @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 ChefVault::Log.warn "The default key for #{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 #{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 get_key("clients") rescue Net::HTTPServerException => http_error if http_error.response.code.eql?("403") print_forbidden_error raise http_error elsif http_error.response.code.eql?("404") raise ChefVault::Exceptions::ClientNotFound, "#{name} is not a valid chef client and/or node" else raise http_error end end def is_client? type == "clients" end def is_admin? 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}/#{name}/keys/default").fetch("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.eql?("404") if request_actor_type.eql?("clients") chef_api_client.load(name).public_key else chef_user.load(name).public_key end end def print_forbidden_error ChefVault::Log.error <= 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