Skip to content

Commit

Permalink
Update ssh_config resource to support returning the current sshd_conf…
Browse files Browse the repository at this point in the history
…ig file in use. (#7070)

* modify resource

* windows compatibility

* end line

* removing comments to clean things up

Signed-off-by: Aaron Lippold <[email protected]>

* 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 <[email protected]>

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

Signed-off-by: Sonu Saha <[email protected]>

* fix: replace io.readlines to file.readlines

Signed-off-by: Sonu Saha <[email protected]>

* chore: fix lint offense, unnecessary space

Signed-off-by: Sonu Saha <[email protected]>

* fix: raise exception for standard errors as FetcherFailure

Signed-off-by: Sonu Saha <[email protected]>

* chore: update exception message

Signed-off-by: Sonu Saha <[email protected]>

---------

Signed-off-by: Sonu Saha <[email protected]>

* fix: Missing regular expression anchor (#7077)

Signed-off-by: Sonu Saha <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* 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 <[email protected]>

* Update sshd_active_config.md

updated version

* doc version update

---------

Signed-off-by: Aaron Lippold <[email protected]>
Signed-off-by: Sonu Saha <[email protected]>
Signed-off-by: Ian Maddaus <[email protected]>
Signed-off-by: Clinton Wolfe <[email protected]>
Co-authored-by: Daniel Medina <[email protected]>
Co-authored-by: Sonu Saha <[email protected]>
Co-authored-by: Chef Expeditor <[email protected]>
Co-authored-by: Ian Maddaus <[email protected]>
Co-authored-by: Clinton Wolfe <[email protected]>
  • Loading branch information
6 people authored and Nik08 committed Sep 13, 2024
1 parent da3baec commit 0acfa8b
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs-chef-io/content/inspec/resources/ssh_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
99 changes: 99 additions & 0 deletions docs-chef-io/content/inspec/resources/sshd_active_config.md
Original file line number Diff line number Diff line change
@@ -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('[email protected],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') }
109 changes: 100 additions & 9 deletions lib/inspec/resources/ssh_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,13 @@ def params(*opts)

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
Expand All @@ -73,11 +70,12 @@ def read_params
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

Expand Down Expand Up @@ -121,4 +119,97 @@ def ssh_config_file(type)
"/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
2 changes: 2 additions & 0 deletions lib/inspec/resources/sshd_active_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This is just here to make the dynamic loader happy.
require "inspec/resources/ssh_config"
15 changes: 14 additions & 1 deletion test/unit/resources/ssh_conf_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
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")
Expand Down Expand Up @@ -48,4 +47,18 @@
_(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

0 comments on commit 0acfa8b

Please sign in to comment.