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
(also: #check_license)
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
933 934 935 936 937 938 939 940 941 942 943 944 |
# File 'lib/chef/knife/bootstrap.rb', line 933 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
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 |
# File 'lib/chef/knife/bootstrap.rb', line 1118 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.
535 536 537 538 539 540 541 542 543 544 |
# File 'lib/chef/knife/bootstrap.rb', line 535 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.
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/chef/knife/bootstrap.rb', line 616 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.
491 492 493 494 |
# File 'lib/chef/knife/bootstrap.rb', line 491 def bootstrap_template # Allow passing a bootstrap template or use the default config[:bootstrap_template] || default_bootstrap_template end |
#check_eula_license ⇒ Object Also known as: check_license
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
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 |
# File 'lib/chef/knife/bootstrap.rb', line 1096 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
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 690 691 692 693 |
# File 'lib/chef/knife/bootstrap.rb', line 639 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
910 911 912 913 914 915 916 917 918 919 920 921 922 |
# File 'lib/chef/knife/bootstrap.rb', line 910 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.
699 700 701 702 703 704 705 |
# File 'lib/chef/knife/bootstrap.rb', line 699 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.
467 468 469 470 471 472 473 |
# File 'lib/chef/knife/bootstrap.rb', line 467 def default_bootstrap_template if connection.windows? "windows-chef-client-msi" else "chef-full" end end |
#do_connect(conn_options) ⇒ Object
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 |
# File 'lib/chef/knife/bootstrap.rb', line 707 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
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 523 524 525 526 |
# File 'lib/chef/knife/bootstrap.rb', line 496 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
546 547 548 |
# File 'lib/chef/knife/bootstrap.rb', line 546 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.
1070 1071 1072 1073 1074 1075 1076 1077 1078 |
# File 'lib/chef/knife/bootstrap.rb', line 1070 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
1080 1081 1082 1083 1084 |
# File 'lib/chef/knife/bootstrap.rb', line 1080 def force_winrm_password_opts(password) { password: password, } end |
#gateway_opts ⇒ Object
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 |
# File 'lib/chef/knife/bootstrap.rb', line 999 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
695 |
# File 'lib/chef/knife/bootstrap.rb', line 695 def handle_ssh_error(e); end |
#host_descriptor ⇒ Object
475 476 477 |
# File 'lib/chef/knife/bootstrap.rb', line 475 def host_descriptor Array(@name_args).first end |
#host_verify_opts ⇒ Object
946 947 948 949 950 951 952 953 954 955 |
# File 'lib/chef/knife/bootstrap.rb', line 946 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
608 609 610 611 612 |
# File 'lib/chef/knife/bootstrap.rb', line 608 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
846 847 848 |
# File 'lib/chef/knife/bootstrap.rb', line 846 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
862 |
# File 'lib/chef/knife/bootstrap.rb', line 862 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
855 |
# File 'lib/chef/knife/bootstrap.rb', line 855 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
837 838 839 |
# File 'lib/chef/knife/bootstrap.rb', line 837 def true end |
#register_client ⇒ Object
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 |
# File 'lib/chef/knife/bootstrap.rb', line 587 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
550 551 552 553 554 555 556 |
# File 'lib/chef/knife/bootstrap.rb', line 550 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
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
# File 'lib/chef/knife/bootstrap.rb', line 558 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
528 529 530 |
# File 'lib/chef/knife/bootstrap.rb', line 528 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.
484 485 486 487 488 |
# File 'lib/chef/knife/bootstrap.rb', line 484 def server_name if host_descriptor @server_name ||= host_descriptor.split("@").reverse[0] end end |
#ssh? ⇒ Boolean
928 929 930 |
# File 'lib/chef/knife/bootstrap.rb', line 928 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
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 994 995 996 997 |
# File 'lib/chef/knife/bootstrap.rb', line 967 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
957 958 959 960 961 962 963 964 965 |
# File 'lib/chef/knife/bootstrap.rb', line 957 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
749 750 751 |
# File 'lib/chef/knife/bootstrap.rb', line 749 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?
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 |
# File 'lib/chef/knife/bootstrap.rb', line 1029 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
1109 1110 1111 1112 1113 1114 |
# File 'lib/chef/knife/bootstrap.rb', line 1109 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.
732 733 734 735 736 737 738 |
# File 'lib/chef/knife/bootstrap.rb', line 732 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
778 779 780 781 782 783 |
# File 'lib/chef/knife/bootstrap.rb', line 778 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
792 793 794 795 796 797 798 799 800 |
# File 'lib/chef/knife/bootstrap.rb', line 792 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
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 |
# File 'lib/chef/knife/bootstrap.rb', line 809 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.
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 |
# File 'lib/chef/knife/bootstrap.rb', line 757 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.
869 870 871 872 873 874 875 876 |
# File 'lib/chef/knife/bootstrap.rb', line 869 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
924 925 926 |
# File 'lib/chef/knife/bootstrap.rb', line 924 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).
745 746 747 |
# File 'lib/chef/knife/bootstrap.rb', line 745 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
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 |
# File 'lib/chef/knife/bootstrap.rb', line 1045 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
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 903 904 905 906 |
# File 'lib/chef/knife/bootstrap.rb', line 878 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 |