Class: Chef::Knife::Bootstrap
- Inherits:
-
Chef::Knife
- Object
- Chef::Knife
- Chef::Knife::Bootstrap
- Includes:
- DataBagSecretOptions, LicenseAcceptance::CLIFlags::MixlibCLI
- Defined in:
- lib/chef/knife/bootstrap.rb,
lib/chef/knife/bootstrap/client_builder.rb,
lib/chef/knife/bootstrap/train_connector.rb,
lib/chef/knife/bootstrap/chef_vault_handler.rb
Defined Under Namespace
Classes: ChefVaultHandler, ClientBuilder, RemoteExecutionFailed, TrainConnector
Constant Summary
Constants inherited from Chef::Knife
CHEF_ORGANIZATION_MANAGEMENT, KNIFE_ROOT, OFFICIAL_PLUGINS, OPSCODE_HOSTED_CHEF_ACCESS_CONTROL, VERSION
Instance Attribute Summary collapse
-
#connection ⇒ Object
readonly
Returns the value of attribute connection.
Attributes inherited from Chef::Knife
Instance Method Summary collapse
-
#base_opts ⇒ Object
Common configuration for all protocols.
-
#bootstrap_command(remote_path) ⇒ Object
build the command string for bootstrapping.
-
#bootstrap_context ⇒ Object
Establish bootstrap context for template rendering.
-
#bootstrap_run_command(cmd) ⇒ Object
Actual bootstrap command to be run on the node.
-
#bootstrap_template ⇒ String
The CLI specific bootstrap template or the default.
-
#check_eula_license ⇒ Object
Determine if we need to accept the Chef Infra license locally in order to successfully bootstrap the remote node.
- #chef_vault_handler ⇒ Object
- #client_builder ⇒ Object
-
#config_value(key, fallback_key = nil, default = nil) ⇒ Object
This is for deprecating config options.
- #connect! ⇒ Object
-
#connection_opts(reset: false, sudo_pass: nil) ⇒ Object
host via train.
-
#connection_protocol ⇒ Object
url values override CLI flags, if you provide both we’ll use the one that you gave in the URL.
-
#default_bootstrap_template ⇒ String
The default bootstrap template to use to bootstrap a server.
- #do_connect(conn_options) ⇒ Object
- #find_template ⇒ Object
- #first_boot_attributes ⇒ Object
-
#force_ssh_password_opts(password) ⇒ Object
Config overrides to force password auth.
- #force_winrm_password_opts(password) ⇒ Object
- #gateway_opts ⇒ Object
- #handle_ssh_error(e) ⇒ Object
- #host_descriptor ⇒ Object
- #host_verify_opts ⇒ Object
- #perform_bootstrap(remote_bootstrap_script_path) ⇒ Object
-
#plugin_create_instance! ⇒ TrueClass
Create the server that we will bootstrap, if necessary.
-
#plugin_finalize ⇒ void
Perform any teardown or cleanup necessary by the plugin.
-
#plugin_setup! ⇒ TrueClass
Perform any setup necessary by the plugin.
-
#plugin_validate_options! ⇒ TrueClass
Validate any additional options.
- #register_client ⇒ Object
- #render_template ⇒ Object
- #run ⇒ Object
- #secret ⇒ Object
-
#server_name ⇒ String
The server_name is the DNS or IP we are going to connect to, it is not necessarily the node name, the fqdn, or the hostname of the server.
- #ssh? ⇒ Boolean
-
#ssh_gateway ⇒ Object
SSH Authentication.
- #ssh_identity_opts ⇒ Object
- #ssh_opts ⇒ Object
- #ssh_verify_host_key ⇒ Object
-
#sudo_opts(sudo_pass) ⇒ Object
use_sudo - tells bootstrap to use the sudo command to run bootstrap use_sudo_password - tells bootstrap to use the sudo command to run bootstrap and to use the password specified with –password TODO: I’d like to make our sudo options sane: –sudo (bool) - use sudo –sudo-password PASSWORD (default: :password) - use this password for sudo –sudo-options “opt,opt,opt” to pass into sudo –sudo-command COMMAND sudo command other than sudo REVIEW NOTE: knife bootstrap did not pull sudo values from Chef::Config, should we change that for consistency?.
- #upload_bootstrap(content) ⇒ Object
-
#validate_first_boot_attributes! ⇒ Object
Fail if both first_boot_attributes and first_boot_attributes_from_file are set.
-
#validate_name_args! ⇒ Object
fail if the server_name is nil.
-
#validate_policy_options! ⇒ TrueClass
Ensure options are valid by checking policyfile values.
-
#validate_protocol! ⇒ TrueClass
Ensure a valid protocol is provided for target host connection.
-
#validate_winrm_transport_opts! ⇒ Object
Fail if using plaintext auth without ssl because this can expose keys in plaintext on the wire.
-
#warn_on_short_session_timeout ⇒ Object
If session_timeout is too short, it is likely a holdover from “–winrm-session-timeout” which used minutes as its unit, instead of seconds.
- #winrm? ⇒ Boolean
-
#winrm_auth_method ⇒ Object
FIXME: someone needs to clean this up properly: github.com/chef/chef/issues/9645 This code is deliberately left without an abstraction around deprecating the config options to avoid knife plugins from using those methods (which will need to be deprecated and break them) via inheritance (ruby does not have a true ‘private` so the lack of any inheritable implementation is because of that).
- #winrm_opts ⇒ Object
- #winrm_warn_no_ssl_verification ⇒ Object
Methods included from DataBagSecretOptions
#encryption_secret_provided?, #encryption_secret_provided_ignore_encrypt_flag?, included, #read_secret, #validate_secrets
Methods inherited from Chef::Knife
#api_key, #apply_computed_config, category, chef_config_dir, common_name, #config_file_defaults, #config_file_settings, config_loader, #config_source, #configure_chef, #create_object, #delete_object, dependency_loaders, deps, #format_rest_error, guess_category, #humanize_exception, #humanize_http_exception, inherited, #initialize, list_commands, load_commands, load_config, load_deps, #maybe_setup_fips, #merge_configs, msg, #noauth_rest, #parse_options, reset_config_loader!, reset_subcommands!, #rest, #root_rest, run, #run_with_pretty_exceptions, #server_url, #show_usage, snake_case_name, subcommand_category, subcommand_class_from, subcommand_files, subcommand_loader, subcommands, subcommands_by_category, #test_mandatory_field, ui, unnamed?, use_separate_defaults?, #username
Constructor Details
This class inherits a constructor from Chef::Knife
Instance Attribute Details
#connection ⇒ Object (readonly)
Returns the value of attribute connection.
419 420 421 |
# File 'lib/chef/knife/bootstrap.rb', line 419 def connection @connection end |
Instance Method Details
#base_opts ⇒ Object
Common configuration for all protocols
929 930 931 932 933 934 935 936 937 938 939 940 |
# File 'lib/chef/knife/bootstrap.rb', line 929 def base_opts port = config_for_protocol(:port) user = config_for_protocol(:user) {}.tap do |opts| opts[:logger] = Chef::Log opts[:password] = config[:connection_password] if config.key?(:connection_password) opts[:user] = user if user opts[:max_wait_until_ready] = config[:max_wait].to_i unless config[:max_wait].nil? # TODO - when would we need to provide rdp_port vs port? Or are they not mutually exclusive? opts[:port] = port if port end end |
#bootstrap_command(remote_path) ⇒ Object
build the command string for bootstrapping
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 |
# File 'lib/chef/knife/bootstrap.rb', line 1114 def bootstrap_command(remote_path) if connection.windows? "cmd.exe /C #{remote_path}" else cmd = "sh #{remote_path}" if config[:su_user] # su - USER is subject to required an interactive console # Otherwise, it will raise: su: must be run from a terminal (pty: true) cmd = "su - #{config[:su_user]} -c '#{cmd}'" cmd = "sudo " << cmd if config[:use_sudo] end cmd end end |
#bootstrap_context ⇒ Object
Establish bootstrap context for template rendering. Requires connection to be a live connection in order to determine the correct platform.
531 532 533 534 535 536 537 538 539 540 |
# File 'lib/chef/knife/bootstrap.rb', line 531 def bootstrap_context @bootstrap_context ||= if connection.windows? require_relative "core/windows_bootstrap_context" Knife::Core::WindowsBootstrapContext.new(config, config[:run_list], Chef::Config, secret) else require_relative "core/bootstrap_context" Knife::Core::BootstrapContext.new(config, config[:run_list], Chef::Config, secret) end end |
#bootstrap_run_command(cmd) ⇒ Object
Actual bootstrap command to be run on the node. Handles recursive calls if su USER failed to authenticate.
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
# File 'lib/chef/knife/bootstrap.rb', line 612 def bootstrap_run_command(cmd) r = connection.run_command(cmd) do |data, channel| ui.msg("#{ui.color(" [#{connection.hostname}]", :cyan)} #{data}") channel.send_data("#{config[:su_password] || config[:connection_password]}\n") if data.match?("Password:") end if r.exit_status != 0 ui.error("The following error occurred on #{server_name}:") ui.error("#{r.stdout} #{r.stderr}".strip) exit(r.exit_status) end rescue Train::UserError => e limit ||= 0 if e.reason == :bad_su_user_password && limit < 3 limit += 1 ui.warn("Failed to authenticate su - #{config[:su_user]} to #{server_name}") config[:su_password] = ui.ask("Enter password for su - #{config[:su_user]}@#{server_name}:", echo: false) retry else raise end end |
#bootstrap_template ⇒ String
Returns The CLI specific bootstrap template or the default.
487 488 489 490 |
# File 'lib/chef/knife/bootstrap.rb', line 487 def bootstrap_template # Allow passing a bootstrap template or use the default config[:bootstrap_template] || default_bootstrap_template end |
#check_eula_license ⇒ Object
Determine if we need to accept the Chef Infra license locally in order to successfully bootstrap the remote node. Remote ‘chef-client’ run will fail if it is >= 15 and the license is not accepted locally.
447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/chef/knife/bootstrap.rb', line 447 def check_eula_license Chef::Log.debug("Checking if we need to accept Chef license to bootstrap node") version = config[:bootstrap_version] || Chef::VERSION.split(".").first acceptor = LicenseAcceptance::Acceptor.new(logger: Chef::Log, provided: Chef::Config[:chef_license]) if acceptor.license_required?("chef", version) Chef::Log.debug("License acceptance required for chef version: #{version}") license_id = acceptor.id_from_mixlib("chef") acceptor.check_and_persist(license_id, version) Chef::Config[:chef_license] ||= acceptor.acceptance_value end end |
#chef_vault_handler ⇒ Object
438 439 440 441 442 443 |
# File 'lib/chef/knife/bootstrap.rb', line 438 def chef_vault_handler @chef_vault_handler ||= Chef::Knife::Bootstrap::ChefVaultHandler.new( config: config, ui: ui ) end |
#client_builder ⇒ Object
430 431 432 433 434 435 436 |
# File 'lib/chef/knife/bootstrap.rb', line 430 def client_builder @client_builder ||= Chef::Knife::Bootstrap::ClientBuilder.new( chef_config: Chef::Config, config: config, ui: ui ) end |
#config_value(key, fallback_key = nil, default = nil) ⇒ Object
This is for deprecating config options. The fallback_key can be used to pull an old knife config option out of the config file when the cli value has been renamed. This is different from the deprecated cli values, since these are for config options that have no corresponding cli value.
DO NOT USE - this whole API is considered deprecated
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 |
# File 'lib/chef/knife/bootstrap.rb', line 1092 def config_value(key, fallback_key = nil, default = nil) Chef.deprecated(:knife_bootstrap_apis, "Use of config_value is deprecated. Knife plugin authors should access the config hash directly, which does correct merging of cli and config options.") if config.key?(key) # the first key is the primary key so we check the merged hash first config[key] elsif config.key?(fallback_key) # we get the old config option here (the deprecated cli option shouldn't exist) config[fallback_key] else default end end |
#connect! ⇒ Object
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 |
# File 'lib/chef/knife/bootstrap.rb', line 635 def connect! ui.info("Connecting to #{ui.color(server_name, :bold)} using #{connection_protocol}") opts ||= connection_opts.dup do_connect(opts) rescue Train::Error => e # We handle these by message text only because train only loads the # transports and protocols that it needs - so the exceptions may not be defined, # and we don't want to require files internal to train. if e. =~ /fingerprint (\S+) is unknown for "(.+)"/ # Train::Transports::SSHFailed fingerprint = $1 hostname, ip = $2.split(",") # TODO: convert the SHA256 base64 value to hex with colons # 'ssh' example output: # RSA key fingerprint is e5:cb:c0:e2:21:3b:12:52:f8:ce:cb:00:24:e2:0c:92. # ECDSA key fingerprint is 5d:67:61:08:a9:d7:01:fd:5e:ae:7e:09:40:ef:c0:3c. # will exit 3 on N ui.confirm <<~EOM The authenticity of host '#{hostname} (#{ip})' can't be established. fingerprint is #{fingerprint}. Are you sure you want to continue connecting EOM # FIXME: this should save the key to known_hosts but doesn't appear to be config[:ssh_verify_host_key] = :accept_new conn_opts = connection_opts(reset: true, sudo_pass: opts[:password]) opts.merge! conn_opts retry elsif (ssh? && e.cause && e.cause.class == Net::SSH::AuthenticationFailed) || (ssh? && e.class == Train::ClientError && e.reason == :no_ssh_password_or_key_available) if connection.password_auth? raise else ui.warn("Failed to authenticate #{opts[:user]} to #{server_name} - trying password auth") password = ui.ask("Enter password for #{opts[:user]}@#{server_name}:", echo: false) end opts.merge! force_ssh_password_opts(password) retry else raise end rescue RuntimeError => e if winrm? && e. == "password is a required option" if connection.password_auth? raise else ui.warn("Failed to authenticate #{opts[:user]} to #{server_name} - trying password auth") password = ui.ask("Enter password for #{opts[:user]}@#{server_name}:", echo: false) end opts.merge! force_winrm_password_opts(password) retry else raise end end |
#connection_opts(reset: false, sudo_pass: nil) ⇒ Object
host via train
906 907 908 909 910 911 912 913 914 915 916 917 918 |
# File 'lib/chef/knife/bootstrap.rb', line 906 def connection_opts(reset: false, sudo_pass: nil ) return @connection_opts unless @connection_opts.nil? || reset == true @connection_opts = {} @connection_opts.merge! base_opts @connection_opts.merge! host_verify_opts @connection_opts.merge! gateway_opts @connection_opts.merge! sudo_opts(sudo_pass) @connection_opts.merge! winrm_opts @connection_opts.merge! ssh_opts @connection_opts.merge! ssh_identity_opts @connection_opts end |
#connection_protocol ⇒ Object
url values override CLI flags, if you provide both we’ll use the one that you gave in the URL.
695 696 697 698 699 700 701 |
# File 'lib/chef/knife/bootstrap.rb', line 695 def connection_protocol return @connection_protocol if @connection_protocol from_url = host_descriptor =~ %r{^(.*)://} ? $1 : nil from_knife = config[:connection_protocol] @connection_protocol = from_url || from_knife || "ssh" end |
#default_bootstrap_template ⇒ String
The default bootstrap template to use to bootstrap a server. This is a public API hook which knife plugins use or inherit and override.
463 464 465 466 467 468 469 |
# File 'lib/chef/knife/bootstrap.rb', line 463 def default_bootstrap_template if connection.windows? "windows-chef-client-msi" else "chef-full" end end |
#do_connect(conn_options) ⇒ Object
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 |
# File 'lib/chef/knife/bootstrap.rb', line 703 def do_connect() @connection = TrainConnector.new(host_descriptor, connection_protocol, ) connection.connect! rescue Train::UserError => e limit ||= 1 if !.key?(:pty) && e.reason == :sudo_no_tty ui.warn("#{e.} - trying with pty request") [:pty] = true # ensure we can talk to systems with requiretty set true in sshd config retry elsif e.reason == :sudo_missing_terminal ui.error "Sudo password is required for this operation. Please enter password using -P or --ssh-password option" elsif config[:use_sudo_password] && (e.reason == :sudo_password_required || e.reason == :bad_sudo_password) && limit < 3 ui.warn("Failed to authenticate #{[:user]} to #{server_name} - #{e.} \n sudo: #{limit} incorrect password attempt") sudo_password = ui.ask("Enter sudo password for #{[:user]}@#{server_name}:", echo: false) limit += 1 [:sudo_password] = sudo_password retry else raise end end |
#find_template ⇒ Object
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
# File 'lib/chef/knife/bootstrap.rb', line 492 def find_template template = bootstrap_template # Use the template directly if it's a path to an actual file if File.exist?(template) Chef::Log.trace("Using the specified bootstrap template: #{File.dirname(template)}") return template end # Otherwise search the template directories until we find the right one bootstrap_files = [] bootstrap_files << File.join(__dir__, "bootstrap/templates", "#{template}.erb") bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{template}.erb") if Chef::Knife.chef_config_dir ChefConfig::PathHelper.home(".chef", "bootstrap", "#{template}.erb") { |p| bootstrap_files << p } bootstrap_files << Gem.find_files(File.join("chef", "knife", "bootstrap", "#{template}.erb")) bootstrap_files.flatten! template_file = Array(bootstrap_files).find do |bootstrap_template| Chef::Log.trace("Looking for bootstrap template in #{File.dirname(bootstrap_template)}") File.exist?(bootstrap_template) end unless template_file ui.info("Can not find bootstrap definition for #{template}") raise Errno::ENOENT end Chef::Log.trace("Found bootstrap template: #{template_file}") template_file end |
#first_boot_attributes ⇒ Object
542 543 544 |
# File 'lib/chef/knife/bootstrap.rb', line 542 def first_boot_attributes @config[:first_boot_attributes] || @config[:first_boot_attributes_from_file] || {} end |
#force_ssh_password_opts(password) ⇒ Object
Config overrides to force password auth.
1066 1067 1068 1069 1070 1071 1072 1073 1074 |
# File 'lib/chef/knife/bootstrap.rb', line 1066 def force_ssh_password_opts(password) { password: password, non_interactive: false, keys_only: false, key_files: [], auth_methods: %i{password keyboard_interactive}, } end |
#force_winrm_password_opts(password) ⇒ Object
1076 1077 1078 1079 1080 |
# File 'lib/chef/knife/bootstrap.rb', line 1076 def force_winrm_password_opts(password) { password: password, } end |
#gateway_opts ⇒ Object
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 |
# File 'lib/chef/knife/bootstrap.rb', line 995 def gateway_opts opts = {} if config[:ssh_gateway] split = config[:ssh_gateway].split("@", 2) if split.length == 1 gw_host = split[0] else gw_user = split[0] gw_host = split[1] end gw_host, gw_port = gw_host.split(":", 2) # TODO - validate convertible port in config validation? gw_port = Integer(gw_port) rescue nil opts[:bastion_host] = gw_host opts[:bastion_user] = gw_user opts[:bastion_port] = gw_port end opts end |
#handle_ssh_error(e) ⇒ Object
691 |
# File 'lib/chef/knife/bootstrap.rb', line 691 def handle_ssh_error(e); end |
#host_descriptor ⇒ Object
471 472 473 |
# File 'lib/chef/knife/bootstrap.rb', line 471 def host_descriptor Array(@name_args).first end |
#host_verify_opts ⇒ Object
942 943 944 945 946 947 948 949 950 951 |
# File 'lib/chef/knife/bootstrap.rb', line 942 def host_verify_opts if winrm? { self_signed: config[:winrm_no_verify_cert] === true } elsif ssh? # Fall back to the old knife config key name for back compat. { verify_host_key: ssh_verify_host_key } else {} end end |
#perform_bootstrap(remote_bootstrap_script_path) ⇒ Object
604 605 606 607 608 |
# File 'lib/chef/knife/bootstrap.rb', line 604 def perform_bootstrap(remote_bootstrap_script_path) ui.info("Bootstrapping #{ui.color(server_name, :bold)}") cmd = bootstrap_command(remote_bootstrap_script_path) bootstrap_run_command(cmd) end |
#plugin_create_instance! ⇒ TrueClass
Create the server that we will bootstrap, if necessary
Plugins that subclass bootstrap, e.g. knife-ec2, can use this method to call out to an API to build an instance of the server we wish to bootstrap
842 843 844 |
# File 'lib/chef/knife/bootstrap.rb', line 842 def plugin_create_instance! true end |
#plugin_finalize ⇒ void
This method returns an undefined value.
Perform any teardown or cleanup necessary by the plugin
Plugins that subclass bootstrap, e.g. knife-ec2, can use this method to display a message or perform any cleanup
858 |
# File 'lib/chef/knife/bootstrap.rb', line 858 def plugin_finalize; end |
#plugin_setup! ⇒ TrueClass
Perform any setup necessary by the plugin
Plugins that subclass bootstrap, e.g. knife-ec2, can use this method to create connection objects
851 |
# File 'lib/chef/knife/bootstrap.rb', line 851 def plugin_setup!; end |
#plugin_validate_options! ⇒ TrueClass
Validate any additional options
Plugins that subclass bootstrap, e.g. knife-ec2, can use this method to validate any additional options before any other actions are executed
833 834 835 |
# File 'lib/chef/knife/bootstrap.rb', line 833 def true end |
#register_client ⇒ Object
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'lib/chef/knife/bootstrap.rb', line 583 def register_client # chef-vault integration must use the new client-side hawtness, otherwise to use the # new client-side hawtness, just delete your validation key. if chef_vault_handler.doing_chef_vault? || (Chef::Config[:validation_key] && !File.exist?(File.(Chef::Config[:validation_key]))) unless config[:chef_node_name] ui.error("You must pass a node name with -N when bootstrapping with user credentials") exit 1 end client_builder.run chef_vault_handler.run(client_builder.client) bootstrap_context.client_pem = client_builder.client_path else ui.warn "Performing legacy client registration with the validation key at #{Chef::Config[:validation_key]}..." ui.warn "Remove the key file or remove the 'validation_key' configuration option from your config.rb (knife.rb) to use more secure user credentials for client registration." end end |
#render_template ⇒ Object
546 547 548 549 550 551 552 |
# File 'lib/chef/knife/bootstrap.rb', line 546 def render_template require "erubis" unless defined?(Erubis) @config[:first_boot_attributes] = first_boot_attributes template_file = find_template template = IO.read(template_file).chomp Erubis::Eruby.new(template).evaluate(bootstrap_context) end |
#run ⇒ Object
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 |
# File 'lib/chef/knife/bootstrap.rb', line 554 def run check_eula_license if ChefUtils::Dist::Org::ENFORCE_LICENSE fetch_license plugin_setup! validate_name_args! validate_protocol! validate_first_boot_attributes! validate_winrm_transport_opts! winrm_warn_no_ssl_verification warn_on_short_session_timeout plugin_create_instance! $stdout.sync = true connect! register_client content = render_template bootstrap_path = upload_bootstrap(content) perform_bootstrap(bootstrap_path) plugin_finalize warn_license_usage ensure connection.del_file!(bootstrap_path) if connection && bootstrap_path end |
#secret ⇒ Object
524 525 526 |
# File 'lib/chef/knife/bootstrap.rb', line 524 def secret @secret ||= encryption_secret_provided_ignore_encrypt_flag? ? read_secret : nil end |
#server_name ⇒ String
The server_name is the DNS or IP we are going to connect to, it is not necessarily the node name, the fqdn, or the hostname of the server. This is a public API hook which knife plugins use or inherit and override.
480 481 482 483 484 |
# File 'lib/chef/knife/bootstrap.rb', line 480 def server_name if host_descriptor @server_name ||= host_descriptor.split("@").reverse[0] end end |
#ssh? ⇒ Boolean
924 925 926 |
# File 'lib/chef/knife/bootstrap.rb', line 924 def ssh? connection_protocol == "ssh" end |
#ssh_gateway ⇒ Object
SSH Authentication
120 121 122 123 |
# File 'lib/chef/knife/bootstrap.rb', line 120 option :ssh_gateway, short: "-G GATEWAY", long: "--ssh-gateway GATEWAY", description: "The SSH gateway." |
#ssh_identity_opts ⇒ Object
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 |
# File 'lib/chef/knife/bootstrap.rb', line 963 def ssh_identity_opts opts = {} return opts if winrm? identity_file = config[:ssh_identity_file] if identity_file opts[:key_files] = [identity_file] # We only set keys_only based on the explicit ssh_identity_file; # someone may use a gateway key and still expect password auth # on the target. Similarly, someone may have a default key specified # in knife config, but have provided a password on the CLI. # REVIEW NOTE: this is a new behavior. Originally, ssh_identity_file # could only be populated from CLI options, so there was no need to check # for this. We will also set keys_only to false only if there are keys # and no password. # If both are present, train(via net/ssh) will prefer keys, falling back to password. # Reference: https://github.com/chef/chef/blob/main/lib/chef/knife/ssh.rb#L272 opts[:keys_only] = config.key?(:connection_password) == false else opts[:key_files] = [] opts[:keys_only] = false end gateway_identity_file = config[:ssh_gateway] ? config[:ssh_gateway_identity] : nil unless gateway_identity_file.nil? opts[:key_files] << gateway_identity_file end opts end |
#ssh_opts ⇒ Object
953 954 955 956 957 958 959 960 961 |
# File 'lib/chef/knife/bootstrap.rb', line 953 def ssh_opts opts = {} return opts if winrm? opts[:non_interactive] = true # Prevent password prompts from underlying net/ssh opts[:forward_agent] = (config[:ssh_forward_agent] === true) opts[:connection_timeout] = session_timeout opts end |
#ssh_verify_host_key ⇒ Object
745 746 747 |
# File 'lib/chef/knife/bootstrap.rb', line 745 def ssh_verify_host_key config.key?(:ssh_verify_host_key) ? config[:ssh_verify_host_key] : config.key?(:host_key_verify) ? config[:host_key_verify] : "always" # rubocop:disable Style/NestedTernaryOperator end |
#sudo_opts(sudo_pass) ⇒ Object
use_sudo - tells bootstrap to use the sudo command to run bootstrap use_sudo_password - tells bootstrap to use the sudo command to run bootstrap
and to use the password specified with --password
TODO: I’d like to make our sudo options sane: –sudo (bool) - use sudo –sudo-password PASSWORD (default: :password) - use this password for sudo –sudo-options “opt,opt,opt” to pass into sudo –sudo-command COMMAND sudo command other than sudo REVIEW NOTE: knife bootstrap did not pull sudo values from Chef::Config,
should we change that for consistency?
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 |
# File 'lib/chef/knife/bootstrap.rb', line 1025 def sudo_opts(sudo_pass) return {} if winrm? opts = { sudo: false } if config[:use_sudo] opts[:sudo] = true if config[:use_sudo_password] opts[:sudo_password] = !config[:connection_password].nil? ? config[:connection_password] : sudo_pass end if config[:preserve_home] opts[:sudo_options] = "-H" end end opts end |
#upload_bootstrap(content) ⇒ Object
1105 1106 1107 1108 1109 1110 |
# File 'lib/chef/knife/bootstrap.rb', line 1105 def upload_bootstrap(content) script_name = connection.windows? ? "bootstrap.bat" : "bootstrap.sh" remote_path = connection.normalize_path(File.join(connection.temp_dir, script_name)) connection.upload_file_content!(content, remote_path) remote_path end |
#validate_first_boot_attributes! ⇒ Object
Fail if both first_boot_attributes and first_boot_attributes_from_file are set.
728 729 730 731 732 733 734 |
# File 'lib/chef/knife/bootstrap.rb', line 728 def validate_first_boot_attributes! if @config[:first_boot_attributes] && @config[:first_boot_attributes_from_file] raise Chef::Exceptions::BootstrapCommandInputError end true end |
#validate_name_args! ⇒ Object
fail if the server_name is nil
774 775 776 777 778 779 |
# File 'lib/chef/knife/bootstrap.rb', line 774 def validate_name_args! if server_name.nil? ui.error("Must pass an FQDN or ip to bootstrap") exit 1 end end |
#validate_policy_options! ⇒ TrueClass
Ensure options are valid by checking policyfile values.
The method call will cause the program to exit(1) if:
* Only one of --policy-name and --policy-group is specified
* Policyfile options are set and --run-list is set as well
788 789 790 791 792 793 794 795 796 |
# File 'lib/chef/knife/bootstrap.rb', line 788 def if ui.error("--policy-name and --policy-group must be specified together") exit 1 elsif policyfile_and_run_list_given? ui.error("Policyfile options and --run-list are exclusive") exit 1 end end |
#validate_protocol! ⇒ TrueClass
Ensure a valid protocol is provided for target host connection
The method call will cause the program to exit(1) if:
* Conflicting protocols are given via the target URI and the --protocol option
* The protocol is not a supported protocol
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 |
# File 'lib/chef/knife/bootstrap.rb', line 805 def validate_protocol! from_cli = config[:connection_protocol] if from_cli && connection_protocol != from_cli # Hanging indent to align with the ERROR: prefix ui.error <<~EOM The URL '#{host_descriptor}' indicates protocol is '#{connection_protocol}' while the --protocol flag specifies '#{from_cli}'. Please include only one or the other. EOM exit 1 end unless SUPPORTED_CONNECTION_PROTOCOLS.include?(connection_protocol) ui.error <<~EOM Unsupported protocol '#{connection_protocol}'. Supported protocols are: #{SUPPORTED_CONNECTION_PROTOCOLS.join(" ")} EOM exit 1 end true end |
#validate_winrm_transport_opts! ⇒ Object
Fail if using plaintext auth without ssl because this can expose keys in plaintext on the wire. TODO test for this method TODO check that the protocol is valid.
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
# File 'lib/chef/knife/bootstrap.rb', line 753 def validate_winrm_transport_opts! return true unless winrm? if Chef::Config[:validation_key] && !File.exist?(File.(Chef::Config[:validation_key])) if winrm_auth_method == "plaintext" && config[:winrm_ssl] != true ui.error <<~EOM Validatorless bootstrap over unsecure winrm channels could expose your key to network sniffing. Please use a 'winrm_auth_method' other than 'plaintext', or enable ssl on #{server_name} then use the ---winrm-ssl flag to connect. EOM exit 1 end end true end |
#warn_on_short_session_timeout ⇒ Object
If session_timeout is too short, it is likely a holdover from “–winrm-session-timeout” which used minutes as its unit, instead of seconds. Warn the human so that they are not surprised.
865 866 867 868 869 870 871 872 |
# File 'lib/chef/knife/bootstrap.rb', line 865 def warn_on_short_session_timeout if session_timeout && session_timeout <= 15 ui.warn <<~EOM You provided '--session-timeout #{session_timeout}' second(s). Did you mean '--session-timeout #{session_timeout * 60}' seconds? EOM end end |
#winrm? ⇒ Boolean
920 921 922 |
# File 'lib/chef/knife/bootstrap.rb', line 920 def winrm? connection_protocol == "winrm" end |
#winrm_auth_method ⇒ Object
FIXME: someone needs to clean this up properly: github.com/chef/chef/issues/9645 This code is deliberately left without an abstraction around deprecating the config options to avoid knife plugins from using those methods (which will need to be deprecated and break them) via inheritance (ruby does not have a true ‘private` so the lack of any inheritable implementation is because of that).
741 742 743 |
# File 'lib/chef/knife/bootstrap.rb', line 741 def winrm_auth_method config.key?(:winrm_auth_method) ? config[:winrm_auth_method] : config.key?(:winrm_authentications_protocol) ? config[:winrm_authentication_protocol] : "negotiate" # rubocop:disable Style/NestedTernaryOperator end |
#winrm_opts ⇒ Object
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 |
# File 'lib/chef/knife/bootstrap.rb', line 1041 def winrm_opts return {} unless winrm? opts = { winrm_transport: winrm_auth_method, # winrm gem and train calls auth method 'transport' winrm_basic_auth_only: config[:winrm_basic_auth_only] || false, ssl: config[:winrm_ssl] === true, ssl_peer_fingerprint: config[:winrm_ssl_peer_fingerprint], } if winrm_auth_method == "kerberos" opts[:kerberos_service] = config[:kerberos_service] if config[:kerberos_service] opts[:kerberos_realm] = config[:kerberos_realm] if config[:kerberos_service] end if config[:ca_trust_file] opts[:ca_trust_path] = config[:ca_trust_file] end opts[:operation_timeout] = session_timeout opts end |
#winrm_warn_no_ssl_verification ⇒ Object
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 |
# File 'lib/chef/knife/bootstrap.rb', line 874 def winrm_warn_no_ssl_verification return unless winrm? # REVIEWER NOTE # The original check from knife plugin did not include winrm_ssl_peer_fingerprint # Reference: # https://github.com/chef/knife-windows/blob/92d151298142be4a4750c5b54bb264f8d5b81b8a/lib/chef/knife/winrm_knife_base.rb#L271-L273 # TODO Seems like we should also do a similar warning if ssh_verify_host == false if config[:ca_trust_file].nil? && config[:winrm_no_verify_cert] && config[:winrm_ssl_peer_fingerprint].nil? ui.warn <<~WARN * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SSL validation of HTTPS requests for the WinRM transport is disabled. HTTPS WinRM connections are still encrypted, but knife is not able to detect forged replies or spoofing attacks. To work around this issue you can use the flag `--winrm-no-verify-cert` or add an entry like this to your knife configuration file: # Verify all WinRM HTTPS connections knife[:winrm_no_verify_cert] = true You can also specify a ca_trust_file via --ca-trust-file, or the expected fingerprint of the target host's certificate via --winrm-ssl-peer-fingerprint. WARN end end |