├── .github └── workflows │ └── krewupdate.yaml ├── .krew.yaml ├── LICENSE ├── README.md ├── Resources └── test_single_example.gif ├── kubectl-datree └── manual_install.sh /.github/workflows/krewupdate.yaml: -------------------------------------------------------------------------------- 1 | name: krew-update 2 | on: workflow_dispatch 3 | jobs: 4 | krew-update: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Checkout 8 | uses: actions/checkout@master 9 | - name: Update new version in krew-index 10 | uses: rajatjindal/krew-release-bot@v0.0.40 11 | -------------------------------------------------------------------------------- /.krew.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: krew.googlecontainertools.github.com/v1alpha2 2 | kind: Plugin 3 | metadata: 4 | name: datree 5 | spec: 6 | version: {{ .TagName }} 7 | homepage: https://github.com/datreeio/kubectl-datree 8 | shortDescription: Scan your cluster resources for misconfigurations 9 | description: | 10 | Datree is a static code analysis tool for kubernetes manifest files. 11 | This plugin allows scanning resources within your cluster for misconfigurations. 12 | caveats: | 13 | Before using this plugin, the Datree CLI needs to be installed. 14 | See https://hub.datree.io/ for quick and easy installation. 15 | platforms: 16 | - selector: 17 | matchExpressions: 18 | - key: os 19 | operator: In 20 | values: 21 | - darwin 22 | - linux 23 | {{addURIAndSha "https://github.com/datreeio/kubectl-datree/releases/download/{{ .TagName }}/kubectl-datree.zip" .TagName }} 24 | files: 25 | - from: "kubectl-datree" 26 | to: "." 27 | - from: LICENSE 28 | to: "." 29 | bin: kubectl-datree 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 datree.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kubectl-datree 2 |

3 | 4 |

5 | 6 | ## Overview 7 | 8 | This **kubectl plugin** extends the [Datree CLI's](https://github.com/datreeio/datree) capabilities to allow scanning resources **within your cluster** for misconfigurations. 9 | 10 |

11 | Datree-kubectl 12 |

13 | 14 | 15 |
16 | 17 | ## Use cases 18 | - Reveal unknown configuration issues 19 | - Get ready for future k8s version upgrade 20 | - Enforce standards and best practices 21 | 22 |
23 | 24 | ## Supported Platforms 25 | This plugin supports **MacOS** and **Linux**. 26 | 27 |
28 | 29 | ## Installation 30 | ### Via Krew 31 | 1. Install [krew](https://krew.sigs.k8s.io/docs/user-guide/setup/install/) 32 | 2. Install the datree plugin: 33 | ``` 34 | kubectl krew install datree 35 | ``` 36 | ### Manual installation 37 | 1. [Download the installation script](https://github.com/datreeio/kubectl-datree/releases/latest/download/manual_install.sh) from this repository. 38 | 2. Open a terminal at the location of the script. 39 | 3. Run ```/bin/sh manual_install.sh``` (an administrator password will be required to complete the installation). 40 | 41 |
42 | 43 | ## Usage 44 | ``` 45 | kubectl datree test [datree CLI args] -- [options] 46 | ``` 47 | **Arguments:** 48 | ``` 49 | datree CLI args: 50 | This plugin supports all of the Datree CLI arguments: https://hub.datree.io/cli-arguments 51 | 52 | options: 53 | [-n ] Test all resources in the cluster belonging to the specified namespace 54 | [--all] Test all resources in the cluster 55 | When using '--all', you can specify namespaces to exclude using '--exclude --exclude ' 56 | [ ] Test a single resource in the cluster 57 | 58 | Running 'kubectl datree test' with no arguments is equivalent to 'kubectl datree test -- -n default' 59 | ``` 60 | 61 |
62 | 63 | ## Specification 64 | The plugin supports the following resource types: 65 | * Pod 66 | * Service 67 | * Ingress 68 | * Daemonset 69 | * Deployment 70 | * Replicaset 71 | * Statefulset 72 | * Job 73 | * CronJob 74 | * CRD (not the custom resource itself, but its definition) 75 | 76 | :warning: When running against a given namespace, only resources of these types will be checked. 77 | 78 |
79 | 80 | ## Examples 81 | The following command will fetch all resources within the namespace `exmpl`, and execute a policy check against them: 82 | ``` 83 | kubectl datree test -- -n exmpl 84 | ``` 85 | 86 | The following command will fetch the resource of kind **Service** named `myAwesomeService` in namespace `mySweetNamespace`, and execute a policy check against it using k8s schema version 1.22.0: 87 | ``` 88 | kubectl datree test -s "1.22.0" -- service myAwesomeService mySweetNamespace 89 | ``` 90 | 91 | The following command will fetch all resources from all namespaces in the cluster except for 'default': 92 | ``` 93 | kubectl datree test -- --all --exclude default 94 | ``` 95 | 96 |
97 | 98 | **Example test with no misconfigurations:** 99 | ![](Resources/test_single_example.gif) 100 | -------------------------------------------------------------------------------- /Resources/test_single_example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datreeio/kubectl-datree/1f3f2817b0386d733f0ebd155b8c53738b67e24d/Resources/test_single_example.gif -------------------------------------------------------------------------------- /kubectl-datree: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # Check if Datree is installed 5 | if ! command -v datree &> /dev/null; then 6 | printf "Datree is not installed on your machine, please run 'curl https://get.datree.io | /bin/bash' to install\n" 7 | printf "For more information, visit https://hub.datree.io/\n" 8 | exit 1 9 | fi 10 | 11 | show_help(){ 12 | printf "Datree's kubectl plugin extends the tool's capabilities to allow scanning k8s yaml files within the cluster for misconfigurations.\n" 13 | printf "For more information and examples, see the official documentation: https://hub.datree.io\n" 14 | printf "\nUsage:\n" 15 | printf " kubectl datree test [datree CLI args] -- [options]\n" 16 | printf "\nDatree CLI args:\n" 17 | printf " This plugin supports all of the Datree CLI arguments: https://hub.datree.io/cli-arguments\n" 18 | printf "\nOptions:\n" 19 | printf " [-n ] Test all resources in the cluster belonging to the specified namespace\n" 20 | printf " [--all] Test all resources in the cluster\n" 21 | printf " When using '--all', you can specify namespaces to exclude using '--exclude --exclude '\n" 22 | printf " [ ] Test a single resource in the cluster\n" 23 | printf "\nRunning 'kubectl datree test' with no arguments is equivalent to 'kubectl datree test -- -n default'\n" 24 | } 25 | 26 | PLUGIN_VERSION="v0.1.2" 27 | 28 | # Validate argument 29 | if [ "$1" == "version" ]; then 30 | echo "kubectl-datree plugin version: $PLUGIN_VERSION" 31 | exit 0 32 | elif [ "$1" != "test" ]; then 33 | show_help 34 | exit 1 35 | fi 36 | 37 | # Get server k8s version and set it in env 38 | SERVER_VERSION=$(kubectl version --short 2>/dev/null | grep "Server Version:") 39 | SERVER_VERSION=${SERVER_VERSION:17:7} 40 | SERVER_VERSION=${SERVER_VERSION%%-*} 41 | export DATREE_SCHEMA_VERSION=$SERVER_VERSION 42 | 43 | DATREE_OPTIONS=() 44 | EOO=0 45 | TEST_BY_NAMESPACE=1 46 | TEST_ALL=0 47 | NAMESPACES=() 48 | EXCLUDED_NAMESPACES=("kube-system" "kube-public" "kube-node-lease") 49 | RESOURCE_KIND="" 50 | RESOURCE_NAME="" 51 | 52 | # Parse command line 53 | while [[ $2 ]]; do 54 | if ! ((EOO)); then 55 | if [[ $2 == "--" ]]; then 56 | EOO=1 57 | else 58 | DATREE_OPTIONS+=("$2") 59 | fi 60 | 61 | shift 62 | else 63 | if [[ $2 == "--all" ]]; then 64 | TEST_BY_NAMESPACE=0 65 | TEST_ALL=1 66 | shift 67 | continue 68 | elif [[ $2 == "--exclude" ]]; then 69 | if [[ $TEST_ALL -ne 1 ]]; then 70 | printf "Incorrect usage of the '--exclude' option.\n\n" 71 | show_help 72 | exit 1 73 | fi 74 | 75 | if [ ! -z "$3" ]; then 76 | EXCLUDED_NAMESPACES+=("$3") 77 | shift 2 78 | continue 79 | else 80 | printf "Incorrect usage of the '--exclude' option.\n\n" 81 | show_help 82 | exit 1 83 | fi 84 | elif [[ $2 == "-n" ]] || [[ $2 == "--namespace" ]]; then 85 | if [ ! -z "$3" ]; then 86 | NAMESPACES+=("$3") 87 | else 88 | echo "No namespace provided, using 'default' namespace" 89 | NAMESPACES+=("default") 90 | fi 91 | elif [ ! -z "$2" ]; then 92 | if [ ! -z "$3" ]; then 93 | TEST_BY_NAMESPACE=0 94 | RESOURCE_KIND="$2" 95 | RESOURCE_NAME="$3" 96 | if [ ! -z "$4" ]; then 97 | NAMESPACES+=("$4") 98 | else 99 | echo "No namespace provided, exiting..." 100 | exit 1 101 | fi 102 | else 103 | echo "No resource name provided, exiting..." 104 | exit 1 105 | fi 106 | else 107 | echo "No resource type or name provided, exiting..." 108 | exit 1 109 | fi 110 | 111 | break 112 | fi 113 | done 114 | 115 | DST_DIR=""$HOME"/.datree/tmp" 116 | mkdir -p $DST_DIR 117 | 118 | get_yamls(){ 119 | while read line 120 | do 121 | FILENAME="kubectl-${line%%/*}-${line##*/}.yaml" 122 | 123 | kubectl apply view-last-applied $line -n "$1" > $DST_DIR/$FILENAME 124 | if [ ! -s $DST_DIR/$FILENAME ]; then 125 | kubectl get $line -n "$1" -o yaml > $DST_DIR/$FILENAME & 126 | fi 127 | 128 | scanned_files+=("$line") 129 | done 130 | } 131 | 132 | get_common_resources(){ 133 | while read line 134 | do 135 | # ignore system resources 136 | if [[ ${line##*/} == "kubernetes" ]]; then 137 | continue 138 | fi 139 | 140 | FILENAME="kubectl-${line%%/*}-${line##*/}.yaml" 141 | 142 | kubectl apply view-last-applied $line -n "$1" > $DST_DIR/$FILENAME 143 | if [ ! -s $DST_DIR/$FILENAME ]; then 144 | kubectl get $line -n "$1" -o yaml > $DST_DIR/$FILENAME & 145 | fi 146 | 147 | scanned_files+=("$line") 148 | done 149 | } 150 | 151 | additional_resources=("ingress") 152 | get_additional_resources(){ 153 | for str in ${additional_resources[@]}; do 154 | get_yamls "$1" < <(kubectl get $str -o name -n $1) 155 | done 156 | } 157 | 158 | get_crds(){ 159 | get_yamls "default" < <(kubectl get crd -o name) 160 | } 161 | 162 | get_all_namespaces(){ 163 | while read line 164 | do 165 | line=${line##*/} 166 | 167 | if [[ " ${EXCLUDED_NAMESPACES[*]} " =~ " ${line} " ]]; then 168 | # skip excluded namespace 169 | continue; 170 | fi 171 | 172 | NAMESPACES+=("$line") 173 | done < <(kubectl get ns -o name) 174 | } 175 | 176 | DATREE_TEST_COMMAND="datree test "${DATREE_OPTIONS[@]}"" 177 | 178 | # List all scanned files to display at end of test 179 | scanned_files=() 180 | wereFilesScanned=0 181 | 182 | # Test file/s 183 | if ((TEST_ALL)); then 184 | # Test all resources in the cluster 185 | echo "Fetching resources from all namespaces, this may take some time depending on the amount of resources in your cluster..." 186 | get_all_namespaces 187 | for namespace in ${NAMESPACES[@]}; do 188 | get_common_resources $namespace < <(kubectl get all -n $namespace --selector='!pod-template-hash','!controller-revision-hash','!controller-uid' -o name) 189 | get_additional_resources $namespace 190 | done 191 | 192 | get_crds 193 | wait 194 | 195 | if [ "$(ls -A $DST_DIR)" ]; then 196 | $DATREE_TEST_COMMAND $DST_DIR/*.yaml 197 | if [ "$?" != 1 ]; then 198 | wereFilesScanned=1 199 | fi 200 | else 201 | echo "Invalid namespace provided, exiting..." 202 | 203 | fi 204 | elif ((TEST_BY_NAMESPACE)); then 205 | # Test all resources in a given namespace 206 | if [ ${#NAMESPACES[@]} -eq 0 ]; then 207 | echo "No namespace provided, using 'default' namespace" 208 | NAMESPACES+=("default") 209 | fi 210 | 211 | echo "Fetching resources, this may take some time depending on the amount of resources in your cluster..." 212 | 213 | get_common_resources ${NAMESPACES[0]} < <(kubectl get all -n ${NAMESPACES[0]} --selector='!pod-template-hash','!controller-revision-hash','!controller-uid' -o name) 214 | get_additional_resources ${NAMESPACES[0]} 215 | get_crds 216 | wait 217 | 218 | if [ "$(ls -A $DST_DIR)" ]; then 219 | $DATREE_TEST_COMMAND $DST_DIR/*.yaml 220 | if [ "$?" != 1 ]; then 221 | wereFilesScanned=1 222 | fi 223 | else 224 | echo "Directory is empty or an error occurred when writing files, exiting..." 225 | exit 1 226 | fi 227 | else 228 | # Test a single file of a given resource type 229 | kubectl get $RESOURCE_KIND $RESOURCE_NAME -n ${NAMESPACES[0]} -o yaml > $DST_DIR/"kubectl-$RESOURCE_KIND-$RESOURCE_NAME".yaml 230 | scanned_files+=("$(kubectl get $RESOURCE_KIND $RESOURCE_NAME -n ${NAMESPACES[0]} -o name)") 231 | 232 | if [ -s $DST_DIR/"kubectl-$RESOURCE_KIND-$RESOURCE_NAME".yaml ]; then 233 | $DATREE_TEST_COMMAND $DST_DIR/"kubectl-$RESOURCE_KIND-$RESOURCE_NAME".yaml 234 | if [ "$?" != 1 ]; then 235 | wereFilesScanned=1 236 | fi 237 | fi 238 | fi 239 | 240 | if [ "$wereFilesScanned" != 0 ]; then 241 | if ((TEST_ALL)); then 242 | printf "All supported resources in the following namespaces were checked:\n\n" 243 | for namespace in ${NAMESPACES[@]} 244 | do 245 | printf "$namespace\n" 246 | done 247 | else 248 | printf "The following resources in namespace '${NAMESPACES[0]}' were checked:\n\n" 249 | for file in "${scanned_files[@]}" 250 | do 251 | printf "$file\n" 252 | done 253 | printf "\n" 254 | fi 255 | fi 256 | 257 | # Cleanup 258 | rm -rf $DST_DIR 259 | -------------------------------------------------------------------------------- /manual_install.sh: -------------------------------------------------------------------------------- 1 | # Install datree if it isn't installed 2 | if ! command -v datree &> /dev/null; then 3 | echo "Datree is not installed on your machine, proceeding to install..." 4 | curl https://get.datree.io | /bin/bash 5 | fi 6 | 7 | curl -L -O https://github.com/datreeio/kubectl-datree/releases/latest/download/kubectl-datree.zip 2> /dev/null 8 | 9 | PACKAGE_NAME="kubectl-datree.zip" 10 | PLUGIN_EXEC_NAME="kubectl-datree" 11 | 12 | mkdir tmpDatree 13 | unzip $PACKAGE_NAME -d tmpDatree > /dev/null 14 | 15 | sudo cp tmpDatree/$PLUGIN_EXEC_NAME /usr/local/bin/$PLUGIN_EXEC_NAME 16 | 17 | rm -rf tmpDatree && rm -rf $PACKAGE_NAME 18 | 19 | if [ -f /usr/local/bin/$PLUGIN_EXEC_NAME ]; then 20 | echo "Plugin installed successfully" 21 | else 22 | echo "Error occurred, please open a ticket in the github repository for assistance: https://github.com/datreeio/kubectl-datree" 23 | fi 24 | --------------------------------------------------------------------------------