diff --git a/src/assets/img/Download_STIG.png b/src/assets/img/Download_STIG.png index ef98b3576..64953f682 100644 Binary files a/src/assets/img/Download_STIG.png and b/src/assets/img/Download_STIG.png differ diff --git a/src/assets/img/Download_STIG_Viewer.png b/src/assets/img/Download_STIG_Viewer.png index 556643cbd..7862584a8 100644 Binary files a/src/assets/img/Download_STIG_Viewer.png and b/src/assets/img/Download_STIG_Viewer.png differ diff --git a/src/assets/img/NIST_requirements_to_STIG.svg b/src/assets/img/NIST_requirements_to_STIG.svg new file mode 100644 index 000000000..08f9a6926 --- /dev/null +++ b/src/assets/img/NIST_requirements_to_STIG.svg @@ -0,0 +1,4 @@ + + + +
DoD Directives and Instructions
DoD Directives and...
NIST SP 800-53 Controls
NIST SP 800-53...
Policy by the Chair of the Joint Chiefs of Staff 
Policy by the Chai...
DoD Components' Chief Technology Officers
DoD Components' Ch...
Control Correlation Identifiers
Control Correlatio...
App Server SRG
App Server S...
Database SRG
Database SRG
OS SRG
OS SRG
Web Server SRG
Web Server S...
Product STIG SCAP Content
Product STIG SCAP...
Security and Privacy Controls for Information Systems and Organizations

Security and Privacy Con...
DoD Policy
DoD Policy
Master Control Mapping
Master Control Ma...
Security Requirements Guides
Security Requirem...
Final Product
Final Product
Text is not SVG - cannot display
\ No newline at end of file diff --git a/src/assets/img/STIGSources.png b/src/assets/img/STIGSources.png deleted file mode 100644 index fa639c683..000000000 Binary files a/src/assets/img/STIGSources.png and /dev/null differ diff --git a/src/assets/img/saf-lifecycle.png b/src/assets/img/saf-lifecycle.png deleted file mode 100644 index dc96455eb..000000000 Binary files a/src/assets/img/saf-lifecycle.png and /dev/null differ diff --git a/src/assets/img/the_stig_file.png b/src/assets/img/the_stig_file.png new file mode 100644 index 000000000..793ded9c7 Binary files /dev/null and b/src/assets/img/the_stig_file.png differ diff --git a/src/courses/advanced/03.md b/src/courses/advanced/03.md index 5c1e21e69..a04600b8c 100644 --- a/src/courses/advanced/03.md +++ b/src/courses/advanced/03.md @@ -48,6 +48,7 @@ In the beginner class, we worked with a simple requirements set to implement in * 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. ``` ::: @@ -58,13 +59,16 @@ InSpec profiles consist of automated tests, that align to security requirements, ::: details Review -If you don't have the `my_nginx` profile, run the following command to initialize your InSpec profile. +Recall that we created a `my_nginx` InSpec profile in the [Beginner Security Automation](../beginner/README.md) class -``` -inspec init profile my_nginx -``` +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: -Append the `inputs` sections in your profile at `my_nginx/inspec.yml` +- an `inspec.yml` file +- a `controls` directory + +You should have an `inputs` section in your profile at `my_nginx/inspec.yml` ```yaml name: my_nginx @@ -96,7 +100,7 @@ inputs: - admin ``` -Create an inputs file in your profile at `inputs-linux.yml` +You should have an inputs file in your profile at `inputs-linux.yml` ```yaml admin_users: @@ -104,7 +108,7 @@ admin_users: - root ``` -Paste the following controls in your profile at `my_nginx/controls/example.rb` +You should have the following controls in your profile at `my_nginx/controls/example.rb` ```ruby control 'nginx-version' do @@ -168,23 +172,23 @@ end ### Running the Controls -To run `inspec exec` on the target, ensure that you are in the directory that has `my_nginx` profile. - ::: code-tabs @tab command ```sh -inspec exec my_nginx -t docker://nginx --input-file inputs-linux.yml +inspec exec my_nginx -t docker://nginx --input-file my_nginx/inputs.yml --enhanced-outcomes ``` @tab output ```sh - Profile: InSpec Profile (my_nginx) - Version: 0.1.0 - Target: docker://DOCKER_CONTAINER_ID - Target ID: TARGET_ID +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" @@ -203,10 +207,12 @@ inspec exec my_nginx -t docker://nginx --input-file inputs-linux.yml ✔ 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, 0 controls skipped -Test Summary: 10 successful, 1 failure, 0 skipped +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 ``` ::: @@ -216,7 +222,7 @@ Test Summary: 10 successful, 1 failure, 0 skipped In the [beginner class](../beginner/08.md), 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. ```sh -inspec exec my_nginx -t docker://nginx --input-file inputs-linux.yml --reporter cli json:my_nginx_results.json --enhanced-outcomes +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 diff --git a/src/courses/advanced/05.md b/src/courses/advanced/05.md index 800946c5f..c19eb5a3e 100644 --- a/src/courses/advanced/05.md +++ b/src/courses/advanced/05.md @@ -89,6 +89,8 @@ inspec exec git @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (git) Version: 0.1.0 Target: local:// @@ -145,6 +147,8 @@ inspec exec git @tab Output ```bash +Redirecting to cinc-auditor... + [2023-02-22T03:21:41+00:00] ERROR: Failed to load profile git: Failed to load source for controls/example.rb: undefined method `git' for # Profile: InSpec Profile (git) diff --git a/src/courses/advanced/06.md b/src/courses/advanced/06.md index 34325b38a..277eb38df 100644 --- a/src/courses/advanced/06.md +++ b/src/courses/advanced/06.md @@ -14,24 +14,25 @@ If you've ever deployed containerized applications before, you might be familiar ### Create a new profile and set up Docker files -First, we need a test target. Check out the `resources/docker-compose.yml` file in Codespaces for what we can test. It looks like this: +First, we need a test target. Luckily, we already have a great one sitting in our Codespaces environment. It's the same Docker Compose file we use in the `build-lab.sh` script to launch the containers we use for this class! It looks like this: ```yaml +# https://docs.docker.com/compose/compose-file/compose-file-v3/ version: '3' services: - workstation: - container_name: workstation - image: learnchef/inspec_workstation - stdin_open: true + operatingsystem: + image: redhat/ubi9 + container_name: redhat9 tty: true - links: - - target - volumes: - - .:/root - target: - image: learnchef/inspec_target stdin_open: true + restart: always + + nginx: + image: nginx:latest + container_name: nginx tty: true + stdin_open: true + restart: always ``` We will continue writing our controls to check against this Compose file. @@ -47,6 +48,8 @@ inspec init profile docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + ─────────────────────────── InSpec Code Generator ─────────────────────────── Creating new profile at /workspaces/saf-training-lab-environment/docker-workstations @@ -83,6 +86,8 @@ inspec exec docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Target: local:// @@ -99,9 +104,9 @@ Test Summary: 0 successful, 0 failures, 1 skipped We need to replace the `file_name` above with the location of the `docker-compose.yml` file. We also need to change the `setting` to grab the tag we want to retrieve. Finally we need to change `value` with the actual value as shown in the docker compose file. You can write multiple expectation statements in the describe block. ```ruby -describe yaml('/path/to/docker-compose.yml') do - its(['services', 'workstation', 'image']) { should eq 'learnchef/inspec_workstation' } - its(['services', 'workstation', 'volumes']) { should cmp '.:/root' } +describe yaml('docker-compose.yml') do + its(['services', 'operatingsystem', 'image']) { should eq 'redhat/ubi9' } + its(['services', 'nginx', 'image']) { should cmp 'nginx:latest' } end ``` @@ -118,54 +123,31 @@ inspec exec docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 - YAML /workspaces/saf-training-lab-environment/resources/docker-compose.yml - ✔ ["services", "workstation", "image"] is expected to eq "learnchef/inspec_workstation" - ✔ ["services", "workstation", "volumes"] is expected to cmp == ".:/root" + YAML docker-compose.yml + ✔ ["services", "operatingsystem", "image"] is expected to eq "redhat/ubi9" + ✔ ["services", "nginx", "image"] is expected to cmp == "nginx:latest" Test Summary: 2 successful, 0 failures, 0 skipped ``` ::: -Much like our `git ` example, this series of tests works, but it could be made better. We essentially parsed the Compose file with a simple YAML file parser which is fine for a one-off. However, if anybody else reads this code, it might not be clear what specific system component we are testing. Recall that we want InSpec tests to be extremely intuitive to read, even by people who did not write the code (and even by people who are not InSpec developers!). Furthermore, Compose files are very common! There's a high likelihood that you'd need to assess the contents of one again. Instead of writing a lot of repetitive code, we could create a resource specific to Compose files that exposes relevant attributes in an easy to access manner for reuse by our other controls - or even the broader security community if we choose to publish it publicly and/or get it merged into InSpec proper. +Much like our `git ` example, this series of tests works, but it could be made better. We essentially parsed the Compose file with a simple YAML file parser which is fine for a one-off. However, if anybody else reads this code, it might not be clear what specific system component we are testing. Recall that we want InSpec tests to be extremely intuitive to read, even by people who did not write the code (and even by people who are not InSpec developers!). Furthermore, Compose files are very common! There's a high likelihood that you'd need to assess the contents of one again. -:::danger If you received an error above! - Concept Check - -If you saw this as your output: - -```bash -Profile: InSpec Profile (docker-workstations) -Version: 0.1.0 -Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce - - YAML /path/to/docker-compose.yml - ↺ Can't find file: /path/to/docker-compose.yml - -Test Summary: 0 successful, 0 failures, 1 skipped -``` - -It is because you did not give YOUR path to the docker-compose file. You need to replace the path in your `example.rb` file to be something like this: - -```ruby -describe yaml('/workspaces/saf-training-lab-environment/resources/docker-compose.yml') do - its(['services', 'workstation', 'image']) { should eq 'learnchef/inspec_workstation' } - its(['services', 'workstation', 'volumes']) { should cmp '.:/root' } -end -``` - -::: +Instead of writing a lot of repetitive code, we could create a resource specific to Compose files that exposes relevant attributes in an easy to access manner for reuse by our other controls - or even the broader security community if we choose to publish it publicly and/or get it merged into InSpec proper. ### Rewrite test to utilize a new resource Going back to the control, we will write it using a resource that doesn't exist called docker-compose-config that is going to take a path as a parameter. :::details Test Driven Development -Remember the idea of Test Driven Development (TDD), the red-green-clean cycle. This way of development is driven by the tests. In this way, you know when you have succeeded while developing something new! In other words, before writing a solution, first write the test (which will fail - red), so that you know exactly what the expectation should be and when you have achieved it. Then you can write the solution to make the test pass (green). Finally, clean up the solution to make it easy to read and efficient! +Remember the idea of Test Driven Development (TDD), the "red-green-clean" cycle. This way of development is driven by the tests. In this way, you know when you have succeeded while developing something new! In other words, before writing a solution, first write the test (which will fail - red), so that you know exactly what the expectation should be and when you have achieved it. Then you can write the solution to make the test pass (green). Finally, clean up the solution to make it easy to read and efficient! ![Test Driven Development](../../assets/img/TestDrivenDevelopment.png) ::: @@ -174,28 +156,14 @@ Remember the idea of Test Driven Development (TDD), the red-green-clean cycle. T @tab Tests ```ruby -describe yaml('/workspaces/saf-training-lab-environment/resources/docker-compose.yml') do - its(['services', 'workstation', 'image']) { should eq 'learnchef/inspec_workstation' } - its(['services', 'workstation', 'volumes']) { should cmp '.:/root' } +describe yaml('docker-compose.yml') do + its(['services', 'operatingsystem', 'image']) { should eq 'redhat/ubi9' } + its(['services', 'nginx', 'image']) { should cmp 'nginx:latest' } end -describe docker_compose_config('/workspaces/saf-training-lab-environment/resources/docker-compose.yml') do - its('services.workstation.image') { should eq 'learnchef/inspec_workstation' } - its('services.workstation.volumes') { should cmp '.:/root' } -end -``` - -@tab Generic Tests - -```ruby -describe yaml('/path/to/docker-compose.yml') do - its(['services', 'workstation', 'image']) { should eq 'learnchef/inspec_workstation' } - its(['services', 'workstation', 'volumes']) { should cmp '.:/root' } -end - -describe docker_compose_config('/path/to/docker-compose.yml') do - its('services.workstation.image') { should eq 'learnchef/inspec_workstation' } - its('services.workstation.volumes') { should cmp '.:/root' } +describe docker_compose_config('docker-compose.yml') do + its('services.operatingsystem.image') { should eq 'redhat/ubi9' } + its('services.nginx.image') { should cmp 'nginx:latest' } end ``` @@ -214,13 +182,31 @@ inspec exec docker-workstations @tab Output ```bash -[2023-02-22T18:37:03+00:00] ERROR: Failed to load profile docker-workstations: Failed to load source for controls/example.rb: undefined method `docker_compose_config' for # +Redirecting to cinc-auditor... + +Profile: InSpec Profile (docker-workstations) +Version: 0.1.0 +Target: local:// +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 + + YAML docker-compose.yml + ✔ ["services", "operatingsystem", "image"] is expected to eq "redhat/ubi9" + ✔ ["services", "nginx", "image"] is expected to cmp == "nginx:latest" + +Test Summary: 2 successful, 0 failures, 0 skipped +@wdower ➜ /workspaces/saf-training-lab-environment (answer_key) $ inspec exec docker-workstations/ +Redirecting to cinc-auditor... + +< lots of error text > Profile: InSpec Profile (docker-workstations) Version: 0.1.0 -Failure Message: Failed to load source for controls/example.rb: undefined method `docker_compose_config' for # +Failure Message: Failed to load source for controls/example.rb: undefined method `docker_compose_config' for + +< lots more error text > + Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 No tests executed. @@ -288,13 +274,14 @@ inspec exec docker-workstations @tab Output ```bash -[2023-02-22T18:38:40+00:00] ERROR: Failed to load profile docker-workstations: Failed to load source for controls/example.rb: wrong number of arguments (given 1, expected 0) +Redirecting to cinc-auditor... +[2024-12-09T07:03:10+00:00] ERROR: Failed to load profile docker-workstations: Failed to load source for controls/example.rb: wrong number of arguments (given 1, expected 0) Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Failure Message: Failed to load source for controls/example.rb: wrong number of arguments (given 1, expected 0) Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 No tests executed. @@ -333,19 +320,21 @@ inspec exec docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 - YAML /workspaces/saf-training-lab-environment/resources/docker-compose.yml - ✔ ["services", "workstation", "image"] is expected to eq "learnchef/inspec_workstation" - ✔ ["services", "workstation", "volumes"] is expected to cmp == ".:/root" + YAML docker-compose.yml + ✔ ["services", "operatingsystem", "image"] is expected to eq "redhat/ubi9" + ✔ ["services", "nginx", "image"] is expected to cmp == "nginx:latest" docker_compose_config - × services.workstation.image - undefined method `services' for #<#:0x00000000032cbbd8> - × services.workstation.volumes - undefined method `services' for #<#:0x00000000032cbbd8> + × services.operatingsystem.image + undefined method `services' for #<#:0x000077e66a0c2358 @resource_skipped=false, @resource_failed=false, @supports=nil, @resource_exception_message=nil, @__backend_runner__=Inspec::Backend::Class @transport=Train::Transports::Local::Connection, @__resource_name__="docker_compose_config", @resource_params=["docker-compose.yml"], @path="docker-compose.yml"> + × services.nginx.image + undefined method `services' for #<#:0x000077e66a0c2358 @resource_skipped=false, @resource_failed=false, @supports=nil, @resource_exception_message=nil, @__backend_runner__=Inspec::Backend::Class @transport=Train::Transports::Local::Connection, @__resource_name__="docker_compose_config", @resource_params=["docker-compose.yml"], @path="docker-compose.yml"> Test Summary: 2 successful, 2 failures, 0 skipped ``` @@ -385,19 +374,21 @@ inspec exec docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 - YAML /workspaces/saf-training-lab-environment/resources/docker-compose.yml - ✔ ["services", "workstation", "image"] is expected to eq "learnchef/inspec_workstation" - ✔ ["services", "workstation", "volumes"] is expected to cmp == ".:/root" + YAML docker-compose.yml + ✔ ["services", "operatingsystem", "image"] is expected to eq "redhat/ubi9" + ✔ ["services", "nginx", "image"] is expected to cmp == "nginx:latest" docker_compose_config - × services.workstation.image - undefined method `workstation' for nil:NilClass - × services.workstation.volumes - undefined method `workstation' for nil:NilClass + × services.operatingsystem.image + undefined method `operatingsystem' for nil:NilClass + × services.nginx.image + undefined method `nginx' for nil:NilClass Test Summary: 2 successful, 2 failures, 0 skipped ``` @@ -438,26 +429,28 @@ inspec exec docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 - YAML /workspaces/saf-training-lab-environment/resources/docker-compose.yml - ✔ ["services", "workstation", "image"] is expected to eq "learnchef/inspec_workstation" - ✔ ["services", "workstation", "volumes"] is expected to cmp == ".:/root" + YAML docker-compose.yml + ✔ ["services", "operatingsystem", "image"] is expected to eq "redhat/ubi9" + ✔ ["services", "nginx", "image"] is expected to cmp == "nginx:latest" docker_compose_config - × services.workstation.image - undefined method `workstation' for - × services.workstation.volumes - undefined method `workstation' for + × services.operatingsystem.image + undefined method `operatingsystem' for {"operatingsystem"=>{"image"=>"redhat/ubi9", "container_name"=>"redhat9", "tty"=>true, "stdin_open"=>true, "restart"=>"always"}, "nginx"=>{"image"=>"nginx:latest", "container_name"=>"nginx", "tty"=>true, "stdin_open"=>true, "restart"=>"always"}}:Hash + × services.nginx.image + undefined method `nginx' for {"operatingsystem"=>{"image"=>"redhat/ubi9", "container_name"=>"redhat9", "tty"=>true, "stdin_open"=>true, "restart"=>"always"}, "nginx"=>{"image"=>"nginx:latest", "container_name"=>"nginx", "tty"=>true, "stdin_open"=>true, "restart"=>"always"}}:Hash Test Summary: 2 successful, 2 failures, 0 skipped ``` ::: -You will notice that it parses correctly, but instead of our result we end up getting a hash. We need to convert the hash into an object that appears like other objects so that we may use our dot notation. So we will wrap our hash in a Ruby class called a `Hashie::Mash`. This gives us a quick way to convert a hash into a Ruby object with a number of methods attached to it. You will have to import the Hashie library by running `gem install hashie` and import it in the resource file to be used. It and is written as follows: +You will notice that it parses correctly, but instead of our result we end up getting a giant hash of data that doesn't seem to parse correctly. We need to convert the hash into an object that appears like other objects so that we may use our dot notation. So we will wrap our hash in a Ruby class called a `Hashie::Mash`. This gives us a quick way to convert a hash into a Ruby object with a number of methods attached to it. You will have to import the Hashie library by running `gem install hashie` and import it in the resource file to be used. It and is written as follows: ```ruby # encoding: utf-8 @@ -494,43 +487,23 @@ inspec exec docker-workstations @tab Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (docker-workstations) Version: 0.1.0 Target: local:// -Target ID: 6dcb9e6f-5ede-5474-9521-595fadf5c7ce +Target ID: bdf4338d-8fb0-5ca6-a949-ced198781ad5 - YAML /workspaces/saf-training-lab-environment/resources/docker-compose.yml - ✔ ["services", "workstation", "image"] is expected to eq "learnchef/inspec_workstation" - ✔ ["services", "workstation", "volumes"] is expected to cmp == ".:/root" + YAML docker-compose.yml + ✔ ["services", "operatingsystem", "image"] is expected to eq "redhat/ubi9" + ✔ ["services", "nginx", "image"] is expected to cmp == "nginx:latest" docker_compose_config - ✔ services.workstation.image is expected to eq "learnchef/inspec_workstation" - ✔ services.workstation.volumes is expected to cmp == ".:/root" + ✔ services.operatingsystem.image is expected to eq "redhat/ubi9" + ✔ services.nginx.image is expected to cmp == "nginx:latest" Test Summary: 4 successful, 0 failures, 0 skipped ``` ::: -Everything passed! - -:::info Check your work -Check your work with the InSpec video below that walks through this docker resource example! -::: - - -
- -
+Everything passed! \ No newline at end of file diff --git a/src/courses/advanced/09.md b/src/courses/advanced/09.md index da536c332..6ba8b7372 100644 --- a/src/courses/advanced/09.md +++ b/src/courses/advanced/09.md @@ -72,7 +72,9 @@ jobs: run: sudo apt-get update - name: PREP - Install InSpec executable - run: curl https://omnitruck.chef.io/install.sh | sudo bash -s -- -P inspec -v 5 + run: | + curl https://omnitruck.chef.io/install.sh | \ + sudo bash -s -- -P inspec -v 5 - name: PREP - Install SAF CLI run: npm install -g @mitre/saf @@ -98,15 +100,24 @@ jobs: # fetch the hardening role and requirements - name: HARDEN - Fetch Ansible role run: | - git clone --branch docker https://github.com/mitre/ansible-nginx-stigready-hardening.git || true + git clone \ + https://github.com/mitre/ansible-nginx-stigready-hardening.git \ + --branch docker \ + || true chmod 755 ansible-nginx-stigready-hardening - name: HARDEN - Fetch Ansible requirements - run: ansible-galaxy install -r ansible-nginx-stigready-hardening/requirements.yml + run: | + ansible-galaxy install \ + -r ansible-nginx-stigready-hardening/requirements.yml # harden! - name: HARDEN - Run Ansible hardening - run: ansible-playbook --inventory=nginx, --connection=docker ansible-nginx-stigready-hardening/hardening-playbook.yml + run: | + ansible-playbook \ + --inventory=nginx, \ + --connection=docker \ + ansible-nginx-stigready-hardening/hardening-playbook.yml - name: VALIDATE - Run InSpec # we dont want to stop if our InSpec run finds failures, we want to continue and record the result @@ -120,7 +131,9 @@ jobs: # attest - name: VALIDATE - Apply an Attestation run: | - saf attest apply -i results/pipeline_run.json attestation.json -o results/pipeline_run_attested.json + saf attest apply \ + -i results/pipeline_run.json attestation.json \ + -o results/pipeline_run_attested.json # save our results to the pipeline artifacts, even if the InSpec run found failing tests - name: VALIDATE - Save Test Result JSON @@ -132,7 +145,11 @@ jobs: - name: VALIDATE - Upload to Heimdall continue-on-error: true run: | - curl -# -s -F data=@results/pipeline_run_attested.json -F "filename=${{ github.actor }}-pipeline-demo-${{ github.sha }}.json" -F "public=true" -F "evaluationTags=${{ github.repository }},${{ github.workflow }}" -H "Authorization: Api-Key ${{ secrets.HEIMDALL_API_KEY }}" "https://heimdall-demo.mitre.org/evaluations" + curl -# -s \ + -F data=@results/pipeline_run_attested.json \ + -F "filename=${{ github.actor }}-pipeline-demo-${{ github.sha }}.json" \ + -F "public=true" -F "evaluationTags=${{ github.repository }},${{ github.workflow }}" \ + -H "Authorization: Api-Key ${{ secrets.HEIMDALL_API_KEY }}" "https://heimdall-demo.mitre.org/evaluations" - name: VERIFY - Display our results summary run: | @@ -228,7 +245,7 @@ jobs: - `gold-image` is an arbitrary name we gave this job. It would be more useful if we were running more than one. - `name` is a simple title for this job. -- `runs-on` declares what operating system we want our runner node to be. We picked Ubuntu (and we suggest you do to to make sure the rest of the workflow commands work correctly). +- `runs-on` declares what operating system we want our runner node to be. We picked Ubuntu (and we suggest you do as well to make sure the rest of the workflow commands work correctly). - `env` declares environment variables for use by any step of this job. We will go ahead and set a few variables for running InSpec later on: - `CHEF_LICENSE` will automatically accept the license prompt when you run InSpec the first time so that we don't hang waiting for input! - `PROFILE` is set to the path of the InSpec profile we will use to test. This will make it easier to refer to the profile multiple times and still make it easy to swap out. diff --git a/src/courses/advanced/README.md b/src/courses/advanced/README.md index 4c99f5fa4..8a119ad7a 100644 --- a/src/courses/advanced/README.md +++ b/src/courses/advanced/README.md @@ -41,7 +41,7 @@ As shown in the picture below, the process for developing automated security tes This challenge is what the [MITRE Security Automation Framework](https://saf.mitre.org) or MITRE SAF was developed to simplify -- to make the journey from a Requirement Document to an automated test profile and back again a little easier to navigate. -![The SAF Lifecycle](../../assets/img/saf-lifecycle.png) +![The SAF Lifecycle](../../assets/img/saf-lifecycle.jpg) ## 1.4 Where can I start on my own? diff --git a/src/courses/beginner/03.md b/src/courses/beginner/03.md index aee42d8a3..73b98d5f4 100644 --- a/src/courses/beginner/03.md +++ b/src/courses/beginner/03.md @@ -32,6 +32,7 @@ Let's say that we are attempting to validate that our NGINX webserver complies w * 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. ``` ### Creating the profile diff --git a/src/courses/beginner/04.md b/src/courses/beginner/04.md index 2882188db..9eb32a621 100644 --- a/src/courses/beginner/04.md +++ b/src/courses/beginner/04.md @@ -27,6 +27,8 @@ inspec exec my_nginx -t docker://nginx --reporter cli ``` @tab Expected Output ```bash +Redirecting to cinc-auditor... + Profile: InSpec Profile (my_nginx) Version: 0.1.0 Target: docker://31e4ea1be052a9bcc13700 @@ -43,13 +45,20 @@ Test Summary: 2 successful, 0 failures, 0 skipped ``` ::: - ### InSpec References The `inspec exec` command is used to run or _execute_ InSpec profiles. Now, let's talk about InSpec's existing documentation and features to support _writing_ those InSpec profiles. Good InSpec tests will use resources, many of which are already built in, to easily describe some part of the system. Remember the `file` resource as an example from the previous section. Additionally, tests should use matchers to implement the logic check of an expected result. The previous example used `be_directory` as a matcher. There are a number of built-in [matchers](https://docs.chef.io/inspec/matchers/): `be_in`, `be_readable`, `cmp`, `include`, to list a few. +::: note What's up with CINC Auditor? +You may note that every time we invoke InSpec in these classes, the first line of output is the following: + +`Redirecting to cinc-auditor...` + +Don't worry - that's just because we are using an open-source community build of the InSpec tool called "CINC Auditor," where CINC stands for "CINC-is-not-Chef." We're doing this because the community build doesn't require a license to run. It is otherwise identical to the Chef-released version of InSpec. +::: + :::tip Make Writing InSpec Easier with Built-in Resources InSpec features dozens of resources and matchers that come predefined in the language. These resources are a core benefit to using InSpec because they allow you to leverage existing stable code to write simple and consistent tests. @@ -86,6 +95,7 @@ inspec shell ``` @tab Output ```sh +Redirecting to cinc-auditor... Welcome to the interactive InSpec Shell To find out how to use it, type: help @@ -277,22 +287,10 @@ The `?` (or `be_` in InSpec) makes your method a Ruby Predicate Method. See [Rub #### `nginx` example -Now's a good time to define the requirements for our NGINX configuration. Let's say that you require: -```sh -1. NGINX should be installed as 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. -``` - -In the next section, we will start writing controls for `my_nginx` profile, but first let's see what resources are available to us to model the NGINX webserver. +For our example use case, we want to be able to run tests against an NGINX webserver. + +In the next section, we will start writing controls for `my_nginx` profile, but first let's see what resources are available to us to model NGINX itself. Run `help resources` a second time to identify InSpec's provided two built-in resources to support NGINX – `nginx` and `nginx_conf`. diff --git a/src/courses/beginner/05.md b/src/courses/beginner/05.md index 5b0fb7e25..d157427fe 100644 --- a/src/courses/beginner/05.md +++ b/src/courses/beginner/05.md @@ -24,6 +24,7 @@ Review the requirements we're testing for: * 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. ``` ### Requirement (1) - NGINX Version @@ -59,27 +60,29 @@ Next, run `inspec exec` to execute the profile on the remote target. @tab Command - req 1 ```sh -inspec exec ./my_nginx -t docker://nginx +inspec exec my_nginx -t docker://nginx ``` @tab Generic Command - req 1 ```sh -inspec exec /root/my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} +inspec exec my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} ``` @tab Output - req 1 ```sh - Profile: InSpec Profile (my_nginx) - Version: 0.1.0 - Target: docker://DOCKER_CONTAINER_ID - Target ID: TARGET_ID +Redirecting to cinc-auditor... - ✔ nginx-version: NGINX version - ✔ Nginx Environment version should cmp >= "1.27.0" +Profile: InSpec Profile (my_nginx) +Version: 0.1.0 +Target: docker://DOCKER_CONTAINER_ID +Target ID: TARGET_ID + ✔ nginx-version: NGINX version + ✔ Nginx Environment version should cmp >= "1.27.0" - Profile Summary: 1 successful control, 0 control failures, 0 controls skipped - Test Summary: 1 successful, 0 failures, 0 skipped + +Profile Summary: 1 successful control, 0 control failures, 0 controls skipped +Test Summary: 1 successful, 0 failures, 0 skipped ``` ::: @@ -117,31 +120,33 @@ Run `inspec exec` on the target. @tab Command - req 2 ```sh -inspec exec ./my_nginx -t docker://nginx +inspec exec my_nginx -t docker://nginx ``` @tab Generic Command - req 2 ```sh -inspec exec /root/my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} +inspec exec my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} ``` @tab Output - req 2 ```sh - Profile: InSpec Profile (my_nginx) - Version: 0.1.0 - Target: docker://DOCKER_CONTAINER_ID - Target ID: TARGET_ID +Redirecting to cinc-auditor... + +Profile: InSpec Profile (my_nginx) +Version: 0.1.0 +Target: docker://DOCKER_CONTAINER_ID +Target ID: TARGET_ID - ✔ nginx-version: NGINX version - ✔ Nginx Environment version should cmp >= "1.27.0" - ✔ nginx-modules: NGINX version - ✔ Nginx Environment modules should include "http_ssl" - ✔ Nginx Environment modules should include "stream_ssl" - ✔ Nginx Environment modules should include "mail_ssl" + ✔ nginx-version: NGINX version + ✔ Nginx Environment version should cmp >= "1.27.0" + ✔ nginx-modules: NGINX version + ✔ Nginx Environment modules should include "http_ssl" + ✔ Nginx Environment modules should include "stream_ssl" + ✔ Nginx Environment modules should include "mail_ssl" - Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped - Test Summary: 4 successful, 0 failures, 0 skipped +Profile Summary: 2 successful controls, 0 control failures, 0 controls skipped +Test Summary: 4 successful, 0 failures, 0 skipped ``` ::: @@ -171,16 +176,18 @@ Run `inspec exec` on the target. @tab Command - req 3 ```sh -inspec exec ./my_nginx -t docker://nginx +inspec exec my_nginx -t docker://nginx ``` @tab Generic Command - req 3 ```sh -inspec exec /root/my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} +inspec exec my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} ``` @tab Output - req 3 ```sh +Redirecting to cinc-auditor... + Profile: InSpec Profile (my_nginx) Version: 0.1.0 Target: docker://DOCKER_CONTAINER_ID @@ -238,16 +245,18 @@ Run `inspec exec` on the target. @tab Command - req 4 ```sh -inspec exec ./my_nginx -t docker://nginx +inspec exec my_nginx -t docker://nginx ``` @tab Generic Command - req 4 ```sh -inspec exec /root/my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} +inspec exec my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} ``` @tab Output - req 4 ```sh +Redirecting to cinc-auditor... + Profile: InSpec Profile (my_nginx) Version: 0.1.0 Target: docker://DOCKER_CONTAINER_ID @@ -280,7 +289,7 @@ This time you see a failure. You discover that `/etc/nginx/nginx.conf` is potent ### Requirement (5) - NGINX shell access -The last requirement checks whether NGINX shell access is provided to non-admin users. In this case, access to `bash` needs to be restricted to admin users. +The next requirement checks whether NGINX shell access is provided to non-admin users. In this case, access to `bash` needs to be restricted to admin users. Append this describe block to your control file: @@ -301,16 +310,18 @@ Run `inspec exec` on the target. @tab Command - req 5 ```sh -inspec exec ./my_nginx -t docker://nginx +inspec exec my_nginx -t docker://nginx ``` @tab Generic Command - req 5 ```sh -inspec exec /root/my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} +inspec exec my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} ``` @tab Output - req 5 ```sh +Redirecting to cinc-auditor... + Profile: InSpec Profile (my_nginx) Version: 0.1.0 Target: docker://DOCKER_CONTAINER_ID @@ -344,6 +355,82 @@ Test Summary: 9 successful, 2 failures, 0 skipped ::: +This new test also fails against our test container. It seems that what we called the "admin" account was labelled "root" on the container. InSpec thinks the test is failing even though we're really talking about the same user account. We'll fix this in the next section; let's just get our controls written out for now. + +### Requirement (6) - NGINX interview + +The last requirement is a bit different than the rest. This one requires that the admin for the webserver should have a document on security procedures for the webserver. Put simply, it's not really possible for us to tell if there exists security documentation for our NGINX webserver by only looking at the actual webserver itself. To accomplish this test, we will have to interview an admin. There's no way to do this automatically (at least not without seriously annoying our admin!) so we will instead use an InSpec feature called a `skip` message to indicate that we need to go talk to our admin. + +Note that we are _not_ just going to ignore writing an InSpec control for this requirement. We are `skip`-ing it in the sense that we are not executing automated test code; we are _still responsible_ for making sure the requirement is assessed at some point. We'll show you how to do this the SAF way in [Section 12](../user/12.md). Don't worry, we made it easy. + +Append this describe block to your control file: + +```ruby +control 'nginx-interview' do + impact 1.0 + title 'NGINX interview' + desc 'NGINX admins should have documentation on security procedures.' + + describe "Manual Review" do + skip "This control must be manually reviewed." + end +end +``` + +Run `inspec exec` on the target. + +::: code-tabs#shell + +@tab Command - req 6 +```sh +inspec exec my_nginx -t docker://nginx +``` + +@tab Generic Command - req 6 +```sh +inspec exec my_nginx -t docker://{DOCKER_CONTAINER_ID or DOCKER_CONTAINER_NAME} +``` + +@tab Output - req 6 +```sh +Redirecting to cinc-auditor... + +Profile: InSpec Profile (my_nginx) +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 (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 + × ["root"] is expected to be in "admin" + expected `["root"]` to be in the list: `["admin"]` + Diff: + ["root"] + ↺ nginx-interview: NGINX interview + ↺ This control must be manually reviewed. + + +Profile Summary: 3 successful controls, 2 control failures, 1 control skipped +Test Summary: 9 successful, 2 failures, 1 skipped +``` + +::: + +Our output correctly indicates that `nginx-interview` neither passed nor failed but is instead a skipped control. ### Fixing Problems @@ -351,4 +438,4 @@ Recall that what we're doing with InSpec falls under [MITRE SAF's Validate pilla For the second step, Hardening (sometimes variously referred to as implementation or remediation) you can use a configuration management tool or some other automation framework to correct compliance failures for you. -We're focused on InSpec right now, so we won't correct this issue right now, but you can check out the Chef [Secure your Infrastructure](https://learn.chef.io/tracks/integrated-compliance#/) tutorial course to learn more about how to correct compliance failures using Chef. \ No newline at end of file +We're focused on InSpec right now, so we won't correct this issue yet. Later in this class we will discuss using Ansible to harden our test target. Another option is Chef's [Secure your Infrastructure](https://learn.chef.io/tracks/integrated-compliance#/) tutorial course to learn more about how to correct compliance failures using Chef. \ No newline at end of file diff --git a/src/courses/beginner/06.md b/src/courses/beginner/06.md index ab891795f..176f92a5e 100644 --- a/src/courses/beginner/06.md +++ b/src/courses/beginner/06.md @@ -62,6 +62,16 @@ control 'nginx-shell-access' do it { should be_in ['admin']} end end + +control 'nginx-interview' do + impact 1.0 + title 'NGINX interview' + desc 'NGINX admins should have documentation on security procedures.' + + describe "Manual Review" do + skip "This control must be manually reviewed." + end +end ``` Although these controls are straightforward, imagine if your `controls` directory contained dozens or _hundreds_ of tests, like we might see for a real security validation profile. Many of these tests will be referring to the same test values over and over again -- what happens when we need to change them? Or if I want to test to a different standard and want to adjust the values the tests are looking for? For example, what happens when a new major release of NGINX happens, and we want to test to make sure our deployed webserver is still up to date with the new latest version? @@ -109,7 +119,7 @@ Since we gave the input a default value of `1.27.0`, that value will be passed d We have now swapped out a hard-coded value in the control with a parameter. This is the process of _parameterization_. It is a common practice during InSpec profile development, where profile authors will write their controls and then read through them to look for values that are hardcoded that could be easily replaced with an input. -Keep in mind that these inputs are **constants**. Their values should not and do not change during the execution of the program. If you want the input to have a different value, change your inputs file accordingly before your next run of the profile. +Keep in mind that these inputs are **constants**. Their values should not and do not change during the execution of the program. If you want the input to have a different value, we will **override** them using an inputs file. ::: tip A good rule of thumb is that any check of a numerical value in an InSpec profile should be replaced with an input. @@ -245,9 +255,126 @@ control 'nginx-shell-access' do end ``` -## Input File Example +## Overriding Inputs with + +We have now defined and parameterized a set of default values for our controls. But what if we want to change those defaults at some point? We can pass in our own values for inputs when we run `inspec exec` to ensure that each individual run of InSpec uses the values we want. + +Create a file inside your `my_nginx` profile: + +``` yaml +admin_users: + - admin + - root +``` + +Note that we are invoking an input name that we defined back in the `inspec.yml` file (`admin_users`). We are now overriding the default value by adding the `root` account to our list of valid account names. + +Remember how our test for requirement 5 was failing because we found an account named `root` when we were expecting the name `admin`? We can now tell InSpec that we were intending to look for an account named `root`, and very importantly, we can do it without having to edit either our control code itself or the `inspec.yml` file. + +When using InSpec in the real world, we want a strong separation between our underlying test code (the profile itself) and the environment-specific parameters we pass to it (the inputs). Therefore, we _never_ edit the `inspec.yml` file to simply erase the default values and put in our own; we will instead use InSpec's ability to _override_ input values via an inputs file. + +Let's re-run the profile and pass it our custom inputs. + + +::: code-tabs#shell + +@tab Command +```sh +inspec exec my_nginx -t docker://nginx --input-file +``` + +@tab Output - `--input-file` flag +```sh +Redirecting to cinc-auditor... + +Profile: InSpec Profile (my_nginx) +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 + ✔ ["root"] is expected to be in "admin" and "root" + ↺ nginx-interview: NGINX interview + ↺ This control must be manually reviewed. + + +Profile Summary: 3 successful controls, 2 control failures, 1 control skipped +Test Summary: 9 successful, 2 failures, 1 skipped +``` +::: + +And there we are, requirement 5 is now correctly indicating that the test is a pass. + +Notice that all the other tests besides number 5 _did not_ change -- we didn't specifically override the inputs for those ones in the inputs file, so InSpec did not change the default values. + +### Passing Inputs Via the `--input` Flags + +There are [many ways](https://docs.chef.io/inspec/profiles/inputs) to pass an input to InSpec at runtime. InSpec [prioritizes](https://docs.chef.io/inspec/profiles/inputs/#input-priority) input values differently depending on where the value comes from. + +For example, we can pass an input directly on the terminal line using a different flag: + +::: code-tabs#shell + +@tab Command +```sh +inspec exec my_nginx -t docker://nginx --input=admin_users=['root'] +``` + +@tab Output - `--input` flag +```sh +Redirecting to cinc-auditor... + +Profile: InSpec Profile (my_nginx) +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 + ✔ ["root"] is expected to be in "root" + ↺ nginx-interview: NGINX interview + ↺ This control must be manually reviewed. + + +Profile Summary: 3 successful controls, 2 control failures, 1 control skipped +Test Summary: 9 successful, 2 failures, 1 skipped +``` +::: + +The test still passes. -To change your inputs for platform specific cases you can set up multiple input files. +### Keeping Multiple Input Files + +To change your inputs for platform specific cases, you can set up multiple input files. For example, an NGINX web server could be run on a Windows or Linux machine, which may require different admin users for each context. The inputs can be tailored for each system. You can create a `inputs-windows.yml` *and* `inputs-linux.yml` file in your home directory and only pass the one you actually need to InSpec at runtime. @@ -271,51 +398,16 @@ admin_users: - randy ``` -@tab inspec.yml -```yaml -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 -``` - -::: - -The following command runs the tests and applies the inputs specified on the Linux system underlying the nginx application in the container: +The following command runs the tests and applies the inputs specified on the Linux system underlying the NGINX application in the container: ```sh -inspec exec ./my_nginx -t docker://nginx --input-file inputs-linux.yml +inspec exec my_nginx -t docker://nginx --input-file inputs.yml ``` -If we'd wanted to do this on a hypothetical Windows system, we would need to create a new inputs file (called `inputs-windows.yml` here) and change our target to an nginx instance hosted on a Windows container or virtual machine: +If we'd wanted to do this on a hypothetical Windows system, we would need to create a new inputs file and change our target to an NGINX instance hosted on a Windows container or virtual machine: ```sh -inspec exec ./my_nginx -t docker://windows-nginx --input-file inputs-windows.yml +inspec exec my_nginx -t docker://windows-nginx --input-file inputs-windows.yml ``` -::: details Best Practice - inputs.yml file -It is best practice to create a separate file for inputs when using the provided profile. The exception to this is when working with an overlay profile, which you will see in [Section 10](./10.md). -::: +We can pass different inputs files in different situations as needed. We could also, for instance, send a different set of values to check with InSpec depending on whether the target of evaluation is deployed to the development or production environment. \ No newline at end of file diff --git a/src/courses/beginner/10.md b/src/courses/beginner/10.md index 4b639ca96..9d390d5f0 100644 --- a/src/courses/beginner/10.md +++ b/src/courses/beginner/10.md @@ -127,7 +127,7 @@ name: my_nginx_overlay depends: - name: my_nginx - path: ../my_nginx # {path relative to the overlay} + path: my_nginx # {path relative to the overlay} ``` ::: diff --git a/src/courses/beginner/11.md b/src/courses/beginner/11.md index a60aaa197..c59b0339f 100644 --- a/src/courses/beginner/11.md +++ b/src/courses/beginner/11.md @@ -8,7 +8,7 @@ headerDepth: 3 ## From STIG to Profile -Recall from our initial example of an InSpec control that a real control will be tied back to an upstream piece of security guidance documentation, like a CIS Benchmark or a STIG. All the context and metadata for that guidance can be added to the control's code via InSpec specific syntax. +Recall from our initial example of an InSpec control that a real control will be tied back to a requirement from an upstream piece of security guidance documentation, like a CIS Benchmark or a STIG. All the context and metadata for that guidance should be added to the control's code via InSpec specific syntax. That way, as the test code is executed, the report that it generates will include all of the context for the test. ::: details InSpec control with many STIG-related tags @@ -55,7 +55,7 @@ $ sudo chown root /boot/grub2/grub.cfg' end ``` -See how many tags we're adding? In fact, best practice is to include the complete text of the requirement we are implementing as `desc` or `tag` fields in the control code itself. We have so much metadata in this control file that the actual `describe` block doesn't show up until 34 lines into the control! +See how many tags we're adding? Best practice is to include the complete text of the requirement we are implementing as `desc` or `tag` fields in the control code itself. We have so much metadata in this control file that the actual `describe` block doesn't show up until 34 lines into the control! We *really* do not want to stuck with writing all of these tags by hand. Instead, let's use the [SAF CLI](https://saf-cli.mitre.org) benchmark generator. @@ -63,19 +63,23 @@ We *really* do not want to stuck with writing all of these tags by hand. Instead First, let's discuss where all of that metadata comes from in the first place -- the baseline security guidance that we are automating using InSpec. We'll crack open a STIG XCCDF XML file to show you where the control metadata is sourced from. +::: note "XCCDF XML" file?! That's a lot of letters! +Yes, it is. Welcome to the wonderful world of government standard format names. See our glossary for more information on [XCCDF](../profile-dev-test/29.md). +::: + Download the latest STIG Viewer located here [STIG Viewer](https://public.cyber.mil/stigs/srg-stig-tools/). ![Downloading STIG Viewer](../../assets/img/Download_STIG_Viewer.png) -Download the `Red Hat Enterprise Linux 8 STIG` located here [RHEL8 STIG Download](https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux) - -(The RHEL8 STIG is at version 1, release 5 at time of writing, but may have been updated by the time you downloaded. This will not affect how we use the STIG in this class.) +Download the `Red Hat Enterprise Linux 9 STIG` located [here](https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux). (Note that the file will be downloaded to your local computer, _not_ your GitHub Codespaces environment.) The RHEL9 STIG is at version V2R2 at time of writing, but may have been updated by the time you downloaded. This will not affect how we use the STIG in this class. ![Downloading STIGs](../../assets/img/Download_STIG.png) +You can then load the STIG document into STIG Viewer to examine the requirements in the real STIG. You could also upload that file to Vulcan for a similar view! + ### Convert the STIG XCCDF Benchmark To an InSpec Stubs Profile -::: note Timesaver Ahead! +The SAF CLI has a function called `generate xccdf_benchmark2inspec_stub`, which can help you quickly convert an XCCDF Benchmark document into the start of an InSpec Profile. We already converted the XCCDF STIG Benchmark into a starter profile using the `saf generate inspec_profile` command with the appropriate flags, mapping file and other options. In a moment we will show you how to grab our pre-made profile that we generated with the SAF CLI. ::: @@ -138,401 +142,40 @@ EXAMPLES ``` ::: -### How to Get the Pre-made Profile +### How to Generate the InSpec Stub Profile +Take a look at the `resources` folder in your Codespace and you will note a file called `U_RHEL_9_STIG_V2R2_Manual-xccdf.xml`. That's a STIG definition file that we grabbed off of the DoD Cyber Exchange for you. (The file starts with 'U' because that is its classification marking -- 'unclassified.' Everything sourced from the DoD Cyber Exchange can be freely used like this.) . -We have a pre-made profile generated with the `saf generate inspec_profile` command sitting in the [Resources](https://mitre.github.io/saf-training/resources/#rhel8-baseline-stubs) page for these classes. For the purposes of this class, you'll need to uncompress it so that we can work with the control files inside. +![The STIG XCCDF XML File](../../assets/img/the_stig_file.png) -::: code-tabs#shell +Let's use the SAF CLI on that file to create an InSpec profile called `my_rhel9_stig_profile`. -@tab Uncompressing the profile +::: code-tabs#shell -```sh -tar zxvfp ./resources/rhel8-baseline-stubs.tar.gz +@tab Command +``` sh +saf generate xccdf_benchmark2inspec_stub -X resources/U_RHEL_9_STIG_V2R2_Manual-xccdf.xml -o my_rhel9_stig_profile ``` @tab Output - -```sh -rhel8-baseline-stubs/ -rhel8-baseline-stubs/libraries/ -rhel8-baseline-stubs/README.md -rhel8-baseline-stubs/controls/ -rhel8-baseline-stubs/inspec.yml -rhel8-baseline-stubs/controls/SV-230281.rb -rhel8-baseline-stubs/controls/SV-230390.rb -rhel8-baseline-stubs/controls/SV-230363.rb -rhel8-baseline-stubs/controls/SV-230223.rb -rhel8-baseline-stubs/controls/SV-230332.rb -rhel8-baseline-stubs/controls/SV-230272.rb -rhel8-baseline-stubs/controls/SV-245540.rb -rhel8-baseline-stubs/controls/SV-230246.rb -rhel8-baseline-stubs/controls/SV-230306.rb -rhel8-baseline-stubs/controls/SV-230357.rb -rhel8-baseline-stubs/controls/SV-230559.rb -rhel8-baseline-stubs/controls/SV-230419.rb -rhel8-baseline-stubs/controls/SV-230508.rb -rhel8-baseline-stubs/controls/SV-230448.rb -rhel8-baseline-stubs/controls/SV-230518.rb -rhel8-baseline-stubs/controls/SV-230409.rb -rhel8-baseline-stubs/controls/SV-230549.rb -rhel8-baseline-stubs/controls/SV-230347.rb -rhel8-baseline-stubs/controls/SV-230316.rb -rhel8-baseline-stubs/controls/SV-230256.rb -rhel8-baseline-stubs/controls/SV-230262.rb -rhel8-baseline-stubs/controls/SV-230322.rb -rhel8-baseline-stubs/controls/SV-230233.rb -rhel8-baseline-stubs/controls/SV-230373.rb -rhel8-baseline-stubs/controls/SV-230380.rb -rhel8-baseline-stubs/controls/SV-230291.rb -rhel8-baseline-stubs/controls/SV-230353.rb -rhel8-baseline-stubs/controls/SV-230302.rb -rhel8-baseline-stubs/controls/SV-230394.rb -rhel8-baseline-stubs/controls/SV-230285.rb -rhel8-baseline-stubs/controls/SV-230336.rb -rhel8-baseline-stubs/controls/SV-230276.rb -rhel8-baseline-stubs/controls/SV-230367.rb -rhel8-baseline-stubs/controls/SV-230227.rb -rhel8-baseline-stubs/controls/SV-230429.rb -rhel8-baseline-stubs/controls/SV-230478.rb -rhel8-baseline-stubs/controls/SV-230538.rb -rhel8-baseline-stubs/controls/SV-230468.rb -rhel8-baseline-stubs/controls/SV-230439.rb -rhel8-baseline-stubs/controls/SV-230237.rb -rhel8-baseline-stubs/controls/SV-230377.rb -rhel8-baseline-stubs/controls/SV-230266.rb -rhel8-baseline-stubs/controls/SV-230326.rb -rhel8-baseline-stubs/controls/SV-230295.rb -rhel8-baseline-stubs/controls/SV-230384.rb -rhel8-baseline-stubs/controls/SV-230312.rb -rhel8-baseline-stubs/controls/SV-230252.rb -rhel8-baseline-stubs/controls/SV-230343.rb -rhel8-baseline-stubs/controls/SV-237641.rb -rhel8-baseline-stubs/controls/SV-230352.rb -rhel8-baseline-stubs/controls/SV-230243.rb -rhel8-baseline-stubs/controls/SV-230303.rb -rhel8-baseline-stubs/controls/SV-230395.rb -rhel8-baseline-stubs/controls/SV-230284.rb -rhel8-baseline-stubs/controls/SV-230337.rb -rhel8-baseline-stubs/controls/SV-230277.rb -rhel8-baseline-stubs/controls/SV-230366.rb -rhel8-baseline-stubs/controls/SV-230226.rb -rhel8-baseline-stubs/controls/SV-230428.rb -rhel8-baseline-stubs/controls/SV-230479.rb -rhel8-baseline-stubs/controls/SV-230539.rb -rhel8-baseline-stubs/controls/SV-230529.rb -rhel8-baseline-stubs/controls/SV-230469.rb -rhel8-baseline-stubs/controls/SV-230438.rb -rhel8-baseline-stubs/controls/SV-230236.rb -rhel8-baseline-stubs/controls/SV-230376.rb -rhel8-baseline-stubs/controls/SV-230267.rb -rhel8-baseline-stubs/controls/SV-230327.rb -rhel8-baseline-stubs/controls/SV-230294.rb -rhel8-baseline-stubs/controls/SV-230385.rb -rhel8-baseline-stubs/controls/SV-230313.rb -rhel8-baseline-stubs/controls/SV-230253.rb -rhel8-baseline-stubs/controls/SV-230342.rb -rhel8-baseline-stubs/controls/SV-237640.rb -rhel8-baseline-stubs/controls/SV-230280.rb -rhel8-baseline-stubs/controls/SV-230362.rb -rhel8-baseline-stubs/controls/SV-230222.rb -rhel8-baseline-stubs/controls/SV-230333.rb -rhel8-baseline-stubs/controls/SV-230273.rb -rhel8-baseline-stubs/controls/SV-230247.rb -rhel8-baseline-stubs/controls/SV-230307.rb -rhel8-baseline-stubs/controls/SV-230356.rb -rhel8-baseline-stubs/controls/SV-230558.rb -rhel8-baseline-stubs/controls/SV-230418.rb -rhel8-baseline-stubs/controls/SV-230509.rb -rhel8-baseline-stubs/controls/SV-230449.rb -rhel8-baseline-stubs/controls/SV-230519.rb -rhel8-baseline-stubs/controls/SV-230408.rb -rhel8-baseline-stubs/controls/SV-230548.rb -rhel8-baseline-stubs/controls/SV-230346.rb -rhel8-baseline-stubs/controls/SV-230317.rb -rhel8-baseline-stubs/controls/SV-230257.rb -rhel8-baseline-stubs/controls/SV-230263.rb -rhel8-baseline-stubs/controls/SV-230323.rb -rhel8-baseline-stubs/controls/SV-230232.rb -rhel8-baseline-stubs/controls/SV-230372.rb -rhel8-baseline-stubs/controls/SV-230381.rb -rhel8-baseline-stubs/controls/SV-230290.rb -rhel8-baseline-stubs/controls/SV-230553.rb -rhel8-baseline-stubs/controls/SV-230413.rb -rhel8-baseline-stubs/controls/SV-230502.rb -rhel8-baseline-stubs/controls/SV-230485.rb -rhel8-baseline-stubs/controls/SV-230476.rb -rhel8-baseline-stubs/controls/SV-230536.rb -rhel8-baseline-stubs/controls/SV-230427.rb -rhel8-baseline-stubs/controls/SV-230369.rb -rhel8-baseline-stubs/controls/SV-244521.rb -rhel8-baseline-stubs/controls/SV-230229.rb -rhel8-baseline-stubs/controls/SV-230338.rb -rhel8-baseline-stubs/controls/SV-230278.rb -rhel8-baseline-stubs/controls/SV-244544.rb -rhel8-baseline-stubs/controls/SV-244554.rb -rhel8-baseline-stubs/controls/SV-230268.rb -rhel8-baseline-stubs/controls/SV-230328.rb -rhel8-baseline-stubs/controls/SV-244531.rb -rhel8-baseline-stubs/controls/SV-230239.rb -rhel8-baseline-stubs/controls/SV-230379.rb -rhel8-baseline-stubs/controls/SV-230437.rb -rhel8-baseline-stubs/controls/SV-230526.rb -rhel8-baseline-stubs/controls/SV-230466.rb -rhel8-baseline-stubs/controls/SV-230495.rb -rhel8-baseline-stubs/controls/SV-230512.rb -rhel8-baseline-stubs/controls/SV-230403.rb -rhel8-baseline-stubs/controls/SV-230543.rb -rhel8-baseline-stubs/controls/SV-251714.rb -rhel8-baseline-stubs/controls/SV-230481.rb -rhel8-baseline-stubs/controls/SV-230423.rb -rhel8-baseline-stubs/controls/SV-230472.rb -rhel8-baseline-stubs/controls/SV-230532.rb -rhel8-baseline-stubs/controls/SV-230506.rb -rhel8-baseline-stubs/controls/SV-230446.rb -rhel8-baseline-stubs/controls/SV-230557.rb -rhel8-baseline-stubs/controls/SV-230359.rb -rhel8-baseline-stubs/controls/SV-230248.rb -rhel8-baseline-stubs/controls/SV-244540.rb -rhel8-baseline-stubs/controls/SV-230308.rb -rhel8-baseline-stubs/controls/SV-244525.rb -rhel8-baseline-stubs/controls/SV-250316.rb -rhel8-baseline-stubs/controls/SV-244535.rb -rhel8-baseline-stubs/controls/SV-230318.rb -rhel8-baseline-stubs/controls/SV-230258.rb -rhel8-baseline-stubs/controls/SV-244550.rb -rhel8-baseline-stubs/controls/SV-230349.rb -rhel8-baseline-stubs/controls/SV-230407.rb -rhel8-baseline-stubs/controls/SV-230547.rb -rhel8-baseline-stubs/controls/SV-230456.rb -rhel8-baseline-stubs/controls/SV-230516.rb -rhel8-baseline-stubs/controls/SV-251710.rb -rhel8-baseline-stubs/controls/SV-230522.rb -rhel8-baseline-stubs/controls/SV-230462.rb -rhel8-baseline-stubs/controls/SV-230433.rb -rhel8-baseline-stubs/controls/SV-230491.rb -rhel8-baseline-stubs/controls/SV-230480.rb -rhel8-baseline-stubs/controls/SV-230422.rb -rhel8-baseline-stubs/controls/SV-230473.rb -rhel8-baseline-stubs/controls/SV-230533.rb -rhel8-baseline-stubs/controls/SV-230507.rb -rhel8-baseline-stubs/controls/SV-230447.rb -rhel8-baseline-stubs/controls/SV-230556.rb -rhel8-baseline-stubs/controls/SV-230358.rb -rhel8-baseline-stubs/controls/SV-244541.rb -rhel8-baseline-stubs/controls/SV-230249.rb -rhel8-baseline-stubs/controls/SV-230309.rb -rhel8-baseline-stubs/controls/SV-244524.rb -rhel8-baseline-stubs/controls/SV-250317.rb -rhel8-baseline-stubs/controls/SV-244534.rb -rhel8-baseline-stubs/controls/SV-230319.rb -rhel8-baseline-stubs/controls/SV-244551.rb -rhel8-baseline-stubs/controls/SV-230259.rb -rhel8-baseline-stubs/controls/SV-230348.rb -rhel8-baseline-stubs/controls/SV-230406.rb -rhel8-baseline-stubs/controls/SV-230546.rb -rhel8-baseline-stubs/controls/SV-230517.rb -rhel8-baseline-stubs/controls/SV-251711.rb -rhel8-baseline-stubs/controls/SV-230523.rb -rhel8-baseline-stubs/controls/SV-230463.rb -rhel8-baseline-stubs/controls/SV-230432.rb -rhel8-baseline-stubs/controls/SV-230552.rb -rhel8-baseline-stubs/controls/SV-230412.rb -rhel8-baseline-stubs/controls/SV-230503.rb -rhel8-baseline-stubs/controls/SV-230484.rb -rhel8-baseline-stubs/controls/SV-230477.rb -rhel8-baseline-stubs/controls/SV-230537.rb -rhel8-baseline-stubs/controls/SV-230426.rb -rhel8-baseline-stubs/controls/SV-230368.rb -rhel8-baseline-stubs/controls/SV-230228.rb -rhel8-baseline-stubs/controls/SV-230339.rb -rhel8-baseline-stubs/controls/SV-230279.rb -rhel8-baseline-stubs/controls/SV-244545.rb -rhel8-baseline-stubs/controls/SV-230269.rb -rhel8-baseline-stubs/controls/SV-230329.rb -rhel8-baseline-stubs/controls/SV-230238.rb -rhel8-baseline-stubs/controls/SV-244530.rb -rhel8-baseline-stubs/controls/SV-230378.rb -rhel8-baseline-stubs/controls/SV-230436.rb -rhel8-baseline-stubs/controls/SV-230527.rb -rhel8-baseline-stubs/controls/SV-230467.rb -rhel8-baseline-stubs/controls/SV-230494.rb -rhel8-baseline-stubs/controls/SV-230513.rb -rhel8-baseline-stubs/controls/SV-230402.rb -rhel8-baseline-stubs/controls/SV-230542.rb -rhel8-baseline-stubs/controls/SV-251715.rb -rhel8-baseline-stubs/controls/SV-230470.rb -rhel8-baseline-stubs/controls/SV-230530.rb -rhel8-baseline-stubs/controls/SV-230421.rb -rhel8-baseline-stubs/controls/SV-230561.rb -rhel8-baseline-stubs/controls/SV-230483.rb -rhel8-baseline-stubs/controls/SV-230555.rb -rhel8-baseline-stubs/controls/SV-230504.rb -rhel8-baseline-stubs/controls/SV-230444.rb -rhel8-baseline-stubs/controls/SV-244542.rb -rhel8-baseline-stubs/controls/SV-244527.rb -rhel8-baseline-stubs/controls/SV-244537.rb -rhel8-baseline-stubs/controls/SV-244552.rb -rhel8-baseline-stubs/controls/SV-251712.rb -rhel8-baseline-stubs/controls/SV-230514.rb -rhel8-baseline-stubs/controls/SV-230405.rb -rhel8-baseline-stubs/controls/SV-230545.rb -rhel8-baseline-stubs/controls/SV-230493.rb -rhel8-baseline-stubs/controls/SV-230431.rb -rhel8-baseline-stubs/controls/SV-230520.rb -rhel8-baseline-stubs/controls/SV-230500.rb -rhel8-baseline-stubs/controls/SV-230551.rb -rhel8-baseline-stubs/controls/SV-230411.rb -rhel8-baseline-stubs/controls/SV-251706.rb -rhel8-baseline-stubs/controls/SV-230425.rb -rhel8-baseline-stubs/controls/SV-230474.rb -rhel8-baseline-stubs/controls/SV-230534.rb -rhel8-baseline-stubs/controls/SV-230487.rb -rhel8-baseline-stubs/controls/SV-230398.rb -rhel8-baseline-stubs/controls/SV-230289.rb -rhel8-baseline-stubs/controls/SV-244523.rb -rhel8-baseline-stubs/controls/SV-244546.rb -rhel8-baseline-stubs/controls/SV-244533.rb -rhel8-baseline-stubs/controls/SV-230299.rb -rhel8-baseline-stubs/controls/SV-230388.rb -rhel8-baseline-stubs/controls/SV-230497.rb -rhel8-baseline-stubs/controls/SV-230524.rb -rhel8-baseline-stubs/controls/SV-230464.rb -rhel8-baseline-stubs/controls/SV-230435.rb -rhel8-baseline-stubs/controls/SV-251716.rb -rhel8-baseline-stubs/controls/SV-230401.rb -rhel8-baseline-stubs/controls/SV-230541.rb -rhel8-baseline-stubs/controls/SV-230510.rb -rhel8-baseline-stubs/controls/SV-230550.rb -rhel8-baseline-stubs/controls/SV-230410.rb -rhel8-baseline-stubs/controls/SV-251707.rb -rhel8-baseline-stubs/controls/SV-230424.rb -rhel8-baseline-stubs/controls/SV-230475.rb -rhel8-baseline-stubs/controls/SV-230535.rb -rhel8-baseline-stubs/controls/SV-230486.rb -rhel8-baseline-stubs/controls/SV-230399.rb -rhel8-baseline-stubs/controls/SV-230288.rb -rhel8-baseline-stubs/controls/SV-244522.rb -rhel8-baseline-stubs/controls/SV-244547.rb -rhel8-baseline-stubs/controls/SV-244532.rb -rhel8-baseline-stubs/controls/SV-230298.rb -rhel8-baseline-stubs/controls/SV-230389.rb -rhel8-baseline-stubs/controls/SV-230496.rb -rhel8-baseline-stubs/controls/SV-230525.rb -rhel8-baseline-stubs/controls/SV-230465.rb -rhel8-baseline-stubs/controls/SV-230434.rb -rhel8-baseline-stubs/controls/SV-251717.rb -rhel8-baseline-stubs/controls/SV-230400.rb -rhel8-baseline-stubs/controls/SV-230540.rb -rhel8-baseline-stubs/controls/SV-230511.rb -rhel8-baseline-stubs/controls/SV-230471.rb -rhel8-baseline-stubs/controls/SV-230531.rb -rhel8-baseline-stubs/controls/SV-230560.rb -rhel8-baseline-stubs/controls/SV-230482.rb -rhel8-baseline-stubs/controls/SV-230554.rb -rhel8-baseline-stubs/controls/SV-230505.rb -rhel8-baseline-stubs/controls/SV-244543.rb -rhel8-baseline-stubs/controls/SV-250315.rb -rhel8-baseline-stubs/controls/SV-244526.rb -rhel8-baseline-stubs/controls/SV-244536.rb -rhel8-baseline-stubs/controls/SV-244553.rb -rhel8-baseline-stubs/controls/SV-251713.rb -rhel8-baseline-stubs/controls/SV-230455.rb -rhel8-baseline-stubs/controls/SV-230515.rb -rhel8-baseline-stubs/controls/SV-230404.rb -rhel8-baseline-stubs/controls/SV-230544.rb -rhel8-baseline-stubs/controls/SV-230492.rb -rhel8-baseline-stubs/controls/SV-230430.rb -rhel8-baseline-stubs/controls/SV-230521.rb -rhel8-baseline-stubs/controls/SV-244548.rb -rhel8-baseline-stubs/controls/SV-230240.rb -rhel8-baseline-stubs/controls/SV-230300.rb -rhel8-baseline-stubs/controls/SV-244519.rb -rhel8-baseline-stubs/controls/SV-230351.rb -rhel8-baseline-stubs/controls/SV-230365.rb -rhel8-baseline-stubs/controls/SV-230225.rb -rhel8-baseline-stubs/controls/SV-230334.rb -rhel8-baseline-stubs/controls/SV-230274.rb -rhel8-baseline-stubs/controls/SV-230287.rb -rhel8-baseline-stubs/controls/SV-230396.rb -rhel8-baseline-stubs/controls/SV-230489.rb -rhel8-baseline-stubs/controls/SV-251708.rb -rhel8-baseline-stubs/controls/SV-251718.rb -rhel8-baseline-stubs/controls/SV-230499.rb -rhel8-baseline-stubs/controls/SV-230386.rb -rhel8-baseline-stubs/controls/SV-230264.rb -rhel8-baseline-stubs/controls/SV-230324.rb -rhel8-baseline-stubs/controls/SV-230235.rb -rhel8-baseline-stubs/controls/SV-230375.rb -rhel8-baseline-stubs/controls/SV-237643.rb -rhel8-baseline-stubs/controls/SV-230341.rb -rhel8-baseline-stubs/controls/SV-230310.rb -rhel8-baseline-stubs/controls/SV-230250.rb -rhel8-baseline-stubs/controls/SV-230330.rb -rhel8-baseline-stubs/controls/SV-230270.rb -rhel8-baseline-stubs/controls/SV-230361.rb -rhel8-baseline-stubs/controls/SV-230221.rb -rhel8-baseline-stubs/controls/SV-244529.rb -rhel8-baseline-stubs/controls/SV-230392.rb -rhel8-baseline-stubs/controls/SV-230283.rb -rhel8-baseline-stubs/controls/SV-230355.rb -rhel8-baseline-stubs/controls/SV-230244.rb -rhel8-baseline-stubs/controls/SV-230304.rb -rhel8-baseline-stubs/controls/SV-230314.rb -rhel8-baseline-stubs/controls/SV-230254.rb -rhel8-baseline-stubs/controls/SV-230345.rb -rhel8-baseline-stubs/controls/SV-230293.rb -rhel8-baseline-stubs/controls/SV-230382.rb -rhel8-baseline-stubs/controls/SV-230231.rb -rhel8-baseline-stubs/controls/SV-244539.rb -rhel8-baseline-stubs/controls/SV-230371.rb -rhel8-baseline-stubs/controls/SV-230260.rb -rhel8-baseline-stubs/controls/SV-230320.rb -rhel8-baseline-stubs/controls/SV-230331.rb -rhel8-baseline-stubs/controls/SV-230271.rb -rhel8-baseline-stubs/controls/SV-230360.rb -rhel8-baseline-stubs/controls/SV-244528.rb -rhel8-baseline-stubs/controls/SV-230393.rb -rhel8-baseline-stubs/controls/SV-230282.rb -rhel8-baseline-stubs/controls/SV-230354.rb -rhel8-baseline-stubs/controls/SV-230245.rb -rhel8-baseline-stubs/controls/SV-230305.rb -rhel8-baseline-stubs/controls/SV-230315.rb -rhel8-baseline-stubs/controls/SV-230255.rb -rhel8-baseline-stubs/controls/SV-230344.rb -rhel8-baseline-stubs/controls/SV-230292.rb -rhel8-baseline-stubs/controls/SV-230383.rb -rhel8-baseline-stubs/controls/SV-244538.rb -rhel8-baseline-stubs/controls/SV-230230.rb -rhel8-baseline-stubs/controls/SV-230370.rb -rhel8-baseline-stubs/controls/SV-230261.rb -rhel8-baseline-stubs/controls/SV-230321.rb -rhel8-baseline-stubs/controls/SV-230241.rb -rhel8-baseline-stubs/controls/SV-244549.rb -rhel8-baseline-stubs/controls/SV-230301.rb -rhel8-baseline-stubs/controls/SV-230350.rb -rhel8-baseline-stubs/controls/SV-230364.rb -rhel8-baseline-stubs/controls/SV-230224.rb -rhel8-baseline-stubs/controls/SV-230335.rb -rhel8-baseline-stubs/controls/SV-230275.rb -rhel8-baseline-stubs/controls/SV-230286.rb -rhel8-baseline-stubs/controls/SV-230397.rb -rhel8-baseline-stubs/controls/SV-230488.rb -rhel8-baseline-stubs/controls/SV-251709.rb -rhel8-baseline-stubs/controls/SV-230498.rb -rhel8-baseline-stubs/controls/SV-230387.rb -rhel8-baseline-stubs/controls/SV-230296.rb -rhel8-baseline-stubs/controls/SV-230265.rb -rhel8-baseline-stubs/controls/SV-230325.rb -rhel8-baseline-stubs/controls/SV-230234.rb -rhel8-baseline-stubs/controls/SV-230374.rb -rhel8-baseline-stubs/controls/SV-237642.rb -rhel8-baseline-stubs/controls/SV-230340.rb -rhel8-baseline-stubs/controls/SV-230311.rb -rhel8-baseline-stubs/controls/SV-230251.rb +``` sh +[Dec-08-2024 20:40:31 +00:00] generate:xccdf_benchmark2inspec_stub Creating output folder with controls and libraries directories +[Dec-08-2024 20:40:31 +00:00] generate:xccdf_benchmark2inspec_stub Processing XCCDF Benchmark file: resources/U_RHEL_9_STIG_V2R2_Manual-xccdf.xml using rule id. +[Dec-08-2024 20:40:31 +00:00] generate:xccdf_benchmark2inspec_stub Writing inspec.yml file to: my_rhel9_stig_profile/inspec.yml +[Dec-08-2024 20:40:31 +00:00] generate:xccdf_benchmark2inspec_stub Writing control to: my_rhel9_stig_profile/controls/SV-257777.rb +[Dec-08-2024 20:40:31 +00:00] SV-257777 does not have a value for tag: documentable + +< . . . a few lines of output per STIG control! > + +[Dec-08-2024 20:40:32 +00:00] generate:xccdf_benchmark2inspec_stub Writing control to: my_rhel9_stig_profile/controls/SV-258241.rb +[Dec-08-2024 20:40:32 +00:00] SV-258241 does not have a value for tag: documentable +[Dec-08-2024 20:40:32 +00:00] generate:xccdf_benchmark2inspec_stub Writing control to: my_rhel9_stig_profile/controls/SV-258242.rb +[Dec-08-2024 20:40:32 +00:00] SV-258242 does not have a value for tag: documentable ``` ::: -### Example 'Stub' Control SV-230502 +We added the `--logLevel=debug` flag so that you could see the SAF CLI touch each control in turn. You will end up with a new local directory InSpec "stub" profile for Red Hat 9. The SAF CLI might note that some expected tags are not present for optional metadata; this is not an issue for the purposes of this class. + +### Example "Stub" Control SV-230502 Let's take a look at one of the stub InSpec controls created by the `saf generate inspec_profile` command and the completed InSpec control. @@ -541,130 +184,101 @@ Let's take a look at one of the stub InSpec controls created by the `saf generat @tab Stub Generated InSpec Control ```ruby -control 'SV-230502' do - title 'The RHEL 8 file system automounter must be disabled unless required.' - desc "Automatically mounting file systems permits easy introduction of -unknown devices, thereby facilitating malicious activity." - desc 'rationale', '' - desc 'check', " - Verify the operating system disables the ability to automount devices. - - Check to see if automounter service is active with the following command: - - Note: If the autofs service is not installed, this requirement is not -applicable. - - $ sudo systemctl status autofs - - autofs.service - Automounts filesystems on demand - Loaded: loaded (/usr/lib/systemd/system/autofs.service; disabled) - Active: inactive (dead) - - If the \"autofs\" status is set to \"active\" and is not documented with -the Information System Security Officer (ISSO) as an operational requirement, -this is a finding. - " - desc 'fix', " - Configure the operating system to disable the ability to automount devices. - - Turn off the automount service with the following commands: +control 'SV-257777' do + title 'RHEL 9 must be a vendor-supported release.' + desc 'An operating system release is considered "supported" if the vendor continues to provide security patches for the product. With an unsupported release, it will not be possible to resolve security issues discovered in the system software. - $ sudo systemctl stop autofs - $ sudo systemctl disable autofs +Red Hat offers the Extended Update Support (EUS) add-on to a Red Hat Enterprise Linux subscription, for a fee, for those customers who wish to standardize on a specific minor release for an extended period.' + desc 'check', 'Verify that the version or RHEL 9 is vendor supported with the following command: - If \"autofs\" is required for Network File System (NFS), it must be -documented with the ISSO. - " - impact 0.5 - tag severity: 'medium' - tag gtitle: 'SRG-OS-000114-GPOS-00059' - tag gid: 'V-230502' - tag rid: 'SV-230502r627750_rule' - tag stig_id: 'RHEL-08-040070' - tag fix_id: 'F-33146r568253_fix' - tag cci: ['CCI-000778'] - tag nist: ['IA-3'] +$ cat /etc/redhat-release - # ...add your describe blocks here ... # +Red Hat Enterprise Linux release 9.2 (Plow) +If the installed version of RHEL 9 is not supported, this is a finding.' + desc 'fix', 'Upgrade to a supported version of RHEL 9.' + impact 0.7 + ref 'DPMS Target Red Hat Enterprise Linux 9' + tag check_id: 'C-61518r925316_chk' + tag severity: 'high' + tag gid: 'V-257777' + tag rid: 'SV-257777r991589_rule' + tag stig_id: 'RHEL-09-211010' + tag gtitle: 'SRG-OS-000480-GPOS-00227' + tag fix_id: 'F-61442r925317_fix' + tag 'documentable' + tag cci: ['CCI-000366'] + tag nist: ['CM-6 b'] end ``` -@tab Completed InSpec Control +@tab Completed InSpec Control From the Published SAF RHEL9 Profile ```ruby -control 'SV-230502' do - title 'The RHEL 8 file system automounter must be disabled unless required.' - desc "Automatically mounting file systems permits easy introduction of -unknown devices, thereby facilitating malicious activity." - desc 'rationale', '' - desc 'check', " - Verify the operating system disables the ability to automount devices. +control 'SV-257777' do + title 'RHEL 9 must be a vendor-supported release.' + desc 'An operating system release is considered "supported" if the vendor continues to provide security patches for the product. With an unsupported release, it will not be possible to resolve security issues discovered in the system software. - Check to see if automounter service is active with the following command: +Red Hat offers the Extended Update Support (EUS) add-on to a Red Hat Enterprise Linux subscription, for a fee, for those customers who wish to standardize on a specific minor release for an extended period.' + desc 'check', 'Verify that the version or RHEL 9 is vendor supported with the following command: - Note: If the autofs service is not installed, this requirement is not -applicable. +$ cat /etc/redhat-release - $ sudo systemctl status autofs +Red Hat Enterprise Linux release 9.2 (Plow) - autofs.service - Automounts filesystems on demand - Loaded: loaded (/usr/lib/systemd/system/autofs.service; disabled) - Active: inactive (dead) +If the installed version of RHEL 9 is not supported, this is a finding.' + desc 'fix', 'Upgrade to a supported version of RHEL 9.' + impact 0.7 + ref 'DPMS Target Red Hat Enterprise Linux 9' + tag severity: 'high' + tag gtitle: 'SRG-OS-000480-GPOS-00227' + tag gid: 'V-257777' + tag rid: 'SV-257777r925318_rule' + tag stig_id: 'RHEL-09-211010' + tag fix_id: 'F-61442r925317_fix' + tag cci: ['CCI-000366'] + tag nist: ['CM-6 b'] + tag 'host' + tag 'container' - If the \"autofs\" status is set to \"active\" and is not documented with -the Information System Security Officer (ISSO) as an operational requirement, -this is a finding. - " - desc 'fix', " - Configure the operating system to disable the ability to automount devices. + release = os.release - Turn off the automount service with the following commands: + # Note that versions 9.0 and 9.2 of RHEL9 are within the EUS window at + # time of writing. - $ sudo systemctl stop autofs - $ sudo systemctl disable autofs + # 9.1 is not a EUS-supported release and is no longer officially supported + # by Red Hat. The date given for the expiration for 9.1 is based on the + # RHEL9 Planning Guide diagram found on Red Hat's Life Cycle page: + # https://access.redhat.com/support/policy/updates/errata/#Life_Cycle_Dates - If \"autofs\" is required for Network File System (NFS), it must be -documented with the ISSO. - " - impact 0.5 - tag severity: 'medium' - tag gtitle: 'SRG-OS-000114-GPOS-00059' - tag gid: 'V-230502' - tag rid: 'SV-230502r627750_rule' - tag stig_id: 'RHEL-08-040070' - tag fix_id: 'F-33146r568253_fix' - tag cci: ['CCI-000778'] - tag nist: ['IA-3'] - - if virtualization.system.eql?('docker') - impact 0.0 - describe "Control not applicable within a container" do - skip "Control not applicable within a container" - end - else - if package('autofs').installed? - describe systemd_service('autofs.service') do - it { should_not be_running } - it { should_not be_enabled } - it { should_not be_installed } + EOMS_DATE = { + /^9\.0/ => '31 May 2024', + /^9\.1/ => 'April 1, 2023', + /^9\.2/ => 'May 31, 2025', + /^9\.4/ => 'May 31, 2026' + }.find { |k, _v| k.match(release) }&.last + + describe "The release \"#{release}\"" do + if EOMS_DATE.nil? + it 'is a supported release' do + expect(EOMS_DATE).not_to be_nil, "Release '#{release}' has no specified support window" end else - impact 0.0 - describe 'The autofs service is not installed' do - skip 'The autofs service is not installed, this control is Not Applicable.' + it 'is still within the support window' do + expect(Date.today).to be <= Date.parse(EOMS_DATE) end end end end + ``` ::: ::: warning Where did the metadata tags come from? -From the structured data inside the published STIG document's XCCDF XML file. The `saf generate` tool simply reformats it into an InSpec control. +From the structured data inside the published STIG document's XCCDF XML file. The `saf generate` tool simply reformats it into an InSpec control. All of our metadata is present, but there are no `describe` blocks in the initial stub profile; _that_ content is not something we can grab straight from the STIG from an XML tag. ::: ::: warning Where did the describe block come from? -From the real [MITRE SAF RHEL8 InSpec profile](https://github.com/mitre/redhat-enterprise-linux-8-stig-baseline/blob/main/controls/SV-230502.rb). Note that the control accounts for a few more edge cases than what we've done in this class, but it's still recognizably just a bunch of *entities* and *expectations* wrapped in `describe` blocks. +From the real [MITRE SAF RHEL9 InSpec profile](https://github.com/mitre/redhat-enterprise-linux-9-stig-baseline/blob/46fd72d144fcda10b07604df037db7f683b74225/controls/SV-257777.rb). You may recognize that we wrote the `describe` blocks for this control using RSpec `expect` syntax as explained in [Section 7](../beginner/07.md). It's still recognizably just an *entity* and some *expectations* wrapped in a `describe` block. ::: You may note that these InSpec controls feature a set of metadata tags -- impact, severity, and alignment back to requirements such as a NIST control family. All of that metadata was taken from the original XCCDF document that we used to create this profile; the SAF CLI automatically added it to the profile controls. These tags are the reason that tools like Heimdall can sort and display data in high fidelity. This is the benefit of using the SAF CLI to generate profiles straight off of the original benchmark documentation where possible -- tagging the controls with the requirement that they are testing means that reading a control will tell you not only _what_ you are testing, but _why_! diff --git a/src/courses/beginner/12.md b/src/courses/beginner/12.md index b5305a745..373778d40 100644 --- a/src/courses/beginner/12.md +++ b/src/courses/beginner/12.md @@ -6,7 +6,7 @@ author: Aaron Lippold headerDepth: 3 --- -## Getting Started on the RHEL8 Baseline +## Getting Started on the RHEL9 Baseline Let's practice writing a few 'real' controls using a security guidance document. @@ -25,44 +25,38 @@ Let's go through an example using control SV-230324 to see the above steps in pr 1. **Read the control** - when referencing the control SV-230324 from the stub profile that was generated with the stub generator, look at the control, especially the check text, to understand the intention of the security guidance for this control. **This control** is talking about verifying all local interactive users are assigned a home directory upon creation. -::: code-tabs#shell - -@tab Stub Generated Control ```ruby -control "SV-230324" do - title "All RHEL 8 local interactive user accounts must be assigned a home directory upon creation." - desc "If local interactive users are not assigned a valid home directory, there is no place for the -storage and control of files they should own." - desc "check", "Verify all local interactive users on RHEL 8 are assigned a home directory upon creation with -the following command: +control 'SV-258043' do + title 'All RHEL 9 local interactive user accounts must be assigned a home directory upon creation.' + desc 'If local interactive users are not assigned a valid home directory, there is no place for the storage and control of files they should own.' + desc 'check', 'Verify all local interactive users on RHEL 9 are assigned a home directory upon creation with the following command: -$ sudo grep -i create_home /etc/login.defs +$ grep -i create_home /etc/login.defs CREATE_HOME yes -If -the value for \"CREATE_HOME\" parameter is not set to \"yes\", the line is missing, or the line is -commented out, this is a finding." - desc "fix", "Configure RHEL 8 to assign home directories to all new local interactive users by setting the -\"CREATE_HOME\" parameter in \"/etc/login.defs\" to \"yes\" as follows. +If the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out, this is a finding.' + desc 'fix', 'Configure RHEL 9 to assign home directories to all new local interactive users by setting the "CREATE_HOME" parameter in "/etc/login.defs" to "yes" as follows. -CREATE_HOME yes" +CREATE_HOME yes' impact 0.5 - tag severity: "medium" - tag gtitle: "SRG-OS-000480-GPOS-00227" - tag gid: "V-230324" - tag rid: "SV-230324r627750_rule" - tag stig_id: "RHEL-08-010760" - tag fix_id: "F-32968r567719_fix" - tag cci: ["CCI-000366"] - tag nist: ["CM-6 b"] + ref 'DPMS Target Red Hat Enterprise Linux 9' + tag check_id: 'C-61784r926114_chk' + tag severity: 'medium' + tag gid: 'V-258043' + tag rid: 'SV-258043r991589_rule' + tag stig_id: 'RHEL-09-411020' + tag gtitle: 'SRG-OS-000480-GPOS-00227' + tag fix_id: 'F-61708r926115_fix' + tag 'documentable' + tag cci: ['CCI-000366'] + tag nist: ['CM-6 b'] end ``` -::: 2. **Look for Key Words and Resources** - Dive more into what key words exist in the check text to determine what InSpec resources to use when writing the test. Most importantly, identify commands that are written in the check test like shown below. Find the _what_ of the command. For this control, `sudo` is not the _what_. `grep` is also not the _what_. `create_home` looks like an attribute of the `/etc/login.defs` file, which looks like the _what_! Look for a resource named `login_defs` in the [resource documentation](https://docs.chef.io/inspec/resources/). ```ruby - desc "check", "Verify all local interactive users on RHEL 8 are assigned a home directory upon creation with + desc "check", "Verify all local interactive users on RHEL 9 are assigned a home directory upon creation with the following command: $ sudo grep -i create_home /etc/login.defs @@ -84,35 +78,32 @@ $ sudo grep -i create_home /etc/login.defs ``` @tab Full Control ```ruby -control 'SV-230324' do - title "All RHEL 8 local interactive user accounts must be assigned a home -directory upon creation." - desc "If local interactive users are not assigned a valid home directory, -there is no place for the storage and control of files they should own." - desc 'rationale', '' - desc 'check', " - Verify all local interactive users on RHEL 8 are assigned a home directory -upon creation with the following command: - $ sudo grep -i create_home /etc/login.defs - CREATE_HOME yes - If the value for \"CREATE_HOME\" parameter is not set to \"yes\", the line -is missing, or the line is commented out, this is a finding. - " - desc 'fix', " - Configure RHEL 8 to assign home directories to all new local interactive -users by setting the \"CREATE_HOME\" parameter in \"/etc/login.defs\" to -\"yes\" as follows. - CREATE_HOME yes - " +control 'SV-258043' do + title 'All RHEL 9 local interactive user accounts must be assigned a home directory upon creation.' + desc 'If local interactive users are not assigned a valid home directory, +there is no place for the storage and control of files they should own.' + desc 'check', 'Verify all local interactive users on RHEL 9 are assigned a home directory upon creation with the following command: + +$ grep -i create_home /etc/login.defs + +CREATE_HOME yes + +If the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out, this is a finding.' + desc 'fix', 'Configure RHEL 9 to assign home directories to all new local interactive users by setting the "CREATE_HOME" parameter in "/etc/login.defs" to "yes" as follows. + +CREATE_HOME yes' impact 0.5 + ref 'DPMS Target Red Hat Enterprise Linux 9' tag severity: 'medium' tag gtitle: 'SRG-OS-000480-GPOS-00227' - tag gid: 'V-230324' - tag rid: 'SV-230324r627750_rule' - tag stig_id: 'RHEL-08-010760' - tag fix_id: 'F-32968r567719_fix' + tag gid: 'V-258043' + tag rid: 'SV-258043r926116_rule' + tag stig_id: 'RHEL-09-411020' + tag fix_id: 'F-61708r926115_fix' tag cci: ['CCI-000366'] tag nist: ['CM-6 b'] + tag 'host' + tag 'container' describe login_defs do its('CREATE_HOME') { should eq 'yes' } @@ -127,7 +118,7 @@ Here, the login_defs resource shows examples using the `includes` and `eq` match 5. **Run the test!** ```bash -inspec exec rhel8-baseline-stubs -t docker://redhat8 +inspec exec my_rhel9_stig_profile -t docker://redhat9 ``` 6. **Troubleshoot errors** - If you have syntax errors or unexpected results, it's time to troubleshoot. The best first step in troubleshooting is to read the error message from the command line. @@ -136,27 +127,26 @@ inspec exec rhel8-baseline-stubs -t docker://redhat8 | Control | Resource Used | | --- | --- | -| SV-230324 | login_defs resource | -| SV-230250 | directory resource | -| SV-230243 | directory looping & file resource | -| SV-230505 | non applicable use case & package resource | +| SV-258043 | login_defs resource | +| SV-257915 | directory resource | +| SV-257929 | directory looping & file resource | +| SV-257936 | non applicable use case & package resource | ### Suggested Level 1 Controls | Control | Resource Used | | --- | --- | -| SV-230383 | login_defs resource | -| SV-230249 | directory resource | -| SV-230471 | directory looping & file resource | -| SV-230241 | non applicable use case & package resource | +| SV-258074 | login_defs resource | +| SV-257914 | directory resource | +| SV-258171 | directory looping & file resource | +| SV-258081 | non applicable use case & package resource | ### Suggested Level 2 Controls | Control | Resource Used | | --- | --- | -| SV-230281 | parse config file | -| SV-230365 | login_defs resource | -| SV-230264 | file content | +| SV-257824 | parse config file | +| SV-258104 | login_defs resource | :::info Strings Single quotes are dumb strings. Double quotes are smart strings. Smart strings means they allow [interpolation](http://ruby-for-beginners.rubymonstas.org/bonus/string_interpolation.html). @@ -171,11 +161,11 @@ Single quotes are dumb strings. Double quotes are smart strings. Smart strings m - [package](https://www.inspec.io/docs/reference/resources/package/) - [login_defs](https://docs.chef.io/inspec/resources/login_defs/) -## Completed RHEL8 Profile for Reference +## Completed RHEL9 Profile for Reference -Below is the url to the completed RHEL8 Inspec Profile for reference, and a few things to take note of. +Below is the url to the completed RHEL9 Inspec Profile for reference, and a few things to take note of. -1. [redhat-enterprise-linux-8-stig-baseline](https://github.com/mitre/redhat-enterprise-linux-8-stig-baseline) +1. [redhat-enterprise-linux-9-stig-baseline](https://github.com/mitre/redhat-enterprise-linux-9-stig-baseline) ::: tip Key Elements in this Profile diff --git a/src/courses/guidance/02.md b/src/courses/guidance/02.md index 8a0048ce4..b6c6b06d8 100644 --- a/src/courses/guidance/02.md +++ b/src/courses/guidance/02.md @@ -51,6 +51,7 @@ Commonly used security guidance is often available on the open Internet. - CIS publishes its popular [Benchmarks](https://www.cisecurity.org/cis-benchmarks) for free with registration (in PDF form, other formats require a subscription to CIS's SecureSuite) - DISA publishes all STIGs (and all the rest of its security documentation materials) for free on the [DOD Cyber Exchange](https://public.cyber.mil/stigs/downloads/) public web page. - DISA distributes STIGs as a set of PDFs describing metadata like a changelog and cover sheets, where the underlying STIG itself is stored as an XML document. +- NIST's [National Checklist Repository (NCP)](https://ncp.nist.gov/repository) is a repository of securit configuration benchmarks and are publicly available. Your first question when planning for securing your software component should always be "is there already published guidance documentation available for it?" diff --git a/src/courses/guidance/03.md b/src/courses/guidance/03.md index 839ed1ef4..2176a8ebe 100644 --- a/src/courses/guidance/03.md +++ b/src/courses/guidance/03.md @@ -8,7 +8,7 @@ headerDepth: 3 ## 3.1 Security Technical Implementation Guides -For the purposes of this class, we will be focusing in on one particular security baseline called a STIG. While MITRE SAF(c)'s Vulcan application is intended to be useful for creatign many types of security documentation, it was originally created with the STIG-writing process in mind. +For the purposes of this class, we will be focusing in on one particular security baseline called a STIG. While MITRE SAF(c)'s Vulcan application is intended to be useful for creating many types of security documentation, it was originally created with the STIG-writing process in mind. ## 3.2.1 What is a STIG? @@ -62,7 +62,7 @@ DISA also publishes the SRGs, which describe *subsets* of CCIs that apply to gen As described before, an SRG can then be tailored into STIGs that give security guidance for individual pieces of software. The full chain of requirements to implementation therefore looks like this: -![Process Flow of DOD Requirements Assembly Into SRGs/STIGs](../../assets/img/STIGSources.png) +![Process Flow of DOD Requirements Assembly Into SRGs/STIGs](../../assets/img/NIST_requirements_to_STIG.svg) ### 3.3.1 Now For The Good News diff --git a/src/courses/guidance/README.md b/src/courses/guidance/README.md index a02990ec0..8f50e9608 100644 --- a/src/courses/guidance/README.md +++ b/src/courses/guidance/README.md @@ -26,4 +26,4 @@ As you can see from the picture below, the process for developing automated secu This challenge is what the [MITRE Security Automation Framework](https://saf.mitre.org) or MITRE SAF was developed to simplify -- to make the journey from a Requirement Document to an automated test profile and back again a little easier to navigate. -![The SAF Lifecycle](../../assets/img/saf-lifecycle.png) +![The SAF Lifecycle](../../assets/img/saf-lifecycle.jpg) diff --git a/src/courses/profile-dev-test/17.md b/src/courses/profile-dev-test/17.md index a4ada43d6..a198aed54 100644 --- a/src/courses/profile-dev-test/17.md +++ b/src/courses/profile-dev-test/17.md @@ -1,6 +1,6 @@ --- order: 17 -next: 16.md +next: 18.md title: Test Kitchen - Converge author: Aaron Lippold index: true diff --git a/src/courses/user/02.md b/src/courses/user/02.md index 714deced6..277a0c715 100644 --- a/src/courses/user/02.md +++ b/src/courses/user/02.md @@ -35,5 +35,3 @@ headerDepth: 3 As illustrated in the picture below, the process for developing automated security tests starts with requirements documents like SRGs, STIGs, or CIS Benchmarks, which are written in human-readable language. These documents are then implemented as code. We need that code to record test results in a standardized format so that we can easily export our security data to a platform where it can be used to make informed decisions (such as the Heimdall visualization app). This challenge is what the [MITRE Security Automation Framework](https://saf.mitre.org) (MITRE SAF) was developed to address. It simplifies the journey from a Requirement Document to an automated test profile and back again, making it easier to navigate. - -![The SAF Lifecycle](../../assets/img/saf-lifecycle.png) diff --git a/src/courses/user/05.md b/src/courses/user/05.md index a950b36e1..161f38d9a 100644 --- a/src/courses/user/05.md +++ b/src/courses/user/05.md @@ -49,14 +49,6 @@ Let's review the READMEs for each profile for more information and specific run 3. Available inputs for tailoring to your environment 4. Instructions for running the profile -### 5.3.1 RHEL8 baseline profile - -Let's take the [RHEL8 baseline profile](https://github.com/CMSgov/redhat-enterprise-linux-8-stig-baseline) as an example. You can find this InSpec profile at the provided link or through the [validation library of the SAF site](https://saf.mitre.org/libs/validate). - -![The Red Hat 8 Profile](../../assets/img/Github_Rhel8.png) - -### 5.3.2 NGINX baseline profile - -Let's take the [NGINX baseline profile](https://github.com/mitre/nginx-stigready-baseline) as an example. You can find this InSpec profile at the provided link or through the [validation library of the SAF site](https://saf.mitre.org/libs/validate). +Take a look at the [RHEL9 baseline profile](https://github.com/mitre/redhat-enterprise-linux-9-stig-baseline) or the [NGINX baseline profile](https://github.com/mitre/nginx-stigready-baseline) for full examples. You can find InSpec profiles written by the MITRE SAF team through the [validation library of the SAF site](https://saf.mitre.org/libs/validate). ![The NGINX Profile](../../assets/img/Github_nginx.png) diff --git a/src/courses/user/06.md b/src/courses/user/06.md index 85b3ad753..6b17a14d4 100644 --- a/src/courses/user/06.md +++ b/src/courses/user/06.md @@ -14,13 +14,13 @@ In this section, we will discuss how to run InSpec. In [Section 8](./08.md), you To run InSpec, you must have: -1. **The InSpec Executable** - InSpec's exectuable must be installed on the machine running the scans. This does not have to be the same machine that is being tested! _(We will run InSpec from the GitHub Codespaces lab environment. InSpec is already downloaded in the GitHub Codespaces lab environment after running the install script using `source build-lab.sh`.)_ Check out the [Installation Tab](../../installation) for more information on installing InSpec in a different environment. +1. **The InSpec Executable** - InSpec's executable must be installed on the machine running the scans. This does not have to be the same machine that is being tested! _(We will run InSpec from the GitHub Codespaces lab environment. InSpec is already downloaded in the GitHub Codespaces lab environment after running the install script using `source build-lab.sh`.)_ Check out the [Installation Tab](../../installation) for more information on installing InSpec in a different environment. 2. **A Target** - You need something to test! _In the GitHub Codespaces lab environment, we have two Docker containers running to test._ 3. **An InSpec Profile** - You need the tests themselves! This is Ruby code containing all of the controls, or tests, that we intend to run against the target. You may have this code stored locally on your runner machine, or you may get it from any accessible network location -- GitHub is an excellent example. We will practice running profiles from local files and from a GitHub repository. ## 6.3 The InSpec Command Formula -To validate a system, we need to run InSpec from the command line. There are many different options we can use with the InSpec exectuable to run our tests. Let's break down the simple formula based on the requirements above. +To validate a system, we need to run InSpec from the command line. There are many different options we can use with the InSpec executable to run our tests. Let's break down the simple formula based on the requirements above. ```sh inspec exec -t --more-flags ... --reporter @@ -39,7 +39,7 @@ inspec exec WHERE_IS_THE_PROFILE # 6.3.1 & 6.3.2 inspec exec ``` -We'll start with `inspec exec` so that the InSpec exectuable knows what we are asking it to do -- in this case, `inspec exec` tells InSpec to execute an existing profile. (There are other options, like `inspec shell` and `inspec profile init`, but they are not our focus right now. We'll look at some of them during other MITRE SAF training classes.) +We'll start with `inspec exec` so that the InSpec executable knows what we are asking it to do -- in this case, `inspec exec` tells InSpec to execute an existing profile. (There are other options, like `inspec shell` and `inspec profile init`, but they are not our focus right now. We'll look at some of them during other MITRE SAF training classes.) ### 6.3.2 WHERE_IS_THE_PROFILE (required) @@ -47,7 +47,7 @@ We'll start with `inspec exec` so that the InSpec exectuable knows what we are a inspec exec WHERE_IS_THE_PROFILE ``` -Then, you must give the _location_ of the InSpec profile. In other words, we need to show the InSpec exectuable where to find the code for the tests themselves. If the InSpec profile is stored locally, you can simply write out the path to that file location, such as `/root/path/to/InSpecProfiles/nginx-profile`. If you wish to run a profile directly from GitHub or some other location on the Internet or other network, you can enter the URL of the profile instead, such as `https://github.com/mitre/nginx-stigready-baseline`. +Then, you must give the _location_ of the InSpec profile. In other words, we need to show the InSpec executable where to find the code for the tests themselves. If the InSpec profile is stored locally, you can simply write out the path to that file location, such as `/root/path/to/InSpecProfiles/nginx-profile`. If you wish to run a profile directly from GitHub or some other location on the Internet or other network, you can enter the URL of the profile instead, such as `https://github.com/mitre/nginx-stigready-baseline`. ### 6.3.3 WHAT_IS_THE_TARGET (default: local machine) @@ -57,7 +57,7 @@ Then, you must give the _location_ of the InSpec profile. In other words, we nee Next, you need to tell your computer what the target is -- or rather, what system we are trying to test. You add this information using the `-t` flag. -Without the `-t` flag, by default, InSpec will execute the selected profile against your local system. However, we are often trying to run tests against a remote target. You could test a bare metal server, a virtual machine, a Docker container, or many other options. You could also specify different protocols to connect to your remote system via SSH, WinRM, or more. For example, we could connect to a system using `-t ssh://user-name@host-name:port` or `-t docker://instance-id`. We will talk more about these options later. +Without the `-t` flag, by default, InSpec will execute the selected profile against your local system. However, we are often trying to run tests against a remote target. You could test a bare metal server, a virtual machine, a Docker container, and many others. You can specify different protocols to connect to your remote system using SSH, WinRM, and more. For example, we could connect to a system using `-t ssh://user-name@host-name:port` or `-t docker://instance-id`. We will talk more about these options later. ### 6.3.4 EXTRA_STUFF (optional) @@ -65,7 +65,7 @@ Without the `-t` flag, by default, InSpec will execute the selected profile agai --more-flags EXTRA_STUFF # 6.3.4 ``` -There are many more options that you can specify when running the InSpec command. The next most common one is specifying inputs for your profile using the `--inputs` or `--input-file` flags. For example, `--input-file /path/to/inputs.yml` allows you to add inputs that tailor your test profile to your environment's particular configuration. You can find more information on inputs in the [Tailoring Inputs](./07) section. +There are many more options that you can specify when running the InSpec command. For example, `--enhanced-outcomes` is used to show additional context when results are displayed in the CLI reporter. Additionally, inputs can be included for your profile using the `--inputs` or `--input-file` flags. For example, `--input-file /path/to/inputs.yml` allows you to add inputs that tailor your test profile to your environment's particular configuration. You can find more information on inputs in the [Tailoring Inputs](./07) section. ### 6.3.5 WHAT_SHOULD_INSPEC_DO_WITH_THE_RESULTS (default: cli) @@ -73,7 +73,7 @@ There are many more options that you can specify when running the InSpec command --reporter WHAT_SHOULD_INSPEC_DO_WITH_THE_RESULTS # 6.3.5 ``` -And of course, once our test has completed, you probably want to see the results! You can specify where those results are displayed or saved based on what you enter after the `--reporter` flag at the end of your command. For example, the following would print the results on the command line and save it to a file (by creating or overwriting) the file at /path/to/results.json: `--reporter cli json:/path/to/results.json`. If you do not add this information, the command will default to providing results on the command line, but it will not save those into a file unless you specify the `--reporter` flag like the example. +And of course, once our test has been completed, you probably want to see the results! You can specify where those results are displayed or saved based on what you enter after the `--reporter` flag at the end of your command. For example, the following would print the results on the command line and save it to a file (by creating or overwriting) the file at /path/to/results.json: `--reporter cli json:/path/to/results.json`. If you do not add this information, the command will default to providing results on the command line, but it will not save those into a file unless you specify the `--reporter` flag like the example. Each profile's README should give an example of running the InSpec command for that profile; however, you can always reference the complete documentation on the InSpec command options [here](https://docs.chef.io/inspec/cli/). @@ -82,10 +82,10 @@ Each profile's README should give an example of running the InSpec command for t We will go more in depth on this example in the next two sections, but if you want a head start, you can give running InSpec a try by running this command in your Codespace terminal. ```sh -inspec exec https://github.com/mitre/nginx-stigready-baseline -t docker://nginx --reporter cli +inspec exec https://github.com/mitre/nginx-stigready-baseline -t docker://nginx --enhanced-outcomes --reporter cli ``` -In the above example, we are testing an NGINX server. We get the InSpec profile (all the tests) from GitHub by stating `https://github.com/mitre/nginx-stigready-baseline`. We use the NGINX target that is running via docker in our Codespace environment by stating `docker://nginx`, we do not put any extra flags in this example, and lastly, we only report the results to the terminal (in other words, cli output). Later we will refine this command and talk through it in more detail. +In the above example, we are testing an NGINX server. We get the InSpec profile (all the tests) from GitHub by stating `https://github.com/mitre/nginx-stigready-baseline`. We use the NGINX target (`-t`) that is running via Docker in our Codespace environment by stating `docker://nginx`, and we report the results to the terminal (CLI output) with `enhanced-outcomes` enabled for readability. Not all the metadata generated by `inspec exec` is displayed in the CLI output. Instead, it is included in the results file so that we can explore it in more detail using Heimdall. _Note: The first time you run InSpec, it will likely ask you to accept Chef's license like this:_ diff --git a/src/courses/user/07.md b/src/courses/user/07.md index 7e10116ff..0848c1209 100644 --- a/src/courses/user/07.md +++ b/src/courses/user/07.md @@ -44,10 +44,10 @@ For the NGINX example, we are going to add the following inputs. Make a new file --- key_file_path: /etc/ssl/nginx-selfsigned.pem org_allowed_nginx_version: 1.23.1 -nginx_owner: "nginx" +nginx_owner: nginx uses_pki: false -sys_admin: ["root"] -sys_admin_group: ["root"] +sys_admin: [root] +sys_admin_group: [root] ``` In your codespaces, it should look like this: diff --git a/src/courses/user/08.md b/src/courses/user/08.md index 872486c07..18de8b667 100644 --- a/src/courses/user/08.md +++ b/src/courses/user/08.md @@ -87,7 +87,7 @@ You should also see your results in a JSON file located in `/results` folder wit InSpec allows you to output your test results to one or more reporters. You can configure the reporter(s) using either the `--config` option or the `--reporter` option. While you can configure multiple reporters to write to different files, only one reporter can output to the screen (stdout). ```sh -inspec exec /root/my_nginx -t ssh://TARGET_USERNAME:TARGET_PASSWORD@TARGET_IP --reporter cli json:baseline_output.json +inspec exec my_nginx -t ssh://TARGET_USERNAME:TARGET_PASSWORD@TARGET_IP --reporter cli json:baseline_output.json ``` #### Syntax @@ -96,27 +96,27 @@ You can specify one or more reporters using the `--reporter` CLI flag. You can a Output JSON to screen. -`inspec exec /root/my_nginx --reporter json` +`inspec exec my_nginx --reporter json` or -`inspec exec /root/my_nginx --reporter json:-` +`inspec exec my_nginx --reporter json:-` Output YAML to screen -`inspec exec /root/my_nginx --reporter yaml` +`inspec exec my_nginx --reporter yaml` or -`inspec exec /root/my_nginx --reporter yaml:-` +`inspec exec my_nginx --reporter yaml:-` Output CLI to screen and write JSON to a file. -`inspec exec /root/my_nginx --reporter cli json:/tmp/output.json` +`inspec exec my_nginx --reporter cli json:/tmp/output.json` Output nothing to screen and write JUnit and HTML to a file. -`inspec exec /root/my_nginx --reporter junit:/tmp/junit.xml html:www/index.html` +`inspec exec my_nginx --reporter junit:/tmp/junit.xml html:www/index.html` Output JSON to screen and write to a file. Write JUnit to a file. -`inspec exec /root/my_nginx --reporter json junit:/tmp/junit.xml | tee out.json` +`inspec exec my_nginx --reporter json junit:/tmp/junit.xml | tee out.json` If you wish to pass the profiles directly after specifying the reporters you will need to use the end of options flag `--`. diff --git a/src/courses/user/10.md b/src/courses/user/10.md index 1da66e255..e3d1f73d1 100644 --- a/src/courses/user/10.md +++ b/src/courses/user/10.md @@ -36,21 +36,13 @@ This command will make sure that the NGINX docker container has the required sof ## 10.4 CLI Results of Hardening Script -You should see the following results from the hardening script. If you run this hardening content multiple times, the numbers in the results may be different because the starting configuration will be different and the script will not have to change the same numbers of settings. - -::: note -Make sure you are in the ansible content's directory before running the following command. You can run the command - `cd ansible-nginx-stigready-hardening` - to enter the directory. That means your current working directory path will look something like `/workspaces/saf-training-lab-environment/ansible-nginx-stigready-hardening` with variation if you named your repository differently in the lab setup. - ::: - Run this command: ```sh ansible-playbook -i hosts.yml hardening-playbook.yml ``` -To see the following results: +You should see the following results from the hardening script. If you run this hardening content multiple times, the numbers in the results may be different because the starting configuration will be different and the script will not have to change the same numbers of settings. ```sh ansible-playbook -i hosts.yml hardening-playbook.yml diff --git a/src/courses/user/12.md b/src/courses/user/12.md index 71dfda70f..491d1f7b9 100644 --- a/src/courses/user/12.md +++ b/src/courses/user/12.md @@ -163,8 +163,27 @@ Here is an example of an attested control that we can create based on 1. The results we saw in Heimdall 2. Our (hypothetical) completed manual check (Let's pretend that we did check this!) +::: code-tabs + +@tab With known control ID + ```sh saf attest create -o ./results/manual_attestation_results.json +``` + +@tab Using search + +```sh +saf attest create -i results/results.json -o results/manual_attestation_results.json +``` + +::: + +::: code-tabs + +@tab Output: with known control ID + +```sh Enter a control ID or enter 'q' to exit: V-40792 Attestation explanation: Verified that the server-side session management is configured correctly. Frequency (1d/3d/1wk/2wk/1m/3m/6m/1y/1.5y/custom): 3m @@ -173,6 +192,25 @@ Updated By: Emily Rodriguez Enter a control ID or enter 'q' to exit: ``` +@tab Output: using search + +```sh +Enter a control ID, search for a control, or enter 'q' to exit: server-side session management + V-40792: The NGINX web server must perform server-side session management. + V-40791: The NGINX web server must limit the number of allowed simultaneous session requests. + V-56003: NGINX web server session IDs must be sent to the client using SSL/TLS. + V-56005: Web server cookies, such as session cookies, sent to the client usingSSL/TLS must not be compressed. + V-41611: The NGINX web server must initiate session logging upon start up. +Enter a control ID, search for a control, or enter 'q' to exit: V-40792 +Attestation explanation: Verified that the server-side session management is configured correctly. +Frequency (1d/3d/1wk/2wk/1m/3m/6m/1y/1.5y/custom): 3m +Enter status ((p)assed/(f)ailed): p +Updated By: Emily Rodriguez +Enter a control ID, search for a control, or enter 'q' to exit: +``` + +::: + Now, go through and add more attestations of the Not Reviewed results. You can decide if they should pass or fail as if you hypothetically did check these controls manually. Type `q` when you are done. ## 12.6 Apply the Manual Attestation Data diff --git a/src/courses/user/14.md b/src/courses/user/14.md index a1890d8a2..b6c75de9f 100644 --- a/src/courses/user/14.md +++ b/src/courses/user/14.md @@ -8,15 +8,15 @@ headerDepth: 3 ## 14.1 Normalize -Remember the "Normalize" pillar? We skipped over it when we were doing InSpec validation because InSpec results are automatically in HDF (or Heimdall Data Format). +Remember the "Normalize" pillar? We skipped over it when we were doing InSpec validation because InSpec results are automatically in OHDF (or Oasis Heimdall Data Format). ![The Normalize Capability](../../assets/img/SAF_Capabilities_Normalize.png) -However, other tools provide useful security data that is not inherently in HDF. So, to make a full picture of security, we have converters to convert third party data to HDF and HDF back into other forms. +However, other tools provide useful security data that is not inherent in OHDF. So, to make a full picture of security, we have converters to convert third-party data to OHDF and OHDF back into other forms. ## 14.2 Convert with SAF CLI -The SAF CLI has utilies to convert files from one output to another. Take a look at the ever-growing list of compatible file types at the [SAF CLI README](https://saf-cli.mitre.org/). +The SAF CLI has utilities to convert files from one output to another. Take a look at the ever-growing list of compatible file types at the [SAF CLI README](https://saf-cli.mitre.org/). ## 14.3 Convert with Heimdall @@ -36,16 +36,16 @@ As you add all of this data into one view, you can see how the NIST 800-53 contr ![The Tree Map](../../assets/img/Heimdall_TreeMap_Fuller.png) -In this big picture view, you can see the whole security posture and filter down, for example, on high failures across all scans. _Your results may look different than these pictures depending on what you have loaded in Heimdall_ +In this big-picture view, you can see the whole security posture and filter down, for example, on high failures across all scans. _Your results may look different than these pictures depending on what you have loaded in Heimdall_ ![Loading Multiple Results Files](../../assets/img/Heimdall_MultiResults2.png) -And in the results details, you can see what file - in other words what scan or part of the system, is causing the problem. +And in the details of the results, you can see what file - in other words, what scan or part of the system, is causing the problem. ![Results Details from Multiple Sources](../../assets/img/Heimdall_MultiResults.png) ## 14.5 Export Data To Other Formats -This is a two-way street! There are other places security data needs to be - maybe in Splunk, eMASS, AWS Security Hub, or even just in an easy, high level diagram to show your boss. Because of this, Heimdall can also export data into different forms using the "Export" button in the top right. Try out some of these forms on your results! +This is a two-way street! There are other places security data needs to be - maybe in Splunk, eMASS, AWS Security Hub, or even just in an easy, high-level diagram to show your boss. Because of this, Heimdall can also export data into different forms using the "Export" button in the top right. Try out some of these forms on your results! ![The Export Menu](../../assets/img/Heimdall_Export_Menu.png) diff --git a/src/courses/user/README.md b/src/courses/user/README.md index 45102bc91..df1678585 100644 --- a/src/courses/user/README.md +++ b/src/courses/user/README.md @@ -43,4 +43,4 @@ As illustrated in the picture below, the process for developing automated securi This challenge is what the [MITRE Security Automation Framework](https://saf.mitre.org) (MITRE SAF) was developed to address. It simplifies the journey from a Requirement Document to an automated test profile and back again, making it easier to navigate. -![SAF Lifecycle](../../assets/img/saf-lifecycle.png) +![SAF Lifecycle](../../assets/img/saf-lifecycle.jpg) diff --git a/src/resources/02.md b/src/resources/02.md index bcf7a64e3..984a1e2ab 100644 --- a/src/resources/02.md +++ b/src/resources/02.md @@ -30,7 +30,7 @@ You'll need to create a fork of the [SAF training lab environment repository](ht 2. Access the [lab environment repository](https://github.com/mitre/saf-training-lab-environment). 3. Click the **fork** button: ![Forking a Repo](../assets/img/fork.png) -You'll be taken to the fork creation screen. Make sure you select the option to create the fork under your own profile, and not under an organizational account (if you are part of one). +You'll be taken to the fork creation screen. Make sure you select the option to create the fork under your own profile, and not under an organizational account (if you are part of one). You may leave "Copy the `main` branch only" checked if it is enabled, but this selection is optional. ![Fork Menu](../assets/img/creating_the_fork.png) 4. You'll be taken to the new webpage for your fork. Note that it is a complete copy of the original MITRE-managed codebase, but you are now the owner.\ ![My Fork](../assets/img/my_fork.png) diff --git a/src/resources/README.md b/src/resources/README.md index 10918cb2a..c9f86f971 100644 --- a/src/resources/README.md +++ b/src/resources/README.md @@ -89,19 +89,6 @@ headerDepth: 3 - [CINC](https://cinc.sh) - [VSCode](https://code.visualstudio.com/download) -## RHEL8 Baseline 'Stubs' - -The RHEL8 Baseline Stubs were `saf-cli generate` command as documented in the [Beginner Class](../courses/beginner/11.md) . You can use this as a reference while you develop your controls. -### Generating the Stubs - -To create the RedHat Enterprise Linux 8 STIG Profile stubs, we used the `saf-cli generate` command: -```sh -saf generate:xccdf2inspec_stub -i U_RHEL_8_STIG_V1R6_Manual-xccdf.xml -r -o rhel8-baseline-stubs -``` -This created a starter profile based of the RHEL8 STIG XCCDF Bechmark - -- [rhel8-baseline-stubs.tar.gz](https://github.com/mitre/saf-training-lab-environment/raw/main/resources/rhel8-baseline-stubs.tar.gz) - ## Chef Community Slack -