Update ssh_config resource to support returning the current sshd_config file in use. (#7070)

* modify resource

* windows compatibility

* end line

* removing comments to clean things up

Signed-off-by: Aaron Lippold <lippold@gmail.com>

* CHEF-12175: Remove use of `Kernel.open` or `IO.read` or similar sinks with a non-constant value (#7079)

* fix: update io reads to fix codescanning vuln

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* fix: remove kernel#open fallback and update open method to handle local files

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* fix: replace io.readlines to file.readlines

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* chore: fix lint offense, unnecessary space

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* fix: raise exception for standard errors as FetcherFailure

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* chore: update exception message

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

---------

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* fix: Missing regular expression anchor (#7077)

Signed-off-by: Sonu Saha <sonu.saha@progress.com>

* Bump version to 6.6.27 by Chef Expeditor

Obvious fix; these changes are the result of automation not creative thinking.

* Fix gitignore file in docs dir (#7082)

Signed-off-by: Ian Maddaus <ian.maddaus@progress.com>

* Bump version to 6.6.28 by Chef Expeditor

Obvious fix; these changes are the result of automation not creative thinking.

* adding docs now that the gitignore is fixed.

Signed-off-by: Aaron Lippold <lippold@gmail.com>

* add docs for sshd_active_config resource

* fix docs

* unit tests

* rubocop on ssh_config.rb, sshd_con_test.rb, and sshd_active_config.md

* rename active path in method

* doc fix

* Linting Corrections for Active SSHD Config (#1)

Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>

* Update sshd_active_config.md

updated version

* doc version update

---------

Signed-off-by: Aaron Lippold <lippold@gmail.com>
Signed-off-by: Sonu Saha <sonu.saha@progress.com>
Signed-off-by: Ian Maddaus <ian.maddaus@progress.com>
Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
Co-authored-by: Daniel Medina <dmedina@mitre.org>
Co-authored-by: Sonu Saha <98935583+ahasunos@users.noreply.github.com>
Co-authored-by: Chef Expeditor <chef-ci@chef.io>
Co-authored-by: Ian Maddaus <IanMadd@users.noreply.github.com>
Co-authored-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
Aaron Lippold 2024-07-24 07:02:09 -04:00 committed by GitHub
parent 0e904a32bf
commit 0ab35681aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 216 additions and 11 deletions

View file

@ -21,7 +21,7 @@ Use the `ssh_config` Chef InSpec audit resource to test OpenSSH client configura
### Version
This resource first became available in v1.0.0 of InSpec.
This resource first became available in v6.8.0 of InSpec.
## Syntax

View file

@ -0,0 +1,99 @@
+++
title = "sshd_active_config resource"
draft = false
gh_repo = "inspec"
platform = "linux"
[menu]
[menu.inspec]
title = "sshd_active_config"
identifier = "inspec/resources/os/sshd_active_config.md sshd_active_config resource"
parent = "inspec/resources/os"
+++
Use the `sshd_active_config` Chef InSpec audit resource to find and test configuration data for the OpenSSH daemon. By default, this configuration data is located at `/etc/ssh/sshd_config` on Linux and Unix platforms. However, this resource is designed to retrieve the active configuration file by the sshd process itself. sshd---the OpenSSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command execution, and data exchanges.
## Availability
### Install
{{< readfile file="content/inspec/reusable/md/inspec_installation.md" >}}
### Version
This resource first became available in v6.8.0 of InSpec.
## Syntax
An `sshd_active_config` resource block declares the OpenSSH daemon configuration data to be tested:
describe sshd_active_config do
its('name') { should include('foo') }
end
where
- `name` is a configuration setting in `sshd_config`
- `{ should include('foo') }` tests the value of `name` as read from `sshd_active_config` versus the value declared in the test
## Examples
The following examples show how to use this Chef InSpec audit resource.
### Inspect the file and path found by the `sshd_active_config` resource
describe sshd_active_config.active_path do
it { should match '/expected/path/sshd_config' }
end
### Test which variables may be sent to the server
describe sshd_active_config do
its('AcceptEnv') { should include('CI_ENABLE_COVERAGE') }
end
### Test for IPv6-only addresses
describe sshd_active_config do
its('AddressFamily') { should cmp 'inet6' }
end
### Test the Protocol setting
describe sshd_active_config do
its('Protocol') { should cmp 2 }
end
### Test for approved, strong ciphers
describe sshd_active_config do
its('Ciphers') { should cmp('chacha20-poly1305@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr') }
end
### Test SSH protocols
describe sshd_active_config do
its('Port') { should cmp 22 }
its('UsePAM') { should eq 'yes' }
its('ListenAddress') { should eq nil }
its('HostKey') do
should eq [
'/etc/ssh/ssh_host_rsa_key',
'/etc/ssh/ssh_host_dsa_key',
'/etc/ssh/ssh_host_ecdsa_key',
]
end
end
## Matchers
{{< readfile file="content/inspec/reusable/md/inspec_matchers_link.md" >}}
This resource has the following special matchers.
### name
The `name` matcher tests the value of `name` as read from `sshd_active_config` versus the value declared in the test:
its('name') { should cmp 'foo' }
or:
its('name') {should include('bar') }

View file

@ -38,16 +38,13 @@ module Inspec::Resources
def convert_hash(hash)
new_hash = {}
hash.each do |k, v|
new_hash[k.downcase] ||= v
end
hash.each { |k, v| new_hash[k.downcase] ||= v }
new_hash
end
def method_missing(name)
param = read_params[name.to_s.downcase]
return nil if param.nil?
# extract first value if we have only one value in array
return param[0] if param.length == 1
param
@ -73,11 +70,12 @@ module Inspec::Resources
return @params if defined?(@params)
return @params = {} if read_content.nil?
conf = SimpleConfig.new(
read_content,
assignment_regex: /^\s*(\S+?)\s+(.*?)\s*$/,
multiple_values: true
)
conf =
SimpleConfig.new(
read_content,
assignment_regex: /^\s*(\S+?)\s+(.*?)\s*$/,
multiple_values: true
)
@params = convert_hash(conf.params)
end
@ -121,4 +119,97 @@ module Inspec::Resources
"/etc/ssh/#{type}"
end
end
class SshdActiveConfig < SshdConfig
name "sshd_active_config"
supports platform: "unix"
supports platform: "windows"
desc "Use the sshd_active_config InSpec audit resource to test configuration data for the Open SSH daemon located at /etc/ssh/sshd_config on Linux and UNIX platforms. sshd---the Open SSH daemon---listens on dedicated ports, starts a daemon for each incoming connection, and then handles encryption, authentication, key exchanges, command execution, and data exchanges."
example <<~EXAMPLE
describe sshd_active_config do
its('Protocol') { should eq '2' }
end
EXAMPLE
attr_reader :active_path
def initialize
@active_path = dynamic_sshd_config_path
super(@active_path)
end
def to_s
"SSHD Active Configuration (active path: #{@conf_path})"
end
private
def ssh_config_file(type)
if inspec.os.windows?
programdata = inspec.os_env("programdata").content
return "#{programdata}\\ssh\\#{type}"
end
"/etc/ssh/#{type}"
end
def dynamic_sshd_config_path
if inspec.os.windows?
script = <<-EOH
$sshdPath = (Get-Command sshd.exe).Source
if ($sshdPath -ne $null) {
Write-Output $sshdPath
} else {
Write-Error "sshd.exe not found"
}
EOH
sshd_path_result = inspec.powershell(script).stdout.strip
sshd_path = "\"#{sshd_path_result}\""
if !sshd_path_result.empty? && sshd_path_result != "sshd.exe not found"
command_output = inspec.command("sudo #{sshd_path} -dd 2>&1").stdout
dynamic_path =
command_output
.lines
.find { |line| line.include?("filename") }
&.split("filename")
&.last
&.strip
env_var_name = dynamic_path.match(/__(.*?)__/)[1]
if env_var_name?
dynamic_path =
dynamic_path.gsub(
/__#{env_var_name}__/,
inspec.os_env(env_var_name).content
)
end
else
Inspec::Log.error("sshd.exe not found using PowerShell script block.")
return nil
end
elsif inspec.os.unix?
sshd_path = "/usr/sbin/sshd"
command_output = inspec.command("sudo #{sshd_path} -dd 2>&1").stdout
dynamic_path =
command_output
.lines
.find { |line| line.include?("filename") }
&.split("filename")
&.last
&.strip
else
Inspec::Log.error(
"Unable to determine sshd configuration path on Windows using -T flag."
)
return nil
end
if dynamic_path.nil? || dynamic_path.empty?
Inspec::Log.warn(
"No active SSHD configuration found. Using default configuration."
)
return ssh_config_file("sshd_config")
end
dynamic_path
end
end
end

View file

@ -0,0 +1,2 @@
# This is just here to make the dynamic loader happy.
require "inspec/resources/ssh_config"

View file

@ -3,7 +3,6 @@ require "inspec/resource"
require "inspec/resources/ssh_config"
describe "Inspec::Resources::SshConfig" do
describe "ssh_config" do
it "check ssh config parsing" do
resource = load_resource("ssh_config")
@ -48,4 +47,18 @@ describe "Inspec::Resources::SshConfig" do
_(resource.resource_exception_message).must_equal "File is empty: /etc/ssh/sshd_config_empty"
end
end
describe "sshd_active_config" do
it "check protocol version" do
resource = load_resource("sshd_active_config")
_(resource.Port).must_equal "22"
_(resource.UsePAM).must_equal "yes"
_(resource.ListenAddress).must_be_nil
_(resource.HostKey).must_equal [
"/etc/ssh/ssh_host_rsa_key",
"/etc/ssh/ssh_host_dsa_key",
"/etc/ssh/ssh_host_ecdsa_key",
]
end
end
end