CyberwatchApi.psm1
# Powershell Cyberwatch Api Client Function SendApiRequest { <# .SYNOPSIS Cyberwatch API Powershell Client. .DESCRIPTION Send REST Query to Cyberwatch API .EXAMPLE SendApiRequest -api_url $API_URL -api_key $API_KEY -secret_key $SECRET_KEY -http_method $http_method -request_URI $request_URI .PARAMETER api_url Your Cyberwatch instance base url #> Param ( [PARAMETER(Mandatory=$true)][string]$api_url, [PARAMETER(Mandatory=$true)][string]$api_key, [PARAMETER(Mandatory=$true)][string]$secret_key, [PARAMETER(Mandatory=$true)][string]$http_method, [PARAMETER(Mandatory=$true)][string]$request_URI, [PARAMETER(Mandatory=$false)][Hashtable]$content, [PARAMETER(Mandatory=$false)][Hashtable]$query_params ) $uri = "${API_URL}${request_URI}" if ($content) { $content_type = 'application/json' $body_content = $content | ConvertTo-Json } elseif ($query_params) { $content_type = '' Add-Type -AssemblyName System.Web $query_strings = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($key in $query_params.GetEnumerator()) { if($key.Value -is [system.array]){ foreach ($value in $key.Value) { $query_strings.Add($key.Key + "[]", "${value}") } } else {$query_strings.Add($key.Key, $key.Value)} } $uriRequest = [System.UriBuilder]"${API_URL}${request_URI}" $uriRequest.Query = $query_strings.ToString() $params = $uriRequest.Query $body_content = $content $uri = "${API_URL}${request_URI}${params}" } $content_MD5 = '' $timestamp = [System.DateTime]::UtcNow.ToString('R') $message = "$http_method,$content_type,$content_MD5,$request_URI$params,$timestamp" $hmacsha = New-Object System.Security.Cryptography.HMACSHA256 $hmacsha.key = [Text.Encoding]::ASCII.GetBytes($SECRET_KEY) $signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message)) $signature = [Convert]::ToBase64String($signature) Invoke-WebRequest -Uri $uri -Method $http_method -Headers @{ "accept" = "application/json"; "Date" = $timestamp "Authorization" = "Cyberwatch APIAuth-HMAC-SHA256 ${API_KEY}:$signature" } -ContentType $content_type -Body $body_content -UseBasicParsing } Function SendApiRequestPagination { Param ( [PARAMETER(Mandatory=$true)][string]$api_url, [PARAMETER(Mandatory=$true)][string]$api_key, [PARAMETER(Mandatory=$true)][string]$secret_key, [PARAMETER(Mandatory=$true)][string]$http_method, [PARAMETER(Mandatory=$true)][string]$request_URI, [PARAMETER(Mandatory=$false)][Hashtable]$content, [PARAMETER(Mandatory=$false)][Hashtable]$query_params = @{} ) if ($query_params.ContainsKey("per_page") -eq $false) { $query_params.Add("per_page", 100) } $response = SendApiRequest -api_url $api_url -api_key $api_key -secret_key $secret_key -http_method $http_method -request_URI $request_URI -content $content -query_params $query_params if ($response.headers["link"] -match "[?&]page=(\d*)" -and $query_params.ContainsKey("page") -eq $false) { $last_page_number = $matches[1] 1..$last_page_number | ForEach-Object { $query_params["page"] = $_; SendApiRequest -api_url $api_url -api_key $api_key -secret_key $secret_key -http_method $http_method -request_URI $request_URI -content $content -query_params $query_params | ConvertFrom-Json | ForEach-Object { $_ } } } else { $response | ConvertFrom-JSON } } Class CbwApiClient { [string]$api_url [string]$api_key [string]$secret_key CbwApiClient ([string]$api_url, [string]$api_key, [string]$secret_key) { $this.api_url = $api_url $this.api_key = $api_key $this.secret_key = $secret_key } [object] request([string]$http_method, [string]$request_URI) { return SendApiRequest -api_url $this.api_url -api_key $this.api_key -secret_key $this.secret_key -http_method $http_method -request_URI $request_URI | ConvertFrom-JSON } [object] request([string]$http_method, [string]$request_URI, [Hashtable]$content) { return SendApiRequest -api_url $this.api_url -api_key $this.api_key -secret_key $this.secret_key -http_method $http_method -request_URI $request_URI -content $content | ConvertFrom-JSON } [object] request_pagination([string]$http_method, [string]$request_URI) { return SendApiRequestPagination -api_url $this.api_url -api_key $this.api_key -secret_key $this.secret_key -http_method $http_method -request_URI $request_URI } [object] request_pagination([string]$http_method, [string]$request_URI, [Hashtable]$query_params) { return SendApiRequestPagination -api_url $this.api_url -api_key $this.api_key -secret_key $this.secret_key -http_method $http_method -request_URI $request_URI -query_params $query_params } [object] ping() { return $this.request('GET', '/api/v3/ping') } [object] servers() { return $this.request_pagination('GET', '/api/v3/vulnerabilities/servers') } [object] servers([Object]$filters) { return $this.request_pagination('GET', '/api/v3/vulnerabilities/servers', $filters) } [object] server([string]$id) { return $this.request('GET', "/api/v3/vulnerabilities/servers/${id}") } [object] update_server([string]$id, [Object]$content) { return $this.request('PUT', "/api/v3/vulnerabilities/servers/${id}", $content) } [object] refresh_server([string]$id) { return $this.request('PUT', "/api/v3/vulnerabilities/servers/${id}/refresh") } [object] delete_server([string]$id) { return $this.request('DELETE', "/api/v3/vulnerabilities/servers/${id}") } [object] update_server_cve([string]$id, [string]$cve_code, [Object]$content) { return $this.request('PUT', "/api/v3/vulnerabilities/servers/${id}/cve_announcements/${cve_code}", $content) } [object] server_schedule_updates([string]$id, [Object]$content) { return $this.request('POST', "/api/v3/vulnerabilities/servers/${id}/updates", $content) } [object] remote_accesses() { return $this.request_pagination('GET', '/api/v3/assets/remote_accesses') } [object] remote_accesses([Object]$filters) { return $this.request_pagination('GET', '/api/v3/assets/remote_accesses', $filters) } [object] remote_access([string]$id) { return $this.request('GET', "/api/v3/assets/remote_accesses/${id}") } [object] create_remote_access([Object]$content) { return $this.request('POST', '/api/v3/assets/remote_accesses', $content) } [object] update_remote_access([string]$id, [Object]$content) { return $this.request('PUT', "/api/v3/assets/remote_accesses/${id}", $content) } [object] delete_remote_access([string]$id) { return $this.request('DELETE', "/api/v3/assets/remote_accesses/${id}") } [object] groups() { return $this.request_pagination('GET', "/api/v3/assets/groups") } [object] groups([Object]$filters) { return $this.request_pagination('GET', '/api/v3/assets/groups', $filters) } [object] group([string]$id) { return $this.request('GET', "/api/v3/assets/groups/${id}") } [object] create_group([Object]$content) { return $this.request('POST', '/api/v3/assets/groups', $content) } [object] update_group([string]$id, [Object]$content) { return $this.request('PATCH', "/api/v3/assets/groups/${id}", $content) } [object] delete_group([string]$id) { return $this.request('DELETE', "/api/v3/assets/groups/${id}") } [object] cve_announcement([string]$id) { return $this.request('GET', "/api/v3/vulnerabilities/cve_announcements/${id}") } [object] cve_announcements() { return $this.request_pagination('GET', "/api/v3/vulnerabilities/cve_announcements") } [object] cve_announcements([Hashtable]$query_params) { return $this.request_pagination('GET', "/api/v3/vulnerabilities/cve_announcements", $query_params) } [object] update_cve_announcement([string]$id, [Object]$content) { return $this.request('PUT', "/api/v3/vulnerabilities/cve_announcements/${id}", $content) } [object] delete_cve_announcement([string]$id) { return $this.request('DELETE', "/api/v3/vulnerabilities/cve_announcements/${id}") } [object] users() { return $this.request_pagination('GET', "/api/v3/users") } [object] users([Hashtable]$filter) { return $this.request_pagination('GET', "/api/v3/users", $filter) } [object] user([string]$id) { return $this.request('GET', "/api/v3/users/${id}") } [object] nodes() { return $this.request_pagination('GET', "/api/v3/nodes") } [object] nodes([Hashtable]$filter) { return $this.request_pagination('GET', "/api/v3/nodes", $filter) } [object] node([string]$id) { return $this.request('GET', "/api/v3/nodes/${id}") } [object] delete_node([string]$id, [Object]$content) { return $this.request('DELETE', "/api/v3/nodes/${id}", $content) } [object] hosts() { return $this.request_pagination('GET', "/api/v3/hosts") } [object] hosts([Object]$filters) { return $this.request_pagination('GET', '/api/v3/hosts', $filters) } [object] host([string]$id) { return $this.request('GET', "/api/v3/hosts/${id}") } [object] create_host([Object]$content) { return $this.request('POST', '/api/v3/hosts', $content) } [object] update_host([string]$id, [Object]$content) { return $this.request('PUT', "/api/v3/hosts/${id}", $content) } [object] delete_host([string]$id) { return $this.request('DELETE', "/api/v3/hosts/${id}") } [object] security_issues() { return $this.request('GET', "/api/v3/vulnerabilities/security_issues") } [object] security_issues([Object]$filters) { return $this.request_pagination('GET', '/api/v3/vulnerabilities/security_issues', $filters) } [object] security_issue([string]$id) { return $this.request('GET', "/api/v3/vulnerabilities/security_issues/${id}") } [object] create_security_issue([Object]$content) { return $this.request('POST', '/api/v3/vulnerabilities/security_issues', $content) } [object] update_security_issue([string]$id, [Object]$content) { return $this.request('PUT', "/api/v3/vulnerabilities/security_issues/${id}", $content) } [object] delete_security_issue([string]$id) { return $this.request('DELETE', "/api/v3/vulnerabilities/security_issues/${id}") } [object] agents() { return $this.request_pagination('GET', "/api/v3/assets/agents") } [object] agents([Hashtable]$filter) { return $this.request_pagination('GET', "/api/v3/assets/agents", $filter) } [object] agent([string]$id) { return $this.request('GET', "/api/v3/assets/agents/${id}") } [object] delete_agent([string]$id) { return $this.request('DELETE', "/api/v3/assets/agents/${id}") } [object] fetch_airgapped_scripts() { return $this.request('GET', "/api/v2/cbw_scans/scripts") } [object] fetch_airgapped_script([string]$id) { return $this.request('GET', "/api/v2/cbw_scans/scripts/${id}") } [object] upload_airgapped_results([Object]$content) { return $this.request('POST', "/api/v2/cbw_scans/scripts", $content) } [object] compliance_servers() { return $this.request_pagination("GET", "/api/v3/compliance/servers") } [object] compliance_servers([Hashtable]$filter) { return $this.request_pagination("GET", "/api/v3/compliance/servers", $filter) } [object] compliance_server([string]$id) { return $this.request("GET", "/api/v3/compliance/servers/${id}") } [object] recheck_rules([string]$id) { return $this.request("PUT", "/api/v3/compliance/servers/${id}/recheck_rules") } [object] compliance_rules() { return $this.request("GET", "/api/v3/compliance/rules") } [object] compliance_rules([Hashtable]$filter) { return $this.request("GET", "/api/v3/compliance/rules", $filter) } [object] compliance_rule([string]$id) { return $this.request("GET", "/api/v3/compliance/rules/${id}") } [object] create_compliance_rule([Object]$content) { return $this.request("POST", "/api/v3/compliance/rules", $content) } [object] delete_compliance_rule([string]$id) { return $this.request("DELETE", "/api/v3/compliance/rules/${id}") } [object] recheck_servers([string]$id) { return $this.request("PUT", "/api/v3/compliance/rules/${id}/recheck_servers") } [object] stored_credentials() { return $this.request('GET', "/api/v3/assets/credentials") } [object] stored_credentials([Object]$filters) { return $this.request_pagination('GET', '/api/v3/assets/credentials', $filters) } [object] stored_credential([string]$id) { return $this.request('GET', "/api/v3/assets/credentials/${id}") } [object] create_stored_credential([Object]$content) { return $this.request('POST', '/api/v3/assets/credentials', $content) } [object] update_stored_credential([string]$id, [Object]$content) { return $this.request('PUT', "/api/v3/assets/credentials/${id}", $content) } [object] delete_stored_credential([string]$id) { return $this.request('DELETE', "/api/v3/assets/credentials/${id}") } [object] applicative_scans() { return $this.request('GET', "/api/v3/assets/applicative_scans") } [object] applicative_scans([Object]$filters) { return $this.request_pagination('GET', '/api/v3/assets/applicative_scans', $filters) } [object] applicative_scan([string]$id) { return $this.request('GET', "/api/v3/assets/applicative_scans/${id}") } [object] create_applicative_scan([Object]$content) { return $this.request('POST', '/api/v3/assets/applicative_scans', $content) } [object] update_applicative_scan([string]$id, [Object]$content) { return $this.request('PATCH', "/api/v3/assets/applicative_scans/${id}", $content) } [object] delete_applicative_scan([string]$id) { return $this.request('DELETE', "/api/v3/assets/applicative_scans/${id}") } [object] docker_images() { return $this.request('GET', "/api/v3/assets/docker_images") } [object] docker_images([Object]$filters) { return $this.request_pagination('GET', '/api/v3/assets/docker_images', $filters) } [object] docker_image([string]$id) { return $this.request('GET', "/api/v3/assets/docker_images/${id}") } [object] create_docker_image([Object]$content) { return $this.request('POST', '/api/v3/assets/docker_images', $content) } [object] update_docker_image([string]$id, [Object]$content) { return $this.request('PATCH', "/api/v3/assets/docker_images/${id}", $content) } [object] delete_docker_image([string]$id) { return $this.request('DELETE', "/api/v3/assets/docker_images/${id}") } [object] assets() { return $this.request_pagination('GET', "/api/v3/assets/servers") } [object] assets([Hashtable]$filter) { return $this.request_pagination('GET', "/api/v3/assets/servers", $filter) } [object] asset([string]$id) { return $this.request('GET', "/api/v3/assets/servers/${id}") } [object] delete_asset([string]$id) { return $this.request('DELETE', "/api/v3/assets/servers/${id}") } [object] server_reboot([string]$id) { return $this.request('PATCH', "/api/v3/vulnerabilities/servers/${id}/reboot") } [object] server_reboot([string]$id, [Object]$content) { return $this.request('PATCH', "/api/v3/vulnerabilities/servers/${id}/reboot", $content) } [object] operating_systems() { return $this.request('GET', "/api/v3/os") } [object] fetch_compliance_airgapped_scripts([Hashtable]$filter) { return $this.request_pagination('GET', "/api/v2/compliances/scripts", $filter) } [object] upload_compliance_airgapped_results([Object]$content) { return $this.request('POST', "/api/v2/compliances/scripts", $content) } [object] test_deploy_remote_access([string]$id) { return $this.request('PUT', "/api/v3/assets/remote_accesses/${id}/test_deploy") } } function Get-CyberwatchApi { <# .SYNOPSIS Cyberwatch API Powershell Client. .DESCRIPTION Send REST Query to Cyberwatch API .EXAMPLE Get-CyberwatchApi -api_url $API_URL -api_key $API_KEY -secret_key $SECRET_KEY Get-CyberwatchApi -api_url $API_URL -api_key $API_KEY -secret_key $SECRET_KEY -trust_all_certificates $ALLOW_SELFSIGNED .PARAMETER api_url Your Cyberwatch instance base url .PARAMETER api_key Your Cyberwatch API key .PARAMETER secret_key Your Cyberwatch API secret .PARAMETER trust_all_certificates Allows the script to connect to Cyberwatch instances with a self-signed certificate .PARAMETER conf_file Allows you to specify a configuration file to be used to connect to the Cyberwatch API A valid configuration file should include the following parameters: api_key, secret_key, api_url #> Param ( [PARAMETER(Mandatory=$false)][string]$api_url, [PARAMETER(Mandatory=$false)][string]$api_key, [PARAMETER(Mandatory=$false)][string]$secret_key, [PARAMETER(Mandatory=$false)][bool]$trust_all_certificates = $false, [PARAMETER(Mandatory=$false)][string]$conf_file ) # Allow request to self-signed certificate if($trust_all_certificates) { add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy } if(!([string]::IsNullOrEmpty($conf_file))) { if(!(Test-Path $conf_file -PathType Leaf)) { Write-Error -Category ObjectNotFound -TargetObject $conf_file "Config file not found or wrong type" } $conf=@{} Get-Content $conf_file | foreach-object -process { $fields = [regex]::split($_,' = '); if($fields[0].StartsWith("[") -eq $True) { $type = $fields[0].Substring(1, $fields[0].Length-2); $conf.$type = @{} } if(($fields[0].CompareTo("") -ne 0) -and ($fields[0].StartsWith("[") -ne $True)) { $conf[$type][$fields[0].trim()] = $fields[1].trim() } } return [CbwApiClient]::new($conf.cyberwatch.url, $conf.cyberwatch.api_key, $conf.cyberwatch.secret_key) } if( !([string]::IsNullOrEmpty($api_url)) -and !([string]::IsNullOrEmpty($api_key)) -and !([string]::IsNullOrEmpty($secret_key)) ) { return [CbwApiClient]::new($api_url, $api_key, $secret_key) } Write-Error -Category AuthenticationError -RecommendedAction "Please provide Cyberwatch's API information" "Missing API informations or configuration file" } |