Язык Chef InSpec
Chef InSpec — это фреймворк выполнения и язык правил, используемый для определения требований к соответствию, безопасности и политике. Он включает набор ресурсов, которые помогут вам быстро и легко написать контрольные аудиты. Синтаксис, используемый как в открытых исходных кодах, так и в аудите соответствия Chef, одинаковый. Фреймворк ресурсов ресурсов Chef InSpec с открытым исходным кодом совместим с аудитом соответствия Chef.
Язык Chef InSpec — это Ruby DSL для написания контрольных аудитов, который включает ресурсы аудита, которые вы можете вызвать.
В следующих разделах описан синтаксис и приведены некоторые простые примеры использования ресурсов Chef InSpec.
Синтаксис
Следующие тесты ресурсов проверяют конфигурацию сервера |ssh|. Например, простое правило может быть описано так:
describe sshd_config do
its('Port') { should cmp 22 }
end
В различных случаях использования, таких как внедрение соответствия ИТ по разным отделам, становится удобно расширять правило метаданными. Каждое правило может определять дополнительные impact, title или desc. Пример выглядит так:
control 'sshd-8' do
impact 0.6
title 'Server: Configure the service port'
desc 'Always specify which port the SSH server should listen.'
desc 'rationale', 'This ensures that there are no unexpected settings' # Requires Chef InSpec >=2.3.4
tag 'ssh','sshd','openssh-server'
tag cce: 'CCE-27072-8'
ref 'NSA-RH6-STIG - Section 3.5.2.1', url: 'https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf'
describe sshd_config do
its('Port') { should cmp 22 }
end
end
где
-
'sshd-8'— это имя правила -
impact,title, иdescопределяют метаданные, которые полностью описывают важность правила, его назначение, с кратким и полным описанием -
descпри получении только одного аргумента устанавливает описание по умолчанию. Начиная с Chef InSpec 2.3.4, при получении 2 аргументов (см.:'rationale') он будет использовать первый аргумент в качестве заголовка при рендеринге в Automate -
impact— это строка или число, которые измеряют важность результатов соответствия. Допустимые строки для влияния —none,low,medium,high, иcritical. Значения основаны на CVSS 3.0. Числовое значение должно быть между0.0и1.0. Диапазоны значений:-
0.0 to <0.01это правила без влияния, они только предоставляют информацию -
0.01 to <0.4это правила с низким влиянием -
0.4 to <0.7это правила со средним влиянием -
0.7 to <0.9это правила с высоким влиянием -
0.9 to 1.0это критические правила
-
-
tag— это необязательная метаинформация с ключами или парами ключ-значение -
ref— ссылка на внешний документ -
describe— это блок, содержащий по крайней мере один тест. Блокcontrolдолжен содержать по крайней мере один блокdescribe, но может содержать столько, сколько требуется -
sshd_config— ресурс Chef InSpec. Полный список ресурсов Chef InSpec см. в документации по ресурсам Chef InSpec -
its('Port')— это соответствие;{ should eq '22' }— это тест. Блокdescribeдолжен содержать по крайней мере одно соответствие, но может содержать столько, сколько требуется
Расширенные концепции
Проверка, выполняется ли по крайней мере одно условие с describe.one
С Chef InSpec можно проверить, истинно ли по крайней мере одно из набора проверок. Например, если вы настраиваете параметр в двух разных местах, то вы можете проверить, установлен ли параметр A или параметр B. Выполните эту задачу с помощью блока describe.one. describe.one определяет набор блоков describe , где должен пройти только один блок.
describe.one do
describe ConfigurationA do
its('setting_1') { should eq true }
end
describe ConfigurationB do
its('setting_2') { should eq true }
end
end
describe.one примечания к использованию
- Блок
describe.oneпроходит, если один из его вложенных блоковdescribeимеет все утверждения, прошедшие проверку. Блокdescribe.oneтребует, чтобы весь блокdescribeпрошел проверку, а не только одно утверждение. - Chef InSpec всегда оценивает все тесты, содержащиеся в
describe.one. Он не прерывает выполнение при обнаружении проходящего блокаdescribe. - Вложение блока
describe.oneвнутри другого блокаdescribe.oneне поддерживается.
Ресурсы с конфиденциальной информацией
В некоторых случаях вы можете писать проверки, которые включают ресурсы с конфиденциальной информацией, например, ресурс файла. В случае сбоев вы можете подавить вывод. Для этого добавьте флаг :sensitive в определение ресурса:
describe file('/tmp/mysecretfile'), :sensitive do
its('content') { should match /secret_info/ }
end
Примеры
Следующие примеры показывают простые тесты соответствия, использующие один блок control.
Проверка журнала событий системы
Следующий тест показывает, как аудировать машины под управлением Windows 2012 R2, чтобы убедиться, что включена сложность паролей:
control 'windows-account-102' do
impact 'critical'
title 'Windows Password Complexity is Enabled'
desc 'Password must meet complexity requirement'
describe security_policy do
its('PasswordComplexity') { should cmp 1 }
end
end
Проверка, пустые ли пароли PostgreSQL
Следующий тест показывает, как аудировать машины под управлением PostgreSQL, чтобы убедиться, что пароли не пустые.
control 'postgres-7' do
impact 1.0
title "Don't allow empty passwords"
describe postgres_session('user', 'pass').query("SELECT * FROM pg_shadow WHERE passwd IS NULL;") do
its('output') { should cmp '' }
end
end
Проверка, хранятся ли пароли MySQL в ENV
Следующий тест показывает, как аудировать машины под управлением MySQL, чтобы убедиться, что пароли не хранятся в ENV:
control 'mysql-3' do
impact 1.0
title 'Do not store your MySQL password in your ENV'
desc '
Storing credentials in your ENV may easily expose
them to an attacker. Prevent this at all costs.
'
describe command('env') do
its('stdout') { should_not match /^MYSQL_PWD=/ }
end
end
Проверка, является ли /etc/ssh каталогом
Следующий тест показывает, как аудировать машины, чтобы убедиться, что /etc/ssh является каталогом:
control 'basic-1' do
impact 1.0
title '/etc/ssh should be a directory'
desc '
In order for OpenSSH to function correctly, its
configuration path must be a folder.
'
describe file('/etc/ssh') do
it { should be_directory }
end
end
Проверка, запущен ли Apache
Следующий тест показывает, как аудировать машины, чтобы убедиться, что Apache включен и запущен:
control 'apache-1' do
impact 'medium'
title 'Apache2 should be configured and running'
describe service(apache.service) do
it { should be_enabled }
it { should be_running }
end
end
Проверка, установлены ли небезопасные пакеты
Следующий тест показывает, как аудировать машины на предмет небезопасных пакетов:
control 'cis-os-services-5.1.3' do
impact 0.7
title '5.1.3 Ensure rsh client is not installed'
describe package('rsh') do
it { should_not be_installed }
end
describe package('rsh-redone-client') do
it { should_not be_installed }
end
end
Проверка ключей реестра Windows
Следующий тест показывает, как аудировать машины, чтобы убедиться, что режим безопасного поиска DLL включен:
control 'windows-base-101' do
impact 1.0
title 'Safe DLL Search Mode is Enabled'
desc '
@link: https://msdn.microsoft.com/en-us/library/ms682586(v=vs.85).aspx
'
describe registry_key('HKLM\\System\\CurrentControlSet\\Control\\Session Manager') do
it { should exist }
it { should_not have_property_value('SafeDllSearchMode', :type_dword, '0') }
end
end
Использование only_if для исключения определенного правила
Этот пример показывает, как пропустить определенные правила, если условия не выполнены, используя only_if. В этом примере правило не будет выполнено, если команда redis-cli не существует. Необязательное сообщение может указать причину пропуска.
control 'nutcracker-connect-redis-001' do
impact 'critical'
title 'Check if nutcracker can pass commands to redis'
desc 'execute redis-cli set key command, to check connectivity of the service'
only_if('redis is not installed.') do
command('redis-cli').exist?
end
describe command('redis-cli SET test_inspec "HELLO"') do
its('stdout') { should match /OK/ }
end
end
Этот пример проверяет установку определенных пакетов pip, только если существует ‘/root/.aws’:
control 'pip-packages-installed' do
title 'Check if essential pips are installed'
only_if('aws-cli config not created.') do
directory('/root/.aws').exist?
end
%w(aws-mfa PyYAML awscli).each do |aws_pip_deps|
describe pip(aws_pip_deps) do
it { should be_installed }
end
end
end
Комбинирование этого с другими условными операторами, например, проверкой существования файлов, может помочь в тестировании различных путей тестов с помощью Chef InSpec. Таким образом, вы можете пропускать определенные правила, которые на 100% провалятся из-за того, как подготовлены серверы, но вы знаете, что те же наборы правил будут повторно использованы позже в разных обстоятельствах разными командами.
Некоторые замечания о only_if:
-
only_ifотносится ко всемуcontrol. Если результаты блокаonly_ifоцениваются как ложь, любые ресурсы Chef InSpec, упомянутые в блокеdescribe, не будут запущены. Кроме того, содержимое блоков describe не будет запущено. Однако базовые выражения Ruby и базовые ресурсы Chef InSpec (не связанные с блоком describe) перед оператором only_if будут выполнены
Для иллюстрации:
control "whatruns" do
command("do_something") # This will ALWAYS run
describe command("do_another_thing") do # This will not run
command("do_yet_another_thing") # This will not run
end
only_if { false }
command("do_something_else") # This will not run
end
- Только один
only_ifразрешен в блокеcontrol. Если присутствуют несколько блоковonly_if, только последний блокonly_ifбудет учтен - Если используется вне блока правила,
only_ifпропускает все правила в текущем файле - Для реализации сложной логики используйте Ruby ‘или’ (
||) и ‘и’ (&&) внутри вашего блокаonly_if:
only_if('ready for launch') do
rocket_is_ready && weather_is_clear
end
Дополнительные метаданные для правил
Следующий пример иллюстрирует различные способы добавления тегов и ссылок к control
control 'ssh-1' do
impact 1.0
title 'Allow only SSH Protocol 2'
desc '
Only SSH protocol version 2 connections should be permitted.
The default setting in /etc/ssh/sshd_config is correct, and can be
verified by ensuring that the following line appears: Protocol 2
'
tag 'production','development'
tag 'ssh','sshd','openssh-server'
tag cce: 'CCE-27072-8'
tag disa: 'RHEL-06-000227'
tag remediation: 'stig_rhel6/recipes/sshd-config.rb'
tag remediation: 'https://supermarket.chef.io/cookbooks/ssh-hardening'
ref 'NSA-RH6-STIG - Section 3.5.2.1', url: 'https://www.nsa.gov/ia/_files/os/redhat/rhel5-guide-i731.pdf'
ref 'http://people.redhat.com/swells/scap-security-guide/RHEL/6/output/ssg-centos6-guide-C2S.html'
describe ssh_config do
its('Protocol') { should cmp 2 }
end
end
Использование Ruby в InSpec
Язык Chef InSpec — это язык на основе Ruby. Это позволяет вам быть гибкими с кодом Ruby в правилах:
json_obj = json('/file.json')
json_obj['keys'].each do |value|
..
end
Ruby предоставляет много возможностей, но их следует ограничивать в правилах, чтобы они оставались портативными и понятными. См. наш руководство по стилю профиля.
Ядра и настраиваемые ресурсы написаны как обычные классы Ruby, которые наследуются от Inspec.resource.
Интерактивная отладка с помощью Pry
Вот пример правила Chef InSpec, которое использует переменные Ruby для создания экземпляра ресурса Chef InSpec один раз и использования содержимого в нескольких тестах.
control 'check-perl' do
impact 0.3
title 'Check perl compiled options and permissions'
perl_out = command('perl -V')
#require 'pry'; binding.pry;
describe perl_out do
its('exit_status') { should eq 0 }
its('stdout') { should match /USE_64_BIT_ALL/ }
its('stdout') { should match /useposix=true/ }
its('stdout') { should match /-fstack-protector/ }
end
# extract an array of include directories
perl_inc = perl_out.stdout.partition('@INC:').last.strip.split("\n")
# ensure include directories are only writable by 'owner'
perl_inc.each do |path|
describe directory(path.strip) do
it { should_not be_writable.by 'group' }
it { should_not be_writable.by 'other' }
end
end
end
Расширенный, но очень полезный совет по Ruby. В предыдущем примере я закомментировал строку require 'pry'; binding.pry;. Если вы удалите префикс # и запустите правило, выполнение остановится на этой строке и предоставит вам оболочку pry. Используйте ее для отладки, вывода переменных, просмотра доступных методов и т. д. Для приведенного выше примера:
[1] pry> perl_out.exit_status
=> 0
[2] pry> perl_out.stderr
=> ""
[3] pry> ls perl_out
Inspec::Plugins::Resource#methods: inspect
Inspec::Resources::Cmd#methods: command exist? exit_status result stderr stdout to_s
Inspec::Resource::Registry::Command#methods: inspec
instance variables: @__backend_runner__ @__resource_name__ @command @result
[4] pry> perl_out.stdout.partition('@INC:').last.strip.split("\n")
=> ["/Library/Perl/5.18/darwin-thread-multi-2level",
" /Library/Perl/5.18",
...REDACTED...
[5] pry> exit # or abort
Вы можете использовать pry как в DSL для правил, так и в ресурсах. Аналогично, для разработки и тестирования вы можете использовать inspec shell, который основан на pry, например:
$ inspec shell
Welcome to the interactive InSpec Shell
To find out how to use it, type: help
inspec> command('ls ~/projects/github/inspec/docs').stdout
=> "README.md\nconfig.md\ndev\ndsl_inspec.md\ndsl_resource.md\nglossary.md\nhabitat.md\ninputs.md\ninspec_and_friends.md\nmatchers.md\nmigration.md\nplatforms.md\nplugin_kitchen_inspec.md\nplugins.md\nprofiles.md\nreporters.md\nresources\nshared\nshell.md\nstyle.md\nwaivers.md\n"
inspec> command('ls ~/projects/github/inspec/docs').stdout.split("\n").first
=> "README.md"
inspec> help command
Name: command
Description:
Use the command InSpec audit resource to test an arbitrary command that is run on the system.
Example:
describe command('ls -al /') do
it { should exist }
its('stdout') { should match /bin/ }
its('stderr') { should eq '' }
its('exit_status') { should eq 0 }
end
© Chef Software, Inc.
Licensed under the Creative Commons Attribution 3.0 Unported License.
The Chef™ Mark and Chef Logo are either registered trademarks/service marks or trademarks/servicemarks of Chef, in the United States and other countries and are used with Chef Inc's permission.
We are not affiliated with, endorsed or sponsored by Chef Inc.
https://docs.chef.io/inspec/dsl_inspec/