Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(engine): improve detection of Ansible host files #6816

Merged
merged 4 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions e2e/fixtures/E2E_CLI_075_RESULT.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"kics_version": "development",
"files_scanned": 2,
"lines_scanned": 48,
"files_parsed": 2,
"lines_parsed": 48,
"lines_ignored": 0,
"files_failed_to_scan": 0,
"queries_total": 1,
"queries_failed_to_execute": 0,
"queries_failed_to_compute_similarity_id": 0,
"scan_id": "console",
"severity_counters": {
"HIGH": 0,
"INFO": 0,
"LOW": 0,
"MEDIUM": 2,
"TRACE": 0
},
"total_counter": 2,
"total_bom_resources": 0,
"start": "2023-11-23T15:54:44.1211396Z",
"end": "2023-11-23T15:54:45.914525Z",
"paths": [
"/path/test/fixtures/analyzer_test_ansible_host/e2e"
],
"queries": [
{
"query_name": "Ansible Tower Exposed To Internet",
"query_id": "1b2bf3ff-31e9-460e-bbfb-45e48f4f20cc",
"query_url": "https://docs.ansible.com/ansible-tower/latest/html/administration/security_best_practices.html#understand-the-architecture-of-ansible-and-tower",
"severity": "MEDIUM",
"platform": "Ansible",
"cloud_provider": "COMMON",
"category": "Best Practices",
"experimental": false,
"description": "Avoid exposing Ansible Tower to the public internet, effectively reducing the potential attack surface of your deployment",
"description_id": "657a8b1d",
"files": [
{
"file_name": "path\\test\\fixtures\\analyzer_test_ansible_host\\e2e\\positive2.yaml",
"similarity_id": "7b9574422b2f0a1a2eb467c930f7d52fb727d0b8839703d668531c1362d09c4b",
"line": 24,
"resource_type": "n/a",
"resource_name": "children",
"issue_type": "IncorrectValue",
"search_key": "all.children.tower.hosts",
"search_line": -1,
"search_value": "",
"expected_value": "Ansible Tower IP should be private",
"actual_value": "Ansible Tower IP is public"
},
{
"file_name": "path\\test\\fixtures\\analyzer_test_ansible_host\\e2e\\positive1.ini",
"similarity_id": "9cb04742c227f8da30d5e3f0ed823fd05334179f79dbe2435ba146af79317c45",
"line": 1,
"resource_type": "n/a",
"resource_name": "children",
"issue_type": "IncorrectValue",
"search_key": "[tower]",
"search_line": -1,
"search_value": "",
"expected_value": "Ansible Tower IP should be private",
"actual_value": "Ansible Tower IP is public"
}
]
}
]
}
27 changes: 27 additions & 0 deletions e2e/testcases/e2e-cli-075_ansible_host_detected.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package testcases

// E2E-CLI-075 - KICS scan
// should perform the scan successfully detect ansible and return result 20
func init() { //nolint
testSample := TestCase{
Name: "should perform a valid scan and and detect ansible [E2E-CLI-075]",
Args: args{
Args: []cmdArgs{
[]string{"scan", "-o", "/path/e2e/output",
"--output-name", "E2E_CLI_074_RESULT",
"-p", "\"/path/test/fixtures/analyzer_test_ansible_host/e2e\"",
"-i", "1b2bf3ff-31e9-460e-bbfb-45e48f4f20cc",
},
},
ExpectedResult: []ResultsValidation{
{
ResultsFile: "E2E_CLI_075_RESULT",
ResultsFormats: []string{"json"},
},
},
},
WantStatus: []int{20},
}

Tests = append(Tests, testSample)
}
22 changes: 21 additions & 1 deletion pkg/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ var (
listKeywordsAnsible = []string{"name", "gather_facts",
"hosts", "tasks", "become", "with_items", "with_dict",
"when", "become_pass", "become_exe", "become_flags"}
playBooks = "playbooks"
playBooks = "playbooks"
ansibleHost = "all"
listKeywordsAnsibleHots = []string{"hosts", "children"}
)

const (
Expand Down Expand Up @@ -552,6 +554,10 @@ func checkYamlPlatform(content []byte, path string) string {
if checkForAnsible(yamlContent) {
return ansible
}
// check if the file contains some keywords related with Ansible Host
if checkForAnsibleHost(yamlContent) {
return ansible
}
return ""
}

Expand All @@ -574,6 +580,20 @@ func checkForAnsible(yamlContent model.Document) bool {
return isAnsible
}

func checkForAnsibleHost(yamlContent model.Document) bool {
isAnsible := false
if hosts := yamlContent[ansibleHost]; hosts != nil {
if listHosts, ok := hosts.(map[string]interface{}); ok {
for _, value := range listKeywordsAnsibleHots {
if host := listHosts[value]; host != nil {
isAnsible = true
}
}
}
}
return isAnsible
}

// computeValues computes expected Lines of Code to be scanned from locCount channel
// and creates the types and unwanted slices from the channels removing any duplicates
func computeValues(types, unwanted chan string, locCount chan int, done chan bool) (typesS, unwantedS []string, locTotal int) {
Expand Down
45 changes: 38 additions & 7 deletions pkg/analyzer/analyzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
name: "analyze_test_multiple_path",
paths: []string{
filepath.FromSlash("../../test/fixtures/analyzer_test/Dockerfile"),
filepath.FromSlash("../../test/fixtures/analyzer_test/terraform.tf")},
filepath.FromSlash("../../test/fixtures/analyzer_test/terraform.tf"),
},
wantTypes: []string{"dockerfile", "terraform"},
wantExclude: []string{},
typesFromFlag: []string{""},
Expand All @@ -66,7 +67,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
{
name: "analyze_test_multi_checks_path",
paths: []string{
filepath.FromSlash("../../test/fixtures/analyzer_test/openAPI_test")},
filepath.FromSlash("../../test/fixtures/analyzer_test/openAPI_test"),
},
wantTypes: []string{"openapi"},
wantExclude: []string{},
typesFromFlag: []string{""},
Expand All @@ -79,7 +81,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
{
name: "analyze_test_not_openapi",
paths: []string{
filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json")},
filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json"),
},
wantTypes: []string{},
wantExclude: []string{filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json")},
typesFromFlag: []string{""},
Expand Down Expand Up @@ -139,7 +142,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
wantTypes: []string{"kubernetes"},
wantExclude: []string{filepath.FromSlash("../../test/fixtures/gitignore/positive.dockerfile"),
filepath.FromSlash("../../test/fixtures/gitignore/secrets.tf"),
filepath.FromSlash("../../test/fixtures/gitignore/gitignore")},
filepath.FromSlash("../../test/fixtures/gitignore/gitignore"),
},
typesFromFlag: []string{""},
excludeTypesFromFlag: []string{""},
wantLOC: 13,
Expand Down Expand Up @@ -225,7 +229,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
filepath.FromSlash("../../test/fixtures/analyzer_test/openAPI_test/openAPI.yaml"),
filepath.FromSlash("../../test/fixtures/analyzer_test/pnpm-lock.yaml"),
filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml"),
filepath.FromSlash("../../test/fixtures/analyzer_test/github.yaml")},
filepath.FromSlash("../../test/fixtures/analyzer_test/github.yaml"),
},
typesFromFlag: []string{"ansible", "pulumi"},
excludeTypesFromFlag: []string{""},
wantLOC: 374,
Expand All @@ -242,7 +247,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json"),
filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml"),
filepath.FromSlash("../../test/fixtures/analyzer_test/pnpm-lock.yaml"),
filepath.FromSlash("../../test/fixtures/analyzer_test/dead_symlink")},
filepath.FromSlash("../../test/fixtures/analyzer_test/dead_symlink"),
},
typesFromFlag: []string{""},
excludeTypesFromFlag: []string{"ansible", "pulumi"},
wantLOC: 576,
Expand All @@ -258,7 +264,8 @@ func TestAnalyzer_Analyze(t *testing.T) {
filepath.FromSlash("../../test/fixtures/analyzer_test/pnpm-lock.yaml"),
filepath.FromSlash("../../test/fixtures/analyzer_test/not_openapi.json"),
filepath.FromSlash("../../test/fixtures/analyzer_test/dead_symlink"),
filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml")},
filepath.FromSlash("../../test/fixtures/analyzer_test/undetected.yaml"),
},
typesFromFlag: []string{""},
excludeTypesFromFlag: []string{""},
wantLOC: 834,
Expand Down Expand Up @@ -331,6 +338,30 @@ func TestAnalyzer_Analyze(t *testing.T) {
gitIgnoreFileName: "",
excludeGitIgnore: false,
},
{
name: "ansible_host",
paths: []string{filepath.FromSlash("../../test/fixtures/analyzer_test_ansible_host/ansiblehost.yaml")},
wantTypes: []string{"ansible"},
wantExclude: []string{},
typesFromFlag: []string{""},
excludeTypesFromFlag: []string{""},
wantLOC: 33,
wantErr: false,
gitIgnoreFileName: "",
excludeGitIgnore: false,
},
{
name: "ansible_host_other",
paths: []string{filepath.FromSlash("../../test/fixtures/analyzer_test_ansible_host/ansiblehost2.yaml")},
wantTypes: []string{"ansible"},
wantExclude: []string{},
typesFromFlag: []string{""},
excludeTypesFromFlag: []string{""},
wantLOC: 22,
wantErr: false,
gitIgnoreFileName: "",
excludeGitIgnore: false,
},
}

for _, tt := range tests {
Expand Down
33 changes: 33 additions & 0 deletions test/fixtures/analyzer_test_ansible_host/ansiblehost.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
all:
children:
automationhub:
hosts:
automationhub.acme.org:
admin_password: <password>
pg_database: awx
pg_host: database-01.acme.org
pg_password: <password>
pg_port: '5432'
pg_sslmode: prefer
pg_username: awx
database:
hosts:
database-01.acme.org:
admin_password: <password>
pg_database: awx
pg_host: database-01.acme.org
pg_password: <password>
pg_port: '5432'
pg_sslmode: prefer
pg_username: awx
tower:
hosts:
172.27.0.5:
admin_password: <password>
pg_database: awx
pg_host: database-01.acme.org
pg_password: <password>
pg_port: '5432'
pg_sslmode: prefer
pg_username: awx
ungrouped: {}
22 changes: 22 additions & 0 deletions test/fixtures/analyzer_test_ansible_host/ansiblehost2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
all:
children:
webservers:
hosts:
webserver1: null
webserver2: null
databases:
hosts:
dbserver1:
ansible_host: 192.168.1.103
ansible_user: postgres
dbserver2:
ansible_host: 192.168.1.104
ansible_user: mysql
hosts:
webserver1:
ansible_host: 192.168.1.101
ansible_user: ubuntu
webserver2:
ansible_host: 192.168.1.102
ansible_user: centos
14 changes: 14 additions & 0 deletions test/fixtures/analyzer_test_ansible_host/e2e/positive1.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[tower]
150.50.1.1
[automationhub]
automationhub.acme.org
[database]
database-01.acme.org
[all:vars]
admin_password='<password>'
pg_host='database-01.acme.org'
pg_port='5432'
pg_database='awx'
pg_username='awx'
pg_password='<password>'
pg_sslmode='prefer'
33 changes: 33 additions & 0 deletions test/fixtures/analyzer_test_ansible_host/e2e/positive2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
all:
children:
automationhub:
hosts:
automationhub.acme.org:
admin_password: <password>
pg_database: awx
pg_host: database-01.acme.org
pg_password: <password>
pg_port: '5432'
pg_sslmode: prefer
pg_username: awx
database:
hosts:
database-01.acme.org:
admin_password: <password>
pg_database: awx
pg_host: database-01.acme.org
pg_password: <password>
pg_port: '5432'
pg_sslmode: prefer
pg_username: awx
tower:
hosts:
139.50.1.1:
admin_password: <password>
pg_database: awx
pg_host: database-01.acme.org
pg_password: <password>
pg_port: '5432'
pg_sslmode: prefer
pg_username: awx
ungrouped: {}
Loading