3. Practice the Fundamentals
Revisiting the NGINX Web Server InSpec Profile
In the beginner class, we wrote and ran an InSpec profile against a test container. We then generated a report on our results and loaded them into Heimdall for analysis. Let's recap this process with some practice.
The Target
InSpec is a framework used to validate the security configuration of a target. In this case, we are interested in validating that an NGINX server complies with our requirements.
First, let's find our NGINX container ID using the docker ps
command:
docker ps
Which will return something like:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8bs80z6b5n9s redhat/ubi9 "/bin/bash" 2 weeks ago Up 1 hour redhat9
8ba6b8av5n7s nginx:latest "/docker.β¦" 2 weeks ago Up 1 hour 80/tcp nginx
We can then use the name of our NGINX container, nginx
, to target the InSpec validation scans at that container.
The Requirements
InSpec profiles are a set of automated tests that relate back to a security guidance document, so the controls are always motivated by the requirements.
Review
In the beginner class, we worked with a simple requirements set to implement in InSpec.
1. NGINX should be installed as version 1.27.0 or later.
2. The following NGINX modules should be installed:
* `http_ssl`
* `stream_ssl`
* `mail_ssl`
3. The NGINX configuration file - `/etc/nginx/nginx.conf`- should exist as a file.
4. The NGINX configuration file should:
* be owned by the `root` user and group.
* not be readable, writeable, or executable by others.
5. The NGINX shell access should be restricted to admin users.
6. NGINX admins should have documentation on security procedures.
The Controls
InSpec profiles consist of automated tests, that align to security requirements, written in Ruby files inside the controls directory.
Review
Recall that we created a my_nginx
InSpec profile in the Beginner Security Automation class
If you don't have the my_nginx
profile for any reason, or if you have tinkered with it too much to use it easily, you can use the my_nginx_answer_key
profile instead.
Our profile has several components:
- an
inspec.yml
file - a
controls
directory
You should have an inputs
section in your profile at my_nginx/inspec.yml
name: my_nginx
title: InSpec Profile
maintainer: The Authors
copyright: The Authors
copyright_email: you@example.com
license: Apache-2.0
summary: An InSpec Compliance Profile
version: 0.1.0
supports:
platform: os
inputs:
- name: nginx_version
type: String
value: 1.27.0
- name: nginx_modules
type: Array
value:
- http_ssl
- stream_ssl
- mail_ssl
- name: admin_users
type: Array
value:
- admin
You should have an inputs file in your profile at my_nginx/inputs.yml
. It should say the following:
admin_users:
- admin
- root
You should have the following controls in your profile at my_nginx/controls/example.rb
control 'nginx-version' do
impact 1.0
title 'NGINX version'
desc 'The required version of NGINX should be installed.'
describe nginx do
its('version') { should cmp >= input('nginx_version') }
end
end
control 'nginx-modules' do
impact 1.0
title 'NGINX modules'
desc 'The required NGINX modules should be installed.'
required_modules = input('nginx_modules')
describe nginx do
required_modules.each do |required_module|
its('modules') { should include required_module }
end
end
end
control 'nginx-conf-file' do
impact 1.0
title 'NGINX configuration file'
desc 'The NGINX config file should exist.'
describe file('/etc/nginx/nginx.conf') do
it { should be_file }
end
end
control 'nginx-conf-perms' do
impact 1.0
title 'NGINX configuration permissions'
desc 'The NGINX config file should owned by root, be writable only by owner, and not writeable or and readable by others.'
describe file('/etc/nginx/nginx.conf') do
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
it { should_not be_readable.by('others') }
it { should_not be_writable.by('others') }
it { should_not be_executable.by('others') }
end
end
control 'nginx-shell-access' do
impact 1.0
title 'NGINX shell access'
desc 'The NGINX shell access should be restricted to admin users.'
non_admin_users = users.shells(/bash/).usernames
describe "Shell access for non-admin users" do
it "should be removed." do
failure_message = "These non-admin should not have shell access: #{non_admin_users.join(", ")}"
expect(non_admin_users).to be_in(input('admin_users')), failure_message
end
end
end
Running the Controls
inspec exec my_nginx -t docker://nginx --input-file my_nginx/inputs.yml --enhanced-outcomes
Redirecting to cinc-auditor...
Profile: InSpec Profile (my_nginx_answer_key)
Version: 0.1.0
Target: docker://DOCKER_CONTAINER_ID
Target ID: TARGET_ID
β nginx-version: NGINX version
β Nginx Environment version is expected to cmp >= "1.27.0"
β nginx-modules: NGINX modules
β Nginx Environment modules is expected to include "http_ssl"
β Nginx Environment modules is expected to include "stream_ssl"
β Nginx Environment modules is expected to include "mail_ssl"
β nginx-conf-file: NGINX configuration file
β File /etc/nginx/nginx.conf is expected to be file
Γ nginx-conf-perms: NGINX configuration permissions (1 failed)
β File /etc/nginx/nginx.conf is expected to be owned by "root"
β File /etc/nginx/nginx.conf is expected to be grouped into "root"
Γ File /etc/nginx/nginx.conf is expected not to be readable by others
expected File /etc/nginx/nginx.conf not to be readable by others
β File /etc/nginx/nginx.conf is expected not to be writable by others
β File /etc/nginx/nginx.conf is expected not to be executable by others
β nginx-shell-access: NGINX shell access
β Shell access for non-admin users should be removed.
N/R nginx-interview: NGINX interview
βΊ This control must be manually reviewed.
Profile Summary: 4 successful controls, 1 control failure, 1 control not reviewed, 0 controls not applicable, 0 controls have error
Test Summary: 10 successful, 1 failure, 1 skipped
Reporting Results
In the beginner class, we mentioned that you can specify an InSpec reporter to indicate the format in which you desire the results. If you want to read the results on the command line as well as save them in a JSON file, you can run this command.
inspec exec my_nginx -t docker://nginx --input-file my_nginx/inputs.yml --reporter cli json:results/my_nginx_results.json --enhanced-outcomes
Visualizing Results
You can use this output file to upload and visualize your results in Heimdall.