├── Graylog_Config.md ├── Keycloak_Config.md ├── README.md ├── Selinux_userns.md ├── Splunk_Config.md ├── basic_pki_auth.md ├── policies └── 30-day-age_policy.json ├── stackrox_classifications.sh ├── stackrox_compliance_scan.sh ├── stackrox_networksim.sh ├── stackrox_offline ├── README.md ├── getoffline_stackrox.sh ├── offline_install.sh └── offline_registry_install.sh ├── stackrox_oss.sh ├── stackrox_policy_importer.sh ├── stackrox_violations_report.sh ├── stackrox_vuln_report.sh └── workshop ├── README.md ├── images ├── api.jpg ├── api_token.jpg ├── banners.jpg ├── edit_nmap.jpg ├── health.jpg ├── help.jpg ├── integrations.jpg ├── jenkins1.jpg ├── jenkins2.jpg ├── nmap.jpg ├── plugins.jpg ├── policy1.jpg ├── runtime_nmap.jpg ├── sr_up.jpg └── success.jpg ├── master_build.sh └── workshop.sh /Graylog_Config.md: -------------------------------------------------------------------------------- 1 | # Graylog Config for Stackrox 2 | 3 | ## Deploy Graylog 4 | 5 | From : [Graylog](https://www.graylog.org/) 6 | 7 | Assumptions: 8 | 9 | * Running Kubernetes 10 | * Will error without [Traefik](https://traefik.io/) 11 | * Stackrox is up and running 12 | * CLI access 13 | 14 | We are going to deploy with https://github.com/clemenko/k8s_yaml/blob/master/graylog.yaml. 15 | 16 | ```bash 17 | # without traefik you will get an error for `IngressRoute` you can ignore this. 18 | kubectl apply -f https://raw.githubusercontent.com/clemenko/k8s_yaml/master/graylog.yaml 19 | ``` 20 | 21 | ### GUI time 22 | 23 | * The default username is `admin`. 24 | * The default password is `Pa22word`. 25 | 26 | We need to create the `input` from `System / Input` --> `Inputs`. Select `Syslog TCP` and click `Launch new Input`. 27 | 28 | Within the Input window select `Global`, give it a name and save. Do not change the bind address or port. 29 | 30 | Or we can use `curl`: 31 | 32 | ```bash 33 | # default username and password 34 | username=admin 35 | password=Pa22word 36 | 37 | # Server 38 | server=graylog.dockr.life 39 | 40 | # curl away 41 | curl -k -u $username:$password -X POST http://$server/api/system/inputs \ 42 | -H 'Connection: keep-alive' -H 'Accept: application/json' -H 'X-Requested-With: XMLHttpRequest' -H 'X-Requested-By: XMLHttpRequest' -H 'Content-Type: application/json' \ 43 | -d '{"title":"syslog","type":"org.graylog2.inputs.syslog.tcp.SyslogTCPInput","configuration":{"bind_address":"0.0.0.0","port":514,"recv_buffer_size":1048576,"number_worker_threads":1,"tls_cert_file":"","tls_key_file":"","tls_enable":false,"tls_key_password":"","tls_client_auth":"disabled","tls_client_auth_cert_file":"","tcp_keepalive":false,"use_null_delimiter":false,"max_message_size":2097152,"override_source":null,"force_rdns":false,"allow_override_date":true,"store_full_message":true,"expand_structured_data":false},"global":true,"node":"1195da76-5df0-4122-b701-ed392e0efe95"}' 44 | ``` 45 | 46 | Done with Graylog... 47 | 48 | ## Configure StackRox 49 | 50 | From the StackRox gui, goto `Platform Configuration` --> `Integrations`. Scroll down to and click on `Syslog`. Click the plus in the upper right. Add a name. Leave the formate `CEF`. Leave the log facility as local0. Set the receiver host to `graylog.graylog`. Set the receiver port to `514`. Now Save. 51 | 52 | Thats it. 53 | 54 | ## Testing 55 | 56 | From an alpine container withing the cluster. 57 | 58 | ```bash 59 | # add logger to the container 60 | apk -U add util-linux 61 | 62 | # test logger 63 | 64 | logger -n graylog.graylog -P 514 -T "hello from the outside" 65 | ``` 66 | -------------------------------------------------------------------------------- /Keycloak_Config.md: -------------------------------------------------------------------------------- 1 | # Keycloak Config 2 | 3 | This doc is to help deploy [Keycloak](https://www.keycloak.org/) and configure [StackRox](https://stackrox.com). 4 | 5 | ## Deploy Keycloak 6 | 7 | This deployment is designed for use with [Traefik](https://traefik.io/). An `IngressRouteTCP` is included for TLS passthrough to the self signed cert of keycloak 8 | 9 | `kubectl apply -f https://raw.githubusercontent.com/clemenko/k8s_yaml/master/keycloak.yml` 10 | 11 | Login with username : `admin` and password `Pa22word`. 12 | 13 | ### Configure Stackrox Realm in Keycloak 14 | 15 | Click **Master --> Add realm** and name it `stackrox`. 16 | 17 | ### Create user 18 | 19 | Next click the **Users** on the left and **Add User**. This should be obvious. Next click the **Credentials** tab to enter a password. Also make sure `Temporary` is off. And click `Reset Password` 20 | 21 | --- 22 | 23 | ## OIDC Configuration 24 | 25 | ### Add Stackrox OIDC Client - Keycloak 26 | 27 | Once created click **Clients** on the left. Then Click **Create**. 28 | 29 | - `Client ID` : stackrox 30 | - `Protocol` : openid-connect 31 | - `Root URL` : "" 32 | 33 | Next we need to change the `Access Type` to `confidental`. We also need to set the `Valid Redirect URLs` to `https://stackrox.dockr.life/sso/providers/oidc/callback`. Make sure you change your domain name. 34 | 35 | now save. 36 | 37 | #### Get Client Secret 38 | 39 | Next click the **Credentials** tab to get the secret. 40 | 41 | ### Configure StackRox OpenID 42 | 43 | #### Add Auth Provider 44 | 45 | Navigate to **PLATFORM CONFIGURATION --> ACCESS CONTROL** 46 | 47 | Then **Add an Auth Provider --> OpenID Connect** 48 | 49 | - `Name` : Generic Name, anything will work. 50 | - `Query` : Checked 51 | - `Issuer` : https+insecure://keycloak.dockr.life/auth/realms/stackrox 52 | - `Client ID` : stackrox 53 | - `Client Secret` : "From the keycloak client credentials page." 54 | 55 | Click Save and Test. 56 | 57 | #### Add Rules as needed - OIDC 58 | 59 | ## OIDC Automation 60 | 61 | ```bash 62 | # URLs 63 | export KEY_URL=keycloak.dockr.life 64 | export ROX_URL=stackrox.dockr.life 65 | export ROX_PASSWORD=Pa22word 66 | 67 | # KEYCLOAK 68 | # get auth token - notice keycloak's password 69 | export key_token=$(curl -sk -X POST https://$KEY_URL/auth/realms/master/protocol/openid-connect/token -d 'client_id=admin-cli&username=admin&password='$ROX_PASSWORD'&credentialId=&grant_type=password' | jq -r .access_token) 70 | 71 | # add realm 72 | curl -sk -X POST https://$KEY_URL/auth/admin/realms -H "authorization: Bearer $key_token" -H 'accept: application/json, text/plain, */*' -H 'content-type: application/json;charset=UTF-8' -d '{"enabled":true,"id":"stackrox","realm":"stackrox"}' 73 | 74 | # add client 75 | curl -sk -X POST https://$KEY_URL/auth/admin/realms/stackrox/clients -H "authorization: Bearer $key_token" -H 'accept: application/json, text/plain, */*' -H 'content-type: application/json;charset=UTF-8' -d '{"enabled":true,"attributes":{},"redirectUris":[],"clientId":"stackrox","protocol":"openid-connect","publicClient": false,"redirectUris":["https://'$ROX_URL'/sso/providers/oidc/callback"]}' 76 | #,"implicitFlowEnabled":true 77 | 78 | # get client id 79 | export client_id=$(curl -sk https://$KEY_URL/auth/admin/realms/stackrox/clients/ -H "authorization: Bearer $key_token" | jq -r '.[] | select(.clientId=="stackrox") | .id') 80 | 81 | # get client_secret 82 | export client_secret=$(curl -sk https://$KEY_URL/auth/admin/realms/stackrox/clients/$client_id/client-secret -H "authorization: Bearer $key_token" | jq -r .value) 83 | 84 | # STACKROX 85 | # config stackrox 86 | export auth_id=$(curl -sk -X POST -u admin:$ROX_PASSWORD https://$ROX_URL/v1/authProviders -d '{"type":"oidc","uiEndpoint":"'$ROX_URL'","enabled":true,"config":{"mode":"query","do_not_use_client_secret":"false","client_secret":"'$client_secret'","issuer":"https+insecure://'$KEY_URL'/auth/realms/stackrox","client_id":"stackrox"},"name":"stackrox"}' | jq -r .id) 87 | 88 | # change default to Analyst 89 | curl -sk -X POST -u admin:$ROX_PASSWORD https://$ROX_URL/v1/groups -d '{"props":{"authProviderId":"'$auth_id'"},"roleName":"Analyst"}' 90 | 91 | ``` 92 | 93 | --- 94 | 95 | ## SAML2 Configuration 96 | 97 | ### Add Stackrox SAML2 Client - Keycloak 98 | 99 | Once created click **Clients** on the left. Then Click **Create**. 100 | 101 | - `Client ID` : stackrox 102 | - `Protocol` : saml 103 | - `Root URL` : "" 104 | 105 | Next we need to validate the following settings. 106 | 107 | - `Client ID`: stackrox 108 | - `Base URL`: https://stackrox.dockr.life 109 | - `Client Protocol`: saml 110 | - `Include AuthnStatement`: ON 111 | - `Force POST Binding`: ON 112 | - `Name ID Format`: username 113 | - `Valid Redirect URIs`: https://stackrox.dockr.life/* 114 | - `IDP Initiated SSO URL Name`: stackrox 115 | 116 | Under Fine Grain SAML Endpoint Configuration 117 | 118 | `Assertion Consumer Service Redirect Binding URL`: https://stackrox.dockr.life/sso/providers/saml/acs 119 | 120 | ### in Stackrox 121 | 122 | - `Integration Name`: Keycloak 123 | - `ServiceProvider Issuer`: https://keycloak.dockr.life 124 | - `Option 2: Static Configuration` 125 | - `idP Issuer`: https://keycloak.dockr.life/auth/realms/stackrox 126 | - `IdP SSO URL`: https://keycloak.dockr.life/auth/realms/stackrox/protocol/saml/clients/stackrox 127 | - `Name/ID Format`: urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 128 | - `IdP Certificate (PEM)`: 129 | (can be retrieved from https://keycloak.dockr.life/auth/realms/stackrox/protocol/saml/descriptor, you have to add this part below:) 130 | 131 | ```bash 132 | # paste in the Realm Cert 133 | export CERT= 134 | 135 | # parse 136 | echo "-----BEGIN CERTIFICATE-----"; echo $CERT | sed -e 's/.\{64\}/&\n/g'; echo "-----END CERTIFICATE-----" 137 | ``` 138 | 139 | #### Add Rules as needed - SAML 140 | 141 | ## Groups 142 | 143 | We need a Keycloak Mapper to present the groups. Navigate to `Client` --> `Stackrox` --> `Mappers` --> `Create` 144 | 145 | - `Name` : Anything you want 146 | - `Mapper Type` : "Group Membership" 147 | - `Token Claim Name` : "groups" 148 | - `Full group path` : Off 149 | 150 | Next great the group in `Groups` and add the users. 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sr_tools 2 | my StackRox tools 3 | 4 | take a look. email me with questions. clemenko@gmail.com -------------------------------------------------------------------------------- /Selinux_userns.md: -------------------------------------------------------------------------------- 1 | 2 | # Edit boot 3 | 4 | ```bash 5 | grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)" 6 | reboot 7 | ``` 8 | # update sysctl 9 | 10 | ```bash 11 | echo "user.max_user_namespaces=15000" >> /etc/sysctl.conf 12 | sysctl -p 13 | ``` 14 | 15 | # install Docker CE 16 | 17 | ```bash 18 | yum install -y yum-utils vim 19 | yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 20 | yum install docker-ce -y 21 | systemctl enable docker 22 | systemctl start docker 23 | ``` 24 | 25 | # add subuid/subgid 26 | 27 | ```bash 28 | echo "dockremap:123000:65536" >> /etc/subuid 29 | echo "dockremap:123000:65536" >> /etc/subgid 30 | ``` 31 | 32 | # update daemon.json 33 | 34 | ```bash 35 | echo -e "{\n \"selinux-enabled\": true,\n \"userns-remap\": \"default\"\n}" > /etc/docker/daemon.json 36 | systemctl restart docker 37 | ``` 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Splunk_Config.md: -------------------------------------------------------------------------------- 1 | # Splunk 2 | 3 | ## Deploy Splunk 4 | 5 | This deployment assumes you are using [Traefik](traefik.io). 6 | 7 | ### Deploy 8 | 9 | ```bash 10 | # this is going to change the domain for the IngressRoute object. 11 | curl -s https://raw.githubusercontent.com/clemenko/k8s_yaml/master/splunk.yml | sed 's/dockr.life/YOURDOMAIN.com/g' | kubectl apply -f - 12 | ``` 13 | 14 | ### Add HTTP Event Collector (HEC) 15 | 16 | Log in to `splunk.dockr.life` or your ingress version with `admin` and `Pa22word`. 17 | 18 | Now we need add the HTTP Event Collector (HEC). 19 | 20 | - Navigate to `Settings` --> `Data inputs`. 21 | - Click `HTTP Event Collector` --> `New Token`. 22 | - `Name` : "Stackrox" --> Click `Next` 23 | - Click `Review`. 24 | - Click `Submit`. 25 | - Get the `Token Value`, we will need it later. 26 | 27 | ## Integrate StackRox 28 | 29 | ### Create Integration 30 | 31 | - Navigate to `Platform Configuration` --> `Integrations`. 32 | - Scroll down and click on "Splunk". 33 | - Click `New Integration`. 34 | - `Integration Name` : "Splunk" 35 | - `HTTP Event Collector URL` : https://splunk.splunk:8088 36 | - `HTTP Event Collector Token` : 37 | - Check `Disable TLS Certificate Validation (Insecure)` 38 | - UnCheck `Derived Source Type (Instead Of Using _json)` 39 | - Click `Create` 40 | 41 | ### Enable Notifications 42 | 43 | - Navigate to `Platform Configuration` --> `System Policies` 44 | - Select the Policies for notifications. 45 | - Click `Actions` --> `Enable Notification` 46 | 47 | ### to test 48 | 49 | ```bash 50 | # test from within the cluster. Get the token from the HEC. 51 | curl -k https://splunk.splunk:8088/services/collector/event -H "Authorization: Splunk e1610a4c-dd8a-48ef-a663-74bb7a811c33" -d '{"event": "Hello, from curl..."}' 52 | ``` 53 | -------------------------------------------------------------------------------- /basic_pki_auth.md: -------------------------------------------------------------------------------- 1 | # StackRox Auth 2 | 3 | ## basic 4 | 5 | ```bash 6 | # preserve the current admin password 7 | kubectl exec -it $(kubectl get pod -n stackrox|grep central|awk '{print $1}') -n stackrox -- /bin/cat /run/secrets/stackrox.io/htpasswd/htpasswd > htpasswd 8 | 9 | # add user to the new file aka change user2 to the desired username 10 | htpasswd -B htpasswd user2 11 | 12 | # delete the old secret 13 | kubectl -n stackrox delete secret central-htpasswd 14 | 15 | # add the new secret file 16 | kubectl -n stackrox create secret generic central-htpasswd --from-file=htpasswd=htpasswd 17 | ``` 18 | 19 | Please be advised that it can take a minute for the new htpasswd to be read. 20 | 21 | ## pki 22 | 23 | ```bash 24 | roxctl -e : central userpki create -c -r --insecure-skip-tls-verify -p $password 25 | ``` -------------------------------------------------------------------------------- /policies/30-day-age_policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "policies": [ 3 | { 4 | "name": "30-Day Image Age", 5 | "description": "Alert on deployments with images that haven't been updated in 30 days", 6 | "rationale": "Base images are updated frequently with bug fixes and vulnerability patches. Image age exceeding 30 days may indicate a higher risk of vulnerabilities existing in the image.", 7 | "remediation": "Rebuild your image, push a new minor version (with a new immutable tag), and update your service to use it.", 8 | "disabled": false, 9 | "categories": [ 10 | "DevOps Best Practices", 11 | "Security Best Practices" 12 | ], 13 | "fields": null, 14 | "lifecycleStages": [ 15 | "BUILD", 16 | "DEPLOY" 17 | ], 18 | "whitelists": [], 19 | "exclusions": [ 20 | { 21 | "name": "Don't alert on kube-system namespace", 22 | "deployment": { 23 | "name": "", 24 | "scope": { 25 | "cluster": "", 26 | "namespace": "kube-system", 27 | "label": null 28 | } 29 | }, 30 | "image": null, 31 | "expiration": null 32 | }, 33 | { 34 | "name": "Don't alert on istio-system namespace", 35 | "deployment": { 36 | "name": "", 37 | "scope": { 38 | "cluster": "", 39 | "namespace": "istio-system", 40 | "label": null 41 | } 42 | }, 43 | "image": null, 44 | "expiration": null 45 | } 46 | ], 47 | "scope": [], 48 | "severity": "LOW_SEVERITY", 49 | "enforcementActions": [], 50 | "notifiers": [], 51 | "lastUpdated": null, 52 | "SORTName": "", 53 | "SORTLifecycleStage": "", 54 | "SORTEnforcement": false, 55 | "policyVersion": "1.1", 56 | "policySections": [ 57 | { 58 | "sectionName": "", 59 | "policyGroups": [ 60 | { 61 | "fieldName": "Image Age", 62 | "booleanOperator": "OR", 63 | "negate": false, 64 | "values": [ 65 | { 66 | "value": "30" 67 | } 68 | ] 69 | } 70 | ] 71 | } 72 | ] 73 | } 74 | ] 75 | } -------------------------------------------------------------------------------- /stackrox_classifications.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # clemenko@gmail.com 3 | #here is how to use the API to push a logon banner as well as header and footers for classification. 4 | 5 | 6 | central_server=$1 7 | class=$2 8 | 9 | # if stackrox_api.token exists 10 | if [ -z $central_server ]; then 11 | echo "$RED [warn]$NORMAL Please add the server name and classification to the command." 12 | echo " $BLUE Use:$NORMAL $0 " 13 | echo " $BLUE Use:$NORMAL $0 stackrox.dockr.life TS " 14 | exit 15 | fi 16 | 17 | ######### 18 | 19 | function get_password (){ 20 | #read the admin password 21 | echo -n " - StackRox Admin Password for $central_server: "; read -s password; echo 22 | } 23 | 24 | #gov logon message 25 | export gov_message=$(cat < /dev/null 2>&1 35 | ;; 36 | 37 | S ) 38 | #secret 39 | get_password 40 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":true,"text":"'"$gov_message"'"},"header":{"enabled":true,"text":"SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#d9534f"},"footer":{"enabled":true,"text":"SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#d9534f"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1 41 | ;; 42 | 43 | TS ) 44 | #top secret 45 | get_password 46 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":true,"text":"'"$gov_message"'"},"header":{"enabled":true,"text":"TOP SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"},"footer":{"enabled":true,"text":"TOP SECRET","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1 47 | ;; 48 | 49 | clear ) 50 | #clear 51 | get_password 52 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":false,"text":"'"$gov_message"'"},"header":{"enabled":false,"text":"","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"},"footer":{"enabled":false,"text":"","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f0ad4e"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1 53 | ;; 54 | 55 | PARTY ) 56 | get_password 57 | curl -sk -X PUT -u admin:$password https://$central_server/v1/config -d '{"config":{"publicConfig":{"loginNotice":{"enabled":false,"text":""},"header":{"enabled":true,"text":"PARTY MODE","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f04ed3"},"footer":{"enabled":true,"text":"PARTY MODE","size":"MEDIUM","color":"#ffffff","backgroundColor":"#f04ed3"}},"privateConfig":{"alertConfig":{"resolvedDeployRetentionDurationDays":7,"deletedRuntimeRetentionDurationDays":7,"allRuntimeRetentionDurationDays":30},"imageRetentionDurationDays":7}}}' > /dev/null 2>&1 58 | ;; 59 | 60 | *) echo "Usage: $0 {clear | TS | S | U | PARTY }"; exit 1 61 | 62 | esac 63 | -------------------------------------------------------------------------------- /stackrox_compliance_scan.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # clemenko@gmail.com 3 | 4 | # supported standards CIS_Kubernetes_v1_5 HIPAA_164 NIST_800_190 NIST_SP_800_53_Rev_4 PCI_DSS_3_2 CIS_Docker_v1_2_0 5 | standardId="NIST_800_190" 6 | 7 | # output formats are json or csv 8 | output_format=json 9 | 10 | ###### no more edits 11 | RED=$(tput setaf 1) 12 | GREEN=$(tput setaf 2) 13 | NORMAL=$(tput sgr0) 14 | 15 | function setup () { # setup role and token 16 | 17 | echo -e "\n Creating the API token. Admin password required. " 18 | #read the admin password 19 | echo -n " - StackRox Admin Password for $serverUrl: "; read -s password; echo 20 | 21 | # check to see if the role is there. 22 | if [ $(curl -sk -u admin:$password https://$serverUrl/v1/roles | jq '.roles[] | select(.name=="Compliance")' | wc -l) = 0 ]; then 23 | # create the role 24 | curl -sk -u admin:$password -X POST 'https://'$serverUrl'/v1/roles/Compliance' \ 25 | -H 'accept: application/json, text/plain, */*' \ 26 | -d '{"name":"Compliance","globalAccess":"NO_ACCESS","resourceToAccess":{"Cluster": "READ_ACCESS","Compliance":"READ_WRITE_ACCESS","ComplianceRunSchedule":"READ_WRITE_ACCESS","ComplianceRuns":"READ_WRITE_ACCESS"}}' 27 | fi 28 | 29 | # create token with new role 30 | curl -sk -X POST -u admin:$password https://$serverUrl/v1/apitokens/generate -d '{"name":"compliance","role":null,"roles":["Compliance"]}'| jq -r .token > stackrox_api.token 31 | 32 | echo -e "\n----------------------------------------------------------------------------------" 33 | } 34 | 35 | echo -e "\n StackRox Complaince Automation Script" 36 | echo " - Inputs: ./stackrox_compliance_scan.sh " 37 | echo " - Outputs: ___Results_$(date +"%m-%d-%y").$output_format" 38 | echo -e "----------------------------------------------------------------------------------\n" 39 | 40 | serverUrl=$1 41 | if [ -z $serverUrl ]; then echo "$RED [warn]$NORMAL Please add the server name to the command."; echo ""; exit; fi 42 | 43 | # if stackrox_api.token exists 44 | if [ ! -f stackrox_api.token ]; then setup; fi 45 | 46 | # get api 47 | export token=$(cat stackrox_api.token) 48 | 49 | echo -n "Running $standardId scan on $serverUrl " 50 | 51 | # get clusterId, can be tuned per cluster 52 | clusterId=$(curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/clusters | jq -r .clusters[0].id) 53 | 54 | # get the clustername from id 55 | clusterName=$(curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/clusters/$clusterId | jq -r .cluster.name) 56 | 57 | # run a scan and get the runid 58 | runId=$(curl -sk -X POST -H "Authorization: Bearer $token" https://$serverUrl/v1/compliancemanagement/runs -d '{"selection": { "clusterId": "'"$clusterId"'", "standardId": "'"$standardId"'" }}' | jq -r .startedRuns[0].id) 59 | 60 | # wait for scan to complete 61 | until [ "$(curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/complianceManagement/runs | jq -r '.complianceRuns[]|select(.id=="'"$runId"'") | .state' )" == "FINISHED" ]; do echo -n "."; sleep 1; done 62 | 63 | if [[ "$output_format" = "json" ]]; then 64 | # get results in json 65 | curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/compliance/runresults?clusterId="$clusterId"'&standardId='$standardId'&runId='$runId'' | jq . > "$serverUrl"_"$clusterName"_"$standardId"_Results_$(date +"%m-%d-%y").json 66 | fi 67 | 68 | if [[ "$output_format" = "csv" ]]; then 69 | # get results in csv 70 | curl -sk -H "Authorization: Bearer $token" https://$serverUrl/api/compliance/export/csv?clusterId="$clusterId"'&standardId='$standardId'&runId='$runId'' > "$serverUrl"_"$clusterName"_"$standardId"_Results_$(date +"%m-%d-%y").csv 71 | fi 72 | 73 | echo -e "$GREEN" "[ok]" "$NORMAL\n" 74 | -------------------------------------------------------------------------------- /stackrox_networksim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # clemenko@gmail.com 3 | # network simulator yaml 4 | 5 | ###### no more edits 6 | RED=$(tput setaf 1) 7 | GREEN=$(tput setaf 2) 8 | NORMAL=$(tput sgr0) 9 | BLUE=$(tput setaf 4) 10 | 11 | serverUrl=$1 12 | namespace=$2 13 | 14 | # if stackrox_api.token exists 15 | if [ -z $serverUrl ]; then 16 | echo "$RED [warn]$NORMAL Please add the server name and namespace to the command." 17 | echo " $BLUE Use:$NORMAL $0 " 18 | exit 19 | fi 20 | 21 | # get password. Can modify to hard code it the password. Or use an auth token. 22 | echo -n " -$BLUE StackRox$NORMAL Admin Password for $serverUrl: "; read -s password; echo 23 | 24 | # get cluster id - assuming 1 cluster. will need loop for multiple clusters 25 | clusterId=$(curl -sk -u admin:$password https://$serverUrl/v1/clusters | jq -r .clusters[0].id) 26 | # to be used in the furture. 27 | clusterName=$(curl -sk -u admin:$password https://$serverUrl/v1/clusters/$clusterId | jq -r .cluster.name) 28 | 29 | # get network sim 30 | if [ -z $namespace ]; then 31 | curl -sk -u admin:$password "https://$serverUrl/v1/networkpolicies/generate/$clusterId?deleteExisting=ALL&includePorts=true" | jq -r .modification.applyYaml > "$serverUrl"_all_network_policy_$(date +"%m-%d-%y").yaml 32 | else 33 | curl -sk -u admin:$password "https://$serverUrl/v1/networkpolicies/generate/$clusterId?deleteExisting=ALL&query=Namespace%3A$namespace&includePorts=true" | jq -r .modification.applyYaml > "$serverUrl"_"$namespace"_network_policy_$(date +"%m-%d-%y").yaml 34 | fi -------------------------------------------------------------------------------- /stackrox_offline/README.md: -------------------------------------------------------------------------------- 1 | # StackRox Offline bits 2 | 3 | ## Install from the super bundle 4 | 5 | ### Get all the bits 6 | 7 | `wget $(curl -s https://andyc.info/rox/|grep href| grep -v Index|awk -F">" '{print "https://andyc.info/rox/"$2}'|sed 's#" '{print "https://andyc.info/rox/"$2}'|sed 's# 59 | 60 | # generate stackrox install 61 | roxctl central generate k8s none --offline --enable-telemetry=false --lb-type np --password $password --main-image $registry/stackrox/main:3.0.52.1 --scanner-db-image $registry/stackrox/scanner-db:2.7.1 --scanner-image $registry/stackrox/scanner:2.7.1 --slim-collector=false --admission-controller-listen-on-updates --create-admission-controller 62 | 63 | # reduce StackRox requirements 64 | sed -i -e 's/4Gi/2Gi/g' -e 's/8Gi/4Gi/g' ./central-bundle/central/01-central-12-deployment.yaml 65 | sed -i -e 's/4Gi/2Gi/g' -e 's/8Gi/4Gi/g' -e 's/replicas: 3/replicas: 1/g' ./central-bundle/scanner/02-scanner-06-deployment.yaml 66 | sed -i -e 's/minReplicas: 2/minReplicas: 1/g' central-bundle/scanner/02-scanner-08-hpa.yaml 67 | 68 | # how do the nodes authenticate to the registry? 69 | ############################################################################################### 70 | # if you have your nodes authenticate for you start here 71 | # if not skip the `sed` statements 72 | 73 | # remove the auth assumptions 74 | sed -i -e '25,$d' central-bundle/central/scripts/setup.sh 75 | sed -i -e '9,$d' central-bundle/scanner/scripts/setup.sh 76 | 77 | # proceed with the `imagePullSecrets` path 78 | 79 | ############################################################################################### 80 | # if you need imagePullSecrets then start here 81 | # run the setup and enter the registry creds 82 | 83 | #deploy 84 | ./central-bundle/central/scripts/setup.sh 85 | 86 | # kube all the things 87 | kubectl apply -R -f central-bundle/central 88 | 89 | # install scanner 90 | ./central-bundle/scanner/scripts/setup.sh 91 | kubectl apply -R -f central-bundle/scanner 92 | 93 | ############################################################################################### 94 | 95 | # get port 96 | rox_port=$(kubectl -n stackrox get svc central-loadbalancer |grep Node|awk '{print $5}'|sed -e 's/443://g' -e 's#/TCP##g') 97 | until [ $(curl -kIs https://$server:$rox_port|head -n1|wc -l) = 1 ]; do echo -n "." ; sleep 2; done 98 | 99 | # get sensor bundle 100 | roxctl -e $server:$rox_port sensor generate k8s --name k3s --central central.stackrox:443 --insecure-skip-tls-verify -p $password --collection-method kernel --main-image $registry/stackrox/main:$version 101 | 102 | # how do the nodes authenticate to the registry? 103 | ############################################################################################### 104 | # if you have your nodes authenticate for you start here 105 | # if not skip the `sed` statement 106 | sed -i -e '25,57d' sensor-k3s/sensor.sh 107 | 108 | # apply the sensor bundle 109 | kubectl apply -R -f sensor-k3s/ 110 | 111 | # update vulns database 112 | roxctl scanner upload-db -e $server:$rox_port --scanner-db-file=scanner-vuln-updates.zip --insecure-skip-tls-verify -p $password 113 | 114 | # update the the kernel modules 115 | roxctl collector support-packages upload $server:$rox_port support-pkg-b6745d-latest.zip 116 | -------------------------------------------------------------------------------- /stackrox_oss.sh: -------------------------------------------------------------------------------- 1 | # Step for installing the open source version of stackrox correctly. 2 | 3 | # Go to https://quay.io/repository/stackrox-io/main?tab=tags and check the latet tag's hash. Then see which version has the same hash. 4 | # this is due to there not being a opensource version of roxctl. 5 | export rox_version=3.69.x-418-gc3c3117695 6 | 7 | # create the default admin password for logging in. 8 | export password=Pa22word 9 | 10 | # get roxctl for your machine 11 | # docs : https://docs.openshift.com/acs/3.68/installing/install-quick-roxctl.html#installing-roxctl-cli 12 | # for Mac 13 | curl -#L https://mirror.openshift.com/pub/rhacs/assets/latest/bin/Darwin/roxctl -o /usr/local/bin/roxctl 14 | chmod +x /usr/local/bin/roxctl 15 | 16 | # create the install yamls 17 | # please read the docs about the interactive installer : https://docs.openshift.com/acs/3.68/installing/install-quick-roxctl.html#using-the-interactive-installer_install-quick-roxctl 18 | # Here we are using a PVC from Longhorn and exposing with NodePort. You can apply an ingress to the central pod later. 19 | roxctl central generate k8s pvc --storage-class longhorn --size 10 --enable-telemetry=false --lb-type np --password $password --main-image quay.io/stackrox-io/main:$rox_version --scanner-db-image quay.io/stackrox-io/scanner-db:$rox_version --scanner-image quay.io/stackrox-io/scanner:$rox_version 20 | 21 | # create namespace and install central and scanner 22 | kubectl create ns stackrox 23 | kubectl apply -R -f central-bundle/central/ 24 | kubectl apply -R -f central-bundle/scanner/ 25 | 26 | # validate the ports for the cluster. 27 | # wait for central to become active. 28 | server=$(kubectl get nodes -o json | jq -r '.items[0].status.addresses[] | select( .type=="InternalIP" ) | .address ') 29 | rox_port=$(kubectl -n stackrox get svc central-loadbalancer |grep Node|awk '{print $5}'|sed -e 's/443://g' -e 's#/TCP##g') 30 | 31 | # create a sensor "cluster" using the ports and the admin password. 32 | roxctl sensor generate k8s -e $server:$rox_port --name k3s --central central.stackrox:443 --insecure-skip-tls-verify --collection-method ebpf --admission-controller-listen-on-updates --admission-controller-listen-on-creates -p $password --main-image-repository quay.io/stackrox-io/main:$rox_version --collector-image-repository quay.io/stackrox-io/collector 33 | 34 | # deploy the sensor/collectors 35 | kubectl apply -R -f sensor-k3s/ 36 | 37 | # Now add an ingress and profit... 38 | # for example I use traefik 39 | kubectl apply -f https://raw.githubusercontent.com/clemenko/k8s_yaml/master/stackrox_traefik_crd.yml 40 | 41 | # bonus - add an api token for roxctl 42 | # change the $URL to your ingress or ip:nodeport 43 | curl -sk -X POST -u admin:$password https://$URL/v1/apitokens/generate -d '{"name":"admin","role":null,"roles":["Admin"]}'| jq -r .token > ROX_API_TOKEN 44 | -------------------------------------------------------------------------------- /stackrox_policy_importer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # clemenko@gmail.com 3 | # import all the policies. 4 | 5 | # where are the policies 6 | pol_folder=policies 7 | 8 | ###### no more edits 9 | set -e 10 | 11 | RED=$(tput setaf 1) 12 | GREEN=$(tput setaf 2) 13 | NORMAL=$(tput sgr0) 14 | BLUE=$(tput setaf 4) 15 | 16 | echo -e "----------------------------------------------------------------------------------" 17 | echo -e "StackRox Policy Import Automation Script" 18 | echo " - Inputs: $0 " 19 | echo -e "----------------------------------------------------------------------------------" 20 | 21 | serverUrl=$1 22 | if [ -z $serverUrl ]; then echo "$RED [warn]$NORMAL Please add the server name to the command."; echo ""; exit; fi 23 | 24 | #read the admin password 25 | echo -n " - StackRox Admin Password for $serverUrl: "; read -s password; echo 26 | 27 | echo " Importing Policies from $pol_folder folder " 28 | for pol in $(ls $pol_folder/*.json); do 29 | echo -n " $pol_folder/$pol " 30 | responses=$(curl -sk -X POST -u admin:$password https://$serverUrl/v1/policies/import -d @$pol) 31 | if [ "$(echo $responses|grep error\"|wc -l|sed 's/ //g')" == "1" ]; then echo " - $RED Error :$NORMAL $responses $RED [fail]$NORMAL" 32 | else 33 | case "$(echo $responses | jq .responses[].succeeded)" in 34 | "true") echo -e " - $BLUE Policy Uploaded $GREEN" "[ok]" "$NORMAL\n" ;; 35 | "false") echo -e " - $BLUE Policy Already Existed $GREEN" "[ok]" "$NORMAL\n" ;; 36 | esac 37 | fi 38 | done 39 | -------------------------------------------------------------------------------- /stackrox_violations_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # clemenko@gmail.com 3 | 4 | # script for pulling violations by namespace. 5 | 6 | # output formats are json or csv 7 | # ONLY JSON right now. Plans for possibly CSV 8 | output_format=json 9 | 10 | ###### no more edits 11 | RED=$(tput setaf 1) 12 | GREEN=$(tput setaf 2) 13 | NORMAL=$(tput sgr0) 14 | 15 | function setup () { # set up token 16 | 17 | echo -e "Creating the API token. Admin password required. " 18 | #read the admin password 19 | echo -n " - StackRox Admin Password for $serverUrl: "; read -s password; echo 20 | 21 | # create token with role 22 | curl -sk -X POST -u admin:$password https://$serverUrl/v1/apitokens/generate -d '{"name":"violations","role":null,"roles":["Analyst"]}'| jq -r .token > "$serverUrl".token 23 | 24 | echo -e "\n----------------------------------------------------------------------------------" 25 | } 26 | 27 | echo -e "\n StackRox Complaince Automation Script" 28 | echo " - Inputs: ./stackrox_violations_report.sh " 29 | echo " - Outputs: ___Results_$(date +"%m-%d-%y").$output_format" 30 | echo -e "----------------------------------------------------------------------------------\n" 31 | 32 | serverUrl=$1 33 | if [ -z $serverUrl ]; then echo "$RED [warn]$NORMAL Please add the server name to the command."; echo ""; exit; fi 34 | 35 | namespace=$2 36 | if [ -z $namespace ]; then echo "$RED [warn]$NORMAL Please add the namespace to the command."; echo ""; exit; fi 37 | 38 | # if stackrox_api.token exists 39 | if [ ! -f "$serverUrl".token ]; then setup; fi 40 | 41 | # get api 42 | export token=$(cat "$serverUrl".token) 43 | 44 | echo -n "Getting Violations from $serverUrl for $namespace" 45 | 46 | if [[ "$output_format" = "json" ]]; then 47 | # get results in json 48 | # curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/alerts |jq '.alerts[]? | select(.deployment.namespace=="'$namespace'")' | jq . > "$serverUrl"_"$namespace"_Violations_$(date +"%m-%d-%y").json 49 | curl -sk -H "Authorization: Bearer $token" https://$serverUrl/v1/alerts?query=Namespace%3A$namespace | jq . > "$serverUrl"_"$namespace"_Violations_$(date +"%m-%d-%y").json 50 | fi 51 | 52 | echo -e "$GREEN" "[ok]" "$NORMAL\n" 53 | -------------------------------------------------------------------------------- /stackrox_vuln_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # clemenko@gmail.com 3 | 4 | set -e 5 | 6 | if [[ -z "${ROX_ENDPOINT}" ]]; then 7 | echo >&2 "ROX_ENDPOINT must be set. ie : export ROX_ENDPOINT=stackrox.dockr.life:443" 8 | exit 1 9 | fi 10 | 11 | if [[ -z "${ROX_API_TOKEN}" ]]; then 12 | echo >&2 "ROX_API_TOKEN must be set" 13 | # export ROX_API_TOKEN=$(curl -sk -X POST -u admin:Pa22word https://stackrox.dockr.life/v1/apitokens/generate -d '{"name":"Report","role":null,"roles":["Analyst"]}'| jq -r .token ) 14 | exit 1 15 | fi 16 | 17 | if [[ -z "$1" ]]; then 18 | echo >&2 "usage: $0 " 19 | exit 1 20 | fi 21 | 22 | export namespace=$1 23 | 24 | output_file="$namespace"_Results_$(date +"%m-%d-%y").csv 25 | echo '"Namespace","Deployment","Image","CVE","CVSS","Fixable"' > "${output_file}" 26 | 27 | function curl_central() { 28 | curl -sk -H "Authorization: Bearer ${ROX_API_TOKEN}" "https://${ROX_ENDPOINT}/$1" 29 | } 30 | 31 | # Collect all deployments 32 | deploy_count=0 33 | image_count=0 34 | offset=0 35 | limit=100 36 | echo -n " Starting Report " 37 | while true; do 38 | res=$(curl_central "v1/deployments?pagination.limit=${limit}&pagination.offset=${offset}" | jq ['.deployments[] |select(.namespace=="'$namespace'")']) 39 | 40 | # If no results, then exist 41 | if [[ "$(echo "${res}" | jq length)" == "0" ]]; then break; fi 42 | 43 | # Iterate over all deployments and get the full deployment 44 | for deployment_id in $(echo "${res}" | jq -r .[].id); do 45 | deployment_res="$(curl_central "v1/deployments/${deployment_id}")" 46 | export deployment_name="$(echo "${deployment_res}" | jq -rc .name)" 47 | deploy_count=$((deploy_count+1)) 48 | # Iterate over all images within the deployment and render the CSV Lines 49 | for image_id in $(echo "${deployment_res}" | jq -r .containers[].image.id); do 50 | if [[ "${image_id}" != "" ]]; then 51 | echo -n "." 52 | image_res="$(curl_central "v1/images/${image_id}" | jq -rc)" 53 | export image_name="$(echo "${image_res}" | jq -rc .name.fullName)" 54 | image_count=$((image_count+1)) 55 | 56 | # Format the CSV correctly 57 | echo "${image_res}" | jq -r '.scan?.components[]?.vulns[]? | {nameSpace: env.namespace, deploymentName: env.deployment_name, imageName: env.image_name, cve: .cve, cvss: .cvss, fixedBy: .fixedBy } | [ .nameSpace, .deploymentName, .imageName, .cve, .cvss, .fixedBy != null ] | @csv' >> "${output_file}" 58 | fi 59 | done 60 | done 61 | echo "" 62 | offset=$(( offset + limit )) 63 | echo "$(date): Processed Namespace: $namespace - $deploy_count deployments and $image_count images." 64 | done -------------------------------------------------------------------------------- /workshop/README.md: -------------------------------------------------------------------------------- 1 | # StackRox Workshop - https://andyc.info/roxshop 2 | 3 | #### clemenko@redhat.com | [@clemenko](https://twitter.com/clemenko) 4 | 5 | ## Agenda 6 | 7 | - [Pre-requisites](#Pre-requisites) 8 | - [Choose Your Own Adventure](#choose-your-own-adventure) 9 | - [K3s](#K3s) 10 | - [Ingress](#Ingress) 11 | - [Storage](#Storage) 12 | - [Code](#Code) 13 | - [StackRox](#stackrox) 14 | - [Install Offline](#Install-Offline---no-registry) 15 | - [Install Online](#Install-Online) 16 | - [Authentication](#Authentication) 17 | - [Policies](#Policies) 18 | - [Stages](#Stages) 19 | - [Integrations & Plugins](#Integrations-&-Plugins) 20 | - [API & Tokens](#API-&-Tokens) 21 | - [Scanner Integration](#scanner-integration) 22 | - [Documentation](#Documentation) 23 | - [Troubleshooting](#Troubleshooting) 24 | - [StackRox Demo](#StackRox-Demo) 25 | - Compliance 26 | - Network 27 | - Violations 28 | - Vulnerability Management 29 | - Risk 30 | - CI/CD 31 | - [Questions, Thoughts](#Questions,-Thoughts) 32 | - [Advanced Topics](#Advanced-Topics) 33 | - [Classification Banners](#classification-banners) 34 | - [Compliance Scans](#compliance-scan-results) 35 | - [KeyCloak](#Keycloak) 36 | - [Jenkins](#Jenkins) 37 | - [Profit](#profit) 38 | 39 | ## Pre-requisites 40 | 41 | - Basic Linux command line skills 42 | - Familiarity with a text editor (VS Code, vi, etc.) 43 | - ASK QUESTIONS! 44 | 45 | ## Choose Your Own Adventure 46 | 47 | - [Self Install K3s](#K3s) - SSH to the first node and start deploying 48 | - [Already Installed K3s](#stackrox) - SSH or use [Code](#Code) to get access to the cluster. 49 | 50 | ## SSH 51 | 52 | Every student has 3 vms. The instructor will assign the student a number. To connect with a root password of `Pa22word`: 53 | 54 | ```bash 55 | ssh root@student$NUMa.stackrox.live # Change $NUM to your student number 56 | 57 | # Validate the student number 58 | echo $NUM 59 | ``` 60 | 61 | ## K3s 62 | 63 | Lets deploy [k3s](https://k3s.io). From the $NUMa node we will run all the commands. Don't for get to set the student number. 64 | 65 | ```bash 66 | # k3sup install 67 | k3sup install --ip $ipa --user root --k3s-extra-args '--no-deploy traefik' --cluster --local-path ~/.kube/config 68 | k3sup join --ip $ipb --server-ip $ipa --user root 69 | k3sup join --ip $ipc --server-ip $ipa --user root 70 | 71 | # Wait about 15 seconds to see the nodes are coming online. 72 | kubectl get node -o wide 73 | ``` 74 | 75 | At this point you should see something similar. 76 | 77 | ```bash 78 | root@student1a:~# kubectl get node -o wide 79 | NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME 80 | student1a Ready master 4m31s v1.18.10+k3s1 157.245.222.116 Ubuntu 20.04.1 LTS 5.4.0-45-generic containerd://1.3.3-k3s2 81 | student1b Ready 48s v1.18.10+k3s1 104.131.182.136 Ubuntu 20.04.1 LTS 5.4.0-45-generic containerd://1.3.3-k3s2 82 | student1c Ready 39s v1.18.10+k3s1 157.245.222.126 Ubuntu 20.04.1 LTS 5.4.0-45-generic containerd://1.3.3-k3s2 83 | ``` 84 | 85 | congrats you just built a 3 node k3s(k8s) cluster. Not that hard right? 86 | 87 | ## Ingress 88 | 89 | If you can't tell I like easy and simple. This also applies to Ingress. For that [Traefik](https://traefik.io/) for the win! 90 | 91 | ```bash 92 | # install Traefik CRD for TLS passthrough 93 | kubectl apply -f https://raw.githubusercontent.com/clemenko/k8s_yaml/master/traefik_crd_deployment.yml 94 | 95 | # verify it is up 96 | kubectl get pod -n traefik 97 | 98 | # lets create an ingress entry for this. CHANGE the $NUM to your student number. 99 | # and yes there are escape characters. 100 | cat < SYSTEM POLICIES**. 373 | 374 | ![policy1](./images/policy1.jpg) 375 | 376 | While we can edit the policies, I would suggest looking at the import/export features. This is will allow for greater automation of clusters. 377 | 378 | Lets edit a policy the `nmap Execution` policy. Search for it in the search field. 379 | 380 | ![nmap](./images/nmap.jpg) 381 | 382 | From there we can click on the policy and then click edit it the top right. 383 | 384 | ![nmap](./images/edit_nmap.jpg) 385 | 386 | With the edit tab open click the right arrow to get to the next page. This is the Policy Criteria page. Click it again to see the Violations Preview page. Click again to see the Execution page. Scroll down and enable the Runtime Execution. Click the disk icon to Save the policy. 387 | 388 | ![nmap](./images/runtime_nmap.jpg) 389 | 390 | We know have Runtime enforcement for nmap execution. 391 | 392 | #### Stages 393 | 394 | Stages refers to the different policy stages. As with the example for the `nmap Execution` policy we can start to see the three stages for policies. The three stages are: 395 | 396 | - Build - Focused on CI/CD interaction with Central/Scanner 397 | - Deploy - Admission Controller 398 | - Runtime - Dynamic Runtime defense 399 | 400 | Each stage has policies uniquely written for it. Some policies are geared for the Build and Deploy stage. 401 | 402 | ### Integrations & Plugins 403 | 404 | The StackRox platform is not a walled garden of knowledge! Navigate to **PLATFORM CONFIGURATION --> INTEGRATIONS** or https://rox.1.stackrox.live/main/integrations. 405 | 406 | ![integrations](./images/integrations.jpg) 407 | 408 | Here we can edit the integrations for setting up external scanners, registries, Slack, Jira, and other plugins. 409 | 410 | ![plugins](./images/plugins.jpg) 411 | 412 | This is also the page where we can create an API Token for use with curl or the Jenkins plugin. 413 | 414 | ### API & Tokens 415 | 416 | The StackRox platform ships with a completely documented API interface. In the lower left hand corner click the **API REFERENCE** button 417 | 418 | ![api](./images/api.jpg) 419 | 420 | We can navigate to **PLATFORM CONFIGURATION --> INTEGRATIONS** and scroll down to **AUTHENTICATION TOKENS**. Once there click the plus symbol in the upper right hand of the page. Here we can create a token with a specific role. 421 | 422 | ![api_token](./images/api_token.jpg) 423 | 424 | OR... 425 | 426 | ```bash 427 | # lets create a toke with the API. 428 | curl -sk -X POST -u admin:$password https://rox.$NUM.stackrox.live/v1/apitokens/generate -d '{"name":"jenkins","role":null,"roles":["Continuous Integration"]}'| jq -r .token > jenkins_API_TOKEN 429 | 430 | # we can export it as a variable for use with roxctl 431 | export ROX_API_TOKEN=$(cat jenkins_API_TOKEN) 432 | ``` 433 | 434 | #### Scanner Integration 435 | 436 | There are two simple ways to integrate with the StackRox scanner. The first way is with the Jenkins plugin. We may cover that later if there is time. The second way is with the `roxctl` binary. This binary was preinstalled onto the first node ahead of time. 437 | 438 | ```bash 439 | # verify the api token is ready for use 440 | echo $ROX_API_TOKEN 441 | 442 | # now we are ready for asking the scanner to scan an image. 443 | # we can use jq to pretty it up 444 | # keep in mind it will take about 30 seconds to complete 445 | roxctl image scan -e rox.$NUM.stackrox.live:443 --image "clemenko/jenkins" --insecure-skip-tls-verify | jq . 446 | 447 | # we can also use the check function to check the image against Build System Policies 448 | roxctl image check -e rox.$NUM.stackrox.live:443 --image "clemenko/jenkins" --insecure-skip-tls-verify 449 | 450 | # here is a sample output 451 | ✗ Image clemenko/jenkins failed policy 'Fixable CVSS >= 7' (policy enforcement caused failure) 452 | - Description: 453 | ↳ Alert on deployments with fixable vulnerabilities with a CVSS of at least 7 454 | - Rationale: 455 | ↳ Known vulnerabilities make it easier for adversaries to exploit your 456 | application. You can fix these high-severity vulnerabilities by updating to a 457 | newer version of the affected component(s). 458 | - Remediation: 459 | ↳ Use your package manager to update to a fixed version in future builds or speak 460 | with your security team to mitigate the vulnerabilities. 461 | - Violations: 462 | - Fixable CVE-2012-0785 (CVSS 7.5) found in component 'jenkins' (version 1.1), resolved by version 1.424.2 463 | - Fixable CVE-2012-4438 (CVSS 8.8) found in component 'jenkins' (version 1.1), resolved by version 1.466.2 464 | - Fixable CVE-2020-10518 (CVSS 8.8) found in component 'github' (version 1.31.0), resolved by version 2.19.21 465 | 466 | Error: Violated a policy with CI enforcement set 467 | 468 | ``` 469 | 470 | ### Documentation 471 | 472 | Similar to the API, the StackRox platform ships with a copy of the complete documentation. In the lower left hand corner click the **HELP CENTER** button. Or Navigate to https://rox.$NUM.stackrox.live/docs/product/ 473 | 474 | ![help](./images/help.jpg) 475 | 476 | ### Troubleshooting 477 | 478 | When troubleshooting StackRox there are two main tools to use. The first one is using kubectl to validate the Central pod is running. Ate the same time we can validate that all the pods are running correctly. Make sure you run the `kubectl` command on the cluster where the components are installed. 479 | 480 | ```bash 481 | root@student1a:~# kubectl get pod -n stackrox 482 | NAME READY STATUS RESTARTS AGE 483 | scanner-db-7964d4794d-ktvmm 1/1 Running 0 80m 484 | central-57c48f8fdc-mmmsq 1/1 Running 0 81m 485 | scanner-96bfb87df-hcr5b 1/1 Running 0 80m 486 | scanner-96bfb87df-h5dfr 1/1 Running 0 80m 487 | collector-2mhfh 2/2 Running 0 79m 488 | collector-8j77w 2/2 Running 0 79m 489 | collector-mp954 2/2 Running 0 79m 490 | sensor-5ccbc8858d-kkndf 1/1 Running 0 79m 491 | ``` 492 | 493 | The second tool is using Central's gui. The gui can help show the current stat of all the components as well. 494 | 495 | ![health](./images/health.jpg) 496 | 497 | ## StackRox Demo 498 | 499 | - Compliance 500 | - Network 501 | - Violations 502 | - Vulnerability Management 503 | - Risk 504 | - CI/CD 505 | 506 | ## Questions, Thoughts 507 | 508 | ## Advanced Topics 509 | 510 | ### Classification Banners 511 | 512 | The settings for the classification banners are located in **PLATFORM CONFIGURATION --> SYSTEM CONFIGURATION**. Here you can change all the settings as needed. 513 | 514 | ![banners](./images/banners.jpg) 515 | 516 | OR you can use a handy script in this repo. 517 | 518 | ```bash 519 | # get the script 520 | wget https://raw.githubusercontent.com/clemenko/sr_tools/main/stackrox_classifications.sh 521 | chmod 755 stackrox_classifications.sh 522 | 523 | # now we can run it for the 524 | ./stackrox_classifications.sh rox.$NUM.stackrox.live TS 525 | ``` 526 | 527 | ### Compliance Scan Results 528 | 529 | How about a handy script to use the API to request a compliance scan. Then save the result as json. 530 | 531 | ```bash 532 | # get the script 533 | wget https://raw.githubusercontent.com/clemenko/sr_tools/main/stackrox_compliance_scan.sh 534 | chmod 755 stackrox_compliance_scan.sh 535 | 536 | # run it 537 | # the script will ask for the admin password 538 | # the script will set up an api token with the correct rbac 539 | ./stackrox_compliance_scan.sh rox.$NUM.stackrox.live 540 | 541 | # here is an example output 542 | root@student1a:~# head rox.1.stackrox.live_k3s_NIST_800_190_Results_10-17-20.json 543 | { 544 | "results": { 545 | "domain": { 546 | "id": "380ecdd4-1686-49bb-a9ad-f1826aaeca53", 547 | "cluster": { 548 | "id": "f741b11d-1d7a-46b9-930b-bd4f2d226d2a", 549 | "name": "k3s", 550 | "type": "KUBERNETES_CLUSTER", 551 | "mainImage": "stackrox.io/main", 552 | "collectorImage": "", 553 | 554 | ``` 555 | 556 | ### Keycloak 557 | 558 | Deploy [Keycloak](https://www.keycloak.org/) and configure [StackRox](https://stackrox.com). 559 | 560 | This deployment is designed for use with [Traefik](https://traefik.io/). An `IngressRouteTCP` is included for TLS passthrough to the self signed cert of keycloak 561 | 562 | ```bash 563 | curl -s https://raw.githubusercontent.com/clemenko/k8s_yaml/master/keycloak.yml | sed 's/dockr.life/'$NUM'.stackrox.live/g' | kubectl apply -f - 564 | ``` 565 | 566 | Login with username : `admin` and password `Pa22word`. 567 | 568 | #### Configure Stackrox Realm in Keycloak 569 | 570 | Click **Master --> Add realm** and name it `stackrox`. 571 | 572 | #### Create user 573 | 574 | Next click the **Users** on the left and **Add User**. This should be obvious. Next click the **Credentials** tab to enter a password. Also make sure `Temporary` is off. And click `Reset Password` 575 | 576 | #### Add Stackrox OIDC Client - Keycloak 577 | 578 | Once created click **Clients** on the left. Then Click **Create**. 579 | 580 | `Client ID` : stackrox 581 | 582 | `Protocol` : openid-connect 583 | 584 | `Root URL` : "" 585 | 586 | Next we need to change the `Access Type` to `confidental`. We also need to set the `Valid Redirect URLs` to `https://rox.$NUM.stackrox.live/sso/providers/oidc/callback`. Make sure you change your domain name. 587 | 588 | now save. 589 | 590 | ##### Get Client Secret 591 | 592 | Next click the **Credentials** tab to get the secret. 593 | 594 | #### Configure StackRox OpenID 595 | 596 | ##### Add Auth Provider 597 | 598 | Navigate to **PLATFORM CONFIGURATION --> ACCESS CONTROL** 599 | 600 | Then **Add an Auth Provider --> OpenID Connect** 601 | 602 | `Name` : Generic Name, anything will work. 603 | 604 | `Query` : Checked 605 | 606 | `Issuer` : https+insecure://keycloak.$NUM.stackrox.live/auth/realms/stackrox 607 | 608 | `Client ID` : stackrox 609 | 610 | `Client Secret` : "From the keycloak client credentials page." 611 | 612 | Click Save and Test. 613 | 614 | ##### Add Rules as needed - OIDC 615 | 616 | ### Jenkins 617 | 618 | Deploy [Jenkins](jenkins.io) and profit! This version of Jenkins has the [StackRox](https://stackrox.com) plugin added. Simple right? 619 | 620 | ```bash 621 | curl -s https://raw.githubusercontent.com/clemenko/k8s_yaml/master/jenkins_containerd.yml | sed 's/dockr.life/'$NUM'.stackrox.live/g' | kubectl apply -f - 622 | ``` 623 | 624 | Now you can validate it is up on Traefik - http://traefik.$NUM.stackrox.live/. And navigate to http://jenkins.$NUM.stackrox.live/ 625 | 626 | Login with username : `admin` and password `Pa22word`. 627 | 628 | First we need to get `ROX_API_TOKEN` from the terminal with : 629 | 630 | ```bash 631 | cat jenkins_API_TOKEN 632 | ``` 633 | 634 | Second add the `ROX_API_TOKEN` to Jenkins. Click on `Manage Jenkins` --> `Configure System`. Scroll down and paste the token from the terminal into the `ROX_API_TOKEN` in and `SAVE`. 635 | 636 | We will leave the `ROX_URL` the same since we are deploying to the same cluster. It would need to be changed if your are deploying to a different cluster. 637 | 638 | ![jenkins1 image](./images/jenkins1.jpg) 639 | 640 | Now click `StackRox_PluginSample` and then `Build Now`. 641 | 642 | We should see a failed build. Huzzah! Take a minute and review the `StackRox Image Security Report` output. 643 | 644 | ![jenkins2 image](./images/jenkins2.jpg) 645 | 646 | ### Profit 647 | 648 | You know have deployed [StackRox](https://stackrox.com) on [k3s](https://k3s.io) with [Traefik](https://traefik.io/), and [Longhorn](https://longhorn.io). 649 | 650 | ![success](./images/success.jpg) -------------------------------------------------------------------------------- /workshop/images/api.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/api.jpg -------------------------------------------------------------------------------- /workshop/images/api_token.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/api_token.jpg -------------------------------------------------------------------------------- /workshop/images/banners.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/banners.jpg -------------------------------------------------------------------------------- /workshop/images/edit_nmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/edit_nmap.jpg -------------------------------------------------------------------------------- /workshop/images/health.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/health.jpg -------------------------------------------------------------------------------- /workshop/images/help.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/help.jpg -------------------------------------------------------------------------------- /workshop/images/integrations.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/integrations.jpg -------------------------------------------------------------------------------- /workshop/images/jenkins1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/jenkins1.jpg -------------------------------------------------------------------------------- /workshop/images/jenkins2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/jenkins2.jpg -------------------------------------------------------------------------------- /workshop/images/nmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/nmap.jpg -------------------------------------------------------------------------------- /workshop/images/plugins.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/plugins.jpg -------------------------------------------------------------------------------- /workshop/images/policy1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/policy1.jpg -------------------------------------------------------------------------------- /workshop/images/runtime_nmap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/runtime_nmap.jpg -------------------------------------------------------------------------------- /workshop/images/sr_up.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/sr_up.jpg -------------------------------------------------------------------------------- /workshop/images/success.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clemenko/sr_tools/961a78c184a1f5e679cd825b96e3b97def02ccd5/workshop/images/success.jpg -------------------------------------------------------------------------------- /workshop/master_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source /root/.profile 4 | 5 | # k3s 6 | k3sup install --ip $ipa --user root --k3s-extra-args "--no-deploy traefik" --cluster 7 | k3sup join --ip $ipb --server-ip $ipa --user root 8 | k3sup join --ip $ipc --server-ip $ipa --user root 9 | sleep 15 10 | sed -i "s/127.0.0.1/$ipa/" /etc/rancher/k3s/k3s.yaml 11 | 12 | # traefik 13 | kubectl apply -f https://raw.githubusercontent.com/clemenko/k8s_yaml/master/traefik_crd_deployment.yml 14 | 15 | # longhorn 16 | kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml 17 | sleep 5 18 | 19 | #wait for longhorn to initiaize 20 | until [ $(kubectl get pod -n longhorn-system | grep -v 'Running\|NAME' | wc -l) = 0 ] && [ "$(kubectl get pod -n longhorn-system | wc -l)" -gt 20 ] ; do sleep 2; done 21 | 22 | kubectl patch storageclass longhorn -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' 23 | kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}' 24 | 25 | # code 26 | curl -s https://raw.githubusercontent.com/clemenko/k8s_yaml/master/workshop-code-server.yml | sed 's/dockr.life/'$NUM'.stackrox.live/g' | kubectl apply -f - 27 | 28 | # ingress 29 | curl -s https://raw.githubusercontent.com/clemenko/k8s_yaml/master/workshop_yamls.yaml | sed "s/\$NUM/$NUM/" | kubectl apply -f - -------------------------------------------------------------------------------- /workshop/workshop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ################################### 3 | # edit vars 4 | ################################### 5 | set -e 6 | num=6 # num of students 7 | prefix=student 8 | password=Pa22word 9 | zone=nyc3 10 | size=s-4vcpu-8gb 11 | key=30:98:4f:c5:47:c2:88:28:fe:3c:23:cd:52:49:51:01 12 | 13 | domain=stackrox.live 14 | 15 | image=ubuntu-20-04-x64 16 | 17 | version=3.0.59.0 18 | 19 | deploy_k3s=false 20 | 21 | ###### NO MOAR EDITS ####### 22 | RED=$(tput setaf 1) 23 | GREEN=$(tput setaf 2) 24 | NORMAL=$(tput sgr0) 25 | BLUE=$(tput setaf 4) 26 | 27 | #better error checking 28 | command -v pdsh >/dev/null 2>&1 || { echo "$RED" " ** Pdsh was not found. Please install before preceeding. ** " "$NORMAL" >&2; exit 1; } 29 | 30 | ################################# up ################################ 31 | function up () { 32 | if [ -f hosts.txt ]; then 33 | echo "$RED" "Warning - cluster already detected..." "$NORMAL" 34 | exit 35 | fi 36 | 37 | build_list="" 38 | for i in $(seq 1 $num); do 39 | build_list="$prefix"$i"a $build_list" 40 | build_list="$prefix"$i"b $build_list" 41 | build_list="$prefix"$i"c $build_list" 42 | done 43 | echo -n " building vms for $num $prefix(s): " 44 | doctl compute droplet create $build_list --region $zone --image $image --size $size --ssh-keys $key --wait > /dev/null 2>&1 45 | doctl compute droplet list|grep -v ID|grep $prefix|awk '{print $3" "$2}'> hosts.txt 46 | echo "$GREEN" "ok" "$NORMAL" 47 | 48 | #check for SSH 49 | echo -n " checking for ssh" 50 | for ext in $(awk '{print $1}' hosts.txt); do 51 | until [ $(ssh -o ConnectTimeout=1 $user@$ext 'exit' 2>&1 | grep 'timed out\|refused' | wc -l) = 0 ]; do echo -n "." ; sleep 5; done 52 | done 53 | echo "$GREEN" "ok" "$NORMAL" 54 | 55 | host_list=$(awk '{printf $1","}' hosts.txt|sed 's/,$//') 56 | master_list=$(awk '/a/{printf $1","}' hosts.txt| sed 's/,$//') 57 | 58 | echo -n " updating dns " 59 | for i in $(seq 1 $num); do 60 | doctl compute domain records create $domain --record-type A --record-name $prefix"$i"a --record-ttl 150 --record-data $(cat hosts.txt|grep $prefix"$i"a|awk '{print $1}') > /dev/null 2>&1 61 | doctl compute domain records create $domain --record-type A --record-name $prefix"$i"b --record-ttl 150 --record-data $(cat hosts.txt|grep $prefix"$i"b|awk '{print $1}') > /dev/null 2>&1 62 | doctl compute domain records create $domain --record-type A --record-name $prefix"$i"c --record-ttl 150 --record-data $(cat hosts.txt|grep $prefix"$i"c|awk '{print $1}') > /dev/null 2>&1 63 | doctl compute domain records create $domain --record-type A --record-name $i --record-ttl 150 --record-data $(cat hosts.txt|grep $prefix"$i"a|awk '{print $1}') > /dev/null 2>&1 64 | doctl compute domain records create $domain --record-type CNAME --record-name "*.$i" --record-ttl 150 --record-data "$i".$domain. > /dev/null 2>&1 65 | done 66 | echo "$GREEN" "ok" "$NORMAL" 67 | 68 | sleep 15 69 | 70 | echo -n " adding os packages" 71 | pdsh -l root -w $host_list 'export DEBIAN_FRONTEND=noninteractive; apt-get update; apt-get install jq pdsh resolvconf -y; #apt upgrade -y; #apt autoremove -y ' > /dev/null 2>&1 72 | echo "$GREEN" "ok" "$NORMAL" 73 | 74 | echo -n " updating sshd " 75 | pdsh -l root -w $host_list 'echo "root:Pa22word" | chpasswd; sed -i "s/PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config; systemctl restart sshd' > /dev/null 2>&1 76 | echo "$GREEN" "ok" "$NORMAL" 77 | 78 | echo -n " install k3sup and roxctl" 79 | pdsh -l root -w $host_list 'curl -sLS https://get.k3sup.dev | sudo sh ; curl -#L https://andyc.info/rox/roxctl_Linux_'$version' -o /usr/local/bin/roxctl; chmod 755 /usr/local/bin/roxctl; echo "StrictHostKeyChecking no" > ~/.ssh/config; echo search '$domain' >> /etc/resolvconf/resolv.conf.d/tail; resolvconf -u' > /dev/null 2>&1 80 | echo "$GREEN" "ok" "$NORMAL" 81 | 82 | echo -n " setting up environment" 83 | pdsh -l root -w $host_list 'echo $(hostname| sed -e "s/student//" -e "s/a//") > /root/NUM; 84 | echo "export NUM=\$(cat /root/NUM)" >> .profile; echo "export ipa=\$(getent hosts student\"\$NUM\"a.stackrox.live|awk '"'"'{print \$1}'"'"')" >> .profile;echo "export ipb=\$(getent hosts student\"\$NUM\"b.stackrox.live|awk '"'"'{print \$1}'"'"')" >> .profile;echo "export ipc=\$(getent hosts student\"\$NUM\"c.stackrox.live|awk '"'"'{print \$1}'"'"')" >> .profile ; echo "export PATH=\$PATH:/opt/bin" >> .profile' 85 | echo "$GREEN" "ok" "$NORMAL" 86 | 87 | echo -n " set up ssh key" 88 | ssh-keygen -b 4092 -t rsa -f sshkey -q -N "" 89 | for i in $(seq 1 $num); do 90 | rsync -avP sshkey root@$prefix"$i"a.$domain:/root/.ssh/id_rsa > /dev/null 2>&1 91 | ssh-copy-id -i sshkey root@$prefix"$i"a.$domain > /dev/null 2>&1 92 | ssh-copy-id -i sshkey root@$prefix"$i"b.$domain > /dev/null 2>&1 93 | ssh-copy-id -i sshkey root@$prefix"$i"c.$domain > /dev/null 2>&1 94 | rsync -avP master_build.sh root@$prefix"$i"a.$domain:/root/ > /dev/null 2>&1 95 | done 96 | echo "$GREEN" "ok" "$NORMAL" 97 | 98 | if [ "$deploy_k3s" = true ]; then 99 | echo -n " deploy k3s, traefik, and code-server" 100 | pdsh -l root -w $master_list '/root/master_build.sh' > /dev/null 2>&1 101 | echo "$GREEN" "ok" "$NORMAL" 102 | fi 103 | 104 | echo -n " preload the offline bundle" 105 | pdsh -l root -w $host_list "curl -# https://andyc.info/rox/stackrox_all_$version.tar.gz -o /root/stackrox_all_$version.tar.gz" > /dev/null 2>&1 106 | echo "$GREEN" "ok" "$NORMAL" 107 | 108 | echo "" 109 | echo "===== Cluster =====" 110 | doctl compute droplet list --no-header |grep $prefix 111 | } 112 | 113 | ############################## kill ################################ 114 | #remove the vms 115 | function kill () { 116 | echo -n " killing it all " 117 | for i in $(doctl compute domain records list $domain --no-header|grep $prefix|awk '{print $1}'; doctl compute domain records list $domain --no-header|grep -w '1\|2\|3\|4\|5\|6\|7\|8\|9\|10\|11'|awk '{print $1}' ); do 118 | doctl compute domain records delete $domain $i --force 119 | done 120 | 121 | for i in $(doctl compute droplet list --no-header|grep $prefix|awk '{print $1}'); do 122 | doctl compute droplet delete --force $i 123 | done 124 | 125 | rm -rf hosts.txt sshkey* 126 | echo "$GREEN" "ok" "$NORMAL" 127 | } 128 | 129 | case "$1" in 130 | up) up;; 131 | kill) kill;; 132 | *) echo " Usage: $0 {up|kill}";; 133 | esac 134 | --------------------------------------------------------------------------------