1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
#
# Author:: Tyler Ball (<tball@opscode.com>)
# Copyright:: Copyright (c) 2014 Opscode, 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 'mixlib/cli'
require 'chef/config'
require 'chef/encrypted_data_bag_item/check_encrypted'
class Chef
class Knife
module DataBagSecretOptions
include Mixlib::CLI
include Chef::EncryptedDataBagItem::CheckEncrypted
# The config object is populated by knife#merge_configs with knife.rb `knife[:*]` config values, but they do
# not overwrite the command line properties. It does mean, however, that `knife[:secret]` and `--secret-file`
# passed at the same time populate both `config[:secret]` and `config[:secret_file]`. We cannot differentiate
# the valid case (`knife[:secret]` in config file and `--secret-file` on CL) and the invalid case (`--secret`
# and `--secret-file` on the CL) - thats why I'm storing the CL options in a different config key if they
# are provided.
def self.included(base)
base.option :secret,
:short => "-s SECRET",
:long => "--secret ",
:description => "The secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret'",
# Need to store value from command line in separate variable - knife#merge_configs populates same keys
# on config object from
:proc => Proc.new { |s| set_cl_secret(s) }
base.option :secret_file,
:long => "--secret-file SECRET_FILE",
:description => "A file containing the secret key to use to encrypt data bag item values. Can also be defaulted in your config with the key 'secret_file'",
:proc => Proc.new { |sf| set_cl_secret_file(sf) }
base.option :encrypt,
:long => "--encrypt",
:description => "If 'secret' or 'secret_file' is present in your config, then encrypt data bags using it",
:boolean => true,
:default => false
end
def encryption_secret_provided?
base_encryption_secret_provided?
end
def encryption_secret_provided_ignore_encrypt_flag?
base_encryption_secret_provided?(false)
end
def read_secret
# Moving the non 'compile-time' requires into here to speed up knife command loading
# IE, if we are not running 'knife data bag *' we don't need to load 'chef/encrypted_data_bag_item'
require 'chef/encrypted_data_bag_item'
if has_cl_secret?
config[:secret]
elsif has_cl_secret_file?
Chef::EncryptedDataBagItem.load_secret(config[:secret_file])
elsif secret = knife_config[:secret]
secret
else
secret_file = knife_config[:secret_file]
Chef::EncryptedDataBagItem.load_secret(secret_file)
end
end
def validate_secrets
if has_cl_secret? && has_cl_secret_file?
ui.fatal("Please specify only one of --secret, --secret-file")
exit(1)
end
if knife_config[:secret] && knife_config[:secret_file]
ui.fatal("Please specify only one of 'secret' or 'secret_file' in your config file")
exit(1)
end
end
private
##
# Determine if the user has specified an appropriate secret for encrypting data bag items.
# @returns boolean
def base_encryption_secret_provided?(need_encrypt_flag = true)
validate_secrets
return true if has_cl_secret? || has_cl_secret_file?
if need_encrypt_flag
if config[:encrypt]
unless knife_config[:secret] || knife_config[:secret_file]
ui.fatal("No secret or secret_file specified in config, unable to encrypt item.")
exit(1)
end
return true
end
return false
elsif knife_config[:secret] || knife_config[:secret_file]
# Certain situations (show and bootstrap) don't need a --encrypt flag to use the config file secret
return true
end
return false
end
def has_cl_secret?
Chef::Config[:knife].has_key?(:cl_secret)
end
def self.set_cl_secret(s)
Chef::Config[:knife][:cl_secret] = s
end
def has_cl_secret_file?
Chef::Config[:knife].has_key?(:cl_secret_file)
end
def self.set_cl_secret_file(sf)
Chef::Config[:knife][:cl_secret_file] = sf
end
def knife_config
Chef::Config.key?(:knife) ? Chef::Config[:knife] : {}
end
end
end
end
|