├── .gitignore ├── LICENSE ├── README.md ├── action templates ├── email │ ├── diffs-details.liquid │ ├── diffs.liquid │ ├── file-diffs-html.liquid │ ├── file-diffs.liquid │ ├── group-diffs.liquid │ ├── policy-failure-detailed.liquid │ ├── policy-failure-simple.liquid │ └── success-with-messages.liquid ├── jira │ ├── file-diffs.liquid │ ├── job-url.liquid │ ├── node-url.liquid │ ├── policy-failures-detailed.liquid │ ├── policy-failures.liquid │ └── policy-results.liquid └── slack │ ├── diffs.liquid │ └── policy-failures.liquid ├── api ├── perl │ ├── nodes-create-csv.pl │ ├── nodes-create.pl │ ├── nodes-lookup.pl │ ├── os-families-index.pl │ └── os-index.pl ├── powershell │ ├── .keep │ ├── Add-File-Scan-Option.ps1 │ ├── Add-GithubRepoNodes.ps1 │ ├── Aggregate-Diffs.ps1 │ ├── Get-JiraCloudNode.ps1 │ ├── Get-LastPassNode.ps1 │ ├── Get-PingdomNode.ps1 │ ├── List-Stale-Nodes.ps1 │ ├── Update-GithubRepoNodes.ps1 │ ├── add-nodes-via-api-from-csv-template.ps1 │ ├── adding-winrm-nodes.ps1 │ ├── azure_resource_node.ps1 │ ├── change_report.ps1 │ ├── ci-query.md │ ├── ci-query.pdf │ ├── ci-query.ps1 │ ├── custom-node-script-example-oracle.ps1 │ ├── custom_reporting_with_api.ps1 │ ├── enable-winrm-https-1-complete.ps1 │ ├── enable-winrm-https-1.ps1 │ ├── enable-winrm-https-2.ps1 │ ├── export-and-aggregate-diffs-to-csv.ps1 │ ├── export-diffs-to-csv.ps1 │ ├── extract-automation-snippets.ps1 │ ├── get-events-with-paging.ps1 │ ├── get-last-login-events.ps1 │ ├── get-node-last-scanned-dates.ps1 │ ├── get-used-space.ps1 │ ├── ignore_ssl_cert_check.ps1 │ ├── iis-site-logs-enabled.ps1 │ ├── list_nodes.ps1 │ ├── move-extinct-aws-nodes.ps1 │ ├── node-group-attach-policy.ps1 │ ├── node-scan.ps1 │ ├── node-update-alternate-password.ps1 │ ├── node-update-medium-hostname.ps1 │ ├── node-update-ssh-creds.ps1 │ ├── node_diff.ps1 │ ├── nodes-create-csv-ps2.ps1 │ ├── nodes-create-csv.ps1 │ ├── nodes-create.ps1 │ ├── nodes-lookup.ps1 │ ├── nodes.csv │ ├── os-families-index.ps1 │ ├── os-index.ps1 │ ├── powershell-2-web-requests.ps1 │ ├── query_vuln_endpoint.ps1 │ ├── retrieve-backups.ps1 │ ├── scan-nodes-in-node-group.ps1 │ ├── set-hostname-to-display-name.ps1 │ ├── simple-email-for-policy-failure.ps1 │ ├── snippets │ │ └── UpGuard-WebRequest.ps1 │ ├── start-scan-if-connected-and-required.ps1 │ ├── update-externalid-from-ad.ps1 │ ├── update-password-from-node-group.ps1 │ ├── upload-csv.ps1 │ └── using-winrm-without-admin-rights.ps1 ├── python │ ├── .keep │ ├── auto_update_policies.py │ ├── change-nodes-environment.py │ ├── custom-node-remote.py │ ├── custom-node.py │ ├── delete-ec2-config-nodes-from-detected-page.py │ ├── delete-stale-nodes.py │ ├── find-environment-id-by-name.py │ ├── find-nodes-without-external-id.py │ ├── get-last-node-scan.py │ ├── get_file_from_node.py │ ├── list-environments.py │ ├── list-operating-system-ids.py │ ├── load-events.py │ ├── move-extinct-aws-nodes.py │ ├── node-membership-via-csv.py │ ├── nodes-create-csv.py │ ├── nodes-create.py │ ├── nodes-lookup.py │ ├── nodes.csv │ ├── os-families-index.py │ ├── os-index.py │ ├── pull_data_into_splunk.py │ ├── set-hostname-to-display-name.py │ ├── snippets │ │ ├── README.md │ │ ├── requests │ │ │ ├── README.md │ │ │ ├── requirements.txt │ │ │ ├── snippets.py │ │ │ └── template.py │ │ ├── requirements.txt │ │ ├── snippets.py │ │ └── template.py │ ├── start_scan_if_connected_and_required.py │ ├── sync-node-scan-history-to-dir.py │ ├── util │ │ ├── README.md │ │ ├── compact.py │ │ └── requirements.txt │ └── yum-check-update.py ├── ruby │ ├── .keep │ ├── add_and_scan_node.rb │ ├── aggregate_events_for_jira_actions.rb │ ├── api-demo.rb │ ├── custom-node-ms-sql.rb │ ├── example-api-scripts.rb │ ├── extact_nodes_to_csv.rb │ ├── get_events_with_paging.rb │ ├── latest-results.rb │ ├── list_all_operating_system_ids.rb │ ├── list_environment_nodes.rb │ ├── list_environments.rb │ ├── list_node_group_nodes.rb │ ├── list_node_groups.rb │ ├── list_nodes.rb │ ├── node-change-environment.rb │ ├── nodes-create-csv.rb │ ├── nodes-create.rb │ ├── nodes-index.rb │ ├── nodes-lookup.rb │ ├── os-families-index.rb │ ├── os-index.rb │ ├── policies-delete-v2.rb │ ├── policies-delete.rb │ └── upguard-tasks.rb └── shell │ ├── .keep │ ├── create-event.sh │ ├── create-legacy-event.sh │ ├── node-scan.sh │ ├── node-update-password.sh │ ├── nodes-create.sh │ └── retrieve-backup.sh ├── automation ├── ansible │ ├── README.md │ └── upguard_node │ │ ├── library │ │ └── upguard_node.py │ │ ├── play.yml │ │ └── requirements.txt ├── puppet │ ├── upguard-async.rb │ ├── upguard-cv.rb │ ├── upguard.rb │ ├── upguard.yaml │ ├── upguard_rb.md │ └── upguard_rb.pdf └── vrealize-orchestrator │ ├── UpGuard Node Registration.workflow │ ├── UpGuard Nodes Create.workflow │ ├── UpGuard Nodes List.workflow │ ├── UpGuard Nodes Start_Scan.workflow │ ├── readme.md │ ├── vRO - Add a REST host.png │ ├── vRO - REST Operation Start Scan.png │ ├── vRO - REST Operation nodes create.png │ ├── vRO - REST Operation nodes list.png │ ├── vRO - Script Auth Header.png │ ├── vRO - UpGuard Add and Scan SCRIPT.png │ ├── vRO - UpGuard Node Reistration Workflow.png │ ├── vRO - UpGuard Workflows.png │ ├── vRO Login.png │ ├── vRO Workflow - Error.png │ ├── vRO Workflow - UpGuard Nodes.png │ ├── vRO_upguard_node_lookup_persistent.js │ ├── vRealize Orchestrator - Integration Guide.pdf │ └── vro_upguard_node_lookup_transient.js ├── blueprints ├── netapp-cdot.js ├── perl │ └── custom-devices │ │ ├── cisco_call_manager.pl │ │ ├── cisco_nam.pl │ │ ├── cisco_source_fire.pl │ │ ├── esxi.pl │ │ ├── hp_onboard_administrator.pl │ │ ├── lantronix.pl │ │ ├── tripplite.pl │ │ └── upguard_cisco_parser.pl ├── shell │ └── blueprint-demo.sh └── ssh-exec-example.js ├── policies ├── CyberRisk.json ├── MS_SQL_testing.txt ├── PCI_3_2_Audit_Check_Windows.json ├── PCI_3_2_MS-SQL_Windows.json ├── PCI_3_2_Password_Check_RHEL7.json ├── PCI_3_2_Password_Check_Windows.json ├── PCI_3_2_Server_Hardening_Windows.json ├── STIG-Windows-2012.json ├── aws_cis_access_analyzer_policy.json ├── aws_cis_cloudtrail_policy.json ├── aws_cis_config_service_policy.json ├── aws_cis_ebs_policy.json ├── aws_cis_iam_policy.json ├── aws_cis_kms_policy.json ├── aws_cis_rds_policy.json ├── aws_cis_s3_policy.json ├── aws_cis_vpc_policy.json ├── aws_iam_best_practice.json ├── azure_cis_activity_log_alerts_policy.json ├── azure_cis_app_service_policy.json ├── azure_cis_keyvault_policy.json ├── azure_cis_mysql_policy.json ├── azure_cis_postgresql_policy.json ├── azure_cis_security_group_policy.json ├── azure_cis_sql_policy.json ├── azure_cis_storage_policy.json ├── azure_cis_virtual_machine_policy.json ├── bluekeep-cve-check-policy.json ├── dchp_address_pool_utilization (1).json ├── dsc_base_resource_configuration.json ├── dsc_configuration_status.json ├── dsc_lcm_settings.json ├── dsc_package_upguard.json ├── gcp_cis_bigquery_policy.json ├── gcp_cis_clouddns_policy.json ├── gcp_cis_cloudlogging_policy.json ├── gcp_cis_cloudsql_policy.json ├── gcp_cis_gce_policy.json ├── gcp_cis_iam_policy.json ├── gcp_cis_kms_policy.json ├── github2FApolicy.json ├── githubPrivateRepoPolicy.json ├── githubRepoIsNotFork.json ├── githubUserFullNamePolicy.json ├── policy_ipv6_disabled_regkey.json ├── rhel_6_meltdown_spectre_kernel_version_policy ├── rhel_7_meltdown_spectre_kernel_version_check ├── s3_access_control_lists.json ├── s3_bucket_and_content_permission_check.json ├── sles_11.4_meltdown_spectre_kernel_version_check └── windows-meltdown-spectre.json ├── scan-options ├── linux │ └── bash │ │ └── file-hash-by-extension.sh └── windows │ └── powershell │ ├── active-directory-schema.ps1 │ ├── com-plus.ps1 │ ├── computers-in-active-directory.ps1 │ ├── dns-reverse-search.ps1 │ ├── file-hash-by-directory-with-excluded-directories.ps1 │ ├── file-hash-by-directory.ps1 │ ├── fim-scanner.ps1 │ ├── gac.md │ ├── gac.ps1 │ ├── iis-app-pools-dynamic.ps1 │ ├── iis-app-pools-static.ps1 │ ├── iis-section.ps1 │ ├── iis-virtual-directories.ps1 │ ├── iis-website-information.ps1 │ ├── local-security-policies.ps1 │ ├── recursive-file-integrity-check.ps1 │ ├── share-permissions.ps1 │ ├── stored-procedures.ps1 │ ├── system-audit-policies.ps1 │ └── users-in-active-directory.ps1 └── setup and utilities ├── Backup.xml ├── WINRM PS Settings.htm ├── WinRM GPO Info.md ├── bat └── wincm │ └── check-service.bat ├── gpreport.xml └── winrm_v1.zip /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Windows template 3 | # Windows image file caches 4 | Thumbs.db 5 | ehthumbs.db 6 | 7 | # Folder config file 8 | Desktop.ini 9 | 10 | # Recycle Bin used on file shares 11 | $RECYCLE.BIN/ 12 | 13 | # Windows Installer files 14 | *.cab 15 | *.msi 16 | *.msm 17 | *.msp 18 | 19 | # Windows shortcuts 20 | *.lnk 21 | 22 | 23 | ### Vim template 24 | [._]*.s[a-w][a-z] 25 | [._]s[a-w][a-z] 26 | *.un~ 27 | Session.vim 28 | .netrwhist 29 | *~ 30 | 31 | 32 | ### OSX template 33 | .DS_Store 34 | .AppleDouble 35 | .LSOverride 36 | 37 | # Icon must end with two \r 38 | Icon 39 | 40 | # Thumbnails 41 | ._* 42 | 43 | # Files that might appear in the root of a volume 44 | .DocumentRevisions-V100 45 | .fseventsd 46 | .Spotlight-V100 47 | .TemporaryItems 48 | .Trashes 49 | .VolumeIcon.icns 50 | 51 | # Directories potentially created on remote AFP share 52 | .AppleDB 53 | .AppleDesktop 54 | Network Trash Folder 55 | Temporary Items 56 | .apdisk 57 | 58 | # JetBrains 59 | .idea 60 | 61 | 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudhouse Guardian Content 2 | 3 | Open source content available for use with [Guardian](https://cloudhouse.com/cloudhouse-guardian/). 4 | 5 | ## Code 6 | 7 | * Working API usage examples provided in Python, PowerShell, Ruby, Perl and Bash 8 | * Standard parameters that require updating include: `apikey`, `secretkey` and `hostname` 9 | * See the [Using the API](https://help.cloudhouse.com/upguard/using-the-api) support article for further details 10 | 11 | ## Contibuting 12 | 13 | * Issues, and Pull Requests are always welcome. 14 | * Questions and feeback can be sent to [helpdesk@cloudhouse.com](mailto:helpdesk@cloudhouse.com) 15 | -------------------------------------------------------------------------------- /action templates/email/diffs-details.liquid: -------------------------------------------------------------------------------- 1 | {% for diff in diffs %} 2 | {% assign new = diff["new"] %} 3 | 4 | {% for val in diff["old"] %} 5 | {% assign attribute = val[0] %} 6 | 7 | {% assign old_val = val[1] %} 8 | {% assign new_val = new[attribute] %} 9 | 10 | {% if old_val != new_val %} 11 | Item: {{ diff["item"] }}
12 | Attribute: {{ attribute }}
13 | Old Value: {{ old_val }}
14 | New Value: {{ new_val }}

15 | 16 | {% endif %} 17 | {% endfor %} 18 | {% endfor %} 19 | -------------------------------------------------------------------------------- /action templates/email/diffs.liquid: -------------------------------------------------------------------------------- 1 | {% for diff in diffs %} 2 | {{ diff['item'] }} - WAS: {{ diff['old'] }} NOW: {{ diff['new'] }} 3 | {% endfor %} 4 | -------------------------------------------------------------------------------- /action templates/email/file-diffs-html.liquid: -------------------------------------------------------------------------------- 1 |

{{ node }} File Differences

2 | 3 | {% for diff in file_diffs %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% endfor %} 15 |

{{ diff['file_path'] }}

Change Type:{{ diff['changed'] }}
Attributes Changed:{{ diff['changed_attributes'] | join: ", " }}
 
16 |
17 | Click here for full diff details. 18 | -------------------------------------------------------------------------------- /action templates/email/file-diffs.liquid: -------------------------------------------------------------------------------- 1 | File Path, Changed Attributes, Owner, Change Type 2 | --------------------------------------------------------------------------- 3 | {% for diff in file_diffs %}{{ diff['file_path'] }}, {{ diff['changed_attributes'] | join: ":" }}, {{diff['owner'] }}, {{ diff['changed'] }} 4 | {% endfor %} 5 | -------------------------------------------------------------------------------- /action templates/email/group-diffs.liquid: -------------------------------------------------------------------------------- 1 |

{{ node_group_name }} Differences

2 |

For full results click here

3 |
4 | {% for ci in group_diffs %} 5 |

{{ ci[0] | replace: ",", " > " }}

6 | {% for result in ci[1] %} 7 |

Value on node(s):  {% for node in result[1] %}{{ node }}  {% endfor %}

8 |
{{ result[0] }}
9 | {% endfor %} 10 |
11 |
12 | {% endfor %} 13 | -------------------------------------------------------------------------------- /action templates/email/policy-failure-simple.liquid: -------------------------------------------------------------------------------- 1 | ########################################################################################################### 2 | # Description: Print out policy failure results. This will loop over affected nodes and construct a # 3 | # table detailing which policy checks have failed. # 4 | # Event variables required: scan_id OR (job_id AND policy_id) # 5 | # Example event: type=Policy Ran AND variables.success=false # 6 | # Website version required: >= v2.28.0 # 7 | ########################################################################################################### 8 | 9 | {% for f in failures %} 10 | Node name: {{ f[0] }} 11 | 12 | 13 | {% for c in f[1] %} 14 | 15 | 16 | 17 | 25 | 26 | {% endfor %} 27 |
Check: {{ c['name'] }}Result: {{ c['result'] }} 18 | {% for a in c['checks'] %} 19 | 20 | 21 | 22 | 23 | {% endfor %} 24 |
Attribute name{{ a[0] }}
Expected{{ a[1]['expected'] }}
Actual{{ a[1]['actual'] }}
Result{{ a[1]['result'] }}
28 | {% endfor %} 29 | -------------------------------------------------------------------------------- /action templates/email/success-with-messages.liquid: -------------------------------------------------------------------------------- 1 | {% if warnings.size > 0 %} 2 |
3 | Messages for tasks: 4 |
5 | {% for warning in warnings %} 6 | {% if warning.messages.size > 0 %} 7 |
8 | Node: {{ warning.source_name }} 9 |
10 | {% for msg in warning.messages %} 11 |  - {{ msg }} 12 | {% endfor %} 13 | {% endif %} 14 | {% endfor %} 15 | {% else %} 16 | No warnings were generated during this job 17 | {% endif %} -------------------------------------------------------------------------------- /action templates/jira/file-diffs.liquid: -------------------------------------------------------------------------------- 1 | {noformat} 2 | File: {{ path }} 3 | Action: {{ subaction }}{% if new_name %} 4 | New Name: {{ new_name }}{% endif %} 5 | Username: {{ username }} 6 | Timestamp: {{ timestamp }} 7 | {noformat} 8 | -------------------------------------------------------------------------------- /action templates/jira/job-url.liquid: -------------------------------------------------------------------------------- 1 | ########################################################################################################### 2 | # Description: Prints out a job URL. # 3 | # Event variables required: job_id # 4 | # Website version required: >= v2.28.0 # 5 | ########################################################################################################### 6 | 7 | *Job URL* 8 | 9 | {{job_url}} 10 | -------------------------------------------------------------------------------- /action templates/jira/node-url.liquid: -------------------------------------------------------------------------------- 1 | ########################################################################################################### 2 | # Description: Prints out a node URL. # 3 | # Event variables required: node_id # 4 | # Website version required: >= v2.28.0 # 5 | ########################################################################################################### 6 | 7 | *Node URL* 8 | 9 | {{node_url}} 10 | -------------------------------------------------------------------------------- /action templates/jira/policy-failures-detailed.liquid: -------------------------------------------------------------------------------- 1 | ########################################################################################################### 2 | # Description: Builds a table to display detailed policy failure results. # 3 | # Event variables required: node_id # 4 | # Website version required: >= v2.28.0 # 5 | ########################################################################################################### 6 | 7 | *Policy Failure Details* 8 | 9 | {% if node_policy_failures.size > 0 %} 10 | ||Check Path||Expected Value||Actual Value||Result|| 11 | {% for f in node_policy_failures %}{% for c in f[1] %}|{{ f[0] }}, {{ c['name'] }}, {% for a in c['checks'] %}{{ a[0] }}|{% if a[1]['expected'] %}{{ a[1]['expected'] }}{% else %}Absent{% endif %}|{% if a[1]['actual'] %}{{ a[1]['actual'] }}{% else %}Absent{% endif %}|{% if a[1]['result'] == 'failure' %}{color:red}FAIL{color}{% else %}{color:#14892c}PASS{color}{% endif %}| 12 | {% endfor %}{% endfor %}{% endfor %} 13 | {% else %} 14 | No detailed policy results to display. 15 | {% endif %} 16 | -------------------------------------------------------------------------------- /action templates/jira/policy-failures.liquid: -------------------------------------------------------------------------------- 1 | ########################################################################################################### 2 | # Description: Print out policy failure results. This will loop over affected nodes and construct a # 3 | # table detailing which policy checks have failed. # 4 | # Event variables required: scan_id OR (job_id AND policy_id) # 5 | # Example event: type=Policy Ran AND variables.success=false # 6 | # Website version required: >= v2.28.0 # 7 | ########################################################################################################### 8 | 9 | {% for f in failures %} 10 | *{{ f[0] }}* 11 | ||Check||Result|| 12 | {% for p in f[1] %}|{{ p['name'] }}|{{ p['result'] }}| 13 | {% endfor %} 14 | {% endfor %} 15 | 16 | {{ job_url }} 17 | -------------------------------------------------------------------------------- /action templates/jira/policy-results.liquid: -------------------------------------------------------------------------------- 1 | ########################################################################################################### 2 | # Description: Builds a table to display policy results (passing and failing). Color codes accordingly. # 3 | # Event variables required: Can only be used with the "Node First Scanned" event. # 4 | # Website version required: >= v2.28.0 # 5 | ########################################################################################################### 6 | 7 | *Policy Results* 8 | 9 | {% if policy_results.size > 0 %} 10 | ||Policy Name||Result|| 11 | {% for p in policy_results %}|{{ p['policy'] }}|{% if p['passed'] == false %}{color:red}FAIL{color}{% else %}{color:#14892c}PASS{color}{% endif %}| 12 | {% endfor %} 13 | {% else %} 14 | No policy results to display. 15 | {% endif %} 16 | -------------------------------------------------------------------------------- /action templates/slack/diffs.liquid: -------------------------------------------------------------------------------- 1 | {% for diff in diffs %} 2 | {{ diff['item'] }} {% if diff['old'] == nil %}Added{% elsif diff['new'] == nil %}Removed{% else %}Modified{% endif %} 3 | {% if diff['old'] != nil and diff['new'] != nil %}{% assign oldvalues = "" %}{% for att in diff['old'] %}{% assign oldvalues = oldvalues | append: att[0] | append: att[1] %}{% endfor %}{% for att in diff['new'] %}{% assign attstring = att[0] | append: att[1] %}{% unless oldvalues contains attstring %} - Attribute changed: {{ att[0] }} => {{ att[1] }} 4 | {% endunless %}{% endfor %}{% endif %}{% endfor %} 5 | -------------------------------------------------------------------------------- /action templates/slack/policy-failures.liquid: -------------------------------------------------------------------------------- 1 | {{ policy }} failed on {% if ran_on == 'environment' %}environment <{{ instance_hostname }}/reports#/policy/{{ policy_id }}?environment={{ environment_id }}|{{ environment }}>{% elsif ran_on == 'group' %}group <{{ instance_hostname }}/reports#/policy/{{ policy_id }}?node_group={{ group_id }}|{{ group }}>{% else %}node <{{ node_url }}|{{ node }}>{% endif %} 2 | -------------------------------------------------------------------------------- /api/perl/nodes-create-csv.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use JSON::PP ("decode_json"); 4 | use HTTP::Request; 5 | use LWP; 6 | use URI::URL; 7 | 8 | sub add_node { 9 | my (%args) = @_; 10 | 11 | my $body = new URI::URL; 12 | my %nodehash; 13 | foreach my $k (keys %args) { 14 | $nodehash{"node[$k]"} = $args{$k}; 15 | } 16 | 17 | $body->query_form(\%nodehash); 18 | my $body_content = $body->as_string; 19 | $body_content =~ s/^.//; 20 | 21 | # NB: Swap in your custom URL below if you have a dedicated instance 22 | my $url = new URI::URL "https://guardrail.scriptrock.com" . "/api/v1/nodes.json"; 23 | my $request = HTTP::Request->new(POST => $url, 24 | HTTP::Headers->new("Authorization" => "Token token=\"ABCD123456EF7890GH\"", 25 | "Accept" => "application/json")); 26 | $request->content($body_content); 27 | my $browser = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); 28 | 29 | my $response = $browser->request($request); 30 | if ($response->is_success) { 31 | my $json = JSON::PP->new->decode($response->decoded_content); 32 | return $json; 33 | } else { 34 | print STDERR $response->status_line, "\n"; 35 | return undef; 36 | } 37 | } 38 | 39 | my $file = $ARGV[0] or die "Need to get CSV file on the command line\n"; 40 | open(my $data, '<', $file) or die "Could not open '$file' $!\n"; 41 | 42 | while (my $line = <$data>) { 43 | chomp $line; 44 | my @fields = split "," , $line; 45 | if ($#fields == 5) { 46 | add_node( 47 | name => $fields[0], 48 | node_type => $fields[1], 49 | medium_type => $fields[2], 50 | medium_password => $fields[3], 51 | medium_username => $fields[4], 52 | connection_manager_group_id => $fields[5] 53 | ); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /api/perl/nodes-create.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use JSON::PP ("decode_json"); 4 | use HTTP::Request; 5 | use LWP; 6 | use URI::URL; 7 | 8 | my $node = { 9 | name => "host.com", 10 | node_type => "SV", 11 | medium_type => 3, 12 | medium_username => "username", 13 | medium_hostname => "hostname", 14 | connection_manager_group_id => 1 15 | } 16 | 17 | my $body = new URI::URL; 18 | $body->query_form(%node); 19 | my $body_content = $body->as_string; 20 | $body_content =~ s/^.//; 21 | 22 | # NB: Swap in your custom URL below if you have a dedicated instance 23 | my $url = new URI::URL "https://guardrail.scriptrock.com" . 24 | "/api/v1/nodes.json" 25 | my $request = HTTP::Request->new(GET => $url, 26 | HTTP::Headers->new("Authorization" => "Token token=\"AB123456CDEF7890GH\"", 27 | "Accept" => "application/json", 28 | "Content-Type" => "application/json")); 29 | $request->content($body_content); 30 | my $browser = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); 31 | 32 | my $response = $browser->request($request); 33 | if ($response->is_success) { 34 | my $json = JSON::PP->new; 35 | $perl_scalar = $json->decode($response->decoded_content); 36 | $pretty_printed = $json->pretty->encode( $perl_scalar ); # pretty-printing 37 | print $pretty_printed; 38 | } else { 39 | print STDERR $response->status_line, "\n"; 40 | print undef; 41 | } 42 | -------------------------------------------------------------------------------- /api/perl/nodes-lookup.pl: -------------------------------------------------------------------------------- 1 | use JSON::PP ("decode_json"); 2 | use HTTP::Request; 3 | use LWP; 4 | use URI::URL; 5 | 6 | $api_key = 'api key here'; 7 | $secret_key = 'secret key here'; 8 | $url = 'appliance.url.here'; 9 | 10 | my $url = new URI::URL $url . 11 | "/api/v1/nodes/42/add_to_node_group.json?node_group_id=23" 12 | my $request = HTTP::Request->new(GET => $url, 13 | HTTP::Headers->new("Authorization" => "Token token=\"" . $api_key . $secret_key . "\"", 14 | "Accept" => "application/json")); 15 | my $browser = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); 16 | 17 | my $response = $browser->request($request); 18 | if ($response->is_success) { 19 | my $json = JSON::PP->new->decode($response->decoded_content); 20 | return $json; 21 | } else { 22 | print STDERR $response->status_line, "\n"; 23 | return undef; 24 | } -------------------------------------------------------------------------------- /api/perl/os-families-index.pl: -------------------------------------------------------------------------------- 1 | use JSON::PP ("decode_json"); 2 | use HTTP::Request; 3 | use LWP; 4 | use URI::URL; 5 | 6 | my $url = new URI::URL "http://localhost:3000" . 7 | "/api/v1/operating_system_families.json"; 8 | my $request = HTTP::Request->new(GET => $url, 9 | HTTP::Headers->new("Authorization" => "Token token=\"AB123456CDEF7890GH\"", 10 | "Accept" => "application/json")); 11 | my $browser = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); 12 | 13 | my $response = $browser->request($request); 14 | if ($response->is_success) { 15 | my $json = JSON::PP->new; 16 | $perl_scalar = $json->decode($response->decoded_content); 17 | $pretty_printed = $json->pretty->encode($perl_scalar); 18 | print $pretty_printed; 19 | } else { 20 | print STDERR $response->status_line, "\n"; 21 | print undef; 22 | } 23 | -------------------------------------------------------------------------------- /api/perl/os-index.pl: -------------------------------------------------------------------------------- 1 | use JSON::PP ("decode_json"); 2 | use HTTP::Request; 3 | use LWP; 4 | use URI::URL; 5 | 6 | my $url = new URI::URL "http://localhost:3000" . 7 | "/api/v1/operating_systems.json" 8 | my $request = HTTP::Request->new(GET => $url, 9 | HTTP::Headers->new("Authorization" => "Token token=\"AB123456CDEF7890GH\"", 10 | "Accept" => "application/json")); 11 | my $browser = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 }); 12 | 13 | my $response = $browser->request($request); 14 | if ($response->is_success) { 15 | my $json = JSON::PP->new; 16 | $perl_scalar = $json->decode($response->decoded_content); 17 | $pretty_printed = $json->pretty->encode($perl_scalar); 18 | print $pretty_printed; 19 | } else { 20 | print STDERR $response->status_line, "\n"; 21 | print undef; 22 | } 23 | -------------------------------------------------------------------------------- /api/powershell/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/api/powershell/.keep -------------------------------------------------------------------------------- /api/powershell/Add-File-Scan-Option.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [string]$URL = $env:GUARDIAN_URL, 3 | [string]$ApiKey = $env:GUARDIAN_API_KEY, 4 | [string]$SecretKey = $env:GUARDIAN_SECRET_KEY, 5 | [string]$NodeGroup, 6 | [string]$ScanOption, 7 | [switch]$Insecure = $(if ($env:GUARDIAN_INSECURE -eq "true") { $true } else { $false }) 8 | ) 9 | $Headers = @{'Authorization' = "Token token=""$($ApiKey)$($SecretKey)"""; 'Accept' = 'application/json'; 'Content-Type' = 'application/json'} 10 | 11 | # Get the ID for the node group 12 | $GroupID = (Invoke-WebRequest -Headers $Headers -Method "GET" -Uri "$($URL)/api/v2/node_groups/lookup.json?name=$($NodeGroup)" -SkipCertificateCheck:$Insecure|ConvertFrom-Json).node_group_id 13 | if (-not $GroupID) { Write-Output "Couldn't find node group '$($NodeGroup)'";return } 14 | Write-Output "$($NodeGroup) has ID $($GroupID)" 15 | 16 | # Get the current scan options for the node group 17 | $FileScanOptions = (Invoke-WebRequest -Headers $Headers -Method "GET" -Uri "$($URL)/api/v2/node_groups/$($GroupID)/node_group_configuration.json" -SkipCertificateCheck:$Insecure|ConvertFrom-Json).scan_options.scan_directory_options 18 | if ($FileScanOptions -eq $null) { $FileScanOptions = @() } 19 | 20 | if ($ScanOption -eq "") { Write-Output "Existing file scan options: $($FileScanOptions)"; return } 21 | 22 | # Add the new scan option to the file scan options 23 | $Exists = $false 24 | ForEach ($o in $FileScanOptions) { if ($o.path -eq $ScanOption) { $Exists = $true } } 25 | if (-not $Exists) 26 | { 27 | # Add the scan option 28 | Write-Output "Adding file scan option: $($ScanOption)" 29 | $FileScanOptions += @{ path = $ScanOption } 30 | $Body = @{ option_name = "scan_directory_options" ; scan_directory_options = $FileScanOptions } 31 | Write-Output (Invoke-WebRequest -Method "PUT" -Headers $Headers -Uri "$($URL)/api/v2/node_groups/$($GroupID)/set_scan_options.json" -Body (ConvertTo-Json $Body) -SkipCertificateCheck:$Insecure).Content 32 | } else { Write-Output "File scan option already exists: $($ScanOption)" } 33 | 34 | Write-Output "Done!" 35 | -------------------------------------------------------------------------------- /api/powershell/Get-JiraCloudNode.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Scans Jira Cloud configuration for Guardian Script Path (Windows) node type 4 | .DESCRIPTION 5 | Gets application properties, advanced settings and configuration from Jira Cloud API using basic auth and returns it as JSON compatible for use in Guardian's Script Path (Windows) node type 6 | .PARAMETER JiraHostname 7 | Host name of Jira cloud you want to connect to. e.g. 'company.atlassian.net' 8 | .PARAMETER Username 9 | Your Jira username 10 | .PARAMETER ApiToken 11 | Your personal Jira ApiToken 12 | .EXAMPLE 13 | .\Get-JiraCloudNode.ps1 -JiraHostName 'company.atlassian.net' -Username you@company.com -ApiToken {{password}} 14 | 15 | Using this as the script path in Guardian node configuration will scan your Jira configuration 16 | #> 17 | 18 | param ( 19 | [Parameter(Mandatory = $true)] 20 | [string]$JiraHostname, 21 | [Parameter(Mandatory = $true)] 22 | [string]$Username, 23 | [Parameter(Mandatory = $true)] 24 | [string]$ApiToken 25 | ) 26 | 27 | Set-Variable JiraRestUri -Option Constant -Value ("https://$JiraHostname" + '/rest/api/3/') 28 | $headers = @{Authorization = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("${Username}:${ApiToken}")))" } 29 | 30 | $applicationProperties = Invoke-RestMethod ($JiraRestUri + 'application-properties') -Headers $headers 31 | $advancedSettings = Invoke-RestMethod ($JiraRestUri + 'application-properties/advanced-settings') -Headers $headers 32 | $configuration = Invoke-RestMethod ($JiraRestUri + 'configuration') -Headers $headers 33 | 34 | # convert property array into hash 35 | $appPropertyHash = @{} 36 | $applicationProperties | ForEach-Object { 37 | $property = $_ 38 | $appPropertyHash[($property.key)] = $property 39 | } 40 | 41 | $advancedSettingsHash = @{} 42 | $advancedSettings | ForEach-Object { 43 | $setting = $_ 44 | $advancedSettingsHash[($setting.key)] = $setting 45 | } 46 | 47 | 48 | ConvertTo-Json @{'Application Properties' = $appPropertyHash 49 | 'Advanced Settings' = $advancedSettingsHash 50 | 'Configuration' = @{'Configuration' = $configuration} 51 | } 52 | 53 | -------------------------------------------------------------------------------- /api/powershell/Get-LastPassNode.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Scans LastPass for Guardian Script Path (Windows) node type 4 | 5 | .DESCRIPTION 6 | Uses LastPass enterprise API to return user and shared folder information for display in Guardian 7 | 8 | .PARAMETER Cid 9 | Your lastpass company id - available from admin dashboard 10 | 11 | .PARAMETER ProvHash 12 | You provisioning hash from LastPass UI 13 | 14 | .EXAMPLE 15 | .\Get-LastPassNode.ps1 -cid yourcid -ProvHash {{password}} 16 | 17 | Using this as your script path in node configuration will scan LastPass user and shared folder data and present it as a Guardian node 18 | #> 19 | 20 | param ( 21 | [Parameter(Mandatory = $true)] 22 | [string]$cid, 23 | [Parameter(Mandatory = $true)] 24 | [string]$provHash 25 | ) 26 | 27 | $body = @{ 28 | cid = $cid 29 | provhash = $provHash 30 | cmd = 'getuserdata' 31 | apiuser = 'guardian' 32 | } 33 | 34 | 35 | 36 | $response = Invoke-RestMethod 'https://lastpass.com/enterpriseapi.php' -Method POST -Body (ConvertTo-json $body) 37 | 38 | $users = @{} 39 | $response.Users | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name | ForEach-Object { 40 | $id = $_ 41 | $user = $response.Users.$id 42 | $users.($user.Username) = $user 43 | } 44 | 45 | $results = @{Users=$users} 46 | 47 | $body.cmd = 'getsfdata' 48 | 49 | $response = Invoke-RestMethod 'https://lastpass.com/enterpriseapi.php' -Method 'POST' -Body (ConvertTo-json $body) 50 | 51 | $sharedFolders = @{} 52 | $response | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name | ForEach-Object { 53 | $id = $_ 54 | $sf = $response.$id 55 | if ($sf.deleted -eq $true) {return} 56 | $sf | Add-Member -MemberType NoteProperty -Name 'Admins' -Value ($sf.users | Where-Object { $_.can_administer -eq 1} | Select-Object -ExpandProperty username) 57 | $sf | Add-Member -MemberType NoteProperty -Name 'Readonly' -Value ($sf.users | Where-Object { $_.readonly -eq 1} | Select-Object -ExpandProperty username) 58 | $sf | Add-Member -MemberType NoteProperty -Name 'Hide Password' -Value ($sf.users | Where-Object { $_.give -eq 0} | Select-Object -ExpandProperty username) 59 | $sf.Users = $sf.users | Select-Object -ExpandProperty username 60 | $sharedFolders.($sf.sharedfoldername) = $sf 61 | } 62 | 63 | $results['Shared Folders'] = $sharedFolders 64 | 65 | ConvertTo-Json -Depth 4 $results -------------------------------------------------------------------------------- /api/powershell/Get-PingdomNode.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Scans checks in pingdom for Guardian Script Path (Windows) node type 4 | 5 | .PARAMETER APIToken 6 | Your token for access the pingdom api 7 | 8 | .EXAMPLE 9 | .\Get-PingdomNode.ps1 -APIToken {{password}} 10 | 11 | Using the above as the script path in the node configuration and setting the password field with your Pingdom api token will securely scan pingdom checks. 12 | #> 13 | 14 | param ( 15 | [Parameter(Mandatory=$true)] 16 | [string]$APIToken 17 | ) 18 | 19 | $headers = @{Authorization='Bearer ' + $APIToken} 20 | $response = Invoke-RestMethod 'https://api.pingdom.com/api/3.1/checks' -Headers $headers 21 | 22 | # grab parts of the resp 23 | $checksArray = $response.checks 24 | $counts = $response.counts 25 | 26 | # convert the array to hash using name as key 27 | $checks = @{} 28 | $checksArray | ForEach-Object { 29 | $ele = $_ 30 | $key = $ele.name.ToString() 31 | $checks[$key] = $ele 32 | } 33 | 34 | # intermediate node for 2 layers 35 | $res = [pscustomobject]@{ 36 | 'Pingdom Checks' = $checks 37 | counts = [pscustomobject]@{all=$counts} 38 | } 39 | 40 | ConvertTo-Json $res 41 | -------------------------------------------------------------------------------- /api/powershell/adding-winrm-nodes.ps1: -------------------------------------------------------------------------------- 1 | [System.Net.ServicePointManager]::DefaultConnectionLimit = 1000 2 | # Uncomment if using a self-signed certificate 3 | # [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 4 | 5 | $global:server = 'companyname.scriptrock.net' 6 | $global:url = "https://" + $server + "/api/v1" 7 | $apiKey = "" 8 | $secretKey = "" 9 | $global:headers = @{ 10 | Authorization = 'Token token="' + $apiKey + $secretKey + '"' 11 | } 12 | 13 | $MyURI = [System.Uri]$global:url 14 | $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($MyURI) 15 | $ServicePoint.CloseConnectionGroup("") 16 | 17 | function createNode($name) 18 | { 19 | Write-Host "createNode $name" 20 | $body = @{ 21 | node = @{ 22 | name = $name; 23 | medium_hostname = $name; 24 | node_type = "SV"; 25 | medium_type = 7; 26 | medium_port = 5985; 27 | operating_system_family_id = 1; 28 | connection_manager_group_id = ; 29 | } 30 | } | ConvertTo-json -Depth 5 31 | 32 | Invoke-RestMethod -Method Post -Uri ($global:url + "/nodes.json") -Headers $global:headers -Body $body -ContentType "application/json; charset=utf-8" 33 | } 34 | 35 | $names = @( 'node1', 'node2', 'node3' ) 36 | foreach ($name in $names) { 37 | createNode $name 38 | } 39 | -------------------------------------------------------------------------------- /api/powershell/ci-query.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/api/powershell/ci-query.pdf -------------------------------------------------------------------------------- /api/powershell/custom_reporting_with_api.ps1: -------------------------------------------------------------------------------- 1 | $instanceUrl = "https://serverurl.net" 2 | $apiKey = "apiKey" 3 | $secretKey = "secretKey" 4 | $headers = @{ 5 | 'Authorization' = 'Token token="' + $apiKey + $secretKey + '"'; 6 | } 7 | 8 | $cmURL = $instanceUrl + "/api/v2/connection_manager_groups.json" 9 | $envURL = $instanceUrl + "/api/v2/environments.json" 10 | $ngURL = $instanceUrl + "/api/v2/node_groups.json" 11 | 12 | # Get all the lists of Nodes, CM Groups, Environments and Node Groups 13 | $connectionManagerGroups = Invoke-RestMethod -Method "GET" -Uri $cmURL -Headers $headers 14 | $environments = Invoke-RestMethod -Method "GET" -Uri $envURL -Headers $headers 15 | $nodeGroups = Invoke-RestMethod -Method "GET" -Uri $ngURL -Headers $headers 16 | 17 | # Create Hashtables for CM Groups, Node Groups and Environments with ID and Name 18 | 19 | $listConnectionManagers = @{} 20 | $listEnvironment = @{} 21 | $listNodeGroups = @{} 22 | 23 | foreach($cm in $connectionManagerGroups) { 24 | $listConnectionManagers.Add($cm.id, $cm.name) 25 | } 26 | 27 | foreach($env in $environments) { 28 | $listEnvironment.Add($env.id, $env.name) 29 | } 30 | 31 | foreach($ng in $nodeGroups) { 32 | $listNodeGroups.Add($ng.id, $ng.name) 33 | } 34 | 35 | # Get Node Data via API 36 | 37 | for ($i = 1; $i -le 50; $i++ ) 38 | { 39 | $nodeIndex = $instanceUrl + "/api/v2/nodes.json?page=" + $i + "&per_page=50" 40 | $nodes += Invoke-RestMethod -Method "GET" -Uri $nodeIndex -Headers $headers 41 | } 42 | 43 | # Get details for each node and dump data into the CSV 44 | 45 | $fullString = "Node Name, Connection Manager Group, Environment, Node Group, External ID" + "`n" 46 | 47 | foreach($node in $nodes) { 48 | $node = Invoke-RestMethod -Method "GET" -Uri $node.url -Headers $headers 49 | 50 | $cmID = $node.connection_manager_group_id 51 | $envID = $node.environment_id 52 | $ngID = $node.primary_node_group_id 53 | 54 | if ($node.name) { $nodeCSV = $node.name + ", "} else {$nodeCSV = "Null Name, "} 55 | if ($cmID) {$nodeCSV += $listConnectionManagers.Get_Item($cmID) + ", "} else {$nodeCSV += "null, "} 56 | if ($envID) {$nodeCSV += $listEnvironment.Get_Item($envID) + ", "} else {$nodeCSV += "null, "} 57 | if ($ngID) {$nodeCSV += $listNodeGroups.Get_Item($ngID) + ", "} else {$nodeCSV += "null, "} 58 | if ($node.external_id) {$nodeCSV += $node.external_id + "`n"} else {$nodeCSV += "null" + "`n"} 59 | 60 | $fullString += $nodeCSV 61 | } 62 | 63 | $fullString | Set-Content 'export.csv' 64 | -------------------------------------------------------------------------------- /api/powershell/enable-winrm-https-1.ps1: -------------------------------------------------------------------------------- 1 | $MyFQDN = "$env:computername.$env:userdnsdomain" 2 | $CertFile = $env:userprofile + "\" + $MyFQDN 3 | 4 | # Create a self-signed certificate and install it 5 | $Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName $MyFQDN 6 | 7 | # Save the certificate for later export to another box 8 | Export-Certificate -Cert $Cert -FilePath $CertFile 9 | 10 | # Ensure that PSRemoting is enabled 11 | Enable-PSRemoting -SkipNetworkProfileCheck -Force 12 | 13 | # (Optional) Remove the WinRM HTTP listener 14 | Get-ChildItem WSMan:\Localhost\listener | Where -Property Keys -eq "Transport=HTTP" | Remove-Item -Recurse 15 | 16 | # (Optional) Disable the firewall rule for HTTP 17 | Disable-NetFirewallRule -DisplayName "Windows Remote Management (HTTP-In)" 18 | 19 | # Create a HTTPS listener with our certificate thumbprint 20 | New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint –Force 21 | 22 | # Allow inbound traffic on port 5986 23 | New-NetFirewallRule -DisplayName "Windows Remote Management (HTTPS-In)" -Name "Windows Remote Management (HTTPS-In)" -Profile Any -LocalPort 5986 -Protocol TCP 24 | -------------------------------------------------------------------------------- /api/powershell/enable-winrm-https-2.ps1: -------------------------------------------------------------------------------- 1 | Import-Certificate -Filepath "C:\Path\To\Certificate" -CertStoreLocation "Cert:\LocalMachine\Root" 2 | -------------------------------------------------------------------------------- /api/powershell/extract-automation-snippets.ps1: -------------------------------------------------------------------------------- 1 | param ( 2 | [string]$fileName, 3 | [string]$newFileName, 4 | [string]$node, 5 | [string]$pattern, 6 | [string]$type, 7 | [string]$ciType 8 | ) 9 | 10 | $apiKey = "[API_KEY]" 11 | $secretKey = "[SECRET_KEY]" 12 | $headers = @{Authorization = 'Token token="' + $apiKey + $secretKey + '"'} 13 | 14 | $hasInserted = $false 15 | $scanURI = "https://qa.upguard.org/api/v2/nodes/" + $node + "/automation_snippet?type=" + $type + "&ci_type=" + $ciType 16 | $result = Invoke-RestMethod -Method "GET" -Uri $scanURI -Headers $headers 17 | $result = $result.Split("`n") 18 | 19 | Get-Content($fileName) | 20 | Foreach-Object { 21 | if ($_ -match $pattern -and !$hasInserted) { 22 | echo $result 23 | $hasInserted = $true 24 | } 25 | else { 26 | echo $_ 27 | } 28 | } | Set-Content($newFileName) 29 | 30 | #Format: 31 | # > .\extract-automation-snippets.ps1 "c:\oldfilename.txt" "c:\newfilename.txt" "node #" "pattern to search for in file" 32 | # "automation type parameter" "CI type parameter" 33 | -------------------------------------------------------------------------------- /api/powershell/get-last-login-events.ps1: -------------------------------------------------------------------------------- 1 | $Events = @{} 2 | $Days = 2 3 | $computer = $env:COMPUTERNAME 4 | 5 | $eventlogs = Get-EventLog System -Source Microsoft-Windows-WinLogon -After (Get-Date).AddDays(-$Days) -ComputerName $Computer 6 | #$eventlogs = $eventlogs | sort InstanceID,Time -Descending 7 | If ($eventlogs) 8 | { 9 | 10 | $eventlogssort = @() 11 | ForEach ($log in $eventlogs) 12 | { 13 | $User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount]) 14 | if($events.ContainsKey("$User") -eq $false) { 15 | $events["$User"] = New-Object Object 16 | $events["$User"] | Add-Member -MemberType NoteProperty -Name "User" -Value "$User" 17 | } 18 | 19 | if($log.InstanceID -eq 7001) { 20 | $events["$User"] | Add-Member -MemberType NoteProperty -Name "$($log.TimeWritten)" -Value "Log on" 21 | } elseif ($log.InstanceID -eq 7002) { 22 | $events["$User"] | Add-Member -MemberType NoteProperty -Name "$($log.TimeWritten)" -Value "Log 0ff" 23 | } 24 | } 25 | } 26 | 27 | $events.Values -------------------------------------------------------------------------------- /api/powershell/get-used-space.ps1: -------------------------------------------------------------------------------- 1 | $freespace = Get-WmiObject -Class Win32_logicalDisk | ? {$_.DriveType -eq '3'} 2 | $drive = ($FreeSpace.DeviceID).Split("=") 3 | $temp = '' | Select FreeSpace, Drive 4 | $temp.FreeSpace = $freespace.Size - $freespace.FreeSpace 5 | $temp.Drive = $drive[0] 6 | $temp 7 | -------------------------------------------------------------------------------- /api/powershell/ignore_ssl_cert_check.ps1: -------------------------------------------------------------------------------- 1 | add-type @" 2 | using System.Net; 3 | using System.Security.Cryptography.X509Certificates; 4 | public class TrustAllCertsPolicy : ICertificatePolicy { 5 | public bool CheckValidationResult( 6 | ServicePoint srvPoint, X509Certificate certificate, 7 | WebRequest request, int certificateProblem) { 8 | return true; 9 | } 10 | } 11 | "@ 12 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 13 | -------------------------------------------------------------------------------- /api/powershell/iis-site-logs-enabled.ps1: -------------------------------------------------------------------------------- 1 | Import-Module WebAdministration 2 | 3 | $output = @() 4 | foreach ($site in Get-ChildItem IIS:\Sites) { 5 | $obj = New-Object -TypeName PSObject 6 | $obj | Add-Member -MemberType NoteProperty -Name Name -Value $site.name 7 | $sitePath = "IIS:\Sites\" + $site.name 8 | $logsEnabled = (GI $sitePath).logfile.enabled 9 | $obj | Add-Member -MemberType NoteProperty -Name LogsEnabled -Value $logsEnabled 10 | $output += $obj 11 | } 12 | $output 13 | 14 | -------------------------------------------------------------------------------- /api/powershell/node-group-attach-policy.ps1: -------------------------------------------------------------------------------- 1 | ######################################################################################## 2 | # Author: UpGuard # 3 | # Description: This script will add a policy (latest policy version) to a node group. # 4 | # Last updated: April 26, 2017 # 5 | ######################################################################################## 6 | 7 | # Setup API 8 | $upGuardServer = 'https://your.instance.url' 9 | $secretKey = '<< secret key >>' 10 | $serviceAccount = '<< api key >>' 11 | 12 | # Setup variables 13 | $NodeGroupID = x # The node group you are wanting to attach the policy to. 14 | $policyId = y # The policy to attach. 15 | 16 | # Uncomment if using a self-signed certificate 17 | add-type @" 18 | using System.Net; 19 | using System.Security.Cryptography.X509Certificates; 20 | public class TrustAllCertsPolicy : ICertificatePolicy { 21 | public bool CheckValidationResult( 22 | ServicePoint srvPoint, X509Certificate certificate, 23 | WebRequest request, int certificateProblem) { 24 | return true; 25 | } 26 | } 27 | "@ 28 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 29 | 30 | $headers = @{'Authorization' = 'Token token="' + $serviceAccount + $secretKey + '"' 31 | 'Accept' = 'application/json' 32 | 'Content-Type' = 'application/json' 33 | } 34 | 35 | # Make an API call to query the "last" policy version Id. 36 | $getPolicyVersionsCall = $upGuardServer + "/api/v2/policies/" + $policyId + "/versions" 37 | $policyVersions = Invoke-RestMethod -Uri $getPolicyVersionsCall -Headers $headers -Method Get 38 | 39 | "Policy versions found for policy id " + $policyId + " ..." 40 | $policyVersions 41 | 42 | # Policy version id at array index -1 is the "latest" policy version 43 | $latestPolicyVersionId = 0 44 | if ($policyVersions -and $policyVersions[-1]) { 45 | $latestPolicyVersionId = ($policyVersions[-1]).id 46 | } 47 | 48 | # If this is stil 0 (the default value), then something has gone wrong. 49 | if ($latestPolicyVersionId -eq 0) { 50 | "Error: latest policy version not found, quitting." 51 | return 52 | } else { 53 | "Latest policy version id is " + $latestPolicyVersionId 54 | } 55 | 56 | # Make an API call to attach the latest policy version to the node group. 57 | $addPVToNodeGroupCall = $upGuardServer + "/api/v2/node_groups/"+$NodeGroupID + "/add_policy_version?policy_version_id=" + $latestPolicyVersionId 58 | try { 59 | $addPVToNodeGroup = Invoke-RestMethod -Uri $addPVToNodeGroupCall -Headers $headers -Method post 60 | "Attached policy_version_id " + $addPVToNodeGroup.policy_version_id + " to node_group_id " + $addPVToNodeGroup.node_group_id 61 | } catch { 62 | "Policy version already attached or API call has invalid parameters." 63 | } 64 | -------------------------------------------------------------------------------- /api/powershell/node-update-alternate-password.ps1: -------------------------------------------------------------------------------- 1 | # Update the alternate_password for a particular SSH node. 2 | # Can be used to set empty ("") passwords. 3 | 4 | # Ignore SSL certificate errors. Comment out if not needed. 5 | add-type @" 6 | using System.Net; 7 | using System.Security.Cryptography.X509Certificates; 8 | public class TrustAllCertsPolicy : ICertificatePolicy { 9 | public bool CheckValidationResult( 10 | ServicePoint srvPoint, X509Certificate certificate, 11 | WebRequest request, int certificateProblem) { 12 | return true; 13 | } 14 | } 15 | "@ 16 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 17 | 18 | $target_url = "<< target_url >>" # Without scheme 19 | $api_key = "<< api_key >>" 20 | $secret_key = "<< secret_key >>" 21 | $node_id = << node_id >> 22 | $new_password = "" # Blank 23 | 24 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'; 25 | 'Accept' = 'application/json'; 'Content-Type' = 'application/json'} 26 | 27 | # Need to perform an additional lookup to get detailed node information. 28 | $node_details = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/nodes/" + $node_id) -Headers $headers -Method "GET" 29 | $node_details = ConvertFrom-Json -InputObject $node_details 30 | 31 | # Only update password for SSH nodes. 32 | if ($node_details.medium_type -ne 7) 33 | { 34 | "Node is not an SSH node, quitting." 35 | continue 36 | } 37 | 38 | "Updating node id {0} alternate_password..." -f $node_id 39 | 40 | $body = @{"node" = @{"alternate_password" = $new_password}} 41 | $body = ConvertTo-Json -InputObject $body 42 | 43 | $response = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/nodes/ " + $node_id + ".json") -Body $body -Headers $headers -Method "PUT" 44 | if ($response.StatusCode > 400) 45 | { 46 | throw [System.Exception] $response.StatusCode.ToString() + " " + $response.StatusDescription 47 | } else { 48 | $response 49 | } 50 | -------------------------------------------------------------------------------- /api/powershell/node-update-ssh-creds.ps1: -------------------------------------------------------------------------------- 1 | # For SSH nodes in a particular node group, update their username/password. 2 | # Use -dry_run to see what would be changed 3 | 4 | # Ignore SSL certificate errors. Comment out if not needed. 5 | add-type @" 6 | using System.Net; 7 | using System.Security.Cryptography.X509Certificates; 8 | public class TrustAllCertsPolicy : ICertificatePolicy { 9 | public bool CheckValidationResult( 10 | ServicePoint srvPoint, X509Certificate certificate, 11 | WebRequest request, int certificateProblem) { 12 | return true; 13 | } 14 | } 15 | "@ 16 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 17 | 18 | 19 | $target_url = "<< upguard_appliance_hostname >>" # Without scheme 20 | $api_key = "<< api_key >>" 21 | $secret_key = "<< secret_key >>" 22 | $node_group_id = "<< node_group_id >>" 23 | $new_username = "<< new_username >>" 24 | $new_password = "<< new_password >>" 25 | $dry_run = $true 26 | 27 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'; 28 | 'Accept' = 'application/json'; 'Content-Type' = 'application/json'} 29 | 30 | $nodes = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/node_groups/$node_group_id/nodes.json?page=1&per_page=500") -Headers $headers -Method "GET" 31 | 32 | if ($nodes.StatusCode > 400) 33 | { 34 | throw [System.Exception] $nodes.StatusCode.ToString() + 35 | " " + $nodes.StatusDescription 36 | } 37 | else 38 | { 39 | $nodes = ConvertFrom-Json -InputObject $nodes 40 | 41 | ForEach ($node in $nodes) 42 | { 43 | # Need to perform an additional lookup to get detailed node information. 44 | $node_details = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/nodes/" + $node.id) -Headers $headers -Method "GET" 45 | $node_details = ConvertFrom-Json -InputObject $node_details 46 | 47 | # Only update username/password for SSH nodes. 48 | if ($node_details.medium_type -ne 3) { continue } 49 | 50 | "Updating node {0} username/password" -f $node.name 51 | $body = @{"node" = @{"medium_username" = $new_username; "medium_password" = $new_password}} 52 | $body = ConvertTo-Json -InputObject $body 53 | 54 | if ($dry_run -eq $false) 55 | { 56 | $response = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/nodes/ " + $node.id + ".json") -Body $body -Headers $headers -Method "PUT" 57 | if ($response.StatusCode > 400) 58 | { 59 | throw [System.Exception] $response.StatusCode.ToString() + " " + $response.StatusDescription 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /api/powershell/node_diff.ps1: -------------------------------------------------------------------------------- 1 | # Ignore self-signed SSL certificates 2 | add-type @" 3 | using System.Net; 4 | using System.Security.Cryptography.X509Certificates; 5 | public class TrustAllCertsPolicy : ICertificatePolicy { 6 | public bool CheckValidationResult( 7 | ServicePoint srvPoint, X509Certificate certificate, 8 | WebRequest request, int certificateProblem) { 9 | return true; 10 | } 11 | } 12 | "@ 13 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 14 | 15 | 16 | $instance_url = "https://upguard.appliance.url" 17 | $api_key = "<< api_key >>" 18 | $secret_key = "<< service_key >>" 19 | $headers = @{ 20 | 'Authorization' = 'Token token="' + $api_key + $secret_key + '"' 21 | 'Accept' = 'application/json' 22 | } 23 | 24 | $scan_id = "<< scan_id >>" 25 | $compare_scan_id = "<< compare_scan_id >>" 26 | 27 | $node_diff_endpoint = $instance_url + "/api/v2/nodes/diff?scan_id=[scan_id]?compare_scan_id=[compare_scan_id]" 28 | 29 | $node_diff_endpoint = $node_diff_endpoint.Replace("[scan_id]", $scan_id) 30 | $node_diff_endpoint = $node_diff_endpoint.Replace("[compare_scan_id]", $compare_scan_id) 31 | 32 | $response = Invoke-WebRequest $node_diff_endpoint -Method Get -Headers $headers 33 | 34 | if ($response.StatusCode -ge 299) { 35 | throw [System.Exception] $response.StatusCode.ToString() + " " + $response.StatusDescription 36 | } 37 | else { 38 | $diff = $response.Content | ConvertFrom-Json 39 | if ($diff.summary) { 40 | "Diff Summary Stats" 41 | "==================" 42 | $diff.summary 43 | } 44 | if ($diff[1]) { 45 | "Diff Details" 46 | "============" 47 | $diff_details = $diff[1] 48 | $diff_details 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /api/powershell/nodes-create-csv-ps2.ps1: -------------------------------------------------------------------------------- 1 | $apiKey = "YOUR API KEY HERE" 2 | $secretKey = "YOUR SECRET KEY HERE" 3 | $token = $apiKey + $secretKey 4 | $headerPart1 = 'Authorization' 5 | $headerPart2 = 'Token token="' + $token + '"' 6 | # NB: Swap in your custom URL below if you have a dedicated instance 7 | $uri = "https://guardrail.scriptrock.com/api/v1/nodes" 8 | $version = $PSVersionTable.PSVersion.Major 9 | 10 | function add_node($node) { 11 | $body = '' 12 | foreach($kvp in $node["node"].GetEnumerator()) { 13 | $body += 'node[' + $kvp.Key + ']=' + $kvp.Value + '&' 14 | } 15 | 16 | $body = $body.TrimEnd('&') 17 | $enc = [system.Text.Encoding]::UTF8 18 | $bodyBytes = $enc.GetBytes($body) 19 | 20 | # PowerShell 2.0 way 21 | $request = [System.Net.HTTPWebRequest]::Create($uri) 22 | $request.Method="Post" 23 | $request.ContentType = "application/json" 24 | $request.Headers.Set($headerPart1, $headerPart2) 25 | $request.ContentType = "application/x-www-form-urlencoded" 26 | $request.Accept = "application/json" 27 | 28 | $dataStream = $request.GetRequestStream() 29 | $dataStream.Write($bodyBytes, 0, $bodyBytes.Length) 30 | $dataStream.Close() 31 | 32 | $requestStream = $request.GetResponse().GetResponseStream() 33 | $readStream = New-Object System.IO.StreamReader $requestStream 34 | $data = $readStream.ReadToEnd() 35 | $readStream.Dispose(); 36 | $readStream.Close(); 37 | 38 | # The loading of this dll assumes that even though you are on PowerShell 2.0 you have .NET 3.5 installed 39 | [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") 40 | $serialization = New-Object System.Web.Script.Serialization.JavaScriptSerializer 41 | $results = $serialization.DeserializeObject($data) 42 | return $results 43 | } 44 | 45 | foreach ($row in Import-Csv -Header name,nodetype,mediumtype,mediumhostname,mediumusername,mediumpassword,mediumport,connectionmanagergroupid,operatingsystemfamilyid,operatingsystemid "nodes.csv") 46 | { 47 | $node = @{ 48 | "node" = @{ 49 | "name" = $row.name; 50 | "node_type" = $row.nodetype; 51 | "medium_type" = $row.mediumtype; 52 | "medium_hostname" = $row.mediumhostname; 53 | "medium_username" = $row.mediumusername; 54 | "medium_password" = $row.mediumpassword; 55 | "medium_port" = $row.mediumport; 56 | "connection_manager_group_id" = $row.connectionmanagergroupid; 57 | "operating_system_family_id" = $row.operatingsystemfamilyid; 58 | "operating_system_id" = $row.operatingsystemid; 59 | } 60 | } 61 | add_node($node) 62 | } 63 | -------------------------------------------------------------------------------- /api/powershell/nodes-create-csv.ps1: -------------------------------------------------------------------------------- 1 | $apiKey = "YOUR SERVICE API KEY" 2 | $secretKey = "YOUR SECRET KEY" 3 | $uri = "https://guardrail.scriptrock.com/api/v1/nodes" 4 | $csvFileLocation = "C:\location\to\nodes.csv" 5 | $token = $apiKey + $secretKey 6 | 7 | Function add_node($node) 8 | { 9 | try { 10 | $headers = @{ 11 | 'Authorization' = 'Token token="' + $token + '"' 12 | 'Accept' = 'application/json' 13 | } 14 | 15 | $body = '' 16 | foreach($kvp in $node["node"].GetEnumerator()) { 17 | $body += 'node[' + $kvp.Key + ']=' + $kvp.Value + '&' 18 | } 19 | $body = $body.TrimEnd('&') 20 | $body 21 | 22 | $req = Invoke-WebRequest $uri -Method POST -Headers $headers -Body $body 23 | $req.Content | ConvertFrom-Json 24 | 25 | } catch [System.Net.WebException] { 26 | if ($_.Exception.Response) { 27 | $_.Exception.Response 28 | $bodyStream = $_.Exception.Response.GetResponseStream() 29 | $bodyReader = New-Object System.IO.StreamReader($bodyStream) 30 | $bodyReader.BaseStream.Position = 0 31 | $bodyReader.DiscardBufferedData() 32 | $bodyReader.ReadToEnd() 33 | } else { # e.g. SSL errors 34 | $_.Exception.Message 35 | } 36 | } catch { 37 | $_.Exception.Message 38 | } 39 | } 40 | 41 | foreach ($row in Import-Csv -Header name,nodetype,mediumtype,mediumhostname,mediumusername,mediumpassword,mediumport,connectionmanagergroupid,operatingsystemfamilyid,operatingsystemid $csvFileLocation) 42 | { 43 | $node = @{ 44 | "node" = @{ 45 | "name" = $row.name 46 | "node_type" = $row.nodetype 47 | "medium_type" = $row.mediumtype 48 | "medium_hostname" = $row.mediumhostname 49 | "medium_username" = $row.mediumusername 50 | "medium_password" = $row.mediumpassword 51 | "medium_port" = $row.mediumport 52 | "connection_manager_group_id" = $row.connectionmanagergroupid 53 | "operating_system_family_id" = $row.operatingsystemfamilyid 54 | "operating_system_id" = $row.operatingsystemid 55 | } 56 | } 57 | add_node($node) 58 | } 59 | -------------------------------------------------------------------------------- /api/powershell/nodes-create.ps1: -------------------------------------------------------------------------------- 1 | $apiKey = "1234" 2 | $secretKey = "5678" 3 | 4 | $node = @{ 5 | 'name' = 'host.com'; 6 | 'node_type' = 'SV'; 7 | 'medium_type' = 3; 8 | 'medium_username' = 'username'; 9 | 'medium_hostname' = 'hostname'; 10 | 'medium_port' = 22; 11 | 'connection_manager_group_id' = 1 12 | } 13 | 14 | 15 | $headers = @{ 16 | 'Authorization' = 'Token token="' + $apiKey + $secretKey + '"'; 17 | } 18 | 19 | $body = '' 20 | foreach($kvp in $node.GetEnumerator()) { 21 | $body += 'node[' + $kvp.Key + ']=' + $kvp.Value + '&' 22 | } 23 | 24 | $body = $body.TrimEnd('&') 25 | 26 | # NB: Swap in your custom URL below if you have a dedicated instance 27 | $req = Invoke-WebRequest "https://guardrail.scriptrock.com/api/v1/nodes.json" -Method Post -Headers $headers -Body $body 28 | 29 | if ($req.StatusCode -ge 400) { 30 | throw [System.Exception] $req.StatusCode.ToString() + 31 | " " + $req.StatusDescription 32 | } 33 | else { 34 | $req.Content | ConvertFrom-Json 35 | } 36 | -------------------------------------------------------------------------------- /api/powershell/nodes-lookup.ps1: -------------------------------------------------------------------------------- 1 | $secret_key = 'secret key goes here' 2 | $api_key = 'api key goes here' 3 | $url = 'appliance.url.here' 4 | 5 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'; 6 | 'Accept' = 'application/json'} 7 | 8 | $req = Invoke-WebRequest 9 | "http://" + $url + "/api/v1/nodes/42/add_to_node_group.json?node_group_id=23" 10 | -Method "Post" -Headers $headers 11 | 12 | if ($req.StatusCode > 400) 13 | { 14 | throw [System.Exception] $req.StatusCode.ToString() + 15 | " " + $req.StatusDescription 16 | } 17 | else 18 | { 19 | $req.Content | ConvertFrom-Json 20 | } -------------------------------------------------------------------------------- /api/powershell/nodes.csv: -------------------------------------------------------------------------------- 1 | name,SV,7,hostname,,,5985,2,1,123 -------------------------------------------------------------------------------- /api/powershell/os-families-index.ps1: -------------------------------------------------------------------------------- 1 | $secret_key = 'secret key goes here' 2 | $api_key = 'api key goes here' 3 | $url = 'appliance.url.here' 4 | 5 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'; 6 | 'Accept' = 'application/json'} 7 | 8 | $req = Invoke-WebRequest "http://" + $url + "/api/v1/operating_system_families.json" -Headers $headers 9 | 10 | if ($req.StatusCode > 400) 11 | { 12 | throw [System.Exception] $req.StatusCode.ToString() + 13 | " " + $req.StatusDescription 14 | } 15 | else 16 | { 17 | $req.Content | ConvertFrom-Json 18 | } 19 | -------------------------------------------------------------------------------- /api/powershell/os-index.ps1: -------------------------------------------------------------------------------- 1 | $secret_key = 'secret key goes here' 2 | $api_key = 'api key goes here' 3 | $url = 'appliance.url.here' 4 | 5 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'; 6 | 'Accept' = 'application/json'} 7 | 8 | $req = Invoke-WebRequest 9 | "http://" + $url + "/api/v1/operating_systems.json" ` 10 | -Headers $headers 11 | 12 | if ($req.StatusCode > 400) 13 | { 14 | throw [System.Exception] $req.StatusCode.ToString() + 15 | " " + $req.StatusDescription 16 | } 17 | else 18 | { 19 | $req.Content | ConvertFrom-Json 20 | } 21 | -------------------------------------------------------------------------------- /api/powershell/powershell-2-web-requests.ps1: -------------------------------------------------------------------------------- 1 | $apiKey = "YOUR_API_KEY_HERE" 2 | $secretKey = " YOUR_SECRET_KEY_HERE " 3 | $token = $apiKey + $secretKey 4 | $headerPart1 = 'Authorization' 5 | $headerPart2 = 'Token token="' + $token + '"' 6 | $uri = "https://YOUR_GUARDRAIL/api/v1/node_groups/GROUP_NUMBER/nodes.json" 7 | $version = $PSVersionTable.PSVersion.Major 8 | 9 | # PowerShell 2.0 way 10 | $request = [System.Net.HTTPWebRequest]::Create($uri) 11 | $request.Method="Get" 12 | $request.ContentType = "application/json" 13 | $request.Headers.Set($headerPart1, $headerPart2) 14 | 15 | $requestStream = $request.GetResponse().GetResponseStream() 16 | $readStream = New-Object System.IO.StreamReader $requestStream 17 | $data = $readStream.ReadToEnd() 18 | $readStream.Dispose(); 19 | $readStream.Close(); 20 | 21 | # The loading of this dll assumes that even though you are on PowerShell 2.0 you have .NET 3.5 installed 22 | [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") 23 | $serialization = New-Object System.Web.Script.Serialization.JavaScriptSerializer 24 | $results = $serialization.DeserializeObject($data) 25 | 26 | # Raw results 27 | $results 28 | -------------------------------------------------------------------------------- /api/powershell/query_vuln_endpoint.ps1: -------------------------------------------------------------------------------- 1 | $apiKey = "[enter API key here]" 2 | $secretKey = "[enter secret key here]" 3 | $headers = @{Authorization = 'Token token="' + $apiKey + $secretKey + '"'} 4 | 5 | $vulnScanURI = "https://app.upguard.com/api/v2/vulns.json?page=" 6 | $counter = 1 7 | 8 | do { 9 | $name = $vulnScanURI + $counter 10 | $result = Invoke-RestMethod -Method "GET" -Uri $name -Headers $headers 11 | $counter += 1 12 | echo $result 13 | } 14 | until($result.length -eq 0) 15 | -------------------------------------------------------------------------------- /api/powershell/retrieve-backups.ps1: -------------------------------------------------------------------------------- 1 | # Author: UpGuard 2 | # Email: support@upguard.com 3 | # Description: BitsTransfer for downloading very large files without using an excessive amount of system memory. 4 | 5 | Import-Module BitsTransfer 6 | 7 | $username = "<< backup username >>" 8 | $password = "<< backup password >>" 9 | $password_secure = ConvertTo-SecureString $password -AsPlainText -Force 10 | $credentials = New-Object System.Management.Automation.PSCredential ($username, $password_secure) 11 | $backup_endpoint = "https://<< your.appliance.hostname >>/backups/latest.tar.gz" 12 | $backup_location = "C:\Backups\" 13 | $backup_file = Get-Date -Format yyyy-MM-ddTHH-mm-ss 14 | $backup_filepath = $backup_location + $backup_file + ".tar.gz" 15 | 16 | # We make a unique display name for the transfer so that it can be uniquely 17 | # referenced by name and will not return an array of jobs if we have run the 18 | # script multiple times simultaneously. 19 | $display_name = "MyBitsTransfer " + (Get-Date) 20 | 21 | Start-BitsTransfer ` 22 | -Source $backup_endpoint ` 23 | -Destination $backup_filepath ` 24 | -DisplayName $display_name ` 25 | -Authentication Basic ` 26 | -Credential $credentials ` 27 | -Asynchronous 28 | 29 | # Enable CRL Check, Ignore invalid common name in server certificate, Ignore invalid date in server certificate 30 | # & "bitsadmin" /SetSecurityFlags $display_name 7 31 | 32 | $job = Get-BitsTransfer $display_name 33 | 34 | # Create a holding pattern while we wait for the connection to be established 35 | # and the transfer to actually begin. Otherwise the next Do...While loop may 36 | # exit before the transfer even starts. Print the job status as it changes 37 | # from Queued to Connecting to Transferring. 38 | # If the download fails, remove the bad job and exit the loop. 39 | $lastStatus = $job.JobState 40 | Do { 41 | If ($lastStatus -ne $job.JobState) { 42 | $lastStatus = $job.JobState 43 | $job 44 | } 45 | If ($lastStatus -like "*Error*") { 46 | Write-Host "Error connecting to download." 47 | Write-Host $job.ErrorDescription 48 | Get-BitsTransfer | Complete-BitsTransfer 49 | Exit 50 | } 51 | } 52 | while ($lastStatus -ne "Transferred" -and $lastStatus -ne "Transferring") 53 | $job 54 | 55 | # Print the transfer status as we go: 56 | # Date & Time BytesTransferred BytesTotal PercentComplete 57 | do { 58 | Write-Host (Get-Date) $job.BytesTransferred $job.BytesTotal ` 59 | ($job.BytesTransferred/$job.BytesTotal*100) 60 | Start-Sleep -s 10 61 | } 62 | while ($job.BytesTransferred -lt $job.BytesTotal) 63 | 64 | # Print the final status once complete. 65 | Write-Host (Get-Date) $job.BytesTransferred $job.BytesTotal ` 66 | ($job.BytesTransferred/$job.BytesTotal*100) 67 | 68 | Complete-BitsTransfer $job 69 | 70 | # Only keep the last two backups. There is no need to store backups beyond this. 71 | # We sort by Name because it includes a DateTime stamp. 72 | $backup_files = Get-ChildItem $backup_location -Filter *.tar.gz | Sort Name -Descending 73 | if ($backup_files.count -gt 2) { 74 | Remove-Item $backup_files[-1].FullName 75 | } 76 | 77 | #Get-BitsTransfer 78 | #Get-BitsTransfer | Complete-BitsTransfer 79 | #net stop BITS 80 | #net start BITS 81 | -------------------------------------------------------------------------------- /api/powershell/scan-nodes-in-node-group.ps1: -------------------------------------------------------------------------------- 1 | $apiKey = "[API_KEY]" 2 | $secretKey = "[SECRET_KEY]" 3 | $headers = @{Authorization = 'Token token="' + $apiKey + $secretKey + '"'} 4 | 5 | 6 | #Get the list of nodes in the node group 7 | $nodeGroupsURI = "https://[SERVER]/api/v2/node_groups/[NODEGROUPID]/nodes.json" 8 | $nodes = Invoke-RestMethod -Method "GET" -Uri $nodeGroupsURI -Headers $headers 9 | 10 | #Loop over each node in the group and call start scan 11 | foreach($node in $nodes) 12 | { 13 | $url = $node.url + "/start_scan.json?label=[LABEL_HERE]" 14 | Invoke-RestMethod -Method "POST" -Uri $url -Headers $headers 15 | } 16 | -------------------------------------------------------------------------------- /api/powershell/set-hostname-to-display-name.ps1: -------------------------------------------------------------------------------- 1 | # For every node in an UpGuard instance, set the hostname to match the display name 2 | # Use -dry_run to see what would be changed 3 | 4 | param ( 5 | [Parameter(Mandatory=$true)][string]$target_url, 6 | [Parameter(Mandatory=$true)][string]$api_key, 7 | [Parameter(Mandatory=$true)][string]$secret_key, 8 | [switch]$dry_run 9 | ) 10 | 11 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'; 12 | 'Accept' = 'application/json'; 'Content-Type' = 'application/json'} 13 | 14 | $nodes = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/nodes.json?page=1&per_page=500") -Headers $headers -Method "GET" 15 | 16 | if ($nodes.StatusCode > 400) 17 | { 18 | throw [System.Exception] $nodes.StatusCode.ToString() + 19 | " " + $nodes.StatusDescription 20 | } 21 | else 22 | { 23 | $nodes = ConvertFrom-Json -InputObject $nodes 24 | $total = $nodes.Count 25 | $count = 1 26 | ForEach ($node in $nodes) 27 | { 28 | $hostname = $node.name 29 | "Setting node {0} hostname to {1} ({2}/{3})" -f $node.name, $hostname, $count, $total 30 | $body = @{"node" = @{"medium_hostname" = $hostname}} 31 | $body = ConvertTo-Json -InputObject $body 32 | 33 | if ($dry_run -eq $false) 34 | { 35 | $response = Invoke-WebRequest -Uri ("https://" + $target_url + "/api/v2/nodes/ " + $node.id + ".json") -Body $body -Headers $headers -Method "PUT" 36 | if ($response.StatusCode > 400) 37 | { 38 | throw [System.Exception] $response.StatusCode.ToString() + " " + $response.StatusDescription 39 | } 40 | } 41 | 42 | $count = $count + 1 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /api/powershell/simple-email-for-policy-failure.ps1: -------------------------------------------------------------------------------- 1 | # This script will send a simple email (no UpGuard headings) when it picks up a policy failure 2 | # This should be run once a day, after the policy has been run (which is after an environment scan has completed) 3 | 4 | $secret_key = 'secret key goes here' 5 | $api_key = 'api key goes here' 6 | $url = 'appliance.url.here' 7 | $policy_id = 0 8 | $insecure = $true 9 | 10 | # Email Settings 11 | $smtp_server = "" 12 | $from = "" 13 | $to = "" 14 | $subject = "UpGuard Policy Failed" 15 | 16 | $headers = @{'Authorization' = 'Token token="' + $api_key + $secret_key + '"'} 17 | $endpoint = "$($url)/api/v2/policies/$($policy_id)/latest_results.json?failed_only=true" 18 | 19 | if ($insecure) 20 | { 21 | add-type @" 22 | using System.Net; 23 | using System.Security.Cryptography.X509Certificates; 24 | public class TrustAllCertsPolicy : ICertificatePolicy { 25 | public bool CheckValidationResult( 26 | ServicePoint srvPoint, X509Certificate certificate, 27 | WebRequest request, int certificateProblem) { 28 | return true; 29 | } 30 | } 31 | "@ 32 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 33 | } 34 | 35 | $req = Invoke-WebRequest $endpoint -Headers $headers -ContentType "application/json" 36 | 37 | if ($req) 38 | { 39 | if ($req.StatusCode > 400) 40 | { 41 | throw [System.Exception] $req.StatusCode.ToString() + 42 | " " + $req.StatusDescription 43 | } 44 | else 45 | { 46 | $json = $req.Content | ConvertFrom-Json 47 | Write-Output "Found $($json.policy_stats.Count) failed policies" 48 | if ($json.policy_stats.Count -gt 0) 49 | { 50 | $message = "The following nodes have failed:`n`n" 51 | foreach ($result in $json.policy_stats) 52 | { 53 | $message += "* $($result.name)`n" 54 | } 55 | # Send-MailMessage -SmtpServer $smtp_server -From $from -To $to -Body $message 56 | Write-Output $message 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /api/powershell/snippets/UpGuard-WebRequest.ps1: -------------------------------------------------------------------------------- 1 | # Perform an API request and return the result as a Powershell object 2 | # If you need to handle pagination, you can provide the Paginate switch with a CombineAttribute if you 3 | # need to combine pages on a specific attribute 4 | # For example, the /api/v2/nodes.json endpoint returns a list so pages can be combined and return a list 5 | # just by passing the Paginate switch 6 | # Alternatively, the /api/v2/diffs.json endpoint returns statistics along with a "diff_items" attribute 7 | # which contains the list of diffs. Passing the Paginate switch with "diff_items" for CombineAttribute 8 | # will return a usable list 9 | function UpGuard-WebRequest 10 | { 11 | param 12 | ( 13 | [string]$Method = 'Get', 14 | [string]$Endpoint, 15 | [string]$ApiKey, 16 | [string]$SecretKey, 17 | [hashtable]$Body = @{}, 18 | [switch]$Paginate, 19 | [string]$CombineAttribute = "" # To paginate, provide the attribute to combine multiple results 20 | ) 21 | 22 | # Handle very large JSON responses (such as scan data) 23 | # [void][System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") 24 | # $jsonserial= New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer 25 | # $jsonserial.MaxJsonLength = 67108864 26 | 27 | $headers = @{'Authorization' = "Token token=""$($ApiKey)$($SecretKey)"""} 28 | if ($Paginate) { 29 | $result = @() 30 | if ($Body.Keys -notcontains "page") { $Body.page = 1 } 31 | if ($Body.Keys -notcontains "per_page") { $Body.per_page = 50 } 32 | while ($true) { 33 | $new = Invoke-WebRequest -Method $Method -Uri $Endpoint -Headers $headers -Body $Body -ContentType "application/json" 34 | if ($new.StatusCode > 400){throw [System.Exception] "$($new.StatusCode.ToString()) $($new.StatusDescription)"} 35 | $new = ConvertFrom-Json $new.Content 36 | 37 | if ($CombineAttribute -ne "") { 38 | $new = $new | Select -ExpandProperty $CombineAttribute 39 | 40 | $result += $new 41 | if ([int]$new.Count -lt [int]$Body.per_page) { return $result} 42 | } 43 | else { 44 | # No CombineAttribute was provided 45 | $result += $new 46 | if ([int]$new.Count -lt [int]$Body.per_page) { return $result } 47 | } 48 | $Body.page = [int]$Body.page + 1 49 | } 50 | } 51 | if ($Method -in "Get","Delete"){$req = Invoke-WebRequest -Method $Method -Uri $Endpoint -Headers $headers -ContentType "application/json"} 52 | else{$req = Invoke-WebRequest -Method $Method -Uri $Endpoint -Headers $headers -Body $Body -ContentType "application/json"} 53 | if ($req) 54 | { 55 | if ($req.StatusCode > 400){throw [System.Exception] "$($req.StatusCode.ToString()) $($req.StatusDescription)"} 56 | # else{return $jsonserial.DeserializeObject($req.Content)} 57 | else { return ConvertFrom-Json $req.Content } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /api/powershell/update-externalid-from-ad.ps1: -------------------------------------------------------------------------------- 1 | # For all nodes in UpGuard, update the external id by pulling the LDAP DN from AD 2 | # You will be prompted for credentials to query AD 3 | 4 | param ( 5 | [string]$ApiKey = '', 6 | [string]$SecretKey = '', 7 | [string]$Url = 'https://', 8 | [string]$DomainController = '', 9 | [switch]$Insecure, 10 | [switch]$DryRun 11 | ) 12 | 13 | # Ignore SSL certificate if `-insecure` is used 14 | if ($Insecure) 15 | { 16 | add-type @" 17 | using System.Net; 18 | using System.Security.Cryptography.X509Certificates; 19 | public class TrustAllCertsPolicy : ICertificatePolicy { 20 | public bool CheckValidationResult( 21 | ServicePoint srvPoint, X509Certificate certificate, 22 | WebRequest request, int certificateProblem) { 23 | return true; 24 | } 25 | } 26 | "@ 27 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 28 | } 29 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::SSL3 -bor [System.Net.SecurityProtocolType]::TLS; 30 | 31 | $creds = (Get-Credential) 32 | 33 | $headers = @{'Authorization' = "Token token=""$($ApiKey)$($SecretKey)"""; 34 | 'Accept' = 'application/json'; 'Content-Type' = 'application/json'} 35 | 36 | $nodes = Invoke-WebRequest -Uri "https://$($Url)/api/v2/nodes.json?page=1&per_page=50000" -Headers $headers -Method "GET" 37 | 38 | if ($nodes.StatusCode > 400) 39 | { 40 | throw [System.Exception] "$($nodes.StatusCode.ToString()) $($nodes.StatusDescription)" 41 | } 42 | else 43 | { 44 | $nodes = ConvertFrom-Json -InputObject $nodes 45 | 46 | ForEach ($node in $nodes) 47 | { 48 | # Need to perform an additional lookup to get detailed node information. 49 | $node_details = Invoke-WebRequest -Uri "https://$($Url)/api/v2/nodes/$($node.id).json" -Headers $headers -Method "GET" 50 | $node_details = ConvertFrom-Json -InputObject $node_details 51 | 52 | $dn = Get-ADComputer -Identity "$($node_details.name)" -Credential $creds -Server $DomainController 53 | $external_id = "LDAP://$($dn.DistinguishedName)" 54 | 55 | if ($DryRun -eq $false) 56 | { 57 | "Updating node $($node_details.name) external id to $($external_id)" 58 | $body = @{"node" = @{"external_id" = $external_id}} 59 | $body = ConvertTo-Json -InputObject $body 60 | $response = Invoke-WebRequest -Uri "https://$($Url)/api/v2/nodes/$($node.id).json" -Body $body -Headers $headers -Method "PUT" 61 | if ($response.StatusCode > 400) 62 | { 63 | throw [System.Exception] "$($response.StatusCode.ToString()) $($response.StatusDescription)" 64 | } 65 | } else { 66 | "Would update node $($node_details.name) external id to $($external_id)" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /api/powershell/update-password-from-node-group.ps1: -------------------------------------------------------------------------------- 1 | # For all nodes in a node group, update the password for each node 2 | 3 | ############### 4 | # Configuration 5 | ############### 6 | 7 | $target_url = "" # Hostname only, without scheme (leave off https) 8 | $api_key = "" 9 | $secret_key = "" 10 | $from_node_group = 0 11 | $password = "" 12 | $dry_run = $true 13 | 14 | ################### 15 | # End Configuration 16 | ################### 17 | 18 | # Ignore SSL certificate errors. Comment out if not needed. 19 | add-type @" 20 | using System.Net; 21 | using System.Security.Cryptography.X509Certificates; 22 | public class TrustAllCertsPolicy : ICertificatePolicy { 23 | public bool CheckValidationResult( 24 | ServicePoint srvPoint, X509Certificate certificate, 25 | WebRequest request, int certificateProblem) { 26 | return true; 27 | } 28 | } 29 | "@ 30 | [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy 31 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::SSL3 -bor [System.Net.SecurityProtocolType]::TLS; 32 | 33 | $headers = @{'Authorization' = "Token token=""$($api_key)$($secret_key)"""; 34 | 'Accept' = 'application/json'; 'Content-Type' = 'application/json'} 35 | 36 | $nodes = Invoke-WebRequest -Uri "https://$($target_url)/api/v2/node_groups/$($from_node_group)/nodes.json?page=1&per_page=50000" -Headers $headers -Method "GET" 37 | 38 | if ($nodes.StatusCode > 400) 39 | { 40 | throw [System.Exception] "$($nodes.StatusCode.ToString()) $($nodes.StatusDescription)" 41 | } 42 | else 43 | { 44 | $nodes = ConvertFrom-Json -InputObject $nodes 45 | 46 | ForEach ($node in $nodes) 47 | { 48 | if ($dry_run -eq $false) 49 | { 50 | Write-Host -NoNewline "Updating password for node $($node.name)..." 51 | $body = @{"node" = @{"medium_password" = $password}} 52 | $body = ConvertTo-Json -InputObject $body 53 | $response = Invoke-WebRequest -Uri "https://$($target_url)/api/v2/nodes/$($node.id).json" -Body $body -Headers $headers -Method "PUT" 54 | if ($response.StatusCode -eq 204) { Write-Host "OK" } 55 | if ($response.StatusCode > 400) 56 | { 57 | Write-Host "ERROR" 58 | throw [System.Exception] "$($response.StatusCode.ToString()) $($response.StatusDescription)" 59 | } 60 | } else { 61 | "Would update medium_password for node $($node.name)" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /api/powershell/upload-csv.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [string]$url='', 3 | [string]$apiKey='', 4 | [string]$secretKey='', 5 | [string]$file='' 6 | ) 7 | 8 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12; 9 | 10 | function webRequest($requestUrl, $method='GET', $body=$null) { 11 | $headers = @{Authorization = 'Token token="' + $apiKey + $secretKey + '"'} 12 | $response = $null 13 | 14 | try { 15 | Write-Host (@{ 'node' = $body } | ConvertTo-JSON) 16 | $response = Invoke-WebRequest -Uri $requestUrl -Headers $headers -Method $method -Body (@{ 'node' = $body } | ConvertTo-Json) -ContentType 'application/json' 17 | } catch { 18 | Write-Host $_ 19 | } 20 | return $response 21 | } 22 | 23 | $index = 0 24 | 25 | Import-Csv $file | ForEach-Object { 26 | $body = @{} 27 | $row = $_ 28 | $row | Get-Member -MemberType NoteProperty | ForEach-Object { 29 | $body[$_.Name] = $row."$($_.Name)" 30 | } 31 | 32 | $response = webRequest ($url + "/api/v2/nodes.json") 'Post' $body 33 | 34 | if ($response -eq $null -or $response.StatusCode -gt 299) { 35 | Write-Host "Failed to upload row $($index), response code was: $($response.StatusCode)" 36 | } 37 | 38 | $index++ 39 | } -------------------------------------------------------------------------------- /api/python/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/api/python/.keep -------------------------------------------------------------------------------- /api/python/change-nodes-environment.py: -------------------------------------------------------------------------------- 1 | import httplib; 2 | import urllib; 3 | import ssl; 4 | import json; 5 | 6 | # Parameters and constants 7 | api_key = 'api key here' 8 | secret_key = 'secret key here' 9 | url = 'appliance.url.here' # use only FQDN, leave out the 'https://' portion 10 | fromEnv = 4 # Set an environment id to transfer from 11 | toEnv = 3 # Set an environment id to transfer to 12 | 13 | try: 14 | # browser = httplib.HTTPConnection(url) 15 | # -- For HTTPS connections 16 | context = ssl._create_unverified_context() 17 | browser = httplib.HTTPSConnection(url, context=context) 18 | get_headers = {"Authorization": 'Token token="' + api_key + secret_key + '"', 19 | "Accept": "application/json"} 20 | browser.request("GET", "/api/v2/nodes.json", '', get_headers) 21 | get_res = browser.getresponse() 22 | # read() must be called before close(), or it will return an empty string 23 | data = get_res.read() 24 | if get_res.status >= 400: 25 | raise httplib.HTTPException(str(get_res.status) + ' ' + 26 | get_res.reason + (': ' + data.strip() if data.strip() else '')) 27 | else: 28 | print str(get_res.status) + get_res.reason; 29 | 30 | if data != '': 31 | nodes = json.loads(data) 32 | for node in nodes: 33 | node_id = node['id'] 34 | environment_id = node['environment_id'] 35 | 36 | if environment_id == fromEnv: 37 | # Change the node's environment_id = toEnv 38 | output = {'node' : { 'environment_id' : toEnv }} 39 | body = json.dumps(output) 40 | # Begin http connection for API call 41 | # conn = httplib.HTTPConnection(url) 42 | # -- For HTTPS connections 43 | conn = httplib.HTTPSConnection(url, context=context) 44 | put_headers = {"Authorization": 'Token token="' + api_key + secret_key + '"', 45 | "Accept": "application/json", 'Content-Type':'application/json'} 46 | conn.request("PUT", "/api/v2/nodes/" + str(node_id) +".json", 47 | body, put_headers) 48 | update_res = conn.getresponse() 49 | if update_res.status >= 400: 50 | raise httplib.HTTPException(str(update_res.status) + ' ' + 51 | update_res.reason + (': ' + data.strip() if data.strip() else '')) 52 | conn.close(); 53 | # close() must be called after each request, or subsequent requests will fail 54 | browser.close() 55 | 56 | except httplib.HTTPException as h: 57 | print h.message; 58 | finally: 59 | browser.close() 60 | -------------------------------------------------------------------------------- /api/python/custom-node-remote.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import json 4 | import subprocess 5 | 6 | command_list = [ 7 | {'command_name': ['ls'], 'command_args': ['-la', '/var/log']}, 8 | {'command_name': ['hostname'], 'command_args': []}, 9 | {'command_name': ['find'], 'command_args': ['/var/log', '-name', '*.conf']} 10 | ] 11 | 12 | def generate_scan(commands, host=None): 13 | output_data = { 14 | 'Commands': {} 15 | } 16 | 17 | for c in commands: 18 | command_output = execute_command(c, host) 19 | output_data['Commands'][c['command_name'][0]] = { 20 | 'Output': { 21 | 'StdOut': command_output 22 | } 23 | } 24 | 25 | 26 | print(json.dumps(output_data, sort_keys=True, 27 | indent=4, separators=(',', ': '))) 28 | 29 | def execute_command(command, host=None): 30 | if host is not None: 31 | ssh = subprocess.Popen(["ssh", "%s" % host] + command['command_name'] + command['command_args'], 32 | shell=False, 33 | stdout=subprocess.PIPE, 34 | stderr=subprocess.PIPE) 35 | ssh.stdout.flush() 36 | result, error = ssh.communicate() 37 | if result == []: 38 | print >> sys.stderr, "ERROR: %s" % error 39 | return None 40 | else: 41 | return result 42 | else: 43 | process = subprocess.Popen(command['command_name'] + command['command_args'], stdout=subprocess.PIPE) 44 | process.stdout.flush() 45 | process_output, error = process.communicate() 46 | if process_output == []: 47 | print >> sys.stderr, "ERROR: %s" % error 48 | return None 49 | else: 50 | return process_output 51 | 52 | generate_scan(command_list, "user@the.server.address") 53 | -------------------------------------------------------------------------------- /api/python/custom-node.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import json 4 | import subprocess 5 | 6 | command_list = [ 7 | {'command_name': ['ls'], 'command_args': ['-la', '/var/log']}, 8 | {'command_name': ['hostname'], 'command_args': []}, 9 | {'command_name': ['find'], 'command_args': ['/var/log', '-name', '*.conf']} 10 | ] 11 | 12 | def generate_scan(commands): 13 | output_data = { 14 | 'Commands': {} 15 | } 16 | 17 | for c in commands: 18 | process = subprocess.Popen(c['command_name'] + c['command_args'], stdout=subprocess.PIPE) 19 | process.stdout.flush() 20 | process_output = process.communicate() 21 | output_data['Commands'][c['command_name'][0]] = { 22 | 'Output': { 23 | 'StdOut': process_output[0] 24 | } 25 | } 26 | 27 | 28 | print(json.dumps(output_data, sort_keys=True, 29 | indent=4, separators=(',', ': '))) 30 | 31 | generate_scan(command_list) 32 | -------------------------------------------------------------------------------- /api/python/find-environment-id-by-name.py: -------------------------------------------------------------------------------- 1 | # pip3 install upguard 2 | import upguard 3 | 4 | api_key = "1234" 5 | sec_key = "5678" 6 | instance = "https://you.upguard.com" 7 | 8 | o = upguard.Account(instance, api_key, sec_key) 9 | 10 | env = o.environment_by_name("Production") 11 | 12 | print("EnvironmentID:" + str(env.id)) 13 | -------------------------------------------------------------------------------- /api/python/find-nodes-without-external-id.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import httplib 4 | import urllib 5 | import json 6 | import ssl 7 | import argparse 8 | import re 9 | 10 | parser = argparse.ArgumentParser(description='Find any node that does not have an external ID set.') 11 | parser.add_argument('--target-url', required=True, help='URL for the UpGuard instance. This should be the hostname only (appliance.upguard.org instead of https://appliance.upguard.org)') 12 | parser.add_argument('--api-key', required=True, help='API key for the UpGuard instance') 13 | parser.add_argument('--secret-key', required=True, help='Secret key for the UpGuard instance') 14 | parser.add_argument('--insecure', action='store_true', help='Ignore SSL certificate check?') 15 | parser.add_argument('--per-page', type=int, default=100, help='Number of nodes to retrieve in each call. (Default: 100)') 16 | args = parser.parse_args() 17 | 18 | # Initializations 19 | browser = None 20 | 21 | def getNodes(browser, method, endpoint, page=1, per_page=100): 22 | """ 23 | Return a JSON-parsed dictionary of nodes 24 | """ 25 | get_headers = { 26 | "Authorization": "Token token=\"{}{}\"".format(args.api_key, args.secret_key), 27 | "Accept": "application/json"} 28 | 29 | browser.request("GET", "{}?page={}&per_page={}".format(endpoint, page, per_page), '', get_headers) 30 | response = browser.getresponse() 31 | if response.status >= 400: 32 | raise httplib.HTTPException("{}: {}".format(str(response.status), str(response.reason))) 33 | 34 | return json.loads(response.read()) 35 | 36 | try: 37 | # Setup browser object 38 | url = args.target_url 39 | if 'http' in url: 40 | # URL needs to be a hostname, so remove 'https://' 41 | url = re.sub('https?:\/\/', '', url) 42 | browser = httplib.HTTPConnection(url) 43 | if args.insecure: 44 | context = ssl._create_unverified_context() 45 | browser = httplib.HTTPSConnection(url, context=context) 46 | 47 | page = 1 48 | nodes = getNodes(browser, "GET", "/api/v2/nodes.json", page=page, per_page=args.per_page) 49 | print "Searching for nodes without an external ID..." 50 | while nodes: 51 | for node in nodes: 52 | if not node['external_id']: 53 | print "{} (hostname: {})".format(node['name']) 54 | 55 | page += 1 56 | nodes = getNodes(browser, "GET", "/api/v2/nodes.json", page=page, per_page=args.per_page) 57 | 58 | except httplib.HTTPException as h: 59 | print h.message; 60 | finally: 61 | if browser: 62 | browser.close() 63 | -------------------------------------------------------------------------------- /api/python/get-last-node-scan.py: -------------------------------------------------------------------------------- 1 | import httplib; 2 | import urllib; 3 | import json; 4 | import sys; 5 | 6 | def recurse_to_key(obj, key): 7 | if isinstance(obj, dict): 8 | for k, value in obj.iteritems(): 9 | if k == key: 10 | return obj[k] 11 | else: 12 | data = recurse_to_key(value, key) 13 | if data != None: 14 | try: 15 | if isinstance(data, unicode): 16 | return json.loads(unicodedata.normalize('NFKD', data).encode('ascii','ignore')) 17 | else: 18 | return json.loads(data) 19 | except: 20 | return data 21 | elif isinstance(obj, list): 22 | for avalue in obj: 23 | data = recurse_to_key(avalue, key) 24 | if data != None: 25 | try: 26 | if isinstance(data, unicode): 27 | return json.loads(unicodedata.normalize('NFKD', data).encode('ascii','ignore')) 28 | else: 29 | return json.loads(data) 30 | except: 31 | return data 32 | else: 33 | try: 34 | parsed = json.loads(obj) 35 | sdata = recurse_to_key(parsed, key) 36 | if sdata != None: 37 | try: 38 | if isinstance(sdata, unicode): 39 | return json.loads(unicodedata.normalize('NFKD', sdata).encode('ascii','ignore')) 40 | else: 41 | return json.loads(sdata) 42 | except: 43 | return sdata 44 | except: 45 | pass 46 | 47 | return None 48 | 49 | def get_key_info(json_string, key): 50 | parsed = json.loads(json_string) 51 | return recurse_to_key(parsed, key) 52 | 53 | hostname = "your.appliance.address" 54 | api_key = "11111" 55 | secret_key = "222222" 56 | 57 | try: 58 | browser = httplib.HTTPConnection(hostname) 59 | 60 | browser.request("GET", "/api/v2/nodes/1/last_node_scan_details?with_data=true", '', 61 | {"Authorization": "Token token=\"" + api_key + secret_key + "\"", 62 | "Accept": "application/json"}) 63 | res = browser.getresponse() 64 | data = res.read() 65 | 66 | if res.status >= 400: 67 | raise httplib.HTTPException(str(res.status) + ' ' + 68 | res.reason + (': ' + data.strip() if data.strip() else '')) 69 | 70 | browser.close() 71 | 72 | if data != '': 73 | print(json.dumps(get_key_info(data, "Sublime Text")['version'], indent=4)) 74 | else: 75 | print str(res.status) + res.reason; 76 | except httplib.HTTPException as h: 77 | print h.message; 78 | finally: 79 | browser.close() 80 | -------------------------------------------------------------------------------- /api/python/get_file_from_node.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import httplib; 3 | import urllib; 4 | import json; 5 | import argparse; 6 | 7 | api_key = 'YOUR API KEY HERE' 8 | secret_key = 'YOUR SECRET KEY HERE' 9 | url = 'your.url.here' 10 | 11 | def get_file_id(node, file_path): 12 | browser = httplib.HTTPConnection(url) 13 | try: 14 | browser.request('GET', '/api/v2/nodes/' + str(node) + '/ci_data?ci_type=files', '', 15 | {'Authorization': 'Token token="' + api_key + secret_key + '"', 16 | 'Accept':'application/json'}) 17 | res = browser.getresponse() 18 | 19 | data = res.read() 20 | 21 | if res.status >= 400: 22 | print str(res.status) + ' ' + res.reason 23 | raise httplib.HTTPException(str(res.status) + ' ' + res.reason + (': ' + data.strip() if data.strip() else '')) 24 | 25 | 26 | browser.close() 27 | 28 | if data != '': 29 | for t, tval in json.loads(data).iteritems(): 30 | for f, fval in tval.iteritems(): 31 | if f == file_path and 'text_file_id' in fval: 32 | return fval['text_file_id'] 33 | 34 | return None 35 | else: 36 | return str(res.status) + res.reason; 37 | except httplib.HTTPException as h: 38 | return h.message; 39 | finally: 40 | browser.close() 41 | 42 | def get_file(text_file_id): 43 | browser = httplib.HTTPConnection(url) 44 | try: 45 | browser.request('GET', '/api/v2/text_files/' + str(text_file_id), '', 46 | {'Authorization': 'Token token="' + api_key + secret_key + '"', 47 | 'Accept':'application/json'}) 48 | res = browser.getresponse() 49 | 50 | data = res.read() 51 | 52 | if res.status >= 400: 53 | print str(res.status) + ' ' + res.reason 54 | raise httplib.HTTPException(str(res.status) + ' ' + res.reason + (': ' + data.strip() if data.strip() else '')) 55 | 56 | 57 | browser.close() 58 | 59 | if data != '': 60 | return json.loads(data)['data'] 61 | else: 62 | return str(res.status) + res.reason; 63 | except httplib.HTTPException as h: 64 | return h.message; 65 | finally: 66 | browser.close() 67 | 68 | parser = argparse.ArgumentParser(description='Retrieve a file associated with a node.') 69 | parser.add_argument('node_id', help='The ID of the node the file is associated with.') 70 | parser.add_argument('file_path', help='The file path as it is stored in ScriptRock.') 71 | 72 | args = parser.parse_args() 73 | 74 | file_id = get_file_id(int(args.node_id), args.file_path) 75 | if file_id is not None: 76 | print(get_file(file_id)) 77 | else: 78 | print("Requested file not associated with specified node") 79 | -------------------------------------------------------------------------------- /api/python/list-environments.py: -------------------------------------------------------------------------------- 1 | # pip3 install upguard 2 | import upguard 3 | 4 | api_key = "1234" 5 | sec_key = "5678" 6 | instance = "https://you.upguard.com" 7 | 8 | o = upguard.Account(instance, api_key, sec_key) 9 | 10 | es = o.environments() 11 | 12 | for e in es: 13 | print("id:" + str(e.id) + "\tname:" + str(e.name)) 14 | -------------------------------------------------------------------------------- /api/python/list-operating-system-ids.py: -------------------------------------------------------------------------------- 1 | # pip3 install upguard 2 | import upguard 3 | 4 | api_key = "1234" 5 | sec_key = "5678" 6 | instance = "https://you.upguard.com" 7 | 8 | o = upguard.Account(instance, api_key, sec_key) 9 | 10 | oss = o.operating_systems() 11 | 12 | print("os.name,os.id,osf.name,osf.id") 13 | for os in oss: 14 | osf = os.operating_system_family() 15 | print("" + os.name + "," + str(os.id) + "," + osf.name + "," + str(osf.id)) 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /api/python/nodes-create-csv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import csv 4 | import httplib; 5 | import urllib; 6 | import json; 7 | import ssl; 8 | 9 | hostname = "your.appliance.hostname" 10 | api_key = "Appliance API Key" 11 | secret_key = "Appliance Secret Key" 12 | 13 | def add_node(node): 14 | # NB: Swap in your custom URL below if you have a dedicated instance 15 | browser = httplib.HTTPSConnection(hostname, timeout=5, context=ssl._create_unverified_context()) 16 | try: 17 | body = '' 18 | for key, val in node.iteritems(): 19 | body += "node[" + urllib.quote_plus(str(key)) + "]=" + urllib.quote_plus(str(val)) + "&" 20 | 21 | body = body[:-1] 22 | 23 | browser.request("POST", "/api/v2/nodes.json", body, 24 | {"Authorization": "Token token=\"" + api_key + secret_key + "\"", 25 | "Accept": "application/json", 26 | "Content-Type": "application/x-www-form-urlencoded"}) 27 | 28 | res = browser.getresponse() 29 | data = res.read() 30 | 31 | if res.status >= 400: 32 | print str(res.status) + ' ' + res.reason 33 | raise httplib.HTTPException(str(res.status) + ' ' + res.reason + 34 | (': ' + data.strip() if data.strip() else '')) 35 | 36 | browser.close() 37 | 38 | if data != '': 39 | return json.dumps(json.loads(data), sort_keys=True, 40 | indent=4, separators=(',', ': ')) 41 | else: 42 | return str(res.status) + res.reason; 43 | except httplib.HTTPException as h: 44 | return h.message; 45 | finally: 46 | browser.close() 47 | 48 | with open("nodes.csv", "rb") as f: 49 | reader = csv.reader(f) 50 | node = {} 51 | for row in reader: 52 | if row[0] == "node_type": 53 | # Looks like an empty row or heading row, skip 54 | continue 55 | else: 56 | node['node_type'] = row[0] 57 | node['medium_type'] = row[1] 58 | node['medium_username'] = row[2] 59 | node['medium_password'] = row[3] 60 | node['medium_port'] = row[4] 61 | node['connection_manager_group_id'] = row[5] 62 | node['operating_system_family_id'] = row[6] 63 | node['operating_system_id'] = row[7] 64 | node['organisation_id'] = row[8] 65 | node['environment_id'] = row[9] 66 | node['name'] = row[10] 67 | node['medium_hostname'] = row[11] 68 | node['short_description'] = row[12] 69 | print "node=" + str(node) 70 | add_node(node) 71 | -------------------------------------------------------------------------------- /api/python/nodes-create.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import httplib; 4 | import urllib; 5 | import json; 6 | 7 | hostname = "guardrail.scriptrock.com" 8 | api_key = "1234..." 9 | secret_key = "5678..." 10 | 11 | browser = None 12 | 13 | try: 14 | browser = httplib.HTTPSConnection(hostname) 15 | 16 | node = { 17 | "name": "host.com", 18 | "node_type": "SV", 19 | "medium_type": 3, 20 | "medium_username": "username", 21 | "medium_hostname": "hostname", 22 | "connection_manager_group_id": 1, 23 | } 24 | body = '' 25 | for key, val in node.iteritems(): 26 | body += 'node[' + urllib.quote_plus(str(key)) + ']=' + urllib.quote_plus(str(val)) + '&' 27 | 28 | body = body[:-1] 29 | 30 | browser.request("POST", "/api/v1/nodes.json", body, 31 | {"Authorization": "Token token=\"" + api_key + secret_key + "\"", 32 | "Accept": "application/json", 33 | "Content-Type": "application/x-www-form-urlencoded"}) 34 | res = browser.getresponse() 35 | data = res.read() 36 | 37 | if res.status >= 400: 38 | raise httplib.HTTPException(str(res.status) + ' ' + 39 | res.reason + (': ' + data.strip() if data.strip() else '')) 40 | 41 | browser.close() 42 | 43 | if data != '': 44 | print json.dumps(json.loads(data), sort_keys=True, 45 | indent=4, separators=(',', ': ')) 46 | else: 47 | print str(res.status) + res.reason; 48 | except httplib.HTTPException as h: 49 | print h.message; 50 | finally: 51 | if browser != None: 52 | browser.close() 53 | -------------------------------------------------------------------------------- /api/python/nodes-lookup.py: -------------------------------------------------------------------------------- 1 | import httplib; 2 | import urllib; 3 | import json; 4 | 5 | api_key = 'api key here' 6 | secret_key = 'secret key here' 7 | url = 'appliance.url.here' 8 | 9 | try: 10 | browser = httplib.HTTPConnection('localhost:3000') 11 | 12 | browser.request("POST", 13 | "/api/v1/nodes/42/add_to_node_group.json?node_group_id=23", 14 | '', 15 | {"Authorization": 'Token token="' + api_key + secret_key + '"', 16 | "Accept": "application/json", 17 | "Content-Type": "application/x-www-form-urlencoded"}) 18 | res = browser.getresponse() 19 | # read() must be called before close(), or it will return an empty string 20 | data = res.read() 21 | 22 | if res.status >= 400: 23 | raise httplib.HTTPException(str(res.status) + ' ' + 24 | res.reason + (': ' + data.strip() if data.strip() else '')) 25 | 26 | # close() must be called after each request, or subsequent requests will fail 27 | browser.close() 28 | 29 | if data != '': 30 | return json.dumps(json.loads(data), sort_keys=True, 31 | indent=4, separators=(',', ': ')) 32 | else: 33 | return str(res.status) + res.reason; 34 | except httplib.HTTPException as h: 35 | return h.message; 36 | finally: 37 | browser.close() -------------------------------------------------------------------------------- /api/python/nodes.csv: -------------------------------------------------------------------------------- 1 | node_type, medium_type, medium_username, medium_password, medium_port, connection_manager_group_id, operating_system_family_id, operating_system_id, organisation_id, environment_id, name, medium_hostname, short_description 2 | SV,3,username,,22,1,2,231,2,2,hostname1,1.2.3.4,Description #1 3 | SV,3,username,,22,1,2,231,2,2,hostname2,1.2.3.5,Description #2 4 | SV,3,username,,22,1,2,231,2,2,hostname3,1.2.3.6,Description #3 -------------------------------------------------------------------------------- /api/python/os-families-index.py: -------------------------------------------------------------------------------- 1 | import httplib; 2 | import json; 3 | 4 | api_key = 'api key here' 5 | secret_key = 'secret key here' 6 | url = 'appliance.url.here' 7 | 8 | try: 9 | browser = httplib.HTTPConnection(url) 10 | browser.request("GET", "/api/v1/operating_system_families.json", '', 11 | {"Authorization": 'Token token="' + api_key + secret_key + '"', 12 | "Accept": "application/json"}) 13 | res = browser.getresponse() 14 | # read() must be called before close(), or it will return an empty string 15 | data = res.read() 16 | 17 | if res.status >= 400: 18 | raise httplib.HTTPException(str(res.status) + ' ' + 19 | res.reason + (': ' + data.strip() if data.strip() else '')) 20 | 21 | # close() must be called after each request, or subsequent requests will fail 22 | browser.close() 23 | 24 | if data != '': 25 | print json.dumps(json.loads(data), sort_keys=True, 26 | indent=4, separators=(',', ': ')) 27 | else: 28 | print str(res.status) + res.reason; 29 | except httplib.HTTPException as h: 30 | print h.message; 31 | finally: 32 | browser.close() 33 | -------------------------------------------------------------------------------- /api/python/os-index.py: -------------------------------------------------------------------------------- 1 | import httplib; 2 | import json; 3 | 4 | api_key = 'api key here' 5 | secret_key = 'secret key here' 6 | url = 'appliance.url.here' 7 | 8 | try: 9 | browser = httplib.HTTPConnection('localhost:3000') 10 | browser.request("GET", "/api/v1/operating_systems.json", '', 11 | {"Authorization": 'Token token="' + api_key + secret_key + '"', 12 | "Accept": "application/json"}) 13 | res = browser.getresponse() 14 | # read() must be called before close(), or it will return an empty string 15 | data = res.read() 16 | 17 | if res.status >= 400: 18 | raise httplib.HTTPException(str(res.status) + ' ' + 19 | res.reason + (': ' + data.strip() if data.strip() else '')) 20 | 21 | # close() must be called after each request, or subsequent requests will fail 22 | browser.close() 23 | 24 | if data != '': 25 | print json.dumps(json.loads(data), sort_keys=True, 26 | indent=4, separators=(',', ': ')) 27 | else: 28 | print str(res.status) + res.reason; 29 | except httplib.HTTPException as h: 30 | print h.message; 31 | finally: 32 | browser.close() 33 | -------------------------------------------------------------------------------- /api/python/snippets/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | A collection of functions that can be used to interact with the UpGuard API. 4 | 5 | # Requirements 6 | 7 | In order to run the `template.py` file, you will need to install the required packages in `requirements.txt`: 8 | 9 | ``` 10 | pip install -r requirements.txt 11 | ``` 12 | 13 | # Files 14 | 15 | There are two files here: 16 | 17 | * `template.py`: Driving script to demonstrate how to use the functions in `snippets.py` 18 | * `snippets.py`: A collection of functions that can be used in other scripts. 19 | 20 | # Usage 21 | 22 | You can import any functions from the `snippets.py` file for use in your own script. 23 | 24 | First, you will need to import the `getBrowser()` function in order to setup the connection: 25 | 26 | ``` 27 | from snippets import getBrowser 28 | ``` 29 | 30 | Then you can create the connection by passing the URL and the optional `insecure` boolean (which defaults to `False`): 31 | 32 | ``` 33 | browser = getBrowser(target_url="https://appliance.upguard.org", insecure=False) 34 | ``` 35 | 36 | You have a connection setup, but you will need your authentication token in order to make calls to the instance. This is a combination of your api and secret key with no spaces in between: 37 | 38 | ``` 39 | token = "{}{}".format("api_key", "secret_key") 40 | ``` 41 | 42 | Now you have a connection and token you can use to make API calls. For example, if you want to get a list of all the nodes: 43 | 44 | ``` 45 | from snippets import getNodes 46 | nodes = getNodes(browser=browser, token=token, details=True) 47 | print("\n\nNodes\n-----") 48 | for node in nodes: 49 | print("{}\n{}".format(node["name"], node)) 50 | ``` 51 | 52 | Refer to the `template.py` file for more examples. 53 | -------------------------------------------------------------------------------- /api/python/snippets/requests/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | A collection of functions that can be used to interact with the UpGuard API using the requests package. 4 | 5 | # Requirements 6 | 7 | In order to run the `template.py` file or use the `snippets.py` (which uses the `requests` library), you will need to install the required packages in `requirements.txt`: 8 | 9 | ``` 10 | pip install -r requirements.txt 11 | ``` 12 | 13 | # Files 14 | 15 | There are two files here: 16 | 17 | * `template.py`: Driving script to demonstrate how to use the functions in `snippets.py` 18 | * `snippets.py`: A collection of functions that can be used in other scripts. 19 | 20 | # Usage 21 | 22 | You can import any functions from the `snippets.py` file for use in your own script. 23 | 24 | First, you will need to import the `getSession()` function in order to setup the connection: 25 | 26 | ``` 27 | from snippets import getSession 28 | ``` 29 | 30 | Then you can create the session by passing the API key, secret key, and the optional `insecure` boolean (which defaults to `False`): 31 | 32 | ``` 33 | session = getSession( 34 | api_key="api_key", 35 | secret_key="secret_key", 36 | insecure=False) 37 | ``` 38 | 39 | You now have a session setup to make API calls. For example, if you want to get a list of all the nodes: 40 | 41 | ``` 42 | from snippets import getNodes 43 | nodes = getNodes(session=session, url="https://appliance.upguard.org", details=True) 44 | print("\n\nNodes\n-----") 45 | for node in nodes: 46 | print("{}\n{}".format(node["name"], node)) 47 | ``` 48 | 49 | Refer to the `template.py` file for more examples. 50 | -------------------------------------------------------------------------------- /api/python/snippets/requests/requirements.txt: -------------------------------------------------------------------------------- 1 | future 2 | six 3 | requests 4 | -------------------------------------------------------------------------------- /api/python/snippets/requirements.txt: -------------------------------------------------------------------------------- 1 | future 2 | six 3 | -------------------------------------------------------------------------------- /api/python/snippets/template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import print_function 4 | 5 | import argparse 6 | import http.client 7 | from snippets import getBrowser, APICall, getNodes, getNodeGroups, getConnectionManagerGroups, getNodesInCMGroups, getPolicies, getEvents, scan 8 | from datetime import date, timedelta 9 | 10 | parser = argparse.ArgumentParser(description='') 11 | parser.add_argument('--target-url', required=True, help='URL for the UpGuard instance') 12 | parser.add_argument('--api-key', required=True, help='API key for the UpGuard instance') 13 | parser.add_argument('--secret-key', required=True, help='Secret key for the UpGuard instance') 14 | parser.add_argument('--insecure', action='store_true', help='Ignore SSL certificate checks') 15 | args = parser.parse_args() 16 | 17 | try: 18 | browser = getBrowser(target_url=args.target_url, insecure=args.insecure) 19 | token = "{}{}".format(args.api_key, args.secret_key) 20 | 21 | # Nodes 22 | nodes = getNodes(browser=browser, token=token, details=True) 23 | print("\n\nNodes\n-----") 24 | for node in nodes: 25 | print("{}\n{}\n\n".format(node["name"], node)) 26 | 27 | # Node Groups 28 | node_groups = getNodeGroups(browser=browser, token=token, details=True) 29 | print("\n\nNode Groups\n-----") 30 | for group in node_groups: 31 | print("{}\n{}\n\n".format(group["name"], group)) 32 | 33 | # CM Groups 34 | cm_groups = getConnectionManagerGroups(browser=browser, token=token) 35 | print("\n\nConnection Manager Groups\n-------------------------") 36 | for group in cm_groups: 37 | print("{}\n{}\n\n".format(group["name"], group)) 38 | 39 | # CM Groups with Nodes 40 | cm_groups = getConnectionManagerGroups(browser=browser, token=token) 41 | cm_groups_with_nodes = getNodesInCMGroups(browser=browser, token=token) 42 | print("\n\nCM Groups Node Count\n--------------------") 43 | for id, nodes in cm_groups_with_nodes.iteritems(): 44 | group_name = next((g["name"] for g in cm_groups if g["id"] == id), None) 45 | print("{}: {}".format(group_name, len(nodes))) 46 | 47 | # Policies 48 | policies = getPolicies(browser=browser, token=token, details=True) 49 | print("\n\nPolicies\n--------") 50 | for policy in policies: 51 | print("{}\n{}\n\n".format(policy["name"], policy)) 52 | 53 | # Events 54 | events = getEvents(browser=browser, token=token, view="User Logins", since=(date.today() - timedelta(1))) 55 | print("\n\nEvents\n-----") 56 | for event in events: 57 | print("{}\n{}\n\n".format(event["id"], event)) 58 | print("Total Events: {}".format(len(events))) 59 | 60 | # Scan 61 | result = scan(browser=browser, token=token, node="dev", wait=True) 62 | print("Node scanned, result:\n{}".format(str(result))) 63 | 64 | except http.client.HTTPException as h: 65 | print(h.message) 66 | finally: 67 | if browser: 68 | browser.close() 69 | -------------------------------------------------------------------------------- /api/python/sync-node-scan-history-to-dir.py: -------------------------------------------------------------------------------- 1 | 2 | # pip install upguard 3 | import upguard 4 | import json 5 | import os 6 | 7 | api_key = "1234" 8 | sec_key = "5678" 9 | instance = "https://you.upguard.com" 10 | dir_to_save_to = "/tmp/scans" 11 | node_name = "My Example Node" 12 | 13 | try: 14 | os.mkdir(dir_to_save_to) 15 | except OSError as error: 16 | print("Dir already exists") # probably 17 | 18 | o = upguard.Account(instance, api_key, sec_key) 19 | 20 | # you can also find the node by ID, if you know the ID 21 | # node = o.node_by_id(node_id) 22 | node = o.node_by_name(node_name) 23 | 24 | scans = node.node_scans() 25 | for scan in scans: 26 | # reload the scan to load the data 27 | scan.load() 28 | 29 | print("Saving scan at " + str(scan.created_at)) 30 | filename = dir_to_save_to + str(scan.created_at) + ".json" 31 | f = open(filename, "w") 32 | f.write(json.dumps(scan.data)) 33 | f.close() 34 | 35 | print("DONE") 36 | 37 | 38 | -------------------------------------------------------------------------------- /api/python/util/README.md: -------------------------------------------------------------------------------- 1 | # Problem: 2 | 3 | 1) UpGuard node scans must be 3 levels deep to work with the storage and display of scan results 4 | 2) Sometimes custom scripts run from scan.d product JSON structures that are not 3 levels 5 | and contain arrays/lists of maps/dicts at certain levels that don't load well with the 6 | node scan viewer 7 | 8 | # Solution: 9 | This script takes any json object and converts it to a proper 3 levels deep structure 10 | that secure is expecting and that the agents subscribe to. 11 | 12 | # To use: 13 | 14 | Ensure that the `pathlib2` module is installed: `pip install -r requirements.txt` 15 | 16 | `convert_scan` is the function that does all the work 17 | 18 | `example_of_how_to_run` shows how you can read a file and output a fixed json format. 19 | 20 | but you could also just import this script and call `convert_scan` on a given structure. 21 | 22 | # Bugs/Author 23 | 24 | Ask steve.cossell@upguard.com 25 | -------------------------------------------------------------------------------- /api/python/util/requirements.txt: -------------------------------------------------------------------------------- 1 | pathlib2 2 | -------------------------------------------------------------------------------- /api/python/yum-check-update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import json 3 | import subprocess 4 | 5 | # Comma delimited list of packages to exclude 6 | exclude_list = "" 7 | 8 | process = subprocess.Popen(["yum", "check-update", "-q", "-x", exclude_list], stdout=subprocess.PIPE) 9 | (output, err) = process.communicate() 10 | exit_code = process.wait() 11 | 12 | if exit_code == 0 and output == "": 13 | print json.dumps({"exit_code": exit_code, "raw": "Up to date"}) 14 | else: 15 | print json.dumps({"exit_code": exit_code, "raw": output}) 16 | -------------------------------------------------------------------------------- /api/ruby/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/api/ruby/.keep -------------------------------------------------------------------------------- /api/ruby/add_and_scan_node.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/all' 2 | require "httparty" 3 | 4 | @website = "https://.upguard.org" 5 | @api_key = 6 | @secret_key = 7 | @headers = { "Authorization" => "Token token=\"#{@api_key}#{@secret_key}\"" } 8 | 9 | # Key Medium Types 10 | # AGENT = 1 11 | # SSH = 3 12 | # HTTPS = 6 13 | # WINRM = 7 14 | 15 | node = { 16 | "name" => "My Node", 17 | "medium_hostname" => "mynode.mydomain.com", 18 | "node_type" => "SV", 19 | "medium_type" => 3, 20 | "medium_username" => "root", 21 | "connection_manager_group_id" => 1, 22 | "operating_system_family_id" => 2, # Linux 23 | "operating_system_id" => 231, # CentOS 24 | } 25 | 26 | puts "Creating #{node["name"]} node record in UpGuard..." 27 | response = HTTParty.post( 28 | "#{@website}/api/v1/nodes.json", 29 | :headers => @headers, 30 | :body => node.map{|k, v| "node[#{k.to_s}]=#{v.to_s}"}.join('&') 31 | ) 32 | 33 | if response.code == 201 34 | puts " Node #{response["name"]} (id: #{response["id"]} Added to UpGuard)" 35 | node["ug_id"] = response["id"] 36 | puts " Initiating first scan..." 37 | response = HTTParty.post( 38 | "#{@website}/api/v1/nodes/#{node["ug_id"]}/start_scan.json", 39 | :headers => @headers, 40 | :body => node.map{|k, v| "node[#{k.to_s}]=#{v.to_s}"}.join('&') 41 | ) 42 | if response.code == 201 43 | puts " Scan started successfully." 44 | else 45 | puts " Error starting scan." 46 | end 47 | else 48 | puts " Failed to add node #{node["name"]}" 49 | puts " ErrorCode = #{response.code}" 50 | puts " ErrorBody = #{response.body}" 51 | end 52 | -------------------------------------------------------------------------------- /api/ruby/custom-node-ms-sql.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'tiny_tds' 4 | require 'json' 5 | 6 | table = {} 7 | columns = {} 8 | 9 | client = TinyTds::Client.new username: '', password: '', host: '', port: 1433, database: '' 10 | result = client.execute("select * from sys.databases where name = ''") 11 | 12 | result.each do |row| 13 | row.to_hash 14 | row.each do |column_name, column_value| 15 | set = {} 16 | set['value'] = column_value 17 | columns[column_name] = set 18 | end 19 | end 20 | 21 | table['settings'] = columns 22 | puts table.to_json 23 | -------------------------------------------------------------------------------- /api/ruby/extact_nodes_to_csv.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/all' 2 | require "httparty" 3 | 4 | @api_key = 5 | @secret_key = 6 | @website = 'https://' 7 | @headers = { "Authorization" => "Token token=\"#{@api_key}#{@secret_key}\"" } 8 | @output_file = '/tmp/node_extract.csv' 9 | 10 | # Get environments 11 | env_lookup = {} 12 | envs = HTTParty.get("#{@website}/api/v2/environments.json", :headers => @headers) 13 | envs.each do |env| 14 | env_lookup[env["id"]] = env["name"] 15 | end 16 | 17 | # Get Operating System Families 18 | osf_lookup = {} 19 | osfs = HTTParty.get("#{@website}/api/v2/operating_system_families.json", :headers => @headers) 20 | osfs.each do |osf| 21 | osf_lookup[osf["id"]] = osf["name"] 22 | end 23 | 24 | # Get Operating Systems 25 | os_lookup = {} 26 | oss = HTTParty.get("#{@website}/api/v2/operating_systems.json", :headers => @headers) 27 | oss.each do |os| 28 | os_lookup[os["id"]] = os["name"] 29 | end 30 | 31 | # Set up file headers 32 | File.open(@output_file, 'w') { |file| file.write("ID,Name,OSF,OS,Environment,URL\n") } 33 | 34 | # Get nodes 35 | nodes = HTTParty.get("#{@website}/api/v2/nodes.json?page=1&per_page=1000", :headers => @headers) 36 | 37 | # Loop and write to file 38 | nodes.each do |node| 39 | File.open(@output_file, 'a') { |file| file.write("#{node["id"]},#{node["name"]},#{osf_lookup[node["operating_system_family_id"]]},#{os_lookup[node["operating_system_id"]]},#{env_lookup[node["environment_id"]]},#{@website}/node_groups#/nodes/#{node["id"]}\n") } 40 | end 41 | -------------------------------------------------------------------------------- /api/ruby/get_events_with_paging.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/all' 2 | require "httparty" 3 | 4 | @website = "https://" 5 | @api_key = 6 | @secret_key = 7 | @headers = { "Authorization" => "Token token=\"#{@api_key}#{@secret_key}\"" } 8 | page = 1 9 | per_page = 500 10 | events = nil 11 | total = 0 12 | all_events = [] 13 | 14 | # Set fixed parts of the URL 15 | url = "#{@website}/api/v2/events.json?view_name=All&per_page=#{per_page}&date_from=10 days ago" 16 | 17 | while events.nil? || events.count == per_page 18 | puts " Retrieving page #{page} of events for view with url #{url}&page=#{page}" 19 | events = HTTParty.get("#{url}&page=#{page}", :headers => @headers) 20 | 21 | if events.response.code.to_i != 200 22 | puts " ERROR trying to retrieve events:" 23 | puts " #{events.body}" 24 | next 25 | end 26 | 27 | puts " Retrieved #{events.count} events" 28 | all_events += events 29 | page += 1 30 | end 31 | 32 | # Loop through all events 33 | all_events.each do |event| 34 | puts event 35 | end 36 | -------------------------------------------------------------------------------- /api/ruby/latest-results.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'net/http' 4 | require 'json' 5 | 6 | api_key = '<<< API KEY >>>' 7 | secret_key = '<<< SECRET KEY >>>' 8 | url = 'https://app.upguard.com' 9 | node_id = 2458 10 | policy_id = 2116 11 | 12 | uri = URI.join(url, "/api/v2/policies/#{policy_id}/latest_results.json") 13 | req = Net::HTTP::Get.new(uri) 14 | req['Authorization'] = 'Token token="' + api_key + secret_key + '"' 15 | req['Accept'] = 'application/json' 16 | 17 | http = Net::HTTP.new(uri.host, uri.port) 18 | http.use_ssl = (uri.port == 443) 19 | 20 | res = http.request(req) 21 | data = res.body 22 | 23 | if Integer(res.code) >= 400 24 | raise res.code + ' ' + res.message + (data.strip() == '' ? ': ' + data.strip() : '') 25 | end 26 | 27 | if data != '' 28 | response = JSON.load(data) 29 | response['policy_stats'].each do |stat| 30 | if stat['node_id'].to_i == node_id 31 | if stat['fail_count'].to_i == 0 32 | puts "node is passing all policy tests" 33 | elsif 34 | puts "node is failing policy tests" 35 | end 36 | end 37 | end 38 | else 39 | return str(res.code) + res.message; 40 | end 41 | -------------------------------------------------------------------------------- /api/ruby/list_all_operating_system_ids.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/all' 2 | require "httparty" 3 | 4 | @website = "https://.upguard.org" 5 | @api_key = 6 | @secret_key = 7 | @headers = { "Authorization" => "Token token=\"#{@api_key}#{@secret_key}\"" } 8 | 9 | def get_operating_system_ids 10 | osfs = HTTParty.get("#{@website}/api/v2/operating_system_families.json", :headers => @headers) 11 | oss = HTTParty.get("#{@website}/api/v2/operating_systems.json", :headers => @headers) 12 | 13 | osfs.each do |osf| 14 | # Get OS for family 15 | oss.select { |os| os["operating_system_family_id"] == osf["id"] }.each do |os| 16 | puts "OSF ID: #{osf["id"]}, OS ID: #{os["id"]} - #{os["description"]}" 17 | end 18 | puts "" 19 | end 20 | end 21 | 22 | get_operating_system_ids 23 | -------------------------------------------------------------------------------- /api/ruby/node-change-environment.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'erb' 3 | 4 | api_key = "<< your api key" 5 | secret_key = "<< your secret key >>" 6 | combined_key = "#{api_key}#{secret_key}" 7 | upguard_instance = "<< your upguard instance url >>" 8 | hostname = `hostname`.strip 9 | to_environment_id = 1 10 | node_details = '{ "node": { "environment_id": ' + "\"#{to_environment_id}\"" + '} }' 11 | 12 | # We need the node Id to edit the node. We can perform a lookup based on the node's hostname 13 | lookup_resp = `curl -X GET -s -k -H 'Authorization: Token token="#{combined_key}"' -H 'Accept: application/json' -H 'Content-Type: application/json' #{upguard_instance}/api/v2/nodes/lookup?name=#{ERB::Util.url_encode(hostname)}` 14 | if lookup_resp.is_a?(String) && lookup_resp.include?("node_id") 15 | lookup_json = JSON.load(lookup_resp) 16 | node_id = lookup_json['node_id'] 17 | # Update node environment 18 | update_resp = `curl -X PUT -s -k -H 'Authorization: Token token="#{combined_key}"' -H 'Accept: application/json' -H 'Content-Type: application/json' -d '#{node_details}' #{upguard_instance}/api/v2/nodes/#{node_id}` 19 | if update_resp.is_a?(String) && update_resp == "" 20 | puts "upguard: node id #{node_id} updated with environment id #{to_environment_id}" 21 | else 22 | puts "upguard: #{update_resp}" 23 | exit 24 | end 25 | else 26 | puts "upguard: #{lookup_resp}" 27 | exit 28 | end 29 | -------------------------------------------------------------------------------- /api/ruby/nodes-create-csv.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'net/http' 4 | require 'json' 5 | require 'csv' 6 | 7 | def add_node(node) 8 | uri = URI.join('http://localhost:3000', '/api/v1/nodes.json') 9 | req = Net::HTTP::Post.new(uri) 10 | 11 | req.body = node.map{|k, v| "node[#{k.to_s}]=#{v.to_s}"}.join('&') 12 | 13 | req['Authorization'] = 'Token token="ABCD123456EF7890GH"' 14 | req['Content-Type'] = 'application/x-www-form-urlencoded' 15 | 16 | Net::HTTP::start(uri.host, uri.port) do |http| 17 | res = http.request(req) 18 | 19 | data = res.body 20 | 21 | if Integer(res.code) >= 400 22 | raise res.code + ' ' + res.message + (data.strip() == '' ? ': ' + 23 | data.strip() : '') 24 | end 25 | 26 | if data != '' 27 | return JSON.pretty_generate(JSON.load(data), {:indent => ' ', :space => ' '}) 28 | else 29 | return str(res.code) + res.message; 30 | end 31 | end 32 | end 33 | 34 | CSV.foreach('nodes.csv') do |row| 35 | node = { 36 | :name => row[0], 37 | :node_type => row[1], 38 | :medium_type => row[2], 39 | :medium_username => row[3], 40 | :medium_password => row[4], 41 | :connection_manager_group_id => row[5] 42 | } 43 | add_node(node) 44 | end 45 | -------------------------------------------------------------------------------- /api/ruby/nodes-create.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'net/http' 4 | require 'json' 5 | 6 | api_key = "" 7 | secret_key = "" 8 | 9 | node = { 10 | :name => "host.com", 11 | :node_type => "SV", 12 | :medium_type => 3, 13 | :medium_username => "username", 14 | :medium_hostname => "hostname", 15 | :connection_manager_group_id => 1, 16 | } 17 | 18 | # NB: Swap in your custom URL here if you have a dedicated instance 19 | uri = URI.join('https://guardrail.scriptrock.com', '/api/v1/nodes.json') 20 | req = Net::HTTP::Get.new(uri) 21 | req['Authorization'] = 'Token token="AB123456CDEF7890GH"' 22 | req['Accept'] = 'application/json' 23 | req['Content-Type'] = 'application/x-www-form-urlencoded' 24 | req.body = node.map{|k, v| "node[#{k.to_s}]=#{v.to_s}"}.join('&') 25 | 26 | Net::HTTP::start(uri.host, uri.port) do |http| 27 | res = http.request(req) 28 | data = res.body 29 | 30 | if Integer(res.code) >= 400 31 | raise res.code + ' ' + res.message + (data.strip() == '' ? 32 | ': ' + data.strip() : '') 33 | end 34 | 35 | if data != '' 36 | puts JSON.pretty_generate(JSON.load(data), {:indent => ' ', 37 | :space => ' '}) 38 | else 39 | puts str(res.code) + res.message; 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /api/ruby/nodes-index.rb: -------------------------------------------------------------------------------- 1 | @nodes = [] 2 | 3 | while true 4 | 5 | page += 1 6 | puts "Getting page #{page}" 7 | 8 | response = HTTParty.get( 9 | "https://guardrail.scriptrock.com/api/v1/nodes.json?page=#{page}&per_page=#{per_page}", 10 | :headers => { "Authorization" => "Token token=\"#{api_key}#{secret_key}\"", 11 | 'Accept' => 'application/json' } 12 | ) 13 | 14 | if response.code.to_s == "200" 15 | node_array = JSON.parse(response.body) 16 | @nodes << node_array 17 | if node_array.size < per_page 18 | break 19 | end 20 | elsif response.code.to_s != "404" 21 | puts "Error getting nodes: http code=#{response.code}" 22 | end 23 | 24 | end 25 | -------------------------------------------------------------------------------- /api/ruby/nodes-lookup.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | require 'json' 3 | 4 | api_key = 'api key here' 5 | secret_key = 'secret key here' 6 | url = 'appliance.url.here' 7 | 8 | uri = URI.join('https://' + url, 9 | '/api/v1/nodes/42/add_to_node_group.json?node_group_id=23') 10 | req = Net::HTTP::Get.new(uri) 11 | req['Authorization'] = 'Token token="' + api_key + secret_key + '"' 12 | req['Accept'] = 'application/json' 13 | 14 | Net::HTTP::start(uri.host, uri.port) do |http| 15 | res = http.request(req) 16 | data = res.body 17 | 18 | if Integer(res.code) >= 400 19 | raise res.code + ' ' + res.message + (data.strip() == '' ? 20 | ': ' + data.strip() : '') 21 | end 22 | 23 | if data != '' 24 | return JSON.pretty_generate(JSON.load(data), {:indent => ' ', 25 | :space => ' '}) 26 | else 27 | return str(res.code) + res.message; 28 | end 29 | end -------------------------------------------------------------------------------- /api/ruby/os-families-index.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | require 'json' 3 | 4 | api_key = 'api key here' 5 | secret_key = 'secret key here' 6 | url = 'appliance.url.here' 7 | 8 | uri = URI.join('https://' + url, '/api/v1/operating_system_families.json') 9 | req = Net::HTTP::Get.new(uri) 10 | req['Authorization'] = 'Token token="' + api_key + secret_key + '"' 11 | req['Accept'] = 'application/json' 12 | 13 | Net::HTTP::start(uri.host, uri.port) do |http| 14 | res = http.request(req) 15 | data = res.body 16 | 17 | if Integer(res.code) >= 400 18 | raise res.code + ' ' + res.message + (data.strip() == '' ? 19 | ': ' + data.strip() : '') 20 | end 21 | 22 | if data != '' 23 | puts JSON.pretty_generate(JSON.load(data), {:indent => ' ', 24 | :space => ' '}) 25 | else 26 | puts str(res.code) + res.message; 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /api/ruby/os-index.rb: -------------------------------------------------------------------------------- 1 | require 'net/http' 2 | require 'json' 3 | 4 | api_key = 'api key here' 5 | secret_key = 'secret key here' 6 | url = 'appliance.url.here' 7 | 8 | uri = URI.join('https://' + url, '/api/v1/operating_system_families.json') 9 | req = Net::HTTP::Get.new(uri) 10 | req['Authorization'] = 'Token token="' + api_key + secret_key + '"' 11 | req['Accept'] = 'application/json' 12 | 13 | Net::HTTP::start(uri.host, uri.port) do |http| 14 | res = http.request(req) 15 | data = res.body 16 | 17 | if Integer(res.code) >= 400 18 | raise res.code + ' ' + res.message + (data.strip() == '' ? 19 | ': ' + data.strip() : '') 20 | end 21 | 22 | if data != '' 23 | puts JSON.pretty_generate(JSON.load(data), {:indent => ' ', 24 | :space => ' '}) 25 | else 26 | puts str(res.code) + res.message; 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /api/ruby/policies-delete-v2.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'net/http' 4 | require 'json' 5 | 6 | def main 7 | 8 | policies = [] 9 | policies_whitelist = [1389, 1263, 1320, 1267, 1345, 1337, 1316, 1344, 1408] 10 | 11 | # Grab all policies 12 | sr = ScriptRock.new 13 | all_policies = sr.get_policies 14 | all_policies.each do |p| 15 | policies.push(p["id"]) 16 | end 17 | 18 | # Nicely display all policies 19 | puts JSON.pretty_generate(all_policies, {:indent => ' ', :space => ' '}) 20 | 21 | # Remove from this the nodes we have whitelisted 22 | policies_whitelist.each do |w| 23 | if policies.index(w) 24 | policies.delete_at(policies.index(w)) 25 | else 26 | puts "Looks like policy id #{w} (from whitelist) has been deleted by someone" 27 | end 28 | end 29 | 30 | # Delete! 31 | sr.delete_policies(policies) 32 | 33 | end 34 | 35 | class ScriptRock 36 | 37 | $api_key = '<<< API_KEY >>>' 38 | $secret_key = '<<< SECRET_KEY >>>' 39 | $website = 'https://app.upguard.com' 40 | $policies_index_api = '/api/v2/policies' 41 | 42 | def delete_policies(policies) 43 | 44 | policies.each do |p| 45 | 46 | uri = URI.join($website, "#{$policies_index_api}/#{p}") 47 | req = Net::HTTP::Delete.new(uri) 48 | req['Authorization'] = "Token token=\"#{$api_key}#{$secret_key}\"" 49 | req['Accept'] = 'application/json' 50 | req['Content-Type'] = 'application/x-www-form-urlencoded' 51 | 52 | http = Net::HTTP.new(uri.host, uri.port) 53 | http.use_ssl = (uri.scheme == "https") 54 | 55 | res = http.request(req) 56 | data = res.body 57 | 58 | if Integer(res.code) >= 400 59 | raise res.code + ' ' + res.message + (data.strip() == '' ? ': ' + data.strip() : '') 60 | elsif Integer(res.code) == 204 61 | puts "Deleted policy id: #{p}" 62 | end 63 | end 64 | end 65 | 66 | def get_policies 67 | 68 | uri = URI.join($website, $policies_index_api, '?page=1&per_page=50') 69 | req = Net::HTTP::Get.new(uri) 70 | req['Authorization'] = "Token token=\"#{$api_key}#{$secret_key}\"" 71 | req['Accept'] = 'application/json' 72 | req['Content-Type'] = 'application/x-www-form-urlencoded' 73 | 74 | http = Net::HTTP.new(uri.host, uri.port) 75 | http.use_ssl = (uri.scheme == "https") 76 | 77 | res = http.request(req) 78 | data = res.body 79 | 80 | if Integer(res.code) >= 400 81 | raise res.code + ' ' + res.message + (data.strip() == '' ? ': ' + data.strip() : '') 82 | end 83 | 84 | if data != '' 85 | return JSON.parse(data) 86 | #puts JSON.pretty_generate(JSON.load(data), {:indent => ' ', :space => ' '}) 87 | else 88 | puts res.code + res.message; 89 | end 90 | end 91 | end 92 | 93 | main 94 | -------------------------------------------------------------------------------- /api/ruby/policies-delete.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | require 'net/http' 4 | require 'json' 5 | 6 | def main 7 | 8 | policies = [] 9 | policies_whitelist = [1389, 1263, 1320, 1267, 1345, 1337, 1316, 1344, 1408] 10 | 11 | # Grab all policies 12 | sr = ScriptRock.new 13 | all_policies = sr.get_policies 14 | all_policies.each do |p| 15 | policies.push(p["id"]) 16 | end 17 | 18 | # Nicely display all policies 19 | puts JSON.pretty_generate(all_policies, {:indent => ' ', :space => ' '}) 20 | 21 | # Remove from this the nodes we have whitelisted 22 | policies_whitelist.each do |w| 23 | if policies.index(w) 24 | policies.delete_at(policies.index(w)) 25 | else 26 | puts "Looks like policy id #{w} (from whitelist) has been deleted by someone" 27 | end 28 | end 29 | 30 | # Delete! 31 | sr.delete_policies(policies) 32 | 33 | end 34 | 35 | class ScriptRock 36 | 37 | $api_key = '<<< API_KEY >>>' 38 | $secret_key = '<<< SECRET_KEY >>>' 39 | $website = 'https://guardrail.scriptrock.com' 40 | $policies_index_api = '/api/v1/policies' 41 | 42 | def delete_policies(policies) 43 | 44 | policies.each do |p| 45 | 46 | uri = URI.join($website, "#{$policies_index_api}/#{p}") 47 | req = Net::HTTP::Delete.new(uri) 48 | req['Authorization'] = "Token token=\"#{$api_key}#{$secret_key}\"" 49 | req['Accept'] = 'application/json' 50 | req['Content-Type'] = 'application/x-www-form-urlencoded' 51 | 52 | http = Net::HTTP.new(uri.host, uri.port) 53 | http.use_ssl = (uri.scheme == "https") 54 | 55 | res = http.request(req) 56 | data = res.body 57 | 58 | if Integer(res.code) >= 400 59 | raise res.code + ' ' + res.message + (data.strip() == '' ? ': ' + data.strip() : '') 60 | elsif Integer(res.code) == 204 61 | puts "Deleted policy id: #{p}" 62 | end 63 | end 64 | end 65 | 66 | def get_policies 67 | 68 | uri = URI.join($website, $policies_index_api, '?page=1&per_page=50') 69 | req = Net::HTTP::Get.new(uri) 70 | req['Authorization'] = "Token token=\"#{$api_key}#{$secret_key}\"" 71 | req['Accept'] = 'application/json' 72 | req['Content-Type'] = 'application/x-www-form-urlencoded' 73 | 74 | http = Net::HTTP.new(uri.host, uri.port) 75 | http.use_ssl = (uri.scheme == "https") 76 | 77 | res = http.request(req) 78 | data = res.body 79 | 80 | if Integer(res.code) >= 400 81 | raise res.code + ' ' + res.message + (data.strip() == '' ? ': ' + data.strip() : '') 82 | end 83 | 84 | if data != '' 85 | return JSON.parse(data) 86 | #puts JSON.pretty_generate(JSON.load(data), {:indent => ' ', :space => ' '}) 87 | else 88 | puts res.code + res.message; 89 | end 90 | end 91 | end 92 | 93 | main 94 | -------------------------------------------------------------------------------- /api/shell/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/api/shell/.keep -------------------------------------------------------------------------------- /api/shell/create-event.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | curl -X POST \ 5 | https://example.upguard.com/api/v2/events.json \ 6 | -H 'Authorization: Token token=""' \ 7 | -H 'Content-Type: application/json' \ 8 | --data '{ "user_id": 2, "node_id": 123, "variables": { "type": "jenkins deploy" } }' 9 | -------------------------------------------------------------------------------- /api/shell/create-legacy-event.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: 4 | # chmod +x api-timeline.sh 5 | # ./api-timeline.sh -c "Build" -a "Started" -s 2 -i "jira" -d 15 -e "Deploy to production" 6 | 7 | while [[ $# > 0 ]] 8 | do 9 | key="$1" 10 | 11 | case $key in 12 | -c|--category) 13 | CATEGORY="$2" 14 | shift # past argument 15 | ;; 16 | -a|--action) 17 | ACTION="$2" 18 | shift 19 | ;; 20 | -s|--status) 21 | STATUS="$2" 22 | shift 23 | ;; 24 | -i|--icon) 25 | ICON="$2" 26 | shift 27 | ;; 28 | -d|--duration) 29 | DURATION="$2" 30 | shift 31 | ;; 32 | -e|--extra) 33 | EXTRA="$2" 34 | shift 35 | ;; 36 | esac 37 | shift 38 | done 39 | 40 | data="{\"event\":{\"sub_category\":\"${CATEGORY}\",\"action_taken\":\"${ACTION}\",\"status\":${STATUS},\"source\":\"${ICON}\",\"duration\":\"${DURATION}\",\"extra\":\"${EXTRA}\"}}" 41 | curl -s -k -H "Authorization: Token token=\"abc123\"" -H "Content-Type: application/json" -d "$data" http://hostname/api/v2/legacy_events 42 | -------------------------------------------------------------------------------- /api/shell/node-scan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # UpGuard parameters 5 | apiKey="abcd" 6 | secretKey="1234" 7 | upguard="https://appliance.url" 8 | linuxConnectionManagerGroupId=1 9 | linuxNodeOSFamily=2 # Linux 10 | ubuntuNodeOS=231 # Centos 11 | nodeIPHostname=$(hostname -f) 12 | manifestDesc="Logoff%20script" 13 | 14 | # UpGuard endpoints 15 | nodes="/api/v2/nodes" 16 | nodesLookup="/api/v2/nodes/lookup.json?external_id=[0]" 17 | nodesScan="/api/v2/nodes/[0]/start_scan.json?label=[1]" 18 | 19 | # Headers 20 | combinedKey="$apiKey$secretKey" 21 | authHeader="Authorization: Token token=\"$combinedKey\"" 22 | acceptHeader="Accept: application/json" 23 | contentHeader="Content-Type: application/json" 24 | 25 | # Check to see if the node has already been added to UpGuard. 26 | nodesLookupReplaced="${nodesLookup/\[0\]/$nodeIPHostname}" 27 | nodeIdResponse=`curl -X GET -s -k -H "$authHeader" -H "$acceptHeader" -H "$contentHeader" $upguard$nodesLookupReplaced` 28 | 29 | if [[ $nodeIdResponse == *"node_id"* ]]; then 30 | # It's already here. 31 | nodeId=`echo $nodeIdResponse | perl -ne 'if ( /\"node_id\":(\d+)\b/ ) { print "$1"; }'` 32 | else 33 | # Not here, need to create it. 34 | nodeIdResponse=`curl -X POST -s -k -H "$authHeader" -H "$acceptHeader" -H "$contentHeader" -d '{"node": {"name": '\"$nodeIPHostname\"', "short_description": "Added via the API.", "node_type": "SV", "operating_system_family_id": '$linuxNodeOSFamily', "operating_system_id": '$ubuntuNodeOS', "medium_type": 3, "medium_port": 22, "connection_manager_group_id": '$linuxConnectionManagerGroupId', "medium_hostname": '\"$nodeIPHostname\"', "external_id": '\"$nodeIPHostname\"' }}' $upguard$nodes` 35 | nodeId=`echo $nodeIdResponse | perl -ne 'if ( /\"id\":(\d+)\b/ ) { print "$1"; }'` 36 | fi 37 | 38 | if [ -n "$nodeId" ]; then 39 | # Kick off a node scan. 40 | nodesScanReplaced="${nodesScan/\[0\]/$nodeId}" 41 | nodesScanReplaced="${nodesScanReplaced/\[1\]/$manifestDesc}" 42 | startScanResponse=`curl -L -w '%{http_code}\n' -X POST -s -k -H "$authHeader" -H "$acceptHeader" -H "$contentHeader" $upguard$nodesScanReplaced` 43 | jobId=`echo $startScanResponse | perl -ne 'if ( /\"job_id\":(\d+)\b/ ) { print "$1"; }'` 44 | else 45 | echo "upguard: unable to find or create node to scan" 46 | fi 47 | 48 | if [ -n "$jobId" ]; then 49 | echo "upguard: node scan kicked off against "$nodeIPHostname" ("$upguard"/jobs/"$jobId"/show_job?show_all=true)" 50 | else 51 | echo "upguard: unable to start a node scan" 52 | fi 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /api/shell/node-update-password.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # UpGuard parameters 5 | apiKey="<< apiKey >>" 6 | secretKey="<< secretKey >>" 7 | upguard="<< https://your.upguard.appliance >>" 8 | mediumPassword="abc" 9 | alternatePassword="123" 10 | cmGroupId=123 11 | nodeId=123 12 | 13 | # UpGuard endpoints 14 | nodesShow="/api/v2/nodes/[0]" 15 | 16 | # Headers 17 | combinedKey="$apiKey$secretKey" 18 | authHeader="Authorization: Token token=\"$combinedKey\"" 19 | acceptHeader="Accept: application/json" 20 | contentHeader="Content-Type: application/json" 21 | 22 | nodesShowReplaced="${nodesShow/\[0\]/$nodeId}" 23 | response=`curl -X PUT -s -k -H "$authHeader" -H "$acceptHeader" -H "$contentHeader" -d '{"node": {"connection_manager_group_id": '\"$cmGroupId\"', "medium_password": '\"$mediumPassword\"', "alternate_password": '\"$alternatePassword\"' }}' $upguard$nodesShowReplaced` 24 | if [[ $response == "" ]]; then 25 | echo "Updated node password." 26 | else 27 | echo $response 28 | fi 29 | -------------------------------------------------------------------------------- /api/shell/nodes-create.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -w '%{http_code}\n' -X POST -s -k -H "Authorization: Token token=\"abcd1234\"" -H "Accept: application/json" -H "Content-Type: application/json" -d '{"node": {"name": "test", "short_description": "added via api", "node_type": "SV", "operating_system_family_id": 2, "operating_system_id": 221, "medium_type": 3, "medium_username": "username", "medium_hostname": "hostname", "connection_manager_group_id": 1}}' https://hostname/api/v1/nodes 4 | -------------------------------------------------------------------------------- /api/shell/retrieve-backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Download nightly backups of the file system backup into a folder for safekeeping 3 | # Usage: retrieve-backup.sh 4 | # 5 | # To run a crontab task, go to your linux/unix terminal and enter the command: 6 | # crontab -e 7 | # Followed by a cron schedule (in this example, set to 5:00am daily) for the task: 8 | # 0 5 * * * retrieve-backup.sh 9 | # 10 | # Please contact your UpGuard technical account manager for the credentials to access 11 | # the backups endpoint of your appliance. 12 | # 13 | # UpGuard Inc 14 | 15 | HOST_URL=$1 16 | USERNAME=$2 17 | PASSWORD=$3 18 | OUTPUT_PATH=$4 19 | 20 | if [ "$HOST_URL" = "" ] ; then 21 | echo UpGuard site URL not provided >&2 22 | echo "Usage: retrieve-backup.sh " >&2 23 | exit 1 24 | fi 25 | 26 | if [ "$USERNAME" = "" ] ; then 27 | echo Please provide a username >&2 28 | echo "Usage: retrieve-backup.sh " >&2 29 | exit 1 30 | fi 31 | 32 | if [ "$PASSWORD" = "" ] ; then 33 | echo Please provide a password >&2 34 | echo "Usage: retrieve-backup.sh " >&2 35 | exit 1 36 | fi 37 | 38 | if [ "$OUTPUT_PATH" = "" ] ; then 39 | echo Please specify an output directory path to place the downloaded backups >&2 40 | echo "Usage: retrieve-backup.sh " >&2 41 | exit 1 42 | fi 43 | 44 | DIR=`wget $HOST_URL/backups --user=$ADMIN --password=$PASSWORD --no-check-certificate -O - 2>/dev/null | sed -e 's/^.*\">//' | sed -e 's/\/.*$//' | grep "^2" | tail -1` 45 | wget $HOST_URL/backups/$DIR/base.tar.gz --user=$ADMIN --password=$PASSWORD --no-check-certificate -O $OUTPUT_PATH/$DIR-base.tar.gz 46 | -------------------------------------------------------------------------------- /automation/ansible/README.md: -------------------------------------------------------------------------------- 1 | # Ansible Modules for UpGuard 2 | 3 | Ansible modules for interacting with UpGuard. 4 | 5 | ## Modules 6 | 7 | ### upguard_node 8 | 9 | * Information: 10 | * GitHub URL: https://github.com/napalm255/ansible-upguard 11 | * Documentation: https://ansible-upguard.readthedocs.io. 12 | 13 | * Features 14 | * CRUD supported. 15 | * Create job to scan node. 16 | * Add node to node group. 17 | * Check mode supported. 18 | -------------------------------------------------------------------------------- /automation/ansible/upguard_node/play.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: all 3 | connection: local 4 | gather_facts: false 5 | 6 | vars: 7 | UPGUARD_VALIDATE_CERTS: false 8 | ENV_UPGUARD_URL: "{{ lookup('env', 'UPGUARD_URL') }}" 9 | ENV_UPGUARD_ACCESS_KEY: "{{ lookup('env', 'UPGUARD_ACCESS_KEY') }}" 10 | ENV_UPGUARD_SECRET_KEY: "{{ lookup('env', 'UPGUARD_SECRET_KEY') }}" 11 | 12 | vars_prompt: 13 | - name: 'UPGUARD_URL' 14 | prompt: 'UpGuard URL' 15 | default: "{{ ENV_UPGUARD_URL }}" 16 | private: false 17 | 18 | - name: 'UPGUARD_ACCESS_KEY' 19 | prompt: 'UpGuard Access Key' 20 | default: "{{ ENV_UPGUARD_ACCESS_KEY }}" 21 | private: false 22 | 23 | - name: 'UPGUARD_SECRET_KEY' 24 | prompt: 'UpGuard Secret Key' 25 | default: "{{ ENV_UPGUARD_SECRET_KEY }}" 26 | private: true 27 | 28 | tasks: 29 | - name: Debug 30 | debug: var=inventory_hostname_short 31 | 32 | - name: upguard node 33 | upguard_node: 34 | url: "{{ UPGUARD_URL }}" 35 | username: "{{ UPGUARD_ACCESS_KEY }}" 36 | password: "{{ UPGUARD_SECRET_KEY }}" 37 | validate_certs: "{{ UPGUARD_VALIDATE_CERTS }}" 38 | name: "{{ inventory_hostname_short }}" 39 | node_type: "RT" 40 | state: "present" 41 | properties: 42 | medium_type: 6 43 | register: results 44 | 45 | - debug: var=results 46 | -------------------------------------------------------------------------------- /automation/ansible/upguard_node/requirements.txt: -------------------------------------------------------------------------------- 1 | ansible>=2.3.1.0 2 | requests>=2.18.1 3 | -------------------------------------------------------------------------------- /automation/puppet/upguard.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :appliance_url: 'https://upguard.instance.url' 3 | :puppetdb_url: 'https://puppetdb.instance.url:8081' 4 | :compile_master_pem: 'name_of_compile_master.pem' 5 | :service_key: 'upguard_service_key' 6 | :secret_key: 'upguard_secret_key' 7 | :unknown_os_node_group_id: check for id in upguard 8 | :windows_node_group_id: check for id in upguard 9 | :linux_node_group_id: check for id in upguard 10 | 11 | #:environment: 'test' 12 | #:test_os: 'centos or windows' 13 | #:test_node_name: 'the name of the node' 14 | #:test_windows_hostname: 'windows hostname' 15 | #:test_linux_hostname: 'linux hostname' 16 | 17 | :sleep_before_scan: 120 18 | :ignore_hostname_prefix: 'test' 19 | 20 | :sites: 21 | - name: 'mtv' 22 | domains: 23 | - name: 'domain.com' 24 | ssh_connection_manager_groups: 25 | - id: 1 26 | service_account: 'username' 27 | service_password: 'password' 28 | windows_connection_manager_groups: 29 | - id: 12 30 | service_account: '' 31 | service_password: '' 32 | -------------------------------------------------------------------------------- /automation/puppet/upguard_rb.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/puppet/upguard_rb.pdf -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/UpGuard Node Registration.workflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/UpGuard Node Registration.workflow -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/UpGuard Nodes Create.workflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/UpGuard Nodes Create.workflow -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/UpGuard Nodes List.workflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/UpGuard Nodes List.workflow -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/UpGuard Nodes Start_Scan.workflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/UpGuard Nodes Start_Scan.workflow -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/readme.md: -------------------------------------------------------------------------------- 1 | vRealize Orchestrator integration with UpGuard 2 | Scripts and workflows provided as examples only 3 | 4 | See vRealize Orchestrator - Integration Guide.pdf for more implementation details. 5 | 6 | Contact support@upguard.com with any questions. 7 | -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - Add a REST host.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - Add a REST host.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - REST Operation Start Scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - REST Operation Start Scan.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - REST Operation nodes create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - REST Operation nodes create.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - REST Operation nodes list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - REST Operation nodes list.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - Script Auth Header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - Script Auth Header.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - UpGuard Add and Scan SCRIPT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - UpGuard Add and Scan SCRIPT.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - UpGuard Node Reistration Workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - UpGuard Node Reistration Workflow.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO - UpGuard Workflows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO - UpGuard Workflows.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO Login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO Login.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO Workflow - Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO Workflow - Error.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO Workflow - UpGuard Nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRO Workflow - UpGuard Nodes.png -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRO_upguard_node_lookup_persistent.js: -------------------------------------------------------------------------------- 1 | //prepare request 2 | //Do not edit 3 | var inParamtersValues = [nodeName]; 4 | var request = restOperation.createRequest(inParamtersValues, null); 5 | //set the request content type 6 | request.contentType = ""; 7 | System.log("Request: " + request); 8 | System.log("Request URL: " + request.fullUrl); 9 | 10 | //Customize the request here 11 | //request.setHeader("headerName", "headerValue"); 12 | request.setHeader('Authorization', 'Token token="{apikey+secretkey}"') 13 | 14 | 15 | //execute request 16 | //Do not edit 17 | var response = request.execute(); 18 | //prepare output parameters 19 | System.log("Response: " + response); 20 | statusCode = response.statusCode; 21 | statusCodeAttribute = statusCode; 22 | System.log("Status code: " + statusCode); 23 | contentLength = response.contentLength; 24 | headers = response.getAllHeaders(); 25 | contentAsString = response.contentAsString; 26 | System.log("Content as string: " + contentAsString); 27 | 28 | var node = JSON.parse(contentAsString); 29 | nodeId = node.node_id.toString(); 30 | System.log("NodeId: " + nodeId); 31 | -------------------------------------------------------------------------------- /automation/vrealize-orchestrator/vRealize Orchestrator - Integration Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/automation/vrealize-orchestrator/vRealize Orchestrator - Integration Guide.pdf -------------------------------------------------------------------------------- /blueprints/perl/custom-devices/cisco_call_manager.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | use IPC::Run3; 5 | use MIME::Base64; 6 | use JSON; 7 | use Data::Dumper; 8 | 9 | use File::Basename; 10 | use lib dirname (__FILE__); 11 | use UpGuardCiscoParser; 12 | 13 | my $json = JSON->new->allow_nonref; 14 | 15 | # use guardrail_agent helper to collect data 16 | my $stdout; 17 | my $stderr; 18 | my @cmd = ("guardrail_agent", "net_helper", "--os", "script_path", "--creds_in_stdin", "--cmd", "show version active"); 19 | run3 \@cmd, undef, \$stdout, \$stderr or die "running guardrail helper failed: $!\n"; 20 | if ($? != 0) { 21 | die "guardrail_agent returns stderr: $stderr\n"; 22 | } 23 | 24 | # output is one base64 line per cmd 25 | my @outputs; 26 | foreach my $b64 (split(/\r*\n/, $stdout)) { 27 | push @outputs, decode_base64($b64); 28 | } 29 | 30 | my $scan; 31 | 32 | # "show version active" is output 0. 33 | $scan->{"inventory"} = undef; 34 | $scan->{"inventory"}->{"facts"} = UpGuardCiscoParser::parse_output($outputs[0]); 35 | 36 | print $json->pretty->encode($scan); -------------------------------------------------------------------------------- /blueprints/perl/custom-devices/cisco_source_fire.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | use strict; 3 | use warnings; 4 | use IPC::Run3; 5 | use MIME::Base64; 6 | use JSON; 7 | use Data::Dumper; 8 | 9 | use File::Basename; 10 | use lib dirname (__FILE__); 11 | 12 | my $json = JSON->new->allow_nonref; 13 | 14 | sub parse_output { 15 | my $lines = shift; 16 | my @lines = split(/\r*\n/, $lines); 17 | 18 | my $scan = {}; 19 | 20 | foreach (@lines) { 21 | if (/^\s*Sourcefire\s*Linux\s*OS\s*([\w\d.]+)-(\S+)\s*$/) { 22 | $scan->{"full_version"} = undef; 23 | $scan->{"full_version"}->{"value"} = "$1-$2"; 24 | $scan->{"version"} = undef; 25 | $scan->{"version"}->{"value"} = $1; 26 | $scan->{"release"} = undef; 27 | $scan->{"release"}->{"value"} = $2; 28 | } 29 | } 30 | 31 | #print Dumper($scan); 32 | 33 | my $ugscan; 34 | $ugscan->{"inventory"} = {}; 35 | $ugscan->{"inventory"}->{"facts"} = $scan; 36 | 37 | return $ugscan; 38 | } 39 | 40 | sub collect_output { 41 | # use guardrail_agent helper to collect data 42 | my $stdout; 43 | my $stderr; 44 | my @cmd = ("guardrail_agent", "net_batch", "--os", "script_path", "--creds_in_stdin", "--cmd", "cat /etc/*release*"); 45 | run3 \@cmd, undef, \$stdout, \$stderr or die "running guardrail helper failed: $!\n"; 46 | if ($? != 0) { 47 | die "guardrail_agent returns stderr: $stderr\n"; 48 | } 49 | 50 | # output is one base64 line per cmd 51 | my @outputs; 52 | foreach my $b64 (split(/\r*\n/, $stdout)) { 53 | push @outputs, decode_base64($b64); 54 | } 55 | 56 | return @outputs; 57 | } 58 | 59 | my @outputs = collect_output(); 60 | my $scan = parse_output($outputs[0]); 61 | print $json->pretty->encode($scan); -------------------------------------------------------------------------------- /blueprints/perl/custom-devices/esxi.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | use IPC::Run3; 5 | use MIME::Base64; 6 | use JSON; 7 | use Data::Dumper; 8 | 9 | my $json = JSON->new->allow_nonref; 10 | 11 | # use guardrail_agent helper to collect data 12 | my $stdout; 13 | my $stderr; 14 | my @cmd = ("guardrail_agent", "net_batch", "--os", "script_path", "--creds_in_stdin", "--cmd", "vmware -v"); 15 | run3 \@cmd, undef, \$stdout, \$stderr or die "running guardrail helper failed: $!\n"; 16 | if($? !=0) { 17 | die "guardrail_agent returned non-zero\n"; 18 | } 19 | 20 | # output is one base64 line per cmd 21 | my @outputs; 22 | foreach my $b64 (split(/\r*\n/, $stdout)) { 23 | push @outputs, decode_base64($b64); 24 | } 25 | 26 | if(1){ 27 | my $fh; 28 | open($fh, ">/tmp/out2") or die "could not open out: $!\n"; 29 | print $fh "stdout $stdout\n"; 30 | print $fh "stderr $stderr\n"; 31 | print $fh "@outputs\n"; 32 | close $fh; 33 | } 34 | 35 | 36 | # output is one line base64 37 | my $scan; 38 | 39 | # ugly scan assembling 40 | $scan->{"version"} = undef; 41 | $scan->{"version"}->{"version"} = undef; 42 | $scan->{"version"}->{"version"}->{"version"} = undef; 43 | 44 | # vmware -v is output 0. 45 | if ( $outputs[0] =~ /^\s*VMware\s+ESXi\s+(\S+)\s+build-(\S+)\s*$/ ) { 46 | my $vmwarev; 47 | $vmwarev->{"version"} = $1; 48 | $vmwarev->{"build"} = $2; 49 | $scan->{"version"}->{"version"}->{"version"} = $vmwarev; 50 | } 51 | 52 | print $json->pretty->encode($scan); 53 | -------------------------------------------------------------------------------- /blueprints/perl/custom-devices/hp_onboard_administrator.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | use IPC::Run3; 5 | use MIME::Base64; 6 | use JSON; 7 | use Data::Dumper; 8 | 9 | my $json = JSON->new->allow_nonref; 10 | 11 | 12 | # use guardrail_agent helper to collect data 13 | my $stdout; 14 | my $stderr; 15 | my @cmd = ("guardrail_agent", "net_helper", "--os", "script_path", "--creds_in_stdin", "--prep", "set script mode on", "--cmd", "show firmware summary", "--cmd", "show config"); 16 | run3 \@cmd, undef, \$stdout, \$stderr or die "running guardrail helper failed: $!\n"; 17 | if ($? != 0) { 18 | die "guardrail_agent returned non-zero\n"; 19 | } 20 | 21 | # output is one base64 line per cmd 22 | my @outputs; 23 | foreach my $b64 (split(/\r*\n/, $stdout)) { 24 | push @outputs, decode_base64($b64); 25 | } 26 | 27 | if (1) { 28 | my $fh; 29 | open ($fh, ">/tmp/hp-onboard-administrator.log") or die "could not open out: $!\n"; 30 | print $fh "stdout $stdout\n"; 31 | print $fh "stderr $stderr\n"; 32 | print $fh "@outputs\n"; 33 | close $fh; 34 | } 35 | 36 | my $scan; 37 | 38 | # ugly scan assembling 39 | 40 | # "show firmware summary" is output 0. 41 | my $last_was_blank = 0; 42 | my $info_block = undef; 43 | foreach (split(/\r*\n/, $outputs[0])) { 44 | my $this_is_blank = 0; 45 | if (/^\s*$/) { 46 | $this_is_blank = 1; 47 | } 48 | 49 | if ($last_was_blank && /^([\w\s]+?\s+Information)\s*$/) { 50 | $info_block = $1; 51 | } 52 | 53 | if (defined($info_block) && ($info_block eq "Onboard Administrator Firmware Information")) { 54 | if (/^(\d+)\s+(.*?)\s+([\d\w._-~]+)\s*$/) { 55 | my $bay = $1; 56 | my $model = $2; 57 | my $firmware_version = $3; 58 | my $attrs = { 59 | "bay" => $bay, 60 | "model" => $model, 61 | "firmware version" => $firmware_version, 62 | }; 63 | $scan->{"version"} ||= undef; 64 | $scan->{"version"}->{"firmware"} ||= undef; 65 | $scan->{"version"}->{"firmware"}->{"bay $bay"} = $attrs; 66 | } 67 | } 68 | 69 | $last_was_blank = $this_is_blank; 70 | } 71 | 72 | print $json->pretty->encode($scan); -------------------------------------------------------------------------------- /blueprints/perl/custom-devices/tripplite.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use warnings; 4 | use IPC::Run3; 5 | use MIME::Base64; 6 | use JSON; 7 | use Data::Dumper; 8 | 9 | my $json = JSON->new->allow_nonref; 10 | 11 | # use guardrail_agent helper to collect data 12 | my $stdout; 13 | my $stderr; 14 | my @cmd = ("guardrail_agent", "net_batch", "--os", "script_path", "--creds_in_stdin", "--cmd", "cat /etc/version"); 15 | run3 \@cmd, undef, \$stdout, \$stderr or die "running guardrail helper failed: $!\n"; 16 | if($? !=0) { 17 | die "guardrail_agent returned non-zero\n"; 18 | } 19 | 20 | # output is one base64 line per cmd 21 | my @outputs; 22 | foreach my $b64 (split(/\r*\n/, $stdout)) { 23 | push @outputs, decode_base64($b64); 24 | } 25 | 26 | 27 | 28 | 29 | # output is one line base64 30 | my $scan; 31 | 32 | # ugly scan assembling 33 | $scan->{"version"} = undef; 34 | $scan->{"version"}->{"version"} = undef; 35 | 36 | # vmware -v is output 0. 37 | if ( $outputs[0] =~ /^TrippLite\/B096\sVersion\s(.*)\s--/ ) { 38 | my $triplite; 39 | $triplite->{"version"} = $1; 40 | $scan->{"version"}->{"version"} = $triplite; 41 | } 42 | if(1){ 43 | my $fh; 44 | open($fh, ">/tmp/tripliteDebug ") or die "could not open out: $!\n"; 45 | print $fh "stdout $stdout\n"; 46 | print $fh "stderr $stderr\n"; 47 | print $fh "@outputs\n"; 48 | print $fh "$scan\n"; 49 | close $fh; 50 | } 51 | print $json->pretty->encode($scan); 52 | -------------------------------------------------------------------------------- /policies/MS_SQL_testing.txt: -------------------------------------------------------------------------------- 1 | Test scripts: 2 | 3.5-7 3 | Test for 3.6 and 3.7 are same as 3.5. Just use other accounts retrived from the query. 4 | a) select * from sys.dm_server_services 5 | b) net localgroup Administrators "NT Service\MSSQLSERVER" /add 6 | c) net localgroup Administrators "NT Service\MSSQLSERVER" /delete 7 | d) net localgroup Administrators 8 | I can not prepare test cript for "Query LocalSystem account (aka NT AUTHORITY\SYSTEM) used for the MSSQL service" 9 | because it requires new installation of MS SQL Server with other configuration steps. 10 | 11 | 3.8 12 | The check is changed (Measure-object + Count=0) 13 | 14 | -- The way to add rows in the query result: 15 | grant ALTER ANY DATABASE to public 16 | go 17 | grant CREATE ANY DATABASE to public 18 | go 19 | 20 | 3.9 21 | The check is changed (Measure-object + Count=0) 22 | You already (default configuration) have one row here. It's enough for testing. 23 | 24 | 3.10 25 | The check is changed (Measure-object + Count=0) 26 | 27 | -- The way to add rows in the query result: 28 | -- 1. create localgroup in the command line 29 | PS C:\Users\Administrator> net localgroup test_group /add 30 | 31 | -- 2. create logon for this group 32 | use [master] 33 | go 34 | CREATE LOGIN "EC2AMAZ-ULB4L5F\test_group" FROM WINDOWS; 35 | GO 36 | 37 | 3.11 38 | The check is changed (Measure-object + Count=0) 39 | -- The way to add rows in the query result: 40 | USE msdb ; 41 | GO 42 | -- already created 43 | --create CREDENTIAL CredentialForEKMq 44 | --WITH IDENTITY='NT Service\SQLSERVERAGENT' 45 | [[GO 46 | 47 | EXEC dbo.sp_add_proxy 48 | @proxy_name = 'Catalog application proxy 3', 49 | @enabled = 1, 50 | @description = 'Maintenance tasks on catalog application.', 51 | @credential_name = 'CredentialForEKMq' ; 52 | GO 53 | 54 | EXEC dbo.sp_grant_login_to_proxy @msdb_role = N'public', @proxy_name =N'Catalog application proxy 3'; 55 | GO 56 | 57 | 58 | -------------------------------------------------------------------------------- /policies/aws_cis_config_service_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "aws_config_service_policy", 4 | "short_description": "AWS Config Service Policy", 5 | "description": null, 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "Config Recorders": [ 18 | { 19 | "Config Recorders": [ 20 | { 21 | "id": "Config-RecordersConfig-Recorders3-5-Ensure-AWS-Config-is-enabled-in-all-regions", 22 | "name": "3.5 Ensure AWS Config is enabled in all regions", 23 | "checks": { 24 | "recording group all supported": [ 25 | { 26 | "exp": true, 27 | "check": "equals", 28 | "expected": true, 29 | "background": "AWS Config is a web service that performs configuration management of supported AWS resources within your account and delivers log files to you. The recorded information includes the configuration item (AWS resource), relationships between configuration items (AWS resources), any configuration changes between resources. It is recommended AWS Config be enabled in all regions.\nThe AWS configuration item history captured by AWS Config enables security analysis, resource change tracking, and compliance auditing.", 30 | "remediation": "To implement AWS Config configuration:\nFrom Console:\n1. Select the region you want to focus on in the top right of the console\n2. Click Services\n3. Click Config\n4. Define which resources you want to record in the selected region\n5. Choose to include global resources (IAM resources)\n6. Specify an S3 bucket in the same account or in another managed AWS account\n7. Create an SNS Topic from the same AWS account or another managed AWS account\nFrom Command Line:\n1. Ensure there is an appropriate S3 bucket, SNS topic, and IAM role per the AWS Config Service prerequisites.\n2. Run this command to set up the configuration recorder\n\n aws configservice subscribe --s3-bucket my-config-bucket --sns-topic arn:aws:sns:us-east-1:012345678912:my-config-notice --iam-role arn:aws:iam::012345678912:role/myConfigRole\n\n3. Run this command to start the configuration recorder:\nstart-configuration-recorder --configuration-recorder-name " 31 | } 32 | ], 33 | "recording group include global resource types": [ 34 | { 35 | "exp": "true", 36 | "check": "equals", 37 | "expected": "true" 38 | } 39 | ] 40 | }, 41 | "ci_path": [ 42 | "Config Recorders", 43 | "Config Recorders", 44 | "*" 45 | ], 46 | "Recorders": { 47 | "name": "default" 48 | }, 49 | "check_type": "recorders", 50 | "description": "3.5 Ensure AWS Config is enabled in all regions", 51 | "nodeGroupsOpen": true 52 | } 53 | ] 54 | } 55 | ] 56 | } 57 | ], 58 | "scan_options": {} 59 | } 60 | -------------------------------------------------------------------------------- /policies/aws_cis_ebs_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "aws_ebs_policy", 4 | "short_description": "AWS EBS Policy", 5 | "description": null, 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "Encryption by Default": [ 18 | { 19 | "id": "Encryption-by-Default2-2-1-Ensure-EBS-volume-encryption-is-enabled", 20 | "name": "2.2.1 Ensure EBS volume encryption is enabled", 21 | "checks": { 22 | "EBS encryption by default": [ 23 | { 24 | "exp": "true", 25 | "check": "equals", 26 | "expected": "true", 27 | "background": "Elastic Compute Cloud (EC2) supports encryption at rest when using the Elastic Block Store (EBS) service. While disabled by default, forcing encryption at EBS volume creation is supported.\nEncrypting data at rest reduces the likelihood that it is unintentionally exposed and can nullify the impact of disclosure if the encryption remains unbroken.", 28 | "remediation": "From Console:\n1. Login to AWS Management Console and open the Amazon EC2 console using https://console.aws.amazon.com/ec2/\n2. Under Account attributes, click EBS encryption.\n3. Click Manage.\n4. Click the Enable checkbox.\n5. Click Update EBS encryption\n6. Repeat for every region requiring the change.\nNote: EBS volume encryption is configured per region.\nFrom Command Line:\n1. Run\naws --region 'region' ec2 enable-ebs-encryption-by-default\n2. Verify that \"EbsEncryptionByDefault\": true is displayed.\n3. Repeat every region requiring the change." 29 | } 30 | ] 31 | }, 32 | "ci_path": [ 33 | "Encryption by Default", 34 | "Encryption by Default", 35 | "Encryption" 36 | ], 37 | "check_type": "encryption by default", 38 | "description": "2.2.1 Ensure EBS volume encryption is enabled", 39 | "nodeGroupsOpen": true, 40 | "Encryption by Default": { 41 | "name": "Encryption" 42 | } 43 | } 44 | ] 45 | } 46 | ], 47 | "scan_options": {} 48 | } 49 | -------------------------------------------------------------------------------- /policies/aws_cis_kms_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "aws_kms_policy", 4 | "short_description": "AWS KMS Policy", 5 | "description": null, 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "Managed Keys": [ 18 | { 19 | "Managed Keys": [ 20 | { 21 | "id": "Managed-KeysManaged-Keys3-8-Ensure-rotation-for-customer-created-CMKs-is-enabled", 22 | "KMS": { 23 | "name": "2ee7baf8-9cc2-4378-aec7-9d38fe24eab8" 24 | }, 25 | "name": "3.8 Ensure rotation for customer created CMKs is enabled", 26 | "checks": { 27 | "key rotation enabled": [ 28 | { 29 | "exp": "true", 30 | "check": "equals", 31 | "expected": "true", 32 | "background": "AWS Key Management Service (KMS) allows customers to rotate the backing key which is key material stored within the KMS which is tied to the key ID of the Customer Created customer master key (CMK). It is the backing key that is used to perform cryptographic operations such as encryption and decryption. Automated key rotation currently retains all prior backing keys so that decryption of encrypted data can take place transparently. It is recommended that CMK key rotation be enabled.\nRotating encryption keys helps reduce the potential impact of a compromised key as data encrypted with a new key cannot be accessed with a previous key that may have been exposed.", 33 | "remediation": "From Console:\n1. Sign in to the AWS Management Console and open the IAM console at https://console.aws.amazon.com/iam.\n2. In the left navigation pane, choose Encryption Keys .\n3. Select a customer created master key (CMK)\n4. Under the Key Policy section, move down to Key Rotation .\n5. Check the Rotate this key every year checkbox.\nFrom Command Line:\n1. Run the following command to enable key rotation:\naws kms enable-key-rotation --key-id 'kms_key_id'" 34 | } 35 | ] 36 | }, 37 | "ci_path": [ 38 | "Managed Keys", 39 | "Managed Keys", 40 | "*" 41 | ], 42 | "check_type": "kms", 43 | "description": "3.8 Ensure rotation for customer created CMKs is enabled", 44 | "nodeGroupsOpen": true 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | ], 51 | "scan_options": {} 52 | } 53 | -------------------------------------------------------------------------------- /policies/aws_cis_vpc_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "aws_vpc_policy", 4 | "short_description": "AWS VPC Policy", 5 | "description": null, 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "flow logs": [ 18 | { 19 | "flow logs": [ 20 | { 21 | "id": "flow-logsflow-logs3-9-Ensure-VPC-flow-logging-is-enabled-in-all-VPCs", 22 | "name": "3.9 Ensure VPC flow logging is enabled in all VPCs", 23 | "error": false, 24 | "checks": { 25 | "Status": [ 26 | { 27 | "exp": "ACTIVE", 28 | "check": "equals", 29 | "expected": "ACTIVE", 30 | "background": "VPC Flow Logs is a feature that enables you to capture information about the IP traffic going to and from network interfaces in your VPC. After you've created a flow log, you can view and retrieve its data in Amazon CloudWatch Logs. It is recommended that VPC Flow Logs be enabled for packet \"Rejects\" for VPCs.\nVPC Flow Logs provide visibility into network traffic that traverses the VPC and can be used to detect anomalous traffic or insight during security workflows.", 31 | "remediation": "Perform the following to determine if VPC Flow logs is enabled:\nFrom Console:\n1. Sign into the management console\n2. Select Services then VPC\n3. In the left navigation pane, select Your VPCs\n4. Select a VPC\n5. In the right pane, select the Flow Logs tab.\n6. If no Flow Log exists, click Create Flow Log\n7. For Filter, select Reject\n8. Enter in a Role and Destination Log Group\n9. Click Create Log Flow\n10. Click on CloudWatch Logs Group\nNote: Setting the filter to \"Reject\" will dramatically reduce the logging data accumulation for this recommendation and provide sufficient information for the purposes of breach detection, research and remediation. However, during periods of least privilege security group engineering, setting this the filter to \"All\" can be very helpful in discovering existing traffic flows required for proper operation of an already running environment." 32 | } 33 | ] 34 | }, 35 | "ci_path": [ 36 | "Flow Logs", 37 | "Flow Logs", 38 | "*" 39 | ], 40 | "check_type": "other", 41 | "path_error": "", 42 | "description": "3.9 Ensure VPC flow logging is enabled in all VPCs", 43 | "nodeGroupsOpen": true 44 | } 45 | ] 46 | } 47 | ] 48 | } 49 | ], 50 | "scan_options": {} 51 | } 52 | -------------------------------------------------------------------------------- /policies/azure_cis_keyvault_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "azure_key_vault_policy", 4 | "short_description": "Azure Key Vault Policy", 5 | "description": null, 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "Properties": [ 18 | { 19 | "Attributes": [ 20 | { 21 | "id": "PropertiesKey-Attributes8-1-Ensure-that-the-Expiration-Date-is-set-for-all-Keys-in-RBAC-Key-Vaults", 22 | "name": "8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults", 23 | "error": false, 24 | "checks": { 25 | "expires": [ 26 | { 27 | "check": "regex", 28 | "expected": ".", 29 | "background": "Azure Key Vault enables users to store and use cryptographic keys within the Microsoft Azure environment. The exp (expiration time) attribute identifies the expiration time on or after which the key MUST NOT be used for a cryptographic operation. By default, keys never expire. It is thus recommended that keys be rotated in the key vault and set an explicit expiration time for all keys. This ensures that the keys cannot be used beyond their assigned lifetimes.", 30 | "remediation": "From Azure Console\n1. Go to Key vaults\n2. For each Key vault, click on Keys.\n3. Under the Settings section, Make sure Enabled? is set to Yes\n4. Set an appropriate EXPIRATION DATE on all keys." 31 | } 32 | ], 33 | "present": [ 34 | { 35 | "check": "equals", 36 | "expected": "true" 37 | } 38 | ] 39 | }, 40 | "ci_path": [ 41 | "Properties", 42 | "*", 43 | "Attributes" 44 | ], 45 | "check_type": "other", 46 | "path_error": "", 47 | "description": "8.1 Ensure that the Expiration Date is set for all Keys in RBAC Key Vaults", 48 | "nodeGroupsOpen": true 49 | } 50 | ] 51 | } 52 | ] 53 | } 54 | ], 55 | "scan_options": {} 56 | } 57 | -------------------------------------------------------------------------------- /policies/dchp_address_pool_utilization (1).json: -------------------------------------------------------------------------------- 1 | {"policy":{"name":"dhcp_address_pool_utilization-discrete","short_description":"DHCP Address Pool Utilization - Discrete","description":"Maintaining pool availability is important to provide operational stability in a large enterprise environment. Monitor pool availability in terms of IP Addresses or Percentage Utilization to ensure operational resiliency. ","settings":{"tests":{"output_format":null}},"operating_system_family_id":null,"operating_system_id":null,"type":null},"data":[{"PowerShell":[{"DHCP":[{"id":"PowerShellDHCPVerify-that-the-DHCP-address-pools-on-a-given-DHCP-server-has-more-than-10-free-addresses","name":"Verify that the DHCP address pools on a given DHCP server has more than 10 free addresses","error":false,"checks":{"AddressesFree":[{"cond":[{"op":">","val":"10"}],"check":"conditional","remediation":"Allocate more IP addresses.","valueSelectList":null,"attributeSelectList":null,"availableAttributes":null}]},"ci_path":["*","*","*"],"check_type":"other","path_error":"","selectList":["*"],"description":"Verify that the DHCP address pools on a given DHCP server has more than 10 free addresses","nodeGroupsOpen":true},{"id":"PowerShellDHCPVerify-that-the-DHCP-address-pools-on-a-given-DHCP-server-has-less-than-90-utilization-","name":"Verify that the DHCP address pools on a given DHCP server has less than 90% utilization.","error":false,"checks":{"PercentageInUse":{"cond":[{"op":"<","val":"90"}],"check":"conditional","remediation":"Extend DHCP pool.","valueSelectList":null,"attributeSelectList":null,"availableAttributes":null}},"ci_path":["*","*","*"],"check_type":"other","path_error":"","description":"Verify that the DHCP address pools on a given DHCP server has less than 90% utilization.","nodeGroupsOpen":true}]}]}],"scan_options":{}} -------------------------------------------------------------------------------- /policies/dsc_base_resource_configuration.json: -------------------------------------------------------------------------------- 1 | {"policy":{"name":"windows-dsc_base_configuration","short_description":"Windows - DSC Base Configuration","description":"This includes core resource definitions that should be included in all DSC configurations.","settings":{"tests":{"output_format":null}},"operating_system_family_id":null,"operating_system_id":null,"type":null},"data":[{"xNetworking":[{"id":"xNetworkingValidate-the-primary-DNS-Server","name":"Validate the primary DNS Server","error":false,"checks":{"Address":[{"check":"includes","expected":"10.0.0.1","background":"Improper DNS settings can lead to various authentication and availability issues.","remediation":"Update to include the proper DNS server","valueSelectList":null,"attributeSelectList":null,"availableAttributes":null}]},"ci_path":["*","DSC Configuration","[xDNSServerAddress]StackSightDNS"],"check_type":"other","path_error":"","description":"Validate the primary DNS Server","nodeGroupsOpen":true},{"id":"xNetworkingValidate-the-Secondary-DNS-server","name":"Validate the Secondary DNS server","error":false,"checks":{"Address":[{"check":"includes","expected":"8.8.8.8","background":"Improper DNS settings can lead to various authentication and availability issues.","remediation":"Update to include the proper DNS server, or validate the configuration being applied.","valueSelectList":null,"attributeSelectList":null,"availableAttributes":null}]},"ci_path":["*","DSC Configuration","[xDNSServerAddress]StackSightDNS"],"check_type":"other","path_error":"","description":"Validate the Secondary DNS server","nodeGroupsOpen":true}]}],"scan_options":{}} -------------------------------------------------------------------------------- /policies/github2FApolicy.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "GitHub 2FA": [ 5 | { 6 | "check_type": "other", 7 | "checks": { 8 | "2FA Enabled": [ 9 | { 10 | "attributeSelectList": null, 11 | "availableAttributes": null, 12 | "check": "equals", 13 | "expected": "true", 14 | "valueSelectList": null 15 | } 16 | ] 17 | }, 18 | "ci_path": [ 19 | "Members", 20 | "*", 21 | "*" 22 | ], 23 | "description": "All GitHub members should have 2FA turned on", 24 | "error": false, 25 | "id": "GitHub-2FAAll-GitHub-members-should-have-2FA-turned-on", 26 | "name": "All GitHub members should have 2FA turned on", 27 | "nodeGroupsOpen": true, 28 | "path_error": "" 29 | } 30 | ] 31 | } 32 | ], 33 | "policy": { 34 | "description": "", 35 | "name": "enforce_github_2fa", 36 | "operating_system_family_id": null, 37 | "operating_system_id": null, 38 | "settings": { 39 | "tests": { 40 | "output_format": null 41 | } 42 | }, 43 | "short_description": "Enforce GitHub 2FA", 44 | "type": null 45 | }, 46 | "scan_options": {} 47 | } 48 | -------------------------------------------------------------------------------- /policies/githubPrivateRepoPolicy.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "GitHub Private Repo Configuration": [ 5 | { 6 | "check_type": "other", 7 | "checks": { 8 | "Private": { 9 | "attributeSelectList": [ 10 | "Allow Merge Commit", 11 | "Allow Rebase Merge", 12 | "Allow Squash Merge", 13 | "Fork", 14 | "Private", 15 | "Topics" 16 | ], 17 | "availableAttributes": [ 18 | { 19 | "Allow Merge Commit": true, 20 | "Allow Rebase Merge": true, 21 | "Allow Squash Merge": true, 22 | "Fork": false, 23 | "Private": true, 24 | "Topics": "" 25 | } 26 | ], 27 | "check": "equals", 28 | "expected": "true", 29 | "valueSelectList": [ 30 | "true" 31 | ] 32 | } 33 | }, 34 | "ci_path": [ 35 | "Configuration", 36 | "*", 37 | "Settings" 38 | ], 39 | "description": "Checks to ensure GitHub repos are private", 40 | "error": false, 41 | "id": "GitHub-Private-Repo-ConfigurationChecks-to-ensure-GitHub-repos-are-private", 42 | "name": "Checks to ensure GitHub repos are private", 43 | "nodeGroupsOpen": true, 44 | "path_error": "" 45 | } 46 | ] 47 | } 48 | ], 49 | "policy": { 50 | "description": null, 51 | "name": "enforce_github_private_repo_configuration", 52 | "operating_system_family_id": null, 53 | "operating_system_id": null, 54 | "settings": { 55 | "tests": { 56 | "output_format": null 57 | } 58 | }, 59 | "short_description": "Enforce GitHub Private Repo Configuration", 60 | "type": null 61 | }, 62 | "scan_options": {} 63 | } 64 | -------------------------------------------------------------------------------- /policies/githubRepoIsNotFork.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "Configuration": [ 5 | { 6 | "Configuration": [ 7 | { 8 | "Configuration": { 9 | "name": "Settings" 10 | }, 11 | "check_type": "configuration", 12 | "checks": { 13 | "Fork": [ 14 | { 15 | "check": "equals", 16 | "expected": false 17 | } 18 | ], 19 | "Fork Count": [ 20 | { 21 | "check": "equals", 22 | "expected": 0 23 | } 24 | ] 25 | }, 26 | "ci_path": [ 27 | "Configuration", 28 | "Configuration", 29 | "Settings" 30 | ], 31 | "name": "Settings" 32 | } 33 | ] 34 | } 35 | ] 36 | } 37 | ], 38 | "policy": { 39 | "description": null, 40 | "name": "github_repo_is_not_forked", 41 | "operating_system_family_id": null, 42 | "operating_system_id": null, 43 | "settings": { 44 | "tests": { 45 | "output_format": null 46 | } 47 | }, 48 | "short_description": "GitHub Repo is not forked", 49 | "type": null 50 | }, 51 | "scan_options": {} 52 | } 53 | -------------------------------------------------------------------------------- /policies/githubUserFullNamePolicy.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "Members": [ 5 | { 6 | "Members": [ 7 | { 8 | "Members": { 9 | "name": "*" 10 | }, 11 | "check_type": "members", 12 | "checks": { 13 | "Full Name": [ 14 | { 15 | "check": "regex", 16 | "expected": ".+" 17 | } 18 | ] 19 | }, 20 | "ci_path": [ 21 | "Members", 22 | "Members", 23 | "*" 24 | ], 25 | "id": "MembersMembersAll-users-should-have-their-full-name-set-", 26 | "name": "All users should have their full name set." 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | ], 33 | "policy": { 34 | "description": null, 35 | "name": "github_user_identity", 36 | "operating_system_family_id": null, 37 | "operating_system_id": null, 38 | "settings": { 39 | "tests": { 40 | "output_format": null 41 | } 42 | }, 43 | "short_description": "GitHub User Identity", 44 | "type": null 45 | }, 46 | "scan_options": {} 47 | } 48 | -------------------------------------------------------------------------------- /policies/policy_ipv6_disabled_regkey.json: -------------------------------------------------------------------------------- 1 | {"policy":{"name":"ipv6-registry_check","short_description":"IPv6 - Registry Check","description":"Verify that a registry key is in place to disable IPv6 is disabled on the OS.","settings":{"tests":{"output_format":null}},"operating_system_family_id":null,"operating_system_id":null,"type":null},"data":[{"Registry":[{"id":"RegistryThe-key-HKEY-LOCAL-MACHINE-SYSTEM-CurrentControlSet-Services-Tcpip6-Parameters-should-have-the-defined-properties","name":"The key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\DisabledComponents should have the defined properties","error":false,"checks":{"present":[{"check":"equals","expected":"true"}]},"ci_path":["registry","*","HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\"],"registry":{"registry_key":"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\DisabledComponents"},"check_type":"registry","description":"The key {{ registry_key }} should have the defined properties","nodeGroupsOpen":true}]}],"scan_options":{"registry_keys":["HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\DisabledComponents"]}} -------------------------------------------------------------------------------- /policies/rhel_6_meltdown_spectre_kernel_version_policy: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "rhel_6_meltdownspectre_", 4 | "short_description": "RHEL 6 Meltdown/Spectre ", 5 | "description": "", 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "packages": [ 18 | { 19 | "yum": [ 20 | { 21 | "name": "kernel", 22 | "checks": { 23 | "version": [ 24 | { 25 | "cond": [ 26 | { 27 | "op": ">=", 28 | "val": "2.6.32-696.18.7.el6" 29 | } 30 | ], 31 | "check": "version_comparison", 32 | "expected": "2.6.32-431.29.2.el6", 33 | "background": "See Red Hat advisory here: https://access.redhat.com/errata/RHSA-2018:0008", 34 | "remediation": "Update kernel to latest version." 35 | } 36 | ] 37 | }, 38 | "ci_path": [ 39 | "packages", 40 | "yum", 41 | "kernel" 42 | ], 43 | "packages": { 44 | "name": "kernel" 45 | }, 46 | "check_type": "packages" 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | ], 53 | "scan_options": {} 54 | } 55 | -------------------------------------------------------------------------------- /policies/rhel_7_meltdown_spectre_kernel_version_check: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "rhel_7_meltdownspectre", 4 | "short_description": "RHEL 7 Meltdown/Spectre", 5 | "description": null, 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "packages": [ 18 | { 19 | "yum": [ 20 | { 21 | "name": "kernel", 22 | "checks": { 23 | "version": [ 24 | { 25 | "cond": [ 26 | { 27 | "op": ">=", 28 | "val": "3.10.0-693.11.6.el7" 29 | } 30 | ], 31 | "check": "version_comparison", 32 | "expected": "3.10.0-693.el7", 33 | "background": "See https://access.redhat.com/errata/RHSA-2018:0007 for the Red Hat advisory.", 34 | "remediation": "Update kernel to latest version." 35 | } 36 | ] 37 | }, 38 | "ci_path": [ 39 | "packages", 40 | "yum", 41 | "kernel" 42 | ], 43 | "packages": { 44 | "name": "kernel" 45 | }, 46 | "check_type": "packages" 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | ], 53 | "scan_options": {} 54 | } 55 | -------------------------------------------------------------------------------- /policies/s3_access_control_lists.json: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "s3_bucket_access", 4 | "short_description": "S3 Bucket Access", 5 | "description": "Validate permissions on S3 buckets to ensure they are not exposing the contents to the general public", 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": 14, 12 | "operating_system_id": 1416, 13 | "type": null 14 | }, 15 | "data": [{ 16 | "Permissions":[{ 17 | "All":[{ 18 | "name":"Item mapping to Permissions,All should not contain the defined values", 19 | "checks":{ 20 | "Value":[{ 21 | "check":"excludes", 22 | "expected":"http://acs.amazonaws.com/groups/global/AllUsers" 23 | }, 24 | { 25 | "check":"excludes", 26 | "expected":"http://acs.amazonaws.com/groups/global/AuthenticatedUsers" 27 | }] 28 | }, 29 | "ci_path":["Permissions","All","*"], 30 | "check_type":"permissions", 31 | "Permissions":{ 32 | "name":"All" 33 | } 34 | }] 35 | }] 36 | }], 37 | "scan_options": {} 38 | } 39 | -------------------------------------------------------------------------------- /policies/s3_bucket_and_content_permission_check.json: -------------------------------------------------------------------------------- 1 | {"policy":{"name":"s3_permission","short_description":"S3 Permission","description":null,"settings":{"tests":{"output_format":null}},"operating_system_family_id":null,"operating_system_id":null,"type":null},"data":[{"S3 Bucket Permissions":[{"id":"S3-Bucket-PermissionsRoot-Bucket-Permission-Check","name":"Root Bucket Permission Check","error":false,"checks":{"Value":{"check":"excludes","expected":"http://acs.amazonaws.com/groups/global/AllUsers","background":"The All Users group exposes the content of a bucket to any registered AWS user which can result in an exposure of data.","remediation":"Confirm that any level of permission to an S3 bucket does not allow for the AWS all users group to access the bucket.","valueSelectList":null,"attributeSelectList":null,"availableAttributes":null}},"ci_path":["Permissions","*","*"],"check_type":"other","path_error":"","description":"Root Bucket Permission Check","nodeGroupsOpen":true}]},{"S3 Content Validation":[{"id":"S3-Content-ValidationValidate-that-S3-bucket-content-isn-t-exposed-to-all-users-","name":"Validate that S3 bucket content isn't exposed to all users.","error":false,"checks":{"ACL":[{"exp":"http://acs.amazonaws.com/groups/global/AllUsers","check":"excludes","expected":"http://acs.amazonaws.com/groups/global/AllUsers","background":"The AllUsers group when granted a level of permission to a piece of content on an S3 bucket could potentially represent an exposure or breach of sensitive data.","remediation":"Modify the content access control list to remove permission to the AWS all users group."}]},"ci_path":["Objects","*","*"],"check_type":"other","path_error":"","selectList":["*"],"description":"Validate that S3 bucket content isn't exposed to all users.","nodeGroupsOpen":true}]}],"scan_options":{}} -------------------------------------------------------------------------------- /policies/sles_11.4_meltdown_spectre_kernel_version_check: -------------------------------------------------------------------------------- 1 | { 2 | "policy": { 3 | "name": "suse_11_sp4_meltdown_kernel_check", 4 | "short_description": "SUSE 11 SP4 Meltdown Kernel Check", 5 | "description": "", 6 | "settings": { 7 | "tests": { 8 | "output_format": null 9 | } 10 | }, 11 | "operating_system_family_id": null, 12 | "operating_system_id": null, 13 | "type": null 14 | }, 15 | "data": [ 16 | { 17 | "packages": [ 18 | { 19 | "yum": [ 20 | { 21 | "id": "packagesyumThe-kernel-package-should-be-upgraded-above-versions-affected-by-Meltdown-", 22 | "name": "The kernel package should be upgraded above versions affected by Meltdown.", 23 | "checks": { 24 | "version": [ 25 | { 26 | "cond": [ 27 | { 28 | "op": ">=", 29 | "val": "3.0.101-108.21.1" 30 | } 31 | ], 32 | "check": "version_comparison", 33 | "expected": "3.0.101-108.21.1", 34 | "background": "See SUSE advisory for Meltdown and Spectre: https://www.suse.com/support/kb/doc/?id=7022512", 35 | "remediation": "Update kernel to latest version." 36 | } 37 | ] 38 | }, 39 | "ci_path": [ 40 | "packages", 41 | "yum", 42 | "kernel-default" 43 | ], 44 | "packages": { 45 | "name": "kernel-default" 46 | }, 47 | "check_type": "packages", 48 | "description": "The kernel package should be upgraded above versions affected by Meltdown.", 49 | "nodeGroupsOpen": true 50 | }, 51 | { 52 | "id": "packagesyumThe-package-microcode-ctl-should-be-installed-", 53 | "name": "The microcode_ctl package should be upgraded above versions affected by Meltdown.", 54 | "error": false, 55 | "checks": { 56 | "version": [ 57 | { 58 | "check": "version_comparison", 59 | "background": "https://www.suse.com/support/kb/doc/?id=7022512", 60 | "absent_pass": true, 61 | "remediation": "Upgrade microcode_ctl." 62 | } 63 | ] 64 | }, 65 | "ci_path": [ 66 | "packages", 67 | "yum", 68 | "microcode_ctl" 69 | ], 70 | "packages": { 71 | "name": "microcode_ctl", 72 | "provider": "*" 73 | }, 74 | "check_type": "packages", 75 | "selectList": [ 76 | "{\"status\":\"installed\",\"version\":\"2.1-22.el7\"}", 77 | "{\"status\":\"installed\",\"version\":\"2.1-16.3.el7_3\"}", 78 | "*" 79 | ], 80 | "description": "The microcode_ctl package should be upgraded above versions affected by Meltdown.", 81 | "nodeGroupsOpen": true 82 | } 83 | ] 84 | } 85 | ] 86 | } 87 | ], 88 | "scan_options": {} 89 | } 90 | -------------------------------------------------------------------------------- /scan-options/linux/bash/file-hash-by-extension.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Get all files in all subdirectories 3 | # find . -type f|sed 's/\.\///'|sort 4 | 5 | /usr/bin/find . \! -type d -a \! -type s | sort | xargs md5sum 6 | 7 | # Prints something like: 8 | # 9ffdedb691b43906e2dc4a29b88f5f1c ./cluster/prod/media/Makefile 9 | # fa95448d456e4e8b5cfbeeb7e1f8b6d1 ./cluster/prod/media/context -------------------------------------------------------------------------------- /scan-options/windows/powershell/active-directory-schema.ps1: -------------------------------------------------------------------------------- 1 | Import-Module ActiveDirectory 2 | 3 | $schema = Get-ADObject -SearchBase ((Get-ADRootDSE -Server (hostname)).schemaNamingContext) -SearchScope OneLevel -Filter * -Property objectClass, name, whenChanged,` 4 | whenCreated | Select-Object objectClass, name, whenCreated, whenChanged, ` 5 | @{name="event";expression={($_.whenCreated).Date.ToShortDateString()}} | ` 6 | Sort-Object whenCreated 7 | 8 | $output = '' | Select name, raw 9 | $output.name = 'AD Schema' 10 | $output.raw = '' 11 | foreach($result in $schema) { 12 | $output.raw += $result | Select objectClass, name, whenCreated, whenChanged 13 | $output.raw += "`r`n" 14 | } 15 | 16 | $output 17 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/com-plus.ps1: -------------------------------------------------------------------------------- 1 | $ComAdmin = New-Object -com COMAdmin.COMAdminCatalog 2 | $oapplications = $ComAdmin.getcollection('Applications') 3 | [HashTable[]]$collected = @() 4 | $baseDetails = @('ID', 'Name', 'AppPartitionID', 'State') 5 | $additionalDetails = @('RecycleMemoryLimit', 'AuthenticationCapability') 6 | $allDetails = $baseDetails + $additionalDetails 7 | $longestFieldLength = 0 8 | 9 | if ($oapplications) { 10 | $oapplications.populate() 11 | 12 | foreach ($oapplication in $oapplications){ 13 | $obj = @{} 14 | $skeyappli = $oapplication.key 15 | $oappliInstances = $oapplications.getcollection('ApplicationInstances',$skeyappli) 16 | $oappliInstances.populate() 17 | 18 | If ($oappliInstances.count -eq 0) { 19 | $obj['State'] = 'Stopped' 20 | } Else{ 21 | $obj['State'] = 'Running' 22 | } 23 | 24 | foreach($prop in $allDetails) { 25 | #"Prop: " + $prop 26 | try { 27 | # state must be included in details for output, but it is not a property per se 28 | if ($prop -ne 'Password' -and $prop -ne 'State') { 29 | # if there are multiple things with the same name, the last value will be reported 30 | $obj[$prop] = $oapplication.Value($prop) 31 | 32 | if($obj[$prop].ToString().Length -gt $longestFieldLength) { 33 | $longestFieldLength = $obj[$prop].ToString().Length 34 | } 35 | } 36 | 37 | } catch { 38 | "Exception encountered: " + $_.Exception.Message 39 | } 40 | } 41 | 42 | $collected += $obj 43 | } 44 | } 45 | 46 | $collected = $collected | Sort-Object { $_['Name'] } 47 | $com_plus = '' 48 | 49 | # need the extra space for padding between columns 50 | foreach($deet in $allDetails) { 51 | $com_plus += $deet + (' ' * ($longestFieldLength - $deet.Length)) + ' ' 52 | } 53 | 54 | $com_plus += "`r`n" 55 | 56 | $com_plus += ('-' * ($com_plus.Length - 2)) + "`r`n" 57 | 58 | foreach($o in $collected) { 59 | foreach($key in $allDetails) { 60 | if($key -ne "Password") { 61 | $com_plus += $o[$key].ToString() + (' ' * ($longestFieldLength - $o[$key].ToString().Length)) + ' ' 62 | } 63 | } 64 | $com_plus += "`r`n" 65 | } 66 | 67 | $output = "" | Select folder, raw 68 | $output.folder = $folder 69 | $output.raw = $com_plus 70 | $output 71 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/computers-in-active-directory.ps1: -------------------------------------------------------------------------------- 1 | $strFilter = '(objectClass=User)' 2 | $objDomain = New-Object System.DirectoryServices.DirectoryEntry 'LDAP://DC=your,DC=ou,DC=here' 3 | $objSearcher = New-Object System.DirectoryServices.DirectorySearcher 4 | $objSearcher.SearchRoot = $objDomain 5 | $objSearcher.PageSize = 1000 6 | $objSearcher.Filter = $strFilter 7 | $objSearcher.SearchScope = 'Subtree' 8 | $colProplist = 'dnshostname','name','operatingsystem' 9 | foreach ($i in $colPropList) { 10 | $objSearcher.PropertiesToLoad.Add($i) 11 | } 12 | $colResults = $objSearcher.FindAll() 13 | $finalResults = @() 14 | foreach ($objResult in $colResults) { 15 | foreach($prop in $objResult.Properties) { 16 | $obj = New-Object -TypeName PSObject 17 | foreach($col in $colProplist) { 18 | $obj | Add-Member -MemberType NoteProperty -Name $col -Value $prop[$col] 19 | } 20 | } 21 | } 22 | $finalResults -------------------------------------------------------------------------------- /scan-options/windows/powershell/dns-reverse-search.ps1: -------------------------------------------------------------------------------- 1 | try { 2 | $dnsObj = @() 3 | $dns_results = (gwmi -query "select * from win32_networkadapterconfiguration where ipenabled = true").dnsserversearchorder 4 | $dns_results_count = 0 5 | foreach ($dns_value in $dns_results) { 6 | $tempObj = New-Object -TypeName PSObject 7 | $dns_results_count += 1 8 | $dns_key = "dnsReverseSearchEntry" + $dns_results_count 9 | $tempObj | Add-Member -MemberType NoteProperty –Name $dns_key –Value $dns_value 10 | $tempObj | Add-Member -MemberType NoteProperty –Name "ReverseDNS" –Value "DNS Reverse Search Entry $dns_results_count" 11 | $dnsObj += $tempObj 12 | } 13 | $dnsObj 14 | } catch { 15 | "Exception encountered: " + $_.Exception.Message 16 | } 17 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/file-hash-by-directory-with-excluded-directories.ps1: -------------------------------------------------------------------------------- 1 | # Given a path, return hashes for all files (in the directory and subdirectories) of a given type 2 | 3 | $path = "C:\files" 4 | # Filetypes that should be returned in the scan 5 | $includeFiles = @( 6 | "*.html", 7 | "*.js", 8 | "*.asp", 9 | "*.dll", 10 | "*.aspx", 11 | "*.config", 12 | "*.xsl", 13 | "*.xml", 14 | "*.json", 15 | "*.htm", 16 | "*.xslt", 17 | "*.properties" 18 | ) 19 | # Exclude directories with regular expressions. At least one exclude is required for the script to work 20 | # Directories with backslashes will need to be escaped as \\ 21 | $excludeDirRegex = @( 22 | "C:\\files\\AddLifecycle\\ApproveData.*" 23 | ".*ignore.*" 24 | ) 25 | 26 | $output = @() 27 | $paths = @(gi $path | % { $_.FullName }) + @(Get-ChildItem $path -Recurse -Directory -ErrorAction SilentlyContinue | Where { $_.FullName -notmatch ( $excludeDirRegex -join '|' ) } | % { $_.FullName }) 28 | $paths | ForEach-Object { 29 | $fullpath = $_ 30 | $dir = New-Object –TypeName PSObject -Property @{ 31 | Directory = "$($fullpath)" 32 | } 33 | Get-ChildItem -Path "$($fullpath)" -Include $includeFiles -File -Name | ForEach-Object { 34 | $filepath = "$($fullpath)\$($_)" 35 | $dir | Add-Member -MemberType NoteProperty -Name $filepath -Value (Get-FileHash $filepath).Hash.ToString() 36 | } 37 | $output += $dir 38 | } 39 | $output 40 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/file-hash-by-directory.ps1: -------------------------------------------------------------------------------- 1 | # Given a path, return hashes for all files (in the directory and subdirectories) of a given type, grouped by directory name 2 | # Powershell Scan Option Key: Directory 3 | 4 | $path = "C:\files" 5 | $include = @( 6 | "*.html", 7 | "*.js", 8 | "*.asp", 9 | "*.dll", 10 | "*.aspx", 11 | "*.config", 12 | "*.xsl", 13 | "*.xml", 14 | "*.json", 15 | "*.htm", 16 | "*.xslt", 17 | "*.properties" 18 | ) 19 | 20 | $output = @() 21 | $paths = @(gi $path) + @(Get-ChildItem $path -Recurse -Directory -ErrorAction SilentlyContinue | % { $_.FullName }) 22 | $paths | ForEach-Object { 23 | $fullpath = $_ 24 | $dir = New-Object –TypeName PSObject -Property @{ 25 | Directory = "$($fullpath)" 26 | } 27 | Get-ChildItem -Path "$($fullpath)" -Include $include -File -Name | ForEach-Object { 28 | $filepath = "$($fullpath)\$($_)" 29 | $dir | Add-Member -MemberType NoteProperty -Name $filepath -Value (Get-FileHash $filepath).Hash.ToString() 30 | } 31 | $output += $dir 32 | } 33 | $output 34 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/fim-scanner.ps1: -------------------------------------------------------------------------------- 1 | $fimDataFolder = 'C:\Program Files (x86)\ScriptRockFIMScanner-1.0\Output' 2 | $dataFiles = (Get-ChildItem $fimDataFolder | Where { $_.Extension -eq '.fim' } | Sort-Object) 3 | $discoveredFiles = @{} 4 | $sortableFiles = @() 5 | $currentIndex = 1 6 | $finalOutput = '' 7 | 8 | if((Get-Service 'ScriptRock FIM').Status -ne [System.ServiceProcess.ServiceControllerStatus]::Stopped) { 9 | Stop-Service -DisplayName 'ScriptRock FIM' 10 | 11 | Start-Sleep -s 10 12 | 13 | Start-Service -DisplayName 'ScriptRock FIM' 14 | } 15 | 16 | foreach($dataFile in $dataFiles) { 17 | 18 | # last one should be in use 19 | if($currentIndex -ge $dataFiles.Length) { 20 | break 21 | } 22 | 23 | foreach($row in Import-Csv $dataFile.FullName) { 24 | $key = '' 25 | 26 | switch ($row.'Change Type') { 27 | 'CREATE' { $key = $row.File } 28 | 'CHANGE' { $key = $row.File } 29 | 'RENAME' { $key = $row.'Old Value' } 30 | 'DELETE' { $key = $row.'Old Value' } 31 | } 32 | 33 | if ($discoveredFiles.ContainsKey($key)) { 34 | if (($discoveredFiles[$key] -contains $row.'Change Type') -eq $FALSE) { 35 | $discoveredFiles[$key] += $row.'Time Stamp'; 36 | $discoveredFiles[$key] += $row.'Change Type'; 37 | } 38 | } else { 39 | $discoveredFiles.Add($key, @($row.'Time Stamp', $row.'Change Type')) 40 | } 41 | } 42 | 43 | Remove-Item $dataFile.FullName 44 | $currentIndex++ 45 | } 46 | 47 | foreach ($kvp in $discoveredFiles.GetEnumerator()) { 48 | $entry = $kvp.Key + ' ' 49 | 50 | foreach($c in $kvp.Value) { 51 | $entry += $c + ' ' 52 | } 53 | 54 | $entry += "`r`n" 55 | $sortableFiles += $entry 56 | } 57 | 58 | $sortableFiles = ($sortableFiles | Sort-Object) 59 | 60 | foreach ($f in $sortableFiles) { 61 | $finalOutput += $f 62 | } 63 | 64 | if((Get-Service 'ScriptRock FIM').Status -eq [System.ServiceProcess.ServiceControllerStatus]::Stopped) { 65 | Start-Service -DisplayName 'ScriptRock FIM' 66 | } 67 | 68 | $output = "" | Select folder, raw 69 | $output.folder = 'FIM' 70 | $output.raw = $finalOutput 71 | 72 | $output 73 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/gac.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | When setting the scan options, use the following values for the `PowerShell Queries` scan option: 4 | 5 | `Description`: `GAC` 6 | `Key Name`: `Name` 7 | `Query`: Script as provided in `scan-options-gac.ps1` 8 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/gac.ps1: -------------------------------------------------------------------------------- 1 | [regex]$regex = '(?\S+), Version=(?\S+), Culture=(?\S+), PublicKeyToken=(?\S+)' 2 | $folder = "C:\Windows\Assembly" 3 | $gac = @() 4 | 5 | foreach($f in Get-ChildItem -Path $folder -Recurse -Force -ErrorAction SilentlyContinue | where { ! $_.PSIsContainer }) 6 | { 7 | try { 8 | $obj = '' | Select Name, Culture, Version, PublicKeyToken 9 | $a = [Reflection.Assembly]::LoadFile($f.FullName).FullName 10 | $fv = [Diagnostics.FileVersionInfo]::GetVersionInfo($f.FullName).FileVersion 11 | $result = $a -match $regex 12 | $subfolder = $f.FullName.Split('\')[3] 13 | $name = $subfolder + '-' + $matches.Name 14 | 15 | $tempObj = New-Object –TypeName PSObject 16 | $tempObj | Add-Member -MemberType NoteProperty –Name Name –Value $name 17 | $tempObj | Add-Member -MemberType NoteProperty –Name Path –Value $f.FullName 18 | $tempObj | Add-Member -MemberType NoteProperty –Name Culture –Value $matches.Culture 19 | $tempObj | Add-Member -MemberType NoteProperty –Name Version –Value $matches.Version 20 | $tempObj | Add-Member -MemberType NoteProperty -Name PublicKeyToken -Value $matches.PublicKeyToken 21 | $tempObj | Add-Member -MemberType NoteProperty -Name FileVersion -Value $fv 22 | $tempObj | Add-Member -MemberType NoteProperty -Name SubFolder -Value $subfolder 23 | 24 | $gac += $tempObj 25 | } catch [System.Exception] { 26 | $err = "Could not read file " + $f + ": " + $_.Exception.Message 27 | } 28 | } 29 | $gac 30 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/iis-app-pools-dynamic.ps1: -------------------------------------------------------------------------------- 1 | if (Get-Module -ListAvailable | Where-Object { $_.Name -eq "WebAdministration" }) { 2 | Import-Module WebAdministration 3 | } else { 4 | Add-PSSnapin WebAdministration 5 | } 6 | 7 | Get-Item IIS:\AppPools | Get-ChildItem | Select Name, State, StartMode, ManagedRuntimeVersion, ManagedPipelineMode 8 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/iis-app-pools-static.ps1: -------------------------------------------------------------------------------- 1 | $webConfig = 'C:\Windows\System32\inetsrv\config\applicationHost.config' 2 | $doc = (Get-Content $webConfig) -as [Xml] 3 | $output = @() 4 | foreach($ap in $doc.configuration."system.applicationHost".applicationPools.add) { 5 | $tempObj = New-Object -TypeName PSObject 6 | $tempObj | Add-Member -MemberType NoteProperty -Name Name -Value $ap.name 7 | $tempObj | Add-Member -MemberType NoteProperty -Name ManagedRuntimeVersion -Value $ap.managedRuntimeVersion 8 | $tempObj | Add-Member -MemberType NoteProperty -Name ManagedPipelineMode -Value $ap.managedPipelineMode 9 | $tempObj | Add-Member -MemberType NoteProperty -Name AutoStart -Value $ap.autoStart 10 | $output += $tempObj 11 | } 12 | $output 13 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/iis-virtual-directories.ps1: -------------------------------------------------------------------------------- 1 | $webConfig = 'C:\Windows\System32\inetsrv\config\applicationHost.config' 2 | $doc = (Get-Content $webConfig) -as [Xml] 3 | $output = @() 4 | foreach($site in $doc.configuration."system.applicationHost".sites.site) { 5 | foreach($vdir in $site.application.virtualDirectory) { 6 | $tempObj = New-Object -TypeName PSObject 7 | $tempObj | Add-Member -MemberType NoteProperty -Name Name -Value "$($site.name): $($vdir.path)" 8 | $tempObj | Add-Member -MemberType NoteProperty -Name PhysicalPath -Value $vdir.physicalPath 9 | $output += $tempObj 10 | } 11 | } 12 | $output 13 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/iis-website-information.ps1: -------------------------------------------------------------------------------- 1 | $webConfig = 'C:\Windows\System32\inetsrv\config\applicationHost.config' 2 | $doc = (Get-Content $webConfig) -as [Xml] 3 | $output = @() 4 | foreach($site in $doc.configuration."system.applicationHost".sites.site) { 5 | $tempObj = New-Object -TypeName PSObject 6 | $tempObj | Add-Member -MemberType NoteProperty -Name Name -Value $site.name 7 | $tempObj | Add-Member -MemberType NoteProperty -Name Id -Value $site.id 8 | $tempObj | Add-Member -MemberType NoteProperty -Name ServerAutoStart -Value $site.serverAutoStart 9 | $output += $tempObj 10 | } 11 | $output 12 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/local-security-policies.ps1: -------------------------------------------------------------------------------- 1 | Function Parse-SecPol($CfgFile){ 2 | secedit /export /cfg "$CfgFile" | out-null 3 | $Result = @() 4 | $index = 0 5 | $contents = Get-Content $CfgFile -raw 6 | [regex]::Matches($contents,"(?<=\[)(.*)(?=\])") | %{ 7 | $obj = New-Object PSObject 8 | $obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $_ 9 | [regex]::Matches($contents,"(?<=\]).*?((?=\[)|(\Z))", [System.Text.RegularExpressions.RegexOptions]::Singleline)[$index] | %{ 10 | $_.value -split "\r\n" | ?{$_.length -gt 0} | %{ 11 | $value = [regex]::Match($_,"(?<=\=).*").value 12 | $name = [regex]::Match($_,".*(?=\=)").value 13 | $obj | Add-Member -MemberType NoteProperty -Name $name.tostring().trim() -Value $value.tostring().trim() -ErrorAction SilentlyContinue | out-null 14 | } 15 | } 16 | $Result += $obj 17 | $index += 1 18 | } 19 | return $Result 20 | } 21 | $SecPol = Parse-SecPol -CfgFile C:\LocalSecurityPolicy.cfg 22 | $SecPol 23 | 24 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/recursive-file-integrity-check.ps1: -------------------------------------------------------------------------------- 1 |  2 | # 1. Set the folder path 3 | $folder = "C:\Windows\System32\drivers" 4 | 5 | # 2. Specify file extentions 6 | $include_extentions = "all"; 7 | #$include_extentions = ".dll", ".config" 8 | 9 | $crypto = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider 10 | 11 | foreach($f in Get-ChildItem -Path $folder -Recurse -Force -ErrorAction SilentlyContinue) { 12 | if ($f.PSIsContainer) { continue; } 13 | try { 14 | $cast = [System.IO.FileInfo]$f 15 | $extension = $f.Extension 16 | if ($include_extentions -contains $extension -or $include_extentions -contains "all" ) { 17 | $bytes = [System.IO.File]::ReadAllBytes($f.FullName) 18 | $hash = [System.BitConverter]::ToString($crypto.ComputeHash($bytes)) 19 | 20 | if ($f.DirectoryName -ne $last_subfolder) { 21 | $hashes += "# " 22 | $hashes += $f.DirectoryName 23 | $hashes += "`r`n" 24 | $last_subfolder = $f.DirectoryName 25 | } 26 | $hashes += $hash.Replace('-','').ToLower() 27 | $hashes += ": " 28 | $version = $f.VersionInfo.FileVersion 29 | if ($version.length -gt 0) { 30 | $hashes += $version 31 | $hashes += " - " 32 | } 33 | $hashes += $f.Name 34 | $hashes += "`r`n" 35 | } 36 | } catch [System.InvalidCastException] { 37 | #Continue 38 | } catch [System.Exception] { 39 | "Error: " + $f.FullName + ": " + $_.Exception.Message 40 | } 41 | } 42 | 43 | $output = "" | Select folder, raw 44 | $output.folder = $folder 45 | $output.raw = $hashes 46 | 47 | $output 48 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/share-permissions.ps1: -------------------------------------------------------------------------------- 1 | # Return all Windows shares along with the permissions for each share 2 | # Description: Share Permissions 3 | # Key Name: Name 4 | 5 | $all_shares = Get-WmiObject win32_LogicalShareSecuritySetting 6 | $shares = @() 7 | if($all_shares){ 8 | foreach($s in $all_shares){ 9 | $obj = New-Object –TypeName PSObject 10 | $obj | Add-Member -MemberType NoteProperty –Name Name –Value $s.name 11 | $ACLS = $s.GetSecurityDescriptor().Descriptor.DACL 12 | $permissions = @{} 13 | foreach($ACL in $ACLS){ 14 | $User = $ACL.Trustee.Name 15 | if(!($user)){$user = $ACL.Trustee.SID} 16 | $Domain = $ACL.Trustee.Domain 17 | switch($ACL.AccessMask) 18 | { 19 | 2032127 {$Perm = "Full Control"} 20 | 1245631 {$Perm = "Change"} 21 | 1179817 {$Perm = "Read"} 22 | } 23 | # Write-Host "$($s.Name) $Domain\$user $Perm" 24 | if($Domain){ 25 | $permissions.Add("$($Domain)\\$($user)", $Perm) 26 | }else{ 27 | $permissions.Add($user, $Perm) 28 | } 29 | } 30 | $obj | Add-Member -MemberType NoteProperty -Name Permissions -Value $permissions 31 | $shares += $obj 32 | } 33 | } 34 | $shares 35 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/stored-procedures.ps1: -------------------------------------------------------------------------------- 1 | # Return a hash for each stored procedure for a given database 2 | # Modify the $databases array to specify the databases to query 3 | # Note: This can take a while, you will likely need to increase the test timeout 4 | 5 | # Description: MS SQL Stored Procedures 6 | # Key Name: Name 7 | 8 | $databases = @("tempdb") 9 | 10 | $result = New-Object –TypeName PSObject 11 | Import-Module “sqlps” -DisableNameChecking 12 | $dbs = Get-ChildItem -FORCE SQLSERVER:\SQL\localhost\DEFAULT\Databases 13 | ForEach($db in $dbs) 14 | { 15 | if($db.Name -in $databases) 16 | { 17 | $procedures = @{} 18 | ForEach($sp in $db.StoredProcedures) 19 | { 20 | $name = "$($sp.Schema).$($sp.Name)" 21 | if($sp.TextBody){$text = $sp.TextBody.ToString()}else{$text = ""} 22 | 23 | # Convert to hash 24 | $hash = New-Object System.Text.StringBuilder 25 | [System.Security.Cryptography.HashAlgorithm]::Create("MD5").ComputeHash([System.Text.Encoding]::UTF8.GetBytes($text))|%{[Void]$hash.Append($_.ToString("x2"))} 26 | 27 | $procedures.Add($name, $hash.ToString()) 28 | } 29 | $result | Add-Member -MemberType NoteProperty –Name $db.Name –Value $procedures 30 | } 31 | } 32 | $result 33 | -------------------------------------------------------------------------------- /scan-options/windows/powershell/system-audit-policies.ps1: -------------------------------------------------------------------------------- 1 | $Result = @() 2 | 3 | $output = auditpol /list /category 4 | 5 | $output | ForEach-Object -Process { 6 | $cat = $_.Trim() 7 | if ($cat -eq "Category/Subcategory") { 8 | return 9 | } 10 | 11 | $obj = New-Object psobject 12 | $obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $cat 13 | 14 | auditpol /get /category:"$cat" | Foreach-Object -Process { 15 | $line = $_ 16 | if (-Not $line.StartsWith(" ")) { 17 | return 18 | } 19 | 20 | $tokens = $line -split " " 21 | $key = "" 22 | $val = "" 23 | foreach ($token in $tokens) { 24 | if ($token.trim() -eq "") { 25 | continue 26 | } 27 | if ($key -eq "") { 28 | $key = $token 29 | } else { 30 | $val = $token 31 | } 32 | } 33 | 34 | $obj | Add-Member -MemberType NoteProperty -Name $key.ToString().Trim() -Value $val.ToString().Trim() -ErrorAction SilentlyContinue 35 | } 36 | $Result += $obj 37 | } 38 | 39 | $Result -------------------------------------------------------------------------------- /scan-options/windows/powershell/users-in-active-directory.ps1: -------------------------------------------------------------------------------- 1 | $strFilter = '(objectClass=User)' 2 | $objDomain = New-Object System.DirectoryServices.DirectoryEntry 'LDAP://DC=your,DC=ou,DC=here' 3 | $objSearcher = New-Object System.DirectoryServices.DirectorySearcher 4 | $objSearcher.SearchRoot = $objDomain 5 | $objSearcher.PageSize = 1000 6 | $objSearcher.Filter = $strFilter 7 | $objSearcher.SearchScope = 'Subtree' 8 | $colProplist = 'sAMAccountName','mail','name' 9 | foreach ($i in $colPropList) { 10 | $objSearcher.PropertiesToLoad.Add($i) 11 | } 12 | $colResults = $objSearcher.FindAll() 13 | $finalResults = @() 14 | foreach ($objResult in $colResults) { 15 | foreach($prop in $objResult.Properties) { 16 | $obj = New-Object -TypeName PSObject 17 | foreach($col in $colProplist) { 18 | $obj | Add-Member -MemberType NoteProperty -Name $col -Value $prop[$col] 19 | } 20 | } 21 | } 22 | $finalResults -------------------------------------------------------------------------------- /setup and utilities/WINRM PS Settings.htm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/setup and utilities/WINRM PS Settings.htm -------------------------------------------------------------------------------- /setup and utilities/bat/wincm/check-service.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | for /F "tokens=3 delims=: " %%H in ('sc query "upguardd" ^| findstr "STATE"') do ( 4 | if /I "%%H" NEQ "RUNNING" ( 5 | echo "UpGuard Service not running" 6 | echo "Starting..." 7 | net start "upguardd" 8 | ) else ( 9 | echo "UpGuard Service running" 10 | ) 11 | ) 12 | 13 | 14 | -------------------------------------------------------------------------------- /setup and utilities/gpreport.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/setup and utilities/gpreport.xml -------------------------------------------------------------------------------- /setup and utilities/winrm_v1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudhousetech/content/84fda2a16d04f56def651abb4694c2afc0a3cce7/setup and utilities/winrm_v1.zip --------------------------------------------------------------------------------