diff --git a/Dockerfile b/Dockerfile index 20d532d..a52b499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,8 @@ RUN apt-get update && \ apt-get -y install sudo RUN apt-get install curl -y RUN apt-get update -RUN apt-get install python-pip -y -RUN pip install requests +RUN apt-get install python3-pip -y +RUN pip3 install requests ibm-cloud-security-advisor-findingsapi-sdk==2.0.5 RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl RUN chmod +x ./kubectl diff --git a/README.md b/README.md index c7bfd4b..12b52d7 100644 --- a/README.md +++ b/README.md @@ -4,118 +4,120 @@ ![Definition of Terms](https://github.com/ibm-cloud-security/security-advisor-k8s-hunter-integration/blob/master/kube-definitions.png) -# Prerequisites -- Install python (Only if you want to do the cleanup of cards, notes and occurances) -- Install [Kubernetes Helm (package manager)](https://docs.helm.sh/using_helm/#from-script) v2.9.0 or higher -- you need to have an IBM Cloud account where you are able to navigate to IBM Cloud Security Advisor Dashboard. Account ID and other account details refered in this document is corresponding to that account +## Prerequisites +- An installation of Python *>=3.5* on your local machine (Only if you want to do the cleanup of cards, notes and occurrences). +- An installation of [Helm Package Manager](https://docs.helm.sh/using_helm/#from-script) *>=2.9.0* for Kubernetes. +- You need to have an IBM Cloud account where you are able to navigate to IBM Cloud Security Advisor Dashboard. Account ID and other account details refered in this document is corresponding to that account. + +
## public-k8s cloud ### Install steps for public-k8s cloud: - Clone this repo -- `cd security-advisor-k8s-hunter-integration/scripts/public` +- `cd security-advisor-k8s-hunter-integration` - Inorder to point to security advisor london endpoint do following changes: uncomment line#16 and comment line#15 in /config/helm/kubehunter-adapter-public/values.yaml -- `./sa_kubehunter_install.sh ""` +- `sh ./scripts/public/sa_kubehunter_install.sh ` - for example: ``` ./sa_kubehunter_install.sh account_id apikey mycluster "/Users/sunilsingh/.bluemix/plugins/container-ser-ice/clusters/mycluster" : Account id on which the card needs to be generated : api-key of the above account-id. -: The target public k8s cluster on which kube-hunter needs to be configured -: Run `ibmcloud cs cluster-config ` to get kube-config +: The target public k8s cluster on which kube-bench needs to be configured +: Run `ibmcloud ks cluster config ` to get kube-config ``` ### Cleanup setup for public-k8s cloud: -- Clone this repo -- `cd security-advisor-k8s-hunter-integration/scripts/public` +- `cd security-advisor-k8s-hunter-integration` - Run below automated script to cleanup all in once. -`./sa_kubehunter_cleanup.sh "full path to directory of kube configs>" ` +`sh ./scripts/public/sa_kubehunter_cleanup.sh ` - For example: ``` - ./sa_kubehunter_cleanup.sh accountid apikey myrhelcluster oc-login-apikey - - ./sa_kubehunter_cleanup.sh accountid apikey "/Users/sunilsingh/.bluemix/plugins/container-service/clusters/mycluster" "https://us-south.secadvisor.cloud.ibm.com/findings/v1" ibmcloud + ./sa_kubehunter_cleanup.sh accountid apikey "/Users/sunilsingh/.bluemix/plugins/container-service/clusters/mycluster" "https://us-south.secadvisor.cloud.ibm.com/findings" ibmcloud -: Account id on which the card needs to be generated +: Account id on which the card needs to be deleted : api-key of the above account-id. -: The target public k8s cluster on which kube-hunter needs to be configured -: Run `ibmcloud cs cluster-config ` to get kube-config +: Run `ibmcloud cs cluster-config ` to get kube-config +: Endpoint of Security Advisor : Value is `ibmcloud` ``` +
## Redhat Openshift ### Install steps for source is public-k8s cloud and target is redhat-openshift cloud: - Clone this repo -- `cd security-advisor-k8s-hunter-integration/scripts/redhat` +- `cd security-advisor-k8s-hunter-integration` - Inorder to point to security advisor london endpoint do following changes: - uncomment line#6 and comment line#15 in /config/helm/kubehunter-adapter/values.yaml -- `./sa_kubehunter_install.sh ` + uncomment line#14 and comment line#13 in /config/helm/kubebench-adapter/values.yaml +- `sh ./scripts/public/sa_kubehunter_install.sh ` - for example: ``` -./sa_kubehunter_install.sh account_id apikey mycluster-rhel "oc-login-api-key" +./sa_kubebench_install.sh account-id apikey mycluster-rhel "oc-login-api-key" : Account id on which the card needs to be generated : api-key of the above account-id. -: The target rhel-openshift cluster on which kube-hunter needs to be configured +: The target rhel-openshift cluster on which kube-bench needs to be configured : The api-key to login to cluster ``` ### Cleanup of setup for source is public-k8s cloud and target is redhat-openshift cloud: - Clone this repo -- `cd security-advisor-k8s-hunter-integration/scripts/redhat` +- `cd security-advisor-k8s-hunter-integration` - Run below automated script to cleanup all in once. -- `./sa_kubehunter_cleanup.sh ` +- `sh ./scripts/public/sa_kubehunter_cleanup.sh ` - For example: ``` -./sa_hunter_cleanup.sh accountid apikey myrhelcluster oc-login-apikey "https://us-south.secadvisor.cloud.ibm.com/findings/v1" +./sa_kubehunter_cleanup.sh accountid apikey myrhelcluster oc-login-apikey "https://us-south.secadvisor.cloud.ibm.com/findings" redhat -: Account id on which the card needs to be generated +: Account id on which the card needs to be generated : api-key of the above account-id. -: The target rhel-openshift cluster on which kube-hunter needs to be configured +: The target rhel-openshift cluster on which kube-bench needs to be configured : The api-key to login to cluster -: The value is `https://us-south.secadvisor.cloud.ibm.com/findings/v1` -: The value is `redhat` +: The value is `https://us-south.secadvisor.cloud.ibm.com/findings` +: The value is `redhat` ``` ### Install steps for source and target as redhat-openshift cloud: - Clone this repo -- `cd security-advisor-k8s-hunter-integration/scripts/redhat` +- `cd security-advisor-k8s-hunter-integration` - Inorder to point to security advisor london endpoint do following changes: - uncomment line#16 and comment line#15 in /config/helm/kubehunter-adapter/values.yaml -- `./sa_kubehunter_install.sh redhat` + uncomment line#14 and comment line#13 in /config/helm/kubebench-adapter/values.yaml +- `sh ./scripts/redhat/sa_kubehunter_install.sh ` - for example: ``` -./sa_kubehunter_install.sh account_id apikey mycluster-rhel "oc login api-key" redhat +sh ./scripts/redhat/sa_kubehunter_install.sh account_id apikey mycluster-rhel "oc login api-key" redhat -: Account id on which the card needs to be generated +: Account id on which the card needs to be generated : api-key of the above account-id. -: The target rhel-openshift k8s cluster on which kube-hunter needs to be configured +: The target rhel-openshift k8s cluster on which kube-bench needs to be configured : The api-key to login to cluster +: The value is `redhat` ``` ### Cleanup of setup for source and target as redhat-openshift: - Clone this repo -- `cd security-advisor-k8s-hunter-integration/scripts/redhat` +- `cd security-advisor-k8s-hunter-integration` - Run below automated script to cleanup all in once. -- `./sa_kubehunter_cleanup.sh ` +- `sh ./scripts/redhat/sa_kubehunter_cleanup.sh ` - For example: ``` -./sa_kubehunter_cleanup.sh accountid apikey mycluster-rhel oc-login-apikey "https://us-south.secadvisor.cloud.ibm.com/findings/v1 redhat" +sh ./scripts/redhat/sa_kubehunter_cleanup.sh accountid apikey mycluster-rhel oc-login-apikey "https://us-south.secadvisor.cloud.ibm.com/findings redhat" -: Account id on which the card needs to be generated +: Account id on which the card needs to be generated : api-key of the above account-id. -: The target rhel-openshift cluster on which kube-hunter needs to be configured +: The target rhel-openshift cluster on which kube-bench needs to be configured : The api-key to login to cluster -: The value is `https://us-south.secadvisor.cloud.ibm.com/findings/v1` -: The value is `redhat` +: The value is `https://us-south.secadvisor.cloud.ibm.com/findings` +: The value is `redhat` ``` +
## Configure cronjob: - The cronjobs are scheduled to run every 15 mins, which is configurable. Change the schedule to run the cronjobs at: ``` -security-advisor-k8s-hunter-integration/blob/master/config/helm/kubehunter-adapter-public/templates/kube-cronjob.yaml#L8 +https://github.com/ibm-cloud-security/security-advisor-k8s-hunter-integration/blob/master/config/helm/kubehunter-adapter-public/templates/kubehunter-cronjob.yaml#L8 ``` ## Troubleshooting diff --git a/config/helm/kubehunter-adapter-public/templates/kubehunter-cronjob.yaml b/config/helm/kubehunter-adapter-public/templates/kubehunter-cronjob.yaml index d191926..46f6f9a 100644 --- a/config/helm/kubehunter-adapter-public/templates/kubehunter-cronjob.yaml +++ b/config/helm/kubehunter-adapter-public/templates/kubehunter-cronjob.yaml @@ -25,7 +25,7 @@ spec: - name: {{ .Values.global.imagePullSecrets }} containers: - name: {{ .Values.global.name }} - image: us.icr.io/{{ .Values.global.registryNamespace }}/{{ .Values.global.imageName }}:{{ .Values.global.tag | default "dummy" }} + image: {{ .Values.global.registryNamespace }}/{{ .Values.global.imageName }}:{{ .Values.global.tag | default "dummy" }} command: - "/bin/sh" - "-c" diff --git a/config/helm/kubehunter-adapter-public/values.yaml b/config/helm/kubehunter-adapter-public/values.yaml index 5c01470..b9e9ca7 100644 --- a/config/helm/kubehunter-adapter-public/values.yaml +++ b/config/helm/kubehunter-adapter-public/values.yaml @@ -2,18 +2,18 @@ global: name: kubehunter-sa-adapter-public - imageName: kubehunter-sa-adapter - tag: "0.0.42" - imagePullSecrets: secadv-dev-secret - registryNamespace: secadv_dev + imageName: hunter-int + tag: "latest" + #imagePullSecrets: secadv-dev-secret + registryNamespace: gary29198 imagePullPolicy: IfNotPresent clusterNamespace: default cloudEnv: ibmcloud region: us-south loginEndpoint: "test.cloud.ibm.com" - saEndpoint: "https://us-south.secadvisor.cloud.ibm.com/findings/v1" - # saEndpoint: "https://eu-gb.secadvisor.cloud.ibm.com/findings/v1" + saEndpoint: "https://us-south.secadvisor.cloud.ibm.com/findings" + # saEndpoint: "https://eu-gb.secadvisor.cloud.ibm.com/findings" tokenUrl: "https://iam.cloud.ibm.com/identity/token" # token_url: "https://iam.test.cloud.ibm.com/identity/token" diff --git a/scripts/public/generate_kubeconfig_secrets.sh b/scripts/public/generate_kubeconfig_secrets.sh index ff9c0d9..4bed9bd 100755 --- a/scripts/public/generate_kubeconfig_secrets.sh +++ b/scripts/public/generate_kubeconfig_secrets.sh @@ -1,4 +1,11 @@ -set -x +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** + if [ "$#" -ne 3 ]; then echo "Required arguments missing!" echo "Usage : ./$(basename "$0") " diff --git a/scripts/public/generate_kubehunter_secrets.sh b/scripts/public/generate_kubehunter_secrets.sh index 75eca25..2262f4e 100755 --- a/scripts/public/generate_kubehunter_secrets.sh +++ b/scripts/public/generate_kubehunter_secrets.sh @@ -1,4 +1,11 @@ -set -x +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** + if [ "$#" -ne 5 ]; then echo "Required arguments missing!" echo "Usage : ./$(basename "$0") " diff --git a/scripts/public/sa_kubehunter_cleanup.sh b/scripts/public/sa_kubehunter_cleanup.sh index 6b492bd..8c11dea 100755 --- a/scripts/public/sa_kubehunter_cleanup.sh +++ b/scripts/public/sa_kubehunter_cleanup.sh @@ -1,26 +1,53 @@ +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** -set +x +# To check if helm is installed on system or not. +command -v helm >/dev/null 2>&1 || { echo >&2 "helm is required. Aborting."; exit 1; } +command -v kubectl >/dev/null 2>&1 || { echo >&2 "kubectl is required. Aborting."; exit 1; } + +# To check what version of helm is installed on system. +helmVer=`helm version --template {{.Version}}` +helmVerMajor="$(cut -d'.' -f 1 <<< ${helmVer:1})" + +# CLI Arguments check if [ "$#" -ne 5 ]; then - echo "Required arguments missing!" + if [ "$#" -lt 5 ]; then + echo "Required arguments missing!" + else + echo "Wrong usage!" + fi echo "Usage : ./$(basename "$0") " exit 1 fi +# Arguments assignment account_id=$1 api_key=$2 kube_config_dir=$3 -cloud_env=$4 -sa_endpoint=$5 -kubeconfig_name=$(ls $kube_config_dir |grep yml) +sa_endpoint=$4 +cloud_env=$5 -python ../../src/$cloud_env/kubeHunterCleanup.py $account_id $api_key $sa_endpoint +# Remove notes and occurrences emitted by kube-hunter +python3 src/$cloud_env/kubehunterCleanup.py $account_id $api_key $sa_endpoint +# Delete secrets from target cluster kubectl delete secret kubehunter-public-secret kubectl delete secret kubehunter-public-credentials -helm del --purge kubehunter-sa-adapter-public -podname=$(kubectl get job |grep kubehunter-sa-adapter-public|awk '{ print $1 }') -kubectl delete job $podname # Delete kube-hunter Job running on target cluster: +kubeconfig_name=$(ls $kube_config_dir |grep yml) export KUBECONFIG=$kube_config_dir/$kubeconfig_name kubectl delete job kube-hunter-public +kubectl delete cronjob kubehunter-sa-adapter-public + +# Remove helm chart from target cluster +if [ $helmVerMajor -gt 2 ]; then + helm uninstall kubehunter-sa-adapter-public +else + helm del --purge kubehunter-sa-adapter-public . +fi \ No newline at end of file diff --git a/scripts/public/sa_kubehunter_install.sh b/scripts/public/sa_kubehunter_install.sh index 91aeebc..8d1eb5e 100755 --- a/scripts/public/sa_kubehunter_install.sh +++ b/scripts/public/sa_kubehunter_install.sh @@ -1,29 +1,49 @@ #******************************************************************************* # * Licensed Materials - Property of IBM # * IBM Bluemix Container Service, 5737-D43 -# * (C) Copyright IBM Corp. 2017 All Rights Reserved. +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. # * US Government Users Restricted Rights - Use, duplication or # * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. #****************************************************************************** -set +x +# To check if helm is installed on system or not. +command -v helm >/dev/null 2>&1 || { echo >&2 "helm is required. Aborting."; exit 1; } +command -v kubectl >/dev/null 2>&1 || { echo >&2 "kubectl is required. Aborting."; exit 1; } + +# To check what version of helm is installed on system. +helmVer=`helm version --template {{.Version}}` +helmVerMajor="$(cut -d'.' -f 1 <<< ${helmVer:1})" + +# CLI Arguments check if [ "$#" -ne 4 ]; then - echo "Required arguments missing!" + if [ "$#" -lt 4 ]; then + echo "Required arguments missing!" + else + echo "Wrong usage!" + fi echo "Usage : ./$(basename "$0") " exit 1 fi +# Arguments assignment account_id=$1 api_key=$2 cluster_name=$3 kube_config_dir=$4 kubeconfig_name=$(ls $kube_config_dir |grep yml) -chmod +x generate_kubeconfig_secrets.sh -chmod +x generate_kubehunter_secrets.sh +# Change mode of scripts for creating kubernetes secrets +chmod +x ./scripts/public/generate_kubeconfig_secrets.sh +chmod +x ./scripts/public/generate_kubehunter_secrets.sh -./generate_kubeconfig_secrets.sh $kube_config_dir kubehunter-public-secret default -./generate_kubehunter_secrets.sh $account_id $api_key $cluster_name $kubeconfig_name default +# Execute scripts for creating kubernetes secrets +./scripts/public/generate_kubeconfig_secrets.sh $kube_config_dir kubehunter-public-secret default +./scripts/public/generate_kubehunter_secrets.sh $account_id $api_key $cluster_name $kubeconfig_name default -cd ../../config/helm/kubehunter-adapter-public -helm install --name kubehunter-sa-adapter-public . +# Install helm chart in kubernetes +cd config/helm/kubehunter-adapter-public +if [ $helmVerMajor -gt 2 ]; then + helm install kubehunter-sa-adapter-public . +else + helm install --name kubehunter-sa-adapter-public . +fi diff --git a/scripts/redhat/generate_kubehunter_secrets.sh b/scripts/redhat/generate_kubehunter_secrets.sh index d666eff..05e56d7 100755 --- a/scripts/redhat/generate_kubehunter_secrets.sh +++ b/scripts/redhat/generate_kubehunter_secrets.sh @@ -1,4 +1,11 @@ -set +x +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** + if [ "$#" -ne 5 ]; then echo "Required arguments missing!" echo "Usage : ./$(basename "$0") " diff --git a/scripts/redhat/sa_kubehunter_cleanup.sh b/scripts/redhat/sa_kubehunter_cleanup.sh index f2753df..de09cba 100755 --- a/scripts/redhat/sa_kubehunter_cleanup.sh +++ b/scripts/redhat/sa_kubehunter_cleanup.sh @@ -1,6 +1,20 @@ +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** -set +x -if [ "$#" -ne 6 ] && [ "$#" -ne 5 ]; then +# To check if helm is installed on system or not. +command -v helm >/dev/null 2>&1 || { echo >&2 "helm is required. Aborting."; exit 1; } +command -v kubectl >/dev/null 2>&1 || { echo >&2 "kubectl is required. Aborting."; exit 1; } + +# To check what version of helm is installed on system. +helmVer=`helm version --template {{.Version}}` +helmVerMajor="$(cut -d'.' -f 1 <<< ${helmVer:1})" + +if [ "$#" -ne 6 ] || [ "$#" -ne 5 ]; then echo "Required arguments missing!" echo "Usage : ./$(basename "$0") " echo -e '\t \t' "-----------OR-----------" @@ -15,7 +29,7 @@ oc_login_apikey=$4 sa_endpoint=$5 source_server=$6 -python ../../src/redhat-openshift/kubeHunterCleanup.py $account_id $api_key $sa_endpoint +python3 src/redhat-openshift/kubehunterCleanup.py $account_id $api_key $sa_endpoint if [ "$source_server" == "redhat" ]; then ibmcloud login -a test.cloud.ibm.com -r us-south --apikey $oc_login_apikey @@ -25,14 +39,22 @@ if [ "$source_server" == "redhat" ]; then oc login -u apikey -p $oc_login_apikey --server=$masterURL kubectl delete secret kubehunter-redhat-credentials - helm del --purge kubehunter-sa-adapter-redhat + if [ $helmVerMajor -gt 2 ]; then + helm uninstall kubehunter-sa-adapter-redhat + else + helm del --purge kubehunter-sa-adapter-redhat . + fi podname=$(kubectl get job |grep kubehunter-sa-adapter-redhat|awk '{ print $1 }') kubectl delete job $podname kubectl delete job kube-hunter-redhat else kubectl delete secret kubehunter-redhat-credentials - helm del --purge kubehunter-sa-adapter-redhat + if [ $helmVerMajor -gt 2 ]; then + helm uninstall kubehunter-sa-adapter-redhat + else + helm del --purge kubehunter-sa-adapter-redhat . + fi podname=$(kubectl get job |grep kubehunter-sa-adapter-redhat|awk '{ print $1 }') kubectl delete job $podname diff --git a/scripts/redhat/sa_kubehunter_install.sh b/scripts/redhat/sa_kubehunter_install.sh index 1e933d0..0937231 100755 --- a/scripts/redhat/sa_kubehunter_install.sh +++ b/scripts/redhat/sa_kubehunter_install.sh @@ -1,12 +1,18 @@ #******************************************************************************* # * Licensed Materials - Property of IBM # * IBM Bluemix Container Service, 5737-D43 -# * (C) Copyright IBM Corp. 2017 All Rights Reserved. +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. # * US Government Users Restricted Rights - Use, duplication or # * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. #****************************************************************************** -set -x +# To check if helm is installed on system or not. +command -v helm >/dev/null 2>&1 || { echo >&2 "helm is required. Aborting."; exit 1; } +command -v kubectl >/dev/null 2>&1 || { echo >&2 "kubectl is required. Aborting."; exit 1; } + +# To check what version of helm is installed on system. +helmVer=`helm version --template {{.Version}}` +helmVerMajor="$(cut -d'.' -f 1 <<< ${helmVer:1})" if [ "$#" -ne 5 ] && [ "$#" -ne 4 ]; then echo "Required arguments missing!" @@ -26,16 +32,21 @@ if [ "$source_server" == "redhat" ]; then ibmcloud login -a test.cloud.ibm.com -r us-south --apikey $oc_login_apikey ibmcloud oc cluster-get --cluster $cluster_name - chmod +x generate_kubehunter_secrets.sh - ./generate_kubehunter_secrets.sh $account_id $api_key $cluster_name $oc_login_apikey default + chmod +x ./scripts/redhat/generate_kubehunter_secrets.sh + ./scripts/redhat/generate_kubehunter_secrets.sh $account_id $api_key $cluster_name $oc_login_apikey default masterURL=$(ibmcloud oc cluster-get --cluster $cluster_name|grep "Master URL" |awk '{ print $3 }') echo "masterURL is $masterURL" oc login -u apikey -p $oc_login_apikey --server=$masterURL else - chmod +x generate_kubehunter_secrets.sh - ./generate_kubehunter_secrets.sh $account_id $api_key $cluster_name $oc_login_apikey default + chmod +x ./scripts/redhat/generate_kubehunter_secrets.sh + ./scripts/redhat/generate_kubehunter_secrets.sh $account_id $api_key $cluster_name $oc_login_apikey default fi -cd ../../config/helm/kubehunter-adapter-redhat -helm install --name kubehunter-sa-adapter-redhat . +# Install helm chart in kubernetes +cd config/helm/kubehunter-adapter-redhat +if [ $helmVerMajor -gt 2 ]; then + helm install kubehunter-sa-adapter-redhat . +else + helm install --name kubehunter-sa-adapter-redhat . +fi diff --git a/src/ibmcloud/kubeHunterAdaptor.py b/src/ibmcloud/kubeHunterAdaptor.py index 0cbce05..a5ef75d 100755 --- a/src/ibmcloud/kubeHunterAdaptor.py +++ b/src/ibmcloud/kubeHunterAdaptor.py @@ -9,57 +9,40 @@ import random from kubeHunterResultsParser import fetchVulList from kubeHunterL1Adaptor import postToSA +from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, IAMAuthenticator +from ibm_security_advisor_findings_api_sdk import FindingsApiV1 - -# Change the context according to your service - -def obtain_iam_token(api_key, token_url): - if not api_key: - raise Exception("obtain_uaa_token: missing api key") - - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - } - - body = 'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=' + api_key + '&response_type=cloud_iam' - - try: - response = requests.post(token_url, data=body, headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while obtaining IAM token" + str(err)) - return None - if response.status_code == 200 and response.json()['access_token']: - return response.json()['access_token'] +logger = logging.getLogger("adaptor") +logger.setLevel(logging.INFO) def adaptInsightsToOccurence(category,vulnerability,evidence,location,description, account_id , cluster_name): - finding_type = "" - provider_id = "" - if category.strip() == "Information Disclosure" : - finding_type = "kubehunteribmcloud-information-disclosure" - provider_id = "kubeHunterIBMCloudInformationDisclosure" - elif category.strip() == "Remote Code Execution" : - finding_type = "kubehunteribmcloud-remote-code-execution" - provider_id = "kubeHunterIBMCloudRemoteCodeExecutor" - elif category.strip() == "Identity Theft" : - finding_type = "kubehunteribmcloud-identity-and-access" - provider_id = "kubeHunterIBMCloudIdentityAndAccess" - - elif category.strip() == "Unauthenticated Access" : - finding_type = "kubehunteribmcloud-identity-and-access" - provider_id = "kubeHunterIBMCloudIdentityAndAccess" - elif category.strip() == "Access Risk" : - finding_type = "kubehunteribmcloud-identity-and-access" - provider_id = "kubeHunterIBMCloudIdentityAndAccess" - elif category.strip() == "Privilege Escalation" : - finding_type = "kubehunteribmcloud-identity-and-access" - provider_id = "kubeHunterRedhatIdentityAndAccess" - elif category.strip() == "Denial of Service" : - finding_type = "kubehunteribmcloud-denial-of-service" - provider_id = "kubeHunterIBMCloudDenialofService" - - pay_json = { + finding_type = "" + provider_id = "" + category = "".join(category.split()).strip() + if category == "InformationDisclosure" : + finding_type = "kubehunteribmcloud-information-disclosure" + provider_id = "kubeHunterIBMCloudInformationDisclosure" + elif category == "RemoteCodeExecution" : + finding_type = "kubehunteribmcloud-remote-code-execution" + provider_id = "kubeHunterIBMCloudRemoteCodeExecutor" + elif category == "IdentityTheft" : + finding_type = "kubehunteribmcloud-identity-and-access" + provider_id = "kubeHunterIBMCloudIdentityAndAccess" + + elif category == "UnauthenticatedAccess" : + finding_type = "kubehunteribmcloud-identity-and-access" + provider_id = "kubeHunterIBMCloudIdentityAndAccess" + elif category == "AccessRisk" : + finding_type = "kubehunteribmcloud-identity-and-access" + provider_id = "kubeHunterIBMCloudIdentityAndAccess" + elif category == "PrivilegeEscalation" : + finding_type = "kubehunteribmcloud-identity-and-access" + provider_id = "kubeHunterRedhatIdentityAndAccess" + elif category == "DenialofService" : + finding_type = "kubehunteribmcloud-denial-of-service" + provider_id = "kubeHunterIBMCloudDenialofService" + + pay_json = { "note_name": str(account_id) + "/providers/" + str(provider_id) + "/notes/" + str(finding_type), "kind": "FINDING", "message": evidence, @@ -74,11 +57,11 @@ def adaptInsightsToOccurence(category,vulnerability,evidence,location,descriptio "finding": { "severity": "LOW", "next_steps": [{ - "title": category +": Please check following : \n"+ description +" "+location - }] + "title": category +": Please check following : \n"+ description +" "+location + }] } } - return pay_json + return pay_json diff --git a/src/ibmcloud/kubeHunterCleanup.py b/src/ibmcloud/kubeHunterCleanup.py index 99275c8..f4d7671 100755 --- a/src/ibmcloud/kubeHunterCleanup.py +++ b/src/ibmcloud/kubeHunterCleanup.py @@ -8,70 +8,60 @@ import string import random import os +from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, IAMAuthenticator +from ibm_security_advisor_findings_api_sdk import FindingsApiV1 -logging.basicConfig() logger = logging.getLogger("cleanup") - +logger.setLevel(logging.INFO) def obtain_iam_token(api_key): if not api_key: - raise Exception("obtain_uaa_token: missing api key") - - token_url = os.environ['TOKEN_URL'] - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - } - - body = 'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=' + api_key + '&response_type=cloud_iam' - + raise Exception("obtain_iam_token: missing api key") try: - response = requests.post(token_url, data=body, headers=headers) - response.raise_for_status() + authenticator = IAMAuthenticator(api_key, url=os.environ['TOKEN_URL']) + token = authenticator.token_manager.get_token() except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while obtaining IAM token" + str(err)) - return None - if response.status_code == 200 and response.json()['access_token']: - return response.json()['access_token'] - + logger.exception("an unexpected error was encountered while obtaining IAM token: "+str(err)) + sys.exit(1) + if token: + return token def get_all_kubehunternotes(account_id, token, endpoint): notes = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) + providers = [ + "kubeHunterIBMCloud", + "kubeHunterIBMCloudInformationDisclosure", + "kubeHunterIBMCloudRemoteCodeExecutor", + "kubeHunterIBMCloudIdentityAndAccess", + "kubeHunterIBMCloudDenialofService" + ] + notes.extend(get_notes(account_id, token, endpoint, providers)) return notes -def get_notes(account_id, token, endpoint, url): +def get_notes(account_id, token, endpoint, providers): notes = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider in providers: + response = findingsAPI.list_notes( + account_id=account_id, + provider_id=provider + ) + if response.get_status_code() == 200: + logger.info("got notes by provider: %s" % provider) + for note in response.get_result()['notes']: + notes.append(note) + else: + logger.error("unable to get notes by provider: %s" % provider) + return notes except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the note" + str(err)) + logger.exception("an unexpected error was encountered while getting the note: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for note in body['notes']: - notes.append(note) - return notes - else: - return [] def delete_all_kubenotes(account_id, token, endpoint): @@ -79,99 +69,92 @@ def delete_all_kubenotes(account_id, token, endpoint): delete_notes(account_id, token, endpoint, notes) def delete_notes(account_id, token, endpoint, notes): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for note in notes: - if note['kind'] == "CARD": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/notes/"+ note['id'] - elif note['provider_id'] == "kubeHunterIBMCloudInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/notes/"+ note['id'] - elif note['provider_id'] == "kubeHunterIBMCloudRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/notes/"+ note['id'] - - elif note['provider_id'] == "kubeHunterIBMCloudIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/notes/"+ note['id'] - elif note['provider_id'] == "kubeHunterIBMCloudDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/notes/"+ note['id'] - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except: - logger.exception("An unexpected error was encountered while deleting the note" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for note in notes: + response = findingsAPI.delete_note( + account_id=account_id, + note_id=note['id'], + **note + ) + if response.get_status_code() == 200: + logger.info("deleted note: %s" % note['id']) + else: + logger.error("unable to delete note: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while deleting the note: "+str(err)) + time.sleep(1) def get_all_kubehunteroccurrences(account_id, token, endpoint): occurrences = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) + occurrences = [] + providers = [ + "kubeHunterIBMCloud", + "kubeHunterIBMCloudInformationDisclosure", + "kubeHunterIBMCloudRemoteCodeExecutor", + "kubeHunterIBMCloudIdentityAndAccess", + "kubeHunterIBMCloudDenialofService" + ] + occurrences.extend(get_occurrences(account_id, token, endpoint, providers)) return occurrences -def get_occurrences(account_id, token, endpoint, url): +def get_occurrences(account_id, token, endpoint, providers): occurrences = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider_id in providers: + response = findingsAPI.list_occurrences( + account_id=account_id, + provider_id=provider_id + ) + if response.get_status_code() == 200: + logger.info("got occurrences by provider: %s" % provider_id) + for occurrence in response.get_result()['occurrences']: + occurrences.append(occurrence) + else: + logger.error("unable to get occurrences by provider: %s" % provider_id) + return occurrences except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the occurrences" + str(err)) + logger.exception("an unexpected error was encountered while getting the occurrences: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for occurrence in body['occurrences']: - occurrences.append(occurrence) - return occurrences def delete_occurrences(account_id, token, endpoint, occurrences): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for occurrence in occurrences: - if occurrence['provider_id'] == "kubeHunterIBMCloudInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterIBMCloudRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/occurrences/" + occurrence['id'] - - elif occurrence['provider_id'] == "kubeHunterIBMCloudIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterIBMCloudDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/occurrences/" + occurrence['id'] - - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while deleting the occurrence" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for occurrence in occurrences: + response = findingsAPI.delete_occurrence( + account_id=account_id, + occurrence_id=occurrence['id'], + **occurrence + ) + if response.get_status_code() == 200: + logger.info("deleted occurrence: %s" % occurrence['id']) + else: + logger.error("unable to delete occurrence: %s" % occurrence['id']) + except requests.exceptions.HTTPError as err: + logger.exception("an unexpected error was encountered while deleting the occurrence: "+str(err)) + time.sleep(1) def cleanup(apikey, account_id, endpoint): token = obtain_iam_token(apikey) try: - delete_all_kubenotes(account_id, token, endpoint) + delete_all_kubenotes(account_id, token, endpoint) vulnerabilityOccurrences = get_all_kubehunteroccurrences(account_id, token, endpoint) delete_occurrences(account_id, token, endpoint, vulnerabilityOccurrences) except: - logger.exception("An unexpected error was encountered while cleanup"); + logger.exception("An unexpected error was encountered while cleanup") def main(args): account_id = args[1] diff --git a/src/ibmcloud/kubeHunterL1Adaptor.py b/src/ibmcloud/kubeHunterL1Adaptor.py index cb34309..c8d2e99 100755 --- a/src/ibmcloud/kubeHunterL1Adaptor.py +++ b/src/ibmcloud/kubeHunterL1Adaptor.py @@ -8,77 +8,79 @@ import string import random import os +from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, IAMAuthenticator +from ibm_security_advisor_findings_api_sdk import FindingsApiV1 -logging.basicConfig() -logger = logging.getLogger("kubehunter") +logger = logging.getLogger("l1_adaptor") +logger.setLevel(logging.INFO) -vulnerablity_notes_defenition = { +vulnerablity_notes_definition = { "notes": [ { "kind": "FINDING", - "short_description": "Kube hunter IBMCloud Information Disclosure", - "long_description": "Kube hunter IBMCloud Information Disclosure", + "short_description": "kube-hunter IBM Cloud Information Disclosure", + "long_description": "Kube-hunter IBM Cloud Information Disclosure", "provider_id": "kubeHunterIBMCloudInformationDisclosure", "id": "kubehunteribmcloud-information-disclosure", "reported_by": { "id": "kubehunteribmcloud-information-disclosure", - "title": "Kubehunter ibmcloud control" + "title": "kube-hunter IBM Cloud Control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter IBMCloud Information Disclosure" + "title": "kube-hunter IBM Cloud Information Disclosure" }] } }, { "kind": "FINDING", - "short_description": "Kube hunter IBMCloud Remote Code Execution", - "long_description": "Kube hunter IBMCloud Remote Code Execution", + "short_description": "kube-hunter IBM Cloud Remote Code Execution", + "long_description": "kube-hunter IBM Cloud Remote Code Execution", "provider_id": "kubeHunterIBMCloudRemoteCodeExecutor", "id": "kubehunteribmcloud-remote-code-execution", "reported_by": { "id": "kubehunteribmcloud-remote-code-execution", - "title": "Kubehunter ibmcloud control" + "title": "kube-hunter IBM Cloud Control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter IBMCloud Remote Code Execution" + "title": "kube-hunter IBM Cloud Remote Code Execution" }] } }, { "kind": "FINDING", - "short_description": "Kube hunter IBMCloud Identity And Access", - "long_description": "Kube hunter IBMCloud Identity And Access", + "short_description": "kube-hunter IBM Cloud Identity And Access", + "long_description": "kube-hunter IBM Cloud Identity And Access", "provider_id": "kubeHunterIBMCloudIdentityAndAccess", "id": "kubehunteribmcloud-identity-and-access", "reported_by": { "id": "kubehunteribmcloud-identity-and-access", - "title": "Kubehunter IBMCloud control" + "title": "kube-hunter IBM Cloud control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter IBMCloud Identity And Access" + "title": "kube-hunter IBM Cloud Identity And Access" }] } }, { "kind": "FINDING", - "short_description": "Kube hunter IBMCloud Denial of Service", - "long_description": "Kube hunter IBMCloud Denial of Service", + "short_description": "kube-hunter IBM Cloud Denial of Service", + "long_description": "kube-hunter IBM Cloud Denial of Service", "provider_id": "kubeHunterIBMCloudDenialofService", "id": "kubehunteribmcloud-denial-of-service", "reported_by": { "id": "kubehunteribmcloud-denial-of-service", - "title": "Kube hunter IBMCloud Kubehunter control" + "title": "kube-hunter IBM Cloud control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter IBMCloud Denial of Service" + "title": "kube-hunter IBM Cloud Denial of Service" }] } }, @@ -86,17 +88,16 @@ "kind": "CARD", "provider_id": "kubeHunterIBMCloud", "id": "kubehunteribmcloud-card", - "short_description": "Kubehunter IBMCloud vulnerabilities", - "long_description": "Kubehunter IBMCloud reported vulnerabilities", + "short_description": "kube-hunter IBM Cloud Vulnerabilities", + "long_description": "kube-hunter IBM Cloud Vulnerabilities", "reported_by": { "id": "kubehunteribmcloud-card", - "title": "Kube hunter IBMCloud vulnerabilities" + "title": "kube-hunter IBM Cloud Vulnerabilities" }, "card": { "section": "Container Config Exposures", - "title": "Kube-Hunter", - "subtitle": "IBM Cloud", - "context" : {}, + "title": "Kube Hunter", + "subtitle": "Kubernetes Security", "finding_note_names": [ "providers/kubeHunterIBMCloudInformationDisclosure/notes/kubehunteribmcloud-information-disclosure", "providers/kubeHunterIBMCloudRemoteCodeExecutor/notes/kubehunteribmcloud-remote-code-execution", @@ -157,180 +158,171 @@ def obtain_iam_token(api_key): if not api_key: - raise Exception("obtain_uaa_token: missing api key") - - token_url = os.environ['TOKEN_URL'] - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - } - - body = 'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=' + api_key + '&response_type=cloud_iam' - + raise Exception("obtain_iam_token: missing api key") try: - response = requests.post(token_url, data=body, headers=headers) - response.raise_for_status() + authenticator = IAMAuthenticator(api_key, url=os.environ['TOKEN_URL']) + token = authenticator.token_manager.get_token() except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while obtaining IAM token" + str(err)) - return None - if response.status_code == 200 and response.json()['access_token']: - return response.json()['access_token'] + logger.exception("an unexpected error was encountered while obtaining IAM token: "+str(err)) + sys.exit(1) + if token: + return token def create_note(account_id, token, endpoint): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for note in vulnerablity_notes_definition["notes"]: + response = findingsAPI.create_note( + account_id=account_id, + **note + ) + if response.get_status_code() == 200: + logger.info("created note: %s" % note['id']) + elif response.get_status_code() == 409 and note['kind'] == "CARD": + logger.info("card already present... attempting to update") + change_card(account_id, token, endpoint, note) + else: + logger.error("unable to create note: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while creating note") + - for note in vulnerablity_notes_defenition["notes"]: - if note['kind'] == "CARD": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/notes" - - elif note['provider_id'] == "kubeHunterIBMCloudInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/notes" - elif note['provider_id'] == "kubeHunterIBMCloudRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/notes" - elif note['provider_id'] == "kubeHunterIBMCloudIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/notes" - elif note['provider_id'] == "kubeHunterIBMCloudDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/notes" - - - try: - response = requests.post(url, data=json.dumps(note), headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while creating note" + str(err)) - if response.status_code == 200: - logger.info("Note created : %s" % note['id']) +def change_card(account_id, token, endpoint, note): + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + response = findingsAPI.update_note( + account_id=account_id, + note_id=note['id'] + **note + ) + if response.get_status_code() == 200: + logger.info("card updated: %s" % note['id']) + else: + logger.error("card not updated: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while updating note") def get_all_kubehunternotes(account_id, token, endpoint): - notes = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) + providers = [ + "kubeHunterIBMCloud", + "kubeHunterIBMCloudInformationDisclosure", + "kubeHunterIBMCloudRemoteCodeExecutor", + "kubeHunterIBMCloudIdentityAndAccess", + "kubeHunterIBMCloudDenialofService" + ] + notes.extend(get_notes(account_id, token, endpoint, providers)) return notes def get_notes(account_id, token, endpoint, url): - occurrences = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - + notes = [] try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider in providers: + response = findingsAPI.list_notes( + account_id=account_id, + provider_id=provider + ) + if response.get_status_code() == 200: + logger.info("got notes by provider: %s" % provider) + for note in response.get_result()['notes']: + notes.append(note) + else: + logger.error("unable to get notes by provider: %s" % provider) + return notes except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the note" + str(err)) + logger.exception("an unexpected error was encountered while getting the note: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for note in body['notes']: - occurrences.append(note['id']) - return note - else: - return [] def delete_notes(account_id, token, endpoint, notes): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for note in notes: - if note['kind'] == "CARD": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/notes" - elif note['provider_id'] == "kubeHunterIBMCloudInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/notes" - elif note['provider_id'] == "kubeHunterIBMCloudRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/notes" - - elif note['provider_id'] == "kubeHunterIBMCloudIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/notes" - elif note['provider_id'] == "kubeHunterIBMCloudDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/notes" - - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except: - logger.exception("An unexpected error was encountered while deleting the note" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for note in notes: + response = findingsAPI.delete_note( + account_id=account_id, + note_id=note['id'], + **note + ) + if response.get_status_code() == 200: + logger.info("deleted note: %s" % note['id']) + else: + logger.error("unable to delete note: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while deleting the note: "+str(err)) + time.sleep(1) def get_all_kubehunteroccurrences(account_id, token, endpoint): occurrences = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloud/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) + providers = [ + "kubeHunterIBMCloud", + "kubeHunterIBMCloudInformationDisclosure", + "kubeHunterRedhatRemoteCodeExecutor", + "kubeHunterIBMCloudIdentityAndAccess", + "kubeHunterIBMCloudDenialofService" + ] + occurrences.extend(get_occurrences(account_id, token, endpoint, providers)) return occurrences -def get_occurrences(account_id, token, endpoint, url): +def get_occurrences(account_id, token, endpoint, providers): occurrences = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider_id in providers: + response = findingsAPI.list_occurrences( + account_id=account_id, + provider_id=provider_id + ) + if response.get_status_code() == 200: + logger.info("got occurrences by provider: %s" % provider_id) + for occurrence in response.get_result()['occurrences']: + occurrences.append(occurrence) + else: + logger.error("unable to get occurrences by provider: %s" % provider_id) + return occurrences except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the occurrences" + str(err)) + logger.exception("an unexpected error was encountered while getting the occurrences: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for occurrence in body['occurrences']: - occurrences.append(occurrence) - return occurrences def delete_occurrences(account_id, token, endpoint, occurrences): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for occurrence in occurrences: - if occurrence['provider_id'] == "kubeHunterIBMCloudInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterIBMCloudRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/occurrences/" + occurrence['id'] - - elif occurrence['provider_id'] == "kubeHunterIBMCloudIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterIBMCloudDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/occurrences/" + occurrence['id'] - - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while deleting the occurrence" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for occurrence in occurrences: + response = findingsAPI.delete_occurrence( + account_id=account_id, + occurrence_id=occurrence['id'], + **occurrence + ) + if response.get_status_code() == 200: + logger.info("deleted occurrence: %s" % occurrence['id']) + else: + logger.error("unable to delete occurrence: %s" % occurrence['id']) + except requests.exceptions.HTTPError as err: + logger.exception("an unexpected error was encountered while deleting the occurrence: "+str(err)) + time.sleep(1) def id_generator(size=6, chars=string.digits): @@ -339,32 +331,22 @@ def id_generator(size=6, chars=string.digits): # This method needs to be defined for any partner application that needs to adapt def createOccurences(account_id, token, endpoint, occurrencesJson): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - - for occurrence in occurrencesJson: - print("occurrencesJson is",occurrencesJson) - if occurrence['provider_id'] == "kubeHunterIBMCloudInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/occurrences" - elif occurrence['provider_id'] == "kubeHunterIBMCloudRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudRemoteCodeExecutor/occurrences" - elif occurrence['provider_id'] == "kubeHunterIBMCloudIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudIdentityAndAccess/occurrences" - elif occurrence['provider_id'] == "kubeHunterIBMCloudDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudDenialofService/occurrences" - else: - url = endpoint + "/" + account_id + "/providers/kubeHunterIBMCloudInformationDisclosure/occurrences" - try: - response = requests.post(url, data=json.dumps(occurrence), headers=headers) - print("response is",response) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while creating occurrence" + str(err)) - if response.status_code == 200: - logging.info("Created occurrence") + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for occurrence in occurrencesJson: + response = findingsAPI.create_occurrence( + account_id=account_id, + **occurrence + ) + if response.get_status_code() == 200: + logger.info("created occurrence: %s" % occurrence['id']) + else: + logger.error("unable to create occurrence: %s" % occurrence['id']) + except requests.exceptions.HTTPError as err: + logger.exception("an unexpected error was encountered while creating occurrence: "+str(err)) def executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint, vulnerabilitiesReportedByPartner): @@ -372,23 +354,21 @@ def executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint try: create_note(account_id, token, endpoint) except: - print("ignoring metadata duplicate errors") + logger.exception("ignoring metadata duplicate errors") try: vulnerabilityOccurrences = get_all_kubehunteroccurrences(account_id, token, endpoint) delete_occurrences(account_id, token, endpoint, vulnerabilityOccurrences) except: - print("ignoring metadata duplicate errors") - - + logger.exception("ignoring metadata duplicate errors") createOccurences(account_id, token, endpoint, vulnerabilitiesReportedByPartner["insights"]) occurrences = get_all_kubehunteroccurrences(account_id, token, endpoint) return occurrences def postToSA(args): + logging.info("Patch Management Monitoring started") apikey = args["apikey"] account_id = args["account"] endpoint = args["endpoint"] - vulnerabilityOccurrences = executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint, - args["vulnerabilityInsights"]) + vulnerabilityOccurrences = executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint, args["vulnerabilityInsights"]) return {'insights': vulnerabilityOccurrences} diff --git a/src/ibmcloud/kubeHunterResultsParser.py b/src/ibmcloud/kubeHunterResultsParser.py index 82a44e4..18aabd1 100755 --- a/src/ibmcloud/kubeHunterResultsParser.py +++ b/src/ibmcloud/kubeHunterResultsParser.py @@ -4,105 +4,93 @@ def fetchVulList(fileName): logData = open(fileName, 'r') logData = list(logData) - - column1 = list() - column2 = list() - column3 = list() + column1 = list() + column2 = list() + column3 = list() column4 = list() column5 = list() - - for iter in logData: - if "|" in iter: - columns = iter.split("|") - else: - columns = iter.split("+") - - columnCount = 0 - for columnData in columns: - if(columnData != '' and columnData != '\n'): - columnCount = columnCount + 1 - if(columnCount == 1): - if(columnData.strip() != ''): - column1.append(columnData) - else: - column1.append("#######") - if(columnCount == 2): - if(columnData.strip() != ''): - column2.append(columnData) - else: - column2.append("#######") - if(columnCount == 3): - if(columnData.strip() != ''): - column3.append(columnData) - else: - column3.append("#######") - if(columnCount == 4): - if(columnData.strip() != ''): - column4.append(columnData) - else: - column4.append("#######") - if(columnCount == 5): - if(columnData.strip() != ''): - column5.append(columnData) - else: - column5.append("#######") - - - processedcolumn1 = list() - processedcolumn2 = list() - processedcolumn3 = list() + if "|" in iter: + columns = iter.split("|") + else: + columns = iter.split("+") + columnCount = 0 + for columnData in columns: + if(columnData!='' and columnData!='\n'): + columnCount=columnCount+1 + if(columnCount == 1): + if(columnData.strip() != ''): + column1.append(columnData) + else: + column1.append("#######") + if(columnCount == 2): + if(columnData.strip() != ''): + column2.append(columnData) + else: + column2.append("#######") + if(columnCount == 3): + if(columnData.strip() != ''): + column3.append(columnData) + else: + column3.append("#######") + if(columnCount == 4): + if(columnData.strip() != ''): + column4.append(columnData) + else: + column4.append("#######") + if(columnCount == 5): + if(columnData.strip() != ''): + column5.append(columnData) + else: + column5.append("#######") + processedcolumn1 = list() + processedcolumn2 = list() + processedcolumn3 = list() processedcolumn4 = list() processedcolumn5 = list() vulnerablityList = list() columnString = "" for columnEntry in column1: - - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn1.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - columnString = "" - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn1.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry + columnString = "" for columnEntry in column2: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn2.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn2.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry for columnEntry in column3: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn3.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn3.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry for columnEntry in column4: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn4.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn4.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry for columnEntry in column5: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn5.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn5.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry column1Length = len(processedcolumn1) column2Length = len(processedcolumn2) column3Length = len(processedcolumn3) @@ -119,29 +107,26 @@ def fetchVulList(fileName): maxCount = column4Length if(column5Length > maxCount) : maxCount = column5Length - for jsonEntry in range(maxCount): - if jsonEntry == 0 : - continue - vulnerablity = {} - if jsonEntry < len(processedcolumn1): - vulnerablity["LOCATION"] = processedcolumn1[jsonEntry] - if jsonEntry < len(processedcolumn2): - vulnerablity["CATEGORY"] = processedcolumn2[jsonEntry] - if jsonEntry < len(processedcolumn3): - vulnerablity["VULNERABILITY"] = processedcolumn3[jsonEntry] - if jsonEntry < len(processedcolumn4): - vulnerablity["DESCRIPTION"] = processedcolumn4[jsonEntry] - if jsonEntry < len(processedcolumn5): - vulnerablity["EVIDENCE"] = processedcolumn5[jsonEntry] - vulnerablityList.append(vulnerablity) - + if jsonEntry == 0 : + continue + vulnerablity = {} + if jsonEntry < len(processedcolumn1): + vulnerablity["LOCATION"] = processedcolumn1[jsonEntry] + if jsonEntry < len(processedcolumn2): + vulnerablity["CATEGORY"] = processedcolumn2[jsonEntry] + if jsonEntry < len(processedcolumn3): + vulnerablity["VULNERABILITY"] = processedcolumn3[jsonEntry] + if jsonEntry < len(processedcolumn4): + vulnerablity["DESCRIPTION"] = processedcolumn4[jsonEntry] + if jsonEntry < len(processedcolumn5): + vulnerablity["EVIDENCE"] = processedcolumn5[jsonEntry] + vulnerablityList.append(vulnerablity) return vulnerablityList def main(args): fetchVulList("vul.txt") - if __name__ == "__main__": main(sys.argv) diff --git a/src/ibmcloud/updateKubeHunterCard_entryPt.sh b/src/ibmcloud/updateKubeHunterCard_entryPt.sh index 61ac60f..eebe500 100755 --- a/src/ibmcloud/updateKubeHunterCard_entryPt.sh +++ b/src/ibmcloud/updateKubeHunterCard_entryPt.sh @@ -1,14 +1,13 @@ #******************************************************************************* # * Licensed Materials - Property of IBM # * IBM Bluemix Container Service, 5737-D43 -# * (C) Copyright IBM Corp. 2017 All Rights Reserved. +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. # * US Government Users Restricted Rights - Use, duplication or # * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. #****************************************************************************** echo "CLOUD_ENV is $CLOUD_ENV" - while true; do - /kubehunter-sa-adapter/$CLOUD_ENV/update_kubehuntercard.sh $1 $2 $3 $4 & + /kubehunter-sa-adapter/$CLOUD_ENV/update_kubehuntercard.sh $1 $2 $3 $4 & sleep 3600 done \ No newline at end of file diff --git a/src/ibmcloud/update_kubehuntercard.sh b/src/ibmcloud/update_kubehuntercard.sh index 42a5223..2e2f103 100755 --- a/src/ibmcloud/update_kubehuntercard.sh +++ b/src/ibmcloud/update_kubehuntercard.sh @@ -1,5 +1,11 @@ +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** -set -x accountid=$1 apikey=$2 clustername=$3 @@ -19,9 +25,8 @@ sleep 20 echo "starting to prepare kubehunter analysis report" kubectl logs -f "$(kubectl get pods |grep kube-hunter-public | awk '{ print $1 }')" | sed -ne '/^Vulnerabilities$/{:a' -e 'n;p;ba' -e '}' >> ../vul.txt echo "analysis report prepared" -echo "Uploading report to SA" +echo "uploading report to SA..." -echo "SA_ENDPOINT is $SA_ENDPOINT" cd ../kubehunter-sa-adapter/$CLOUD_ENV -python kubeHunterAdaptor.py $accountid $apikey $clustername $SA_ENDPOINT -echo "Uploaded kube hunter report to SA" \ No newline at end of file +python3 kubeHunterAdaptor.py $accountid $apikey $clustername $SA_ENDPOINT +echo "uploaded kube-hunter report to SA" \ No newline at end of file diff --git a/src/redhat-openshift/kubeHunterAdaptor.py b/src/redhat-openshift/kubeHunterAdaptor.py index 76af2d1..0e282e1 100644 --- a/src/redhat-openshift/kubeHunterAdaptor.py +++ b/src/redhat-openshift/kubeHunterAdaptor.py @@ -8,54 +8,32 @@ import string import random from kubeHunterResultsParser import fetchVulList -from kubeHunterL1Adaptor import postToSA - - -# Change the context according to your service - -def obtain_iam_token(api_key, token_url): - if not api_key: - raise Exception("obtain_uaa_token: missing api key") - - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - } - - body = 'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=' + api_key + '&response_type=cloud_iam' - - try: - response = requests.post(token_url, data=body, headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while obtaining IAM token" + str(err)) - return None - if response.status_code == 200 and response.json()['access_token']: - return response.json()['access_token'] +from kubeHunterL1Adaptor import postToSA def adaptInsightsToOccurence(category,vulnerability,evidence,location,description, account_id , cluster_name): finding_type = "" - provider_id = "" - if category.strip() == "Information Disclosure" : + provider_id = "" + category = "".join(category.split()).strip() + if category == "Information Disclosure" : finding_type = "kubehunterredhat-information-disclosure" provider_id = "kubeHunterRedhatInformationDisclosure" - elif category.strip() == "Remote Code Execution" : + elif category == "Remote Code Execution" : finding_type = "kubehunterredhat-remote-code-execution" provider_id = "kubeHunterRedhatRemoteCodeExecutor" - elif category.strip() == "Identity Theft" : + elif category == "Identity Theft" : finding_type = "kubehunterredhat-identity-and-access" provider_id = "kubeHunterRedhatIdentityAndAccess" - elif category.strip() == "Unauthenticated Access" : + elif category == "Unauthenticated Access" : finding_type = "kubehunterredhat-identity-and-access" provider_id = "kubeHunterRedhatIdentityAndAccess" - elif category.strip() == "Access Risk" : + elif category == "Access Risk" : finding_type = "kubehunterredhat-identity-and-access" provider_id = "kubeHunterRedhatIdentityAndAccess" - elif category.strip() == "Privilege Escalation" : + elif category == "Privilege Escalation" : finding_type = "kubehunterredhat-identity-and-access" provider_id = "kubeHunterRedhatIdentityAndAccess" - elif category.strip() == "Denial of Service" : + elif category == "Denial of Service" : finding_type = "kubehunterredhat-denial-of-service" provider_id = "kubeHunterRedhatDenialofService" diff --git a/src/redhat-openshift/kubeHunterCleanup.py b/src/redhat-openshift/kubeHunterCleanup.py index fd426a6..d1efbe7 100644 --- a/src/redhat-openshift/kubeHunterCleanup.py +++ b/src/redhat-openshift/kubeHunterCleanup.py @@ -8,70 +8,60 @@ import string import random import os +from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, IAMAuthenticator +from ibm_security_advisor_findings_api_sdk import FindingsApiV1 -logging.basicConfig() logger = logging.getLogger("cleanup") - +logger.setLevel(logging.INFO) def obtain_iam_token(api_key): if not api_key: - raise Exception("obtain_uaa_token: missing api key") - - token_url = os.environ['TOKEN_URL'] - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - } - - body = 'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=' + api_key + '&response_type=cloud_iam' - + raise Exception("obtain_iam_token: missing api key") try: - response = requests.post(token_url, data=body, headers=headers) - response.raise_for_status() + authenticator = IAMAuthenticator(api_key, url=os.environ['TOKEN_URL']) + token = authenticator.token_manager.get_token() except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while obtaining IAM token" + str(err)) - return None - if response.status_code == 200 and response.json()['access_token']: - return response.json()['access_token'] - + logger.exception("an unexpected error was encountered while obtaining IAM token: "+str(err)) + sys.exit(1) + if token: + return token def get_all_kubehunternotes(account_id, token, endpoint): notes = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) + providers = [ + "kubeHunterRedhatOpenshift", + "kubeHunterRedhatInformationDisclosure", + "kubeHunterRedhatRemoteCodeExecutor", + "kubeHunterRedhatIdentityAndAccess", + "kubeHunterRedhatDenialofService" + ] + notes.extend(get_notes(account_id, token, endpoint, providers)) return notes -def get_notes(account_id, token, endpoint, url): +def get_notes(account_id, token, endpoint, providers): notes = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider in providers: + response = findingsAPI.list_notes( + account_id=account_id, + provider_id=provider + ) + if response.get_status_code() == 200: + logger.info("got notes by provider: %s" % provider) + for note in response.get_result()['notes']: + notes.append(note) + else: + logger.error("unable to get notes by provider: %s" % provider) + return notes except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the note" + str(err)) + logger.exception("an unexpected error was encountered while getting the note: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for note in body['notes']: - notes.append(note) - return notes - else: - return [] def delete_all_kubenotes(account_id, token, endpoint): @@ -79,99 +69,92 @@ def delete_all_kubenotes(account_id, token, endpoint): delete_notes(account_id, token, endpoint, notes) def delete_notes(account_id, token, endpoint, notes): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for note in notes: - if note['kind'] == "CARD": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/notes/"+ note['id'] - elif note['provider_id'] == "kubeHunterRedhatInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/notes/"+ note['id'] - elif note['provider_id'] == "kubeHunterRedhatRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/notes/"+ note['id'] - - elif note['provider_id'] == "kubeHunterRedhatIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/notes/"+ note['id'] - elif note['provider_id'] == "kubeHunterRedhatDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/notes/"+ note['id'] - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except: - logger.exception("An unexpected error was encountered while deleting the note" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for note in notes: + response = findingsAPI.delete_note( + account_id=account_id, + note_id=note['id'], + **note + ) + if response.get_status_code() == 200: + logger.info("deleted note: %s" % note['id']) + else: + logger.error("unable to delete note: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while deleting the note: "+str(err)) + time.sleep(1) def get_all_kubehunteroccurrences(account_id, token, endpoint): occurrences = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) + occurrences = [] + providers = [ + "kubeHunterRedhatOpenshift", + "kubeHunterRedhatInformationDisclosure", + "kubeHunterRedhatRemoteCodeExecutor", + "kubeHunterRedhatIdentityAndAccess", + "kubeHunterRedhatDenialofService" + ] + occurrences.extend(get_occurrences(account_id, token, endpoint, providers)) return occurrences -def get_occurrences(account_id, token, endpoint, url): +def get_occurrences(account_id, token, endpoint, providers): occurrences = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider_id in providers: + response = findingsAPI.list_occurrences( + account_id=account_id, + provider_id=provider_id + ) + if response.get_status_code() == 200: + logger.info("got occurrences by provider: %s" % provider_id) + for occurrence in response.get_result()['occurrences']: + occurrences.append(occurrence) + else: + logger.error("unable to get occurrences by provider: %s" % provider_id) + return occurrences except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the occurrences" + str(err)) + logger.exception("an unexpected error was encountered while getting the occurrences: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for occurrence in body['occurrences']: - occurrences.append(occurrence) - return occurrences def delete_occurrences(account_id, token, endpoint, occurrences): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for occurrence in occurrences: - if occurrence['provider_id'] == "kubeHunterRedhatInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterRedhatRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/occurrences/" + occurrence['id'] - - elif occurrence['provider_id'] == "kubeHunterRedhatIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterRedhatDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/occurrences/" + occurrence['id'] - - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while deleting the occurrence" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for occurrence in occurrences: + response = findingsAPI.delete_occurrence( + account_id=account_id, + occurrence_id=occurrence['id'], + **occurrence + ) + if response.get_status_code() == 200: + logger.info("deleted occurrence: %s" % occurrence['id']) + else: + logger.error("unable to delete occurrence: %s" % occurrence['id']) + except requests.exceptions.HTTPError as err: + logger.exception("an unexpected error was encountered while deleting the occurrence: "+str(err)) + time.sleep(1) def cleanup(apikey, account_id, endpoint): token = obtain_iam_token(apikey) try: - delete_all_kubenotes(account_id, token, endpoint) + delete_all_kubenotes(account_id, token, endpoint) vulnerabilityOccurrences = get_all_kubehunteroccurrences(account_id, token, endpoint) delete_occurrences(account_id, token, endpoint, vulnerabilityOccurrences) except: - logger.exception("An unexpected error was encountered while cleanup"); + logger.exception("An unexpected error was encountered while cleanup") def main(args): account_id = args[1] diff --git a/src/redhat-openshift/kubeHunterL1Adaptor.py b/src/redhat-openshift/kubeHunterL1Adaptor.py index 4b77062..735d0e7 100644 --- a/src/redhat-openshift/kubeHunterL1Adaptor.py +++ b/src/redhat-openshift/kubeHunterL1Adaptor.py @@ -8,100 +8,101 @@ import string import random import os +from ibm_cloud_sdk_core.authenticators import BearerTokenAuthenticator, IAMAuthenticator +from ibm_security_advisor_findings_api_sdk import FindingsApiV1 -logging.basicConfig() -logger = logging.getLogger("kubehunter") +logger = logging.getLogger("l1_adaptor") +logger.setLevel(logging.INFO) -vulnerablity_notes_defenition = { +vulnerablity_notes_definition = { "notes": [ { "kind": "FINDING", - "short_description": "Kube hunter redhatOS Information Disclosure", - "long_description": "Kube hunter redhatOS Information Disclosure", - "provider_id": "kubeHunterRedhatInformationDisclosure", - "id": "kubehunterredhat-information-disclosure", + "short_description": "kube-hunter IBM Cloud Information Disclosure", + "long_description": "Kube-hunter IBM Cloud Information Disclosure", + "provider_id": "kubeHunterIBMCloudInformationDisclosure", + "id": "kubehunteribmcloud-information-disclosure", "reported_by": { - "id": "kubehunterredhat-information-disclosure", - "title": "Kubehunter redhat openshift control" + "id": "kubehunteribmcloud-information-disclosure", + "title": "kube-hunter IBM Cloud Control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter redhatOS Information Disclosure" + "title": "kube-hunter IBM Cloud Information Disclosure" }] } }, { "kind": "FINDING", - "short_description": "Kube hunter redhatOS Remote Code Execution", - "long_description": "Kube hunter redhatOS Remote Code Execution", - "provider_id": "kubeHunterRedhatRemoteCodeExecutor", - "id": "kubehunterredhat-remote-code-execution", + "short_description": "kube-hunter IBM Cloud Remote Code Execution", + "long_description": "kube-hunter IBM Cloud Remote Code Execution", + "provider_id": "kubeHunterIBMCloudRemoteCodeExecutor", + "id": "kubehunteribmcloud-remote-code-execution", "reported_by": { - "id": "kubehunterredhat-remote-code-execution", - "title": "Kubehunter redhat openshift control" + "id": "kubehunteribmcloud-remote-code-execution", + "title": "kube-hunter IBM Cloud Control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter redhatOS Remote Code Execution" + "title": "kube-hunter IBM Cloud Remote Code Execution" }] } }, { "kind": "FINDING", - "short_description": "Kube hunter redhatOS Identity And Access", - "long_description": "Kube hunter redhatOS Identity And Access", - "provider_id": "kubeHunterRedhatIdentityAndAccess", - "id": "kubehunterredhat-identity-and-access", + "short_description": "kube-hunter IBM Cloud Identity And Access", + "long_description": "kube-hunter IBM Cloud Identity And Access", + "provider_id": "kubeHunterIBMCloudIdentityAndAccess", + "id": "kubehunteribmcloud-identity-and-access", "reported_by": { - "id": "kubehunterredhat-identity-and-access", - "title": "Kubehunter redhat openshift control" + "id": "kubehunteribmcloud-identity-and-access", + "title": "kube-hunter IBM Cloud control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter redhatOS Identity And Access" + "title": "kube-hunter IBM Cloud Identity And Access" }] } }, { "kind": "FINDING", - "short_description": "Kube hunter redhatOS Denial of Service", - "long_description": "Kube hunter redhatOS Denial of Service", - "provider_id": "kubeHunterRedhatDenialofService", - "id": "kubehunterredhat-denial-of-service", + "short_description": "kube-hunter IBM Cloud Denial of Service", + "long_description": "kube-hunter IBM Cloud Denial of Service", + "provider_id": "kubeHunterIBMCloudDenialofService", + "id": "kubehunteribmcloud-denial-of-service", "reported_by": { - "id": "kubehunterredhat-denial-of-service", - "title": "Kube hunter redhatOS Kubehunter control" + "id": "kubehunteribmcloud-denial-of-service", + "title": "kube-hunter IBM Cloud control" }, "finding": { "severity": "HIGH", "next_steps": [{ - "title": "Kube hunter redhatOS Denial of Service" + "title": "kube-hunter IBM Cloud Denial of Service" }] } }, { "kind": "CARD", - "provider_id": "kubeHunterRedhatOpenshift", - "id": "kubehunterredhat-openshift-card", - "short_description": "Kubehunter redhat openshift vulnerabilities", - "long_description": "Kubehunter redhat openshift reported vulnerabilities", + "provider_id": "kubeHunterIBMCloud", + "id": "kubehunteribmcloud-card", + "short_description": "kube-hunter IBM Cloud Vulnerabilities", + "long_description": "kube-hunter IBM Cloud Vulnerabilities", "reported_by": { - "id": "kubehunterredhat-openshift-card", - "title": "Kubehunter redhat openshift vulnerabilities" + "id": "kubehunteribmcloud-card", + "title": "kube-hunter IBM Cloud Vulnerabilities" }, "card": { "section": "Container Config Exposures", - "title": "Kube-Hunter", - "subtitle": "Redhat Openshift", - "context" : {}, + "title": "Kube Hunter", + "subtitle": "Kubernetes Security", "finding_note_names": [ - "providers/kubeHunterRedhatInformationDisclosure/notes/kubehunterredhat-information-disclosure", - "providers/kubeHunterRedhatRemoteCodeExecutor/notes/kubehunterredhat-remote-code-execution", - "providers/kubeHunterRedhatIdentityAndAccess/notes/kubehunterredhat-identity-and-access", - "providers/kubeHunterRedhatDenialofService/notes/kubehunterredhat-denial-of-service" + "providers/kubeHunterIBMCloudInformationDisclosure/notes/kubehunteribmcloud-information-disclosure", + "providers/kubeHunterIBMCloudRemoteCodeExecutor/notes/kubehunteribmcloud-remote-code-execution", + "providers/kubeHunterIBMCloudIdentityAndAccess/notes/kubehunteribmcloud-identity-and-access", + "providers/kubeHunterIBMCloudDenialofService/notes/kubehunteribmcloud-denial-of-service" ], "elements": [{ "kind": "NUMERIC", @@ -110,7 +111,7 @@ "value_type": { "kind": "FINDING_COUNT", "finding_note_names": [ - "providers/kubeHunterRedhatInformationDisclosure/notes/kubehunterredhat-information-disclosure" + "providers/kubeHunterIBMCloudInformationDisclosure/notes/kubehunteribmcloud-information-disclosure" ] } }, @@ -121,7 +122,7 @@ "value_type": { "kind": "FINDING_COUNT", "finding_note_names": [ - "providers/kubeHunterRedhatRemoteCodeExecutor/notes/kubehunterredhat-remote-code-execution" + "providers/kubeHunterIBMCloudRemoteCodeExecutor/notes/kubehunteribmcloud-remote-code-execution" ] } }, @@ -132,7 +133,7 @@ "value_type": { "kind": "FINDING_COUNT", "finding_note_names": [ - "providers/kubeHunterRedhatIdentityAndAccess/notes/kubehunterredhat-identity-and-access" + "providers/kubeHunterIBMCloudIdentityAndAccess/notes/kubehunteribmcloud-identity-and-access" ] } }, @@ -143,7 +144,7 @@ "value_type": { "kind": "FINDING_COUNT", "finding_note_names": [ - "providers/kubeHunterRedhatDenialofService/notes/kubehunterredhat-denial-of-service" + "providers/kubeHunterIBMCloudDenialofService/notes/kubehunteribmcloud-denial-of-service" ] } } @@ -157,180 +158,171 @@ def obtain_iam_token(api_key): if not api_key: - raise Exception("obtain_uaa_token: missing api key") - - token_url = os.environ['TOKEN_URL'] - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - } - - body = 'grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey=' + api_key + '&response_type=cloud_iam' - + raise Exception("obtain_iam_token: missing api key") try: - response = requests.post(token_url, data=body, headers=headers) - response.raise_for_status() + authenticator = IAMAuthenticator(api_key, url=os.environ['TOKEN_URL']) + token = authenticator.token_manager.get_token() except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while obtaining IAM token" + str(err)) - return None - if response.status_code == 200 and response.json()['access_token']: - return response.json()['access_token'] + logger.exception("an unexpected error was encountered while obtaining IAM token: "+str(err)) + sys.exit(1) + if token: + return token def create_note(account_id, token, endpoint): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for note in vulnerablity_notes_definition["notes"]: + response = findingsAPI.create_note( + account_id=account_id, + **note + ) + if response.get_status_code() == 200: + logger.info("created note: %s" % note['id']) + elif response.get_status_code() == 409 and note['kind'] == "CARD": + logger.info("card already present... attempting to update") + change_card(account_id, token, endpoint, note) + else: + logger.error("unable to create note: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while creating note") + - for note in vulnerablity_notes_defenition["notes"]: - if note['kind'] == "CARD": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/notes" - - elif note['provider_id'] == "kubeHunterRedhatInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/notes" - elif note['provider_id'] == "kubeHunterRedhatRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/notes" - elif note['provider_id'] == "kubeHunterRedhatIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/notes" - elif note['provider_id'] == "kubeHunterRedhatDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/notes" - - - try: - response = requests.post(url, data=json.dumps(note), headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while creating note" + str(err)) - if response.status_code == 200: - logger.info("Note created : %s" % note['id']) +def change_card(account_id, token, endpoint, note): + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + response = findingsAPI.update_note( + account_id=account_id, + note_id=note['id'] + **note + ) + if response.get_status_code() == 200: + logger.info("card updated: %s" % note['id']) + else: + logger.error("card not updated: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while updating note") def get_all_kubehunternotes(account_id, token, endpoint): - notes = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/notes" - notes.extend(get_notes(account_id, token, endpoint, url)) + providers = [ + "kubeHunterRedhatOpenshift", + "kubeHunterRedhatInformationDisclosure", + "kubeHunterRedhatRemoteCodeExecutor", + "kubeHunterRedhatIdentityAndAccess", + "kubeHunterRedhatDenialofService" + ] + notes.extend(get_notes(account_id, token, endpoint, providers)) return notes def get_notes(account_id, token, endpoint, url): - occurrences = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - + notes = [] try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider in providers: + response = findingsAPI.list_notes( + account_id=account_id, + provider_id=provider + ) + if response.get_status_code() == 200: + logger.info("got notes by provider: %s" % provider) + for note in response.get_result()['notes']: + notes.append(note) + else: + logger.error("unable to get notes by provider: %s" % provider) + return notes except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the note" + str(err)) + logger.exception("an unexpected error was encountered while getting the note: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for note in body['notes']: - occurrences.append(note['id']) - return note - else: - return [] def delete_notes(account_id, token, endpoint, notes): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for note in notes: - if note['kind'] == "CARD": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/notes" - elif note['provider_id'] == "kubeHunterRedhatInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/notes" - elif note['provider_id'] == "kubeHunterRedhatRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/notes" - - elif note['provider_id'] == "kubeHunterRedhatIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/notes" - elif note['provider_id'] == "kubeHunterRedhatDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/notes" - - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except: - logger.exception("An unexpected error was encountered while deleting the note" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for note in notes: + response = findingsAPI.delete_note( + account_id=account_id, + note_id=note['id'], + **note + ) + if response.get_status_code() == 200: + logger.info("deleted note: %s" % note['id']) + else: + logger.error("unable to delete note: %s" % note['id']) + except: + logger.exception("an unexpected error was encountered while deleting the note: "+str(err)) + time.sleep(1) def get_all_kubehunteroccurrences(account_id, token, endpoint): occurrences = [] - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatOpenshift/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/occurrences" - occurrences.extend(get_occurrences(account_id, token, endpoint, url)) + providers = [ + "kubeHunterRedhatOpenshift", + "kubeHunterRedhatInformationDisclosure", + "kubeHunterRedhatRemoteCodeExecutor", + "kubeHunterRedhatIdentityAndAccess", + "kubeHunterRedhatDenialofService" + ] + occurrences.extend(get_occurrences(account_id, token, endpoint, providers)) return occurrences -def get_occurrences(account_id, token, endpoint, url): +def get_occurrences(account_id, token, endpoint, providers): occurrences = [] - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - try: - response = requests.get(url, headers=headers) - response.raise_for_status() + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for provider_id in providers: + response = findingsAPI.list_occurrences( + account_id=account_id, + provider_id=provider_id + ) + if response.get_status_code() == 200: + logger.info("got occurrences by provider: %s" % provider_id) + for occurrence in response.get_result()['occurrences']: + occurrences.append(occurrence) + else: + logger.error("unable to get occurrences by provider: %s" % provider_id) + return occurrences except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while getting the occurrences" + str(err)) + logger.exception("an unexpected error was encountered while getting the occurrences: "+str(err)) return False - if response.status_code == 200: - body = response.json() - for occurrence in body['occurrences']: - occurrences.append(occurrence) - return occurrences def delete_occurrences(account_id, token, endpoint, occurrences): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - for occurrence in occurrences: - if occurrence['provider_id'] == "kubeHunterRedhatInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterRedhatRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/occurrences/" + occurrence['id'] - - elif occurrence['provider_id'] == "kubeHunterRedhatIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/occurrences/" + occurrence['id'] - elif occurrence['provider_id'] == "kubeHunterRedhatDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/occurrences/" + occurrence['id'] - - try: - response = requests.delete(url, headers=headers) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while deleting the occurrence" + str(err)) - time.sleep(1) + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for occurrence in occurrences: + response = findingsAPI.delete_occurrence( + account_id=account_id, + occurrence_id=occurrence['id'], + **occurrence + ) + if response.get_status_code() == 200: + logger.info("deleted occurrence: %s" % occurrence['id']) + else: + logger.error("unable to delete occurrence: %s" % occurrence['id']) + except requests.exceptions.HTTPError as err: + logger.exception("an unexpected error was encountered while deleting the occurrence: "+str(err)) + time.sleep(1) def id_generator(size=6, chars=string.digits): @@ -339,30 +331,22 @@ def id_generator(size=6, chars=string.digits): # This method needs to be defined for any partner application that needs to adapt def createOccurences(account_id, token, endpoint, occurrencesJson): - headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Authorization': 'Bearer ' + token - } - - for occurrence in occurrencesJson: - print("occurrencesJson is",occurrencesJson) - if occurrence['provider_id'] == "kubeHunterRedhatInformationDisclosure": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatInformationDisclosure/occurrences" - elif occurrence['provider_id'] == "kubeHunterRedhatRemoteCodeExecutor": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatRemoteCodeExecutor/occurrences" - elif occurrence['provider_id'] == "kubeHunterRedhatIdentityAndAccess": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatIdentityAndAccess/occurrences" - elif occurrence['provider_id'] == "kubeHunterRedhatDenialofService": - url = endpoint + "/" + account_id + "/providers/kubeHunterRedhatDenialofService/occurrences" - try: - response = requests.post(url, data=json.dumps(occurrence), headers=headers) - print("response is",response) - response.raise_for_status() - except requests.exceptions.HTTPError as err: - logger.exception("An unexpected error was encountered while creating occurrence" + str(err)) - if response.status_code == 200: - logging.info("Created occurrence") + try: + findingsAPI = FindingsApiV1( + authenticator=BearerTokenAuthenticator(token) + ) + findingsAPI.set_service_url(endpoint) + for occurrence in occurrencesJson: + response = findingsAPI.create_occurrence( + account_id=account_id, + **occurrence + ) + if response.get_status_code() == 200: + logger.info("created occurrence: %s" % occurrence['id']) + else: + logger.error("unable to create occurrence: %s" % occurrence['id']) + except requests.exceptions.HTTPError as err: + logger.exception("an unexpected error was encountered while creating occurrence: "+str(err)) def executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint, vulnerabilitiesReportedByPartner): @@ -370,23 +354,21 @@ def executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint try: create_note(account_id, token, endpoint) except: - print("ignoring metadata duplicate errors") + logger.exception("ignoring metadata duplicate errors") try: vulnerabilityOccurrences = get_all_kubehunteroccurrences(account_id, token, endpoint) delete_occurrences(account_id, token, endpoint, vulnerabilityOccurrences) except: - print("ignoring metadata duplicate errors") - - + logger.exception("ignoring metadata duplicate errors") createOccurences(account_id, token, endpoint, vulnerabilitiesReportedByPartner["insights"]) occurrences = get_all_kubehunteroccurrences(account_id, token, endpoint) return occurrences def postToSA(args): + logging.info("Patch Management Monitoring started") apikey = args["apikey"] account_id = args["account"] endpoint = args["endpoint"] - vulnerabilityOccurrences = executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint, - args["vulnerabilityInsights"]) + vulnerabilityOccurrences = executePointInTimeVulnerabilityOccurenceAdapter(apikey, account_id, endpoint, args["vulnerabilityInsights"]) return {'insights': vulnerabilityOccurrences} diff --git a/src/redhat-openshift/kubeHunterResultsParser.py b/src/redhat-openshift/kubeHunterResultsParser.py index 82a44e4..18aabd1 100755 --- a/src/redhat-openshift/kubeHunterResultsParser.py +++ b/src/redhat-openshift/kubeHunterResultsParser.py @@ -4,105 +4,93 @@ def fetchVulList(fileName): logData = open(fileName, 'r') logData = list(logData) - - column1 = list() - column2 = list() - column3 = list() + column1 = list() + column2 = list() + column3 = list() column4 = list() column5 = list() - - for iter in logData: - if "|" in iter: - columns = iter.split("|") - else: - columns = iter.split("+") - - columnCount = 0 - for columnData in columns: - if(columnData != '' and columnData != '\n'): - columnCount = columnCount + 1 - if(columnCount == 1): - if(columnData.strip() != ''): - column1.append(columnData) - else: - column1.append("#######") - if(columnCount == 2): - if(columnData.strip() != ''): - column2.append(columnData) - else: - column2.append("#######") - if(columnCount == 3): - if(columnData.strip() != ''): - column3.append(columnData) - else: - column3.append("#######") - if(columnCount == 4): - if(columnData.strip() != ''): - column4.append(columnData) - else: - column4.append("#######") - if(columnCount == 5): - if(columnData.strip() != ''): - column5.append(columnData) - else: - column5.append("#######") - - - processedcolumn1 = list() - processedcolumn2 = list() - processedcolumn3 = list() + if "|" in iter: + columns = iter.split("|") + else: + columns = iter.split("+") + columnCount = 0 + for columnData in columns: + if(columnData!='' and columnData!='\n'): + columnCount=columnCount+1 + if(columnCount == 1): + if(columnData.strip() != ''): + column1.append(columnData) + else: + column1.append("#######") + if(columnCount == 2): + if(columnData.strip() != ''): + column2.append(columnData) + else: + column2.append("#######") + if(columnCount == 3): + if(columnData.strip() != ''): + column3.append(columnData) + else: + column3.append("#######") + if(columnCount == 4): + if(columnData.strip() != ''): + column4.append(columnData) + else: + column4.append("#######") + if(columnCount == 5): + if(columnData.strip() != ''): + column5.append(columnData) + else: + column5.append("#######") + processedcolumn1 = list() + processedcolumn2 = list() + processedcolumn3 = list() processedcolumn4 = list() processedcolumn5 = list() vulnerablityList = list() columnString = "" for columnEntry in column1: - - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn1.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - columnString = "" - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn1.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry + columnString = "" for columnEntry in column2: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn2.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn2.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry for columnEntry in column3: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn3.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn3.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry for columnEntry in column4: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn4.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn4.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry for columnEntry in column5: - if '--' in columnEntry: - if columnString.strip() != '': - processedcolumn5.append(columnString) - columnString = "" - else: - if columnEntry != '#######': - columnString = columnString + columnEntry - + if '--' in columnEntry: + if columnString.strip() != '': + processedcolumn5.append(columnString) + columnString = "" + else: + if columnEntry != '#######': + columnString = columnString + columnEntry column1Length = len(processedcolumn1) column2Length = len(processedcolumn2) column3Length = len(processedcolumn3) @@ -119,29 +107,26 @@ def fetchVulList(fileName): maxCount = column4Length if(column5Length > maxCount) : maxCount = column5Length - for jsonEntry in range(maxCount): - if jsonEntry == 0 : - continue - vulnerablity = {} - if jsonEntry < len(processedcolumn1): - vulnerablity["LOCATION"] = processedcolumn1[jsonEntry] - if jsonEntry < len(processedcolumn2): - vulnerablity["CATEGORY"] = processedcolumn2[jsonEntry] - if jsonEntry < len(processedcolumn3): - vulnerablity["VULNERABILITY"] = processedcolumn3[jsonEntry] - if jsonEntry < len(processedcolumn4): - vulnerablity["DESCRIPTION"] = processedcolumn4[jsonEntry] - if jsonEntry < len(processedcolumn5): - vulnerablity["EVIDENCE"] = processedcolumn5[jsonEntry] - vulnerablityList.append(vulnerablity) - + if jsonEntry == 0 : + continue + vulnerablity = {} + if jsonEntry < len(processedcolumn1): + vulnerablity["LOCATION"] = processedcolumn1[jsonEntry] + if jsonEntry < len(processedcolumn2): + vulnerablity["CATEGORY"] = processedcolumn2[jsonEntry] + if jsonEntry < len(processedcolumn3): + vulnerablity["VULNERABILITY"] = processedcolumn3[jsonEntry] + if jsonEntry < len(processedcolumn4): + vulnerablity["DESCRIPTION"] = processedcolumn4[jsonEntry] + if jsonEntry < len(processedcolumn5): + vulnerablity["EVIDENCE"] = processedcolumn5[jsonEntry] + vulnerablityList.append(vulnerablity) return vulnerablityList def main(args): fetchVulList("vul.txt") - if __name__ == "__main__": main(sys.argv) diff --git a/src/redhat-openshift/updateKubeHunterCard_entryPt.sh b/src/redhat-openshift/updateKubeHunterCard_entryPt.sh index 26fb197..eebe500 100755 --- a/src/redhat-openshift/updateKubeHunterCard_entryPt.sh +++ b/src/redhat-openshift/updateKubeHunterCard_entryPt.sh @@ -1,14 +1,13 @@ #******************************************************************************* # * Licensed Materials - Property of IBM # * IBM Bluemix Container Service, 5737-D43 -# * (C) Copyright IBM Corp. 2017 All Rights Reserved. +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. # * US Government Users Restricted Rights - Use, duplication or # * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. #****************************************************************************** -set -x - +echo "CLOUD_ENV is $CLOUD_ENV" while true; do - /kubehunter-sa-adapter/$CLOUD_ENV/update_kubehuntercard.sh $1 $2 $3 $4 & + /kubehunter-sa-adapter/$CLOUD_ENV/update_kubehuntercard.sh $1 $2 $3 $4 & sleep 3600 done \ No newline at end of file diff --git a/src/redhat-openshift/update_kubehuntercard.sh b/src/redhat-openshift/update_kubehuntercard.sh index 6b75927..840f76e 100755 --- a/src/redhat-openshift/update_kubehuntercard.sh +++ b/src/redhat-openshift/update_kubehuntercard.sh @@ -1,10 +1,15 @@ +#******************************************************************************* +# * Licensed Materials - Property of IBM +# * IBM Bluemix Container Service, 5737-D43 +# * (C) Copyright IBM Corp. 2020 All Rights Reserved. +# * US Government Users Restricted Rights - Use, duplication or +# * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +#****************************************************************************** -set -x accountid=$1 apikey=$2 clustername=$3 oc_login_apikey=$4 -echo "CLOUD_ENV is $CLOUD_ENV" git clone https://github.com/aquasecurity/kube-hunter.git cd kube-hunter/ @@ -27,7 +32,8 @@ sleep 20 echo "starting to prepare kubehunter analysis report" kubectl logs -f "$(kubectl get pods |grep kube-hunter-redhat | awk '{ print $1 }')" | sed -ne '/^Vulnerabilities$/{:a' -e 'n;p;ba' -e '}' >> ../vul.txt echo "analysis report prepared" -echo "Uploading report to SA" +echo "uploading report to SA..." cd ../kubehunter-sa-adapter/$CLOUD_ENV -python kubeHunterAdaptor.py $accountid $apikey $clustername $SA_ENDPOINT \ No newline at end of file +python3 kubeHunterAdaptor.py $accountid $apikey $clustername $SA_ENDPOINT +echo "uploaded kube-hunter report to SA" \ No newline at end of file