├── .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 |
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 | 
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 |
--------------------------------------------------------------------------------