From 48535dde295dd676e222f9b7c119b602cffb7804 Mon Sep 17 00:00:00 2001 From: Daniel Medina Date: Thu, 24 Oct 2024 16:28:35 -0400 Subject: [PATCH 1/7] adjust chrony conf for arrays and strings from input and config file --- controls/SV-230484.rb | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index ab6d7e0..71c5aae 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -72,12 +72,19 @@ only_if('This control is Not Applicable to containers', impact: 0.0) { !virtualization.system.eql?('docker') } + + + # Get input, convert to array if string + authoritative_timeserver = input('authoritative_timeserver') + authoritative_timeserver = [authoritative_timeserver] if authoritative_timeserver.is_a? String + # No need to provide filepath time_sources = chrony_conf.server # Cover case when a single server is defined and resource returns a string and not an array time_sources = [time_sources] if time_sources.is_a? String + # Get and map maxpoll values to an array unless time_sources.nil? max_poll_values = time_sources.map { |val| val.match?(/.*maxpoll.*/) ? val.gsub(/.*maxpoll\s+(\d+)(\s+.*|$)/, '\1').to_i : 10 @@ -89,28 +96,17 @@ its('server') { should_not be_nil } end - unless chrony_conf.server.nil? - # If there is only one server and the resource returns a string, check if the server matches the input - if chrony_conf.server.is_a? String - describe chrony_conf do - its('server') { should match input('authoritative_timeserver') } - end - end + unless time_sources.nil? # Check if each server in the server array exists in the input - if chrony_conf.server.is_a? Array - chrony_conf.server.each do |server| - describe server do - it { should match input('authoritative_timeserver') } - end + time_sources.each do |server| + describe server do + it { should be_in authoritative_timeserver } end end - # All time sources must contain valid maxpoll entries - unless time_sources.nil? - describe 'chronyd maxpoll values (99=maxpoll absent)' do - subject { max_poll_values } - it { should all be < 17 } - end + describe 'chronyd maxpoll values (99=maxpoll absent)' do + subject { max_poll_values } + it { should all be < 17 } end end end From 59c32ccf86f466618bd138c28d0b7ce0e1294e4f Mon Sep 17 00:00:00 2001 From: Daniel Medina Date: Thu, 24 Oct 2024 16:38:56 -0400 Subject: [PATCH 2/7] bundle exec rake lint --- controls/SV-230484.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index 71c5aae..4ea39b2 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -73,7 +73,6 @@ !virtualization.system.eql?('docker') } - # Get input, convert to array if string authoritative_timeserver = input('authoritative_timeserver') authoritative_timeserver = [authoritative_timeserver] if authoritative_timeserver.is_a? String From 4b9f2bebcaa2778fc8516093615d8e68c18e45a7 Mon Sep 17 00:00:00 2001 From: Will Date: Fri, 25 Oct 2024 10:58:06 -0400 Subject: [PATCH 3/7] using .any? Signed-off-by: Will --- controls/SV-230484.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index 4ea39b2..a4ab31f 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -97,10 +97,10 @@ unless time_sources.nil? # Check if each server in the server array exists in the input - time_sources.each do |server| - describe server do - it { should be_in authoritative_timeserver } - end + valid_time_source_present = time_sources.any? { |server| authoritative_timeserver.include?(server) } + describe 'chrony.conf includes at least one valid timeserver' do + subject { valid_time_source_present } + it { should be true } end # All time sources must contain valid maxpoll entries describe 'chronyd maxpoll values (99=maxpoll absent)' do From de3cfab311965e1f6942a12174b08858004412e1 Mon Sep 17 00:00:00 2001 From: Daniel Medina Date: Tue, 29 Oct 2024 13:45:57 -0400 Subject: [PATCH 4/7] check corresponding maxpoll entry instead of all maxpoll values --- controls/SV-230484.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index a4ab31f..e61deb4 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -81,7 +81,7 @@ time_sources = chrony_conf.server # Cover case when a single server is defined and resource returns a string and not an array - time_sources = [time_sources] if time_sources.is_a? String + time_sources = [time_sources].flatten # Get and map maxpoll values to an array unless time_sources.nil? @@ -97,15 +97,10 @@ unless time_sources.nil? # Check if each server in the server array exists in the input - valid_time_source_present = time_sources.any? { |server| authoritative_timeserver.include?(server) } + valid_time_source_present = time_sources.any? { |server, index| authoritative_timeserver.include?(server) && max_poll_values[index] < 17 } describe 'chrony.conf includes at least one valid timeserver' do subject { valid_time_source_present } it { should be true } end - # All time sources must contain valid maxpoll entries - describe 'chronyd maxpoll values (99=maxpoll absent)' do - subject { max_poll_values } - it { should all be < 17 } - end end end From ae5b126bc7d438b1081b7a82706ca43eb5a3da07 Mon Sep 17 00:00:00 2001 From: Daniel Medina Date: Mon, 13 Jan 2025 14:45:50 -0500 Subject: [PATCH 5/7] handle multiple inputs, implement exact case --- controls/SV-230484.rb | 47 +++++++++++++++++++++++++++++++------------ inspec.yml | 14 +++++++++---- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index e61deb4..eddc37e 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -73,21 +73,25 @@ !virtualization.system.eql?('docker') } - # Get input, convert to array if string - authoritative_timeserver = input('authoritative_timeserver') - authoritative_timeserver = [authoritative_timeserver] if authoritative_timeserver.is_a? String + # Get inputs + authoritative_timeservers = input('authoritative_timeservers') + authoritative_timeservers_exact = input('authoritative_timeservers_exact') - # No need to provide filepath - time_sources = chrony_conf.server - - # Cover case when a single server is defined and resource returns a string and not an array - time_sources = [time_sources].flatten + # Get the system server values + # Converts to array if only one value present + time_sources = [chrony_conf.server].flatten # Get and map maxpoll values to an array unless time_sources.nil? + # Map max poll values only max_poll_values = time_sources.map { |val| val.match?(/.*maxpoll.*/) ? val.gsub(/.*maxpoll\s+(\d+)(\s+.*|$)/, '\1').to_i : 10 } + + # Map server values only + server_values = time_sources.map { |val| + val.split(' ').first + } end # Verify the "chrony.conf" file is configured to a time source by running the following command: @@ -96,11 +100,28 @@ end unless time_sources.nil? - # Check if each server in the server array exists in the input - valid_time_source_present = time_sources.any? { |server, index| authoritative_timeserver.include?(server) && max_poll_values[index] < 17 } - describe 'chrony.conf includes at least one valid timeserver' do - subject { valid_time_source_present } - it { should be true } + # Verify the chrony.conf file is configured to at least one authoritative DoD time source + # Check for valid maxpoll value <17 + describe "chrony.conf" do + # authoritative_timeservers_exact specifies whether to verify all inputted timeservers or just one + if authoritative_timeservers_exact + it "should include all specified valid timeservers" do + expect(authoritative_timeservers.all? { |input| + server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 + }).to be true + end + else + it "should include at least one valid timeserver" do + expect(authoritative_timeservers.any? { |input| + server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 + }).to be true + end + end end end + end + + + + diff --git a/inspec.yml b/inspec.yml index 88a46c5..9148585 100644 --- a/inspec.yml +++ b/inspec.yml @@ -441,10 +441,16 @@ inputs: value: "aide" # SV-230484 - - name: authoritative_timeserver - description: Timeserver used in /etc/chrony.conf - type: String - value: 0.us.pool.ntp.mil + - name: authoritative_timeservers + description: Timeserver(s) used in /etc/chrony.conf + type: Array + value: ["0.us.pool.ntp.mil"] + + # SV-230484 + - name: authoritative_timeservers_exact + description: Specify that all timeservers in authoritative_timeservers must be present and valid + type: Boolean + value: false # SV-230537 - name: non_removable_media_fs From 42f94ead01566974b8244cd26a3eab037c56e351 Mon Sep 17 00:00:00 2001 From: Daniel Medina Date: Mon, 13 Jan 2025 14:53:12 -0500 Subject: [PATCH 6/7] bundle exec rake lint:auto_correct --- controls/SV-230484.rb | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index eddc37e..aa58038 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -102,26 +102,21 @@ unless time_sources.nil? # Verify the chrony.conf file is configured to at least one authoritative DoD time source # Check for valid maxpoll value <17 - describe "chrony.conf" do + describe 'chrony.conf' do # authoritative_timeservers_exact specifies whether to verify all inputted timeservers or just one if authoritative_timeservers_exact - it "should include all specified valid timeservers" do + it 'should include all specified valid timeservers' do expect(authoritative_timeservers.all? { |input| - server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 - }).to be true - end + server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 + }).to be true + end else - it "should include at least one valid timeserver" do - expect(authoritative_timeservers.any? { |input| - server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 + it 'should include at least one valid timeserver' do + expect(authoritative_timeservers.any? { |input| + server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 }).to be true end end end end - end - - - - From b8c925b0ba9527370f81a8e9a5285c133b442162 Mon Sep 17 00:00:00 2001 From: Daniel Medina Date: Tue, 14 Jan 2025 12:59:43 -0500 Subject: [PATCH 7/7] Adjust input name and values for clarity --- controls/SV-230484.rb | 8 ++++---- inspec.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/controls/SV-230484.rb b/controls/SV-230484.rb index aa58038..c4cc409 100644 --- a/controls/SV-230484.rb +++ b/controls/SV-230484.rb @@ -75,7 +75,7 @@ # Get inputs authoritative_timeservers = input('authoritative_timeservers') - authoritative_timeservers_exact = input('authoritative_timeservers_exact') + match_all_authoritative_timeservers_enabled = input('match_all_authoritative_timeservers_enabled') # Get the system server values # Converts to array if only one value present @@ -104,16 +104,16 @@ # Check for valid maxpoll value <17 describe 'chrony.conf' do # authoritative_timeservers_exact specifies whether to verify all inputted timeservers or just one - if authoritative_timeservers_exact + if match_all_authoritative_timeservers_enabled it 'should include all specified valid timeservers' do expect(authoritative_timeservers.all? { |input| - server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 + server_values.include?(input) && max_poll_values[server_values.index(input)] <= 16 }).to be true end else it 'should include at least one valid timeserver' do expect(authoritative_timeservers.any? { |input| - server_values.include?(input) && max_poll_values[server_values.index(input)] < 17 + server_values.include?(input) && max_poll_values[server_values.index(input)] <= 16 }).to be true end end diff --git a/inspec.yml b/inspec.yml index 9148585..eb9eb9f 100644 --- a/inspec.yml +++ b/inspec.yml @@ -447,7 +447,7 @@ inputs: value: ["0.us.pool.ntp.mil"] # SV-230484 - - name: authoritative_timeservers_exact + - name: match_all_authoritative_timeservers_enabled description: Specify that all timeservers in authoritative_timeservers must be present and valid type: Boolean value: false