-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: support autofixing files This change adds support for autofixing files. This is achieved by expanding the script that runs as the Docker entrypoint to run the `kubescape fix` command if a user requests it. It also validates that the prerequisites to fix the files are met: a scan must include a JSON output. * fix: use proper input variable * chore!: remove artifacts to test * fix: specify JSON format for fixing files * refactor: use proper string non-zero checks * refactor: implement most ShellCheck suggestions * style: lowercase all script-local variables * style: use curly brackets for variable expansion * refactor: use native mechanism to skip confirmation * feat: automatically add JSON to formats when fixes are requested * feat: do not enforce severity threshold if fixes requested * docs: document how to use autofixing * docs: update `outputFile` usage for multiple outputs This change specifies that `outputFile` should omit the extension. * docs: mention artifacts TODO in entrypoint * fix: do not suggest autofixes on push in README Co-authored-by: David Wertenteil <[email protected]> * fix: do not suggest fixes on push in example workflow * docs: mention the autofixing workflow limitations Co-authored-by: David Wertenteil <[email protected]>
- Loading branch information
1 parent
a978d98
commit 1e1cf90
Showing
4 changed files
with
186 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,4 +17,40 @@ jobs: | |
- name: Upload Kubescape scan results to Github Code Scanning | ||
uses: github/codeql-action/upload-sarif@v2 | ||
with: | ||
sarif_file: results.sarif | ||
sarif_file: results.sarif | ||
|
||
--- | ||
|
||
name: Suggest autofixes with Kubescape | ||
on: [pull_request] | ||
jobs: | ||
kubescape: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
- name: Get changed files | ||
id: changed-files | ||
uses: tj-actions/[email protected] | ||
- uses: kubescape/github-action@main | ||
with: | ||
account: ${{secrets.KUBESCAPE_ACCOUNT}} | ||
files: ${{ steps.changed-files.outputs.all_changed_files }} | ||
fixFiles: true | ||
format: "sarif" | ||
- uses: peter-evans/create-pull-request@v4 | ||
with: | ||
add-paths: | | ||
*.yaml | ||
commit-message: "chore: fix K8s misconfigurations" | ||
title: "[Kubescape] chore: fix K8s misconfigurations" | ||
body: | | ||
# What this PR changes | ||
[Kubescape](https://github.com/kubescape/kubescape) has found misconfigurations in the targeted branch. This PR fixes the misconfigurations that have automatic fixes available. | ||
You may still need to fix misconfigurations that do not have automatic fixes. | ||
base: ${{ github.head_ref }} | ||
branch: kubescape-auto-fix-${{ github.head_ref || github.ref_name }} | ||
delete-branch: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ You need to make sure that workflows have [Read and write permissions](https://d | |
|
||
## Usage | ||
|
||
### Scanning with Kubescape | ||
|
||
To scan your repository with [Kubescape in your Github workflow](https://www.armosec.io/blog/kubescape-now-integrates-with-github-actions/?utm_source=github&utm_medium=repository), add the following steps to your workflow configuration: | ||
|
||
```yaml | ||
|
@@ -21,7 +23,7 @@ jobs: | |
continue-on-error: true | ||
with: | ||
format: sarif | ||
outputFile: results.sarif | ||
outputFile: results | ||
# # Optional: Specify the Kubescape cloud account ID | ||
# account: ${{secrets.KUBESCAPE_ACCOUNT}} | ||
# # Optional: Scan a specific path. Default will scan the whole repository | ||
|
@@ -35,12 +37,56 @@ jobs: | |
This workflow definition scans your repository with Kubescape and publishes the results to Github. | ||
You can then see the results in the Pull Request that triggered the scan and the _Security → Code scanning_ tab. | ||
### Automatically Suggest Fixes | ||
To make Kubescape automatically suggest fixes to your pushes and pull requests, use the following workflow: | ||
```yaml | ||
name: Suggest autofixes with Kubescape | ||
on: [pull_request] | ||
jobs: | ||
kubescape: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
with: | ||
fetch-depth: 0 | ||
- name: Get changed files | ||
id: changed-files | ||
uses: tj-actions/[email protected] | ||
- uses: kubescape/github-action@main | ||
with: | ||
account: ${{secrets.KUBESCAPE_ACCOUNT}} | ||
files: ${{ steps.changed-files.outputs.all_changed_files }} | ||
fixFiles: true | ||
format: "sarif" | ||
- uses: peter-evans/create-pull-request@v4 | ||
with: | ||
add-paths: | | ||
*.yaml | ||
commit-message: "chore: fix K8s misconfigurations" | ||
title: "[Kubescape] chore: fix K8s misconfigurations" | ||
body: | | ||
# What this PR changes | ||
[Kubescape](https://github.com/kubescape/kubescape) has found misconfigurations in the targeted branch. This PR fixes the misconfigurations that have automatic fixes available. | ||
You may still need to fix misconfigurations that do not have automatic fixes. | ||
base: ${{ github.head_ref }} | ||
branch: kubescape-auto-fix-${{ github.head_ref || github.ref_name }} | ||
delete-branch: true | ||
``` | ||
Please note that since Kubescape provides automatic fixes only to the rendered YAML manifests, the workflow above will not produce correct fixes for Helm charts. | ||
The next important thing to note is that Kubescape only fixes the files. It does not open pull requests on its own. In the example above, a separate step that runs a different action opens the appropriate pull request. Due to how Github works, there are [limitations](https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs) on running and opening pull requests to forks. The action running in this step is maintained by its respective maintainers, and not the Kubescape team, so you should review its documentation when troubleshooting the process of triggering the workflow run and opening pull requests. | ||
## Inputs | ||
| Name | Description | Required | | ||
| --- | --- | ---| | ||
| files | YAML files or Helm charts to scan for misconfigurations. The files need to be provided with the complete path from the root of the repository. | No (default is `.` which scans the whole repository) | | ||
| outputFile | Name of the output file where the scan result will be stored. | No (default is `results.out`) | | ||
| outputFile | Name of the output file where the scan result will be stored without the extension. | No (default is `results`) | | ||
| frameworks | Security framework(s) to scan the files against. Multiple frameworks can be specified separated by a comma with no spaces. Example - `nsa,devopsbest`. Run `kubescape list frameworks` in the [Kubescape CLI](https://hub.armo.cloud/docs/installing-kubescape) to get a list of all frameworks. Either frameworks have to be specified or controls. | No | | ||
| controls | Security control(s) to scan the files against. Multiple controls can be specified separated by a comma with no spaces. Example - `Configured liveness probe,Pods in default namespace`. Run `kubescape list controls` in the [Kubescape CLI](https://hub.armo.cloud/docs/installing-kubescape) to get a list of all controls. You can use either the complete control name or the control ID such as `C-0001` to specify the control you want use. You must specify either the control(s) or the framework(s) you want used in the scan. | No | | ||
| account | Account ID for [Kubescape cloud](https://cloud.armosec.io/). Used for custom configuration, such as frameworks, control configuration, etc. | No | | ||
|
@@ -64,7 +110,7 @@ jobs: | |
continue-on-error: true | ||
with: | ||
format: sarif | ||
outputFile: results.sarif | ||
outputFile: results | ||
# Specify the Kubescape cloud account ID | ||
account: ${{secrets.KUBESCAPE_ACCOUNT}} | ||
- name: Upload Kubescape scan results to Github Code Scanning | ||
|
@@ -89,7 +135,7 @@ jobs: | |
continue-on-error: true | ||
with: | ||
format: sarif | ||
outputFile: results.sarif | ||
outputFile: results | ||
# Scan a specific path. Default will scan the whole repository | ||
files: "examples/kubernetes-manifests/*.yaml" | ||
- name: Upload Kubescape scan results to Github Code Scanning | ||
|
@@ -114,7 +160,7 @@ jobs: | |
continue-on-error: true | ||
with: | ||
format: sarif | ||
outputFile: results.sarif | ||
outputFile: results | ||
frameworks: | | ||
nsa,mitre | ||
- name: Upload Kubescape scan results to Github Code Scanning | ||
|
@@ -139,7 +185,7 @@ jobs: | |
continue-on-error: false | ||
with: | ||
format: sarif | ||
outputFile: results.sarif | ||
outputFile: results | ||
failedThreshold: 50 | ||
- name: Upload Kubescape scan results to Github Code Scanning | ||
uses: github/codeql-action/upload-sarif@v2 | ||
|
@@ -162,7 +208,7 @@ jobs: | |
continue-on-error: false | ||
with: | ||
format: sarif | ||
outputFile: results.sarif | ||
outputFile: results | ||
severityThreshold: medium | ||
- name: Upload Kubescape scan results to Github Code Scanning | ||
uses: github/codeql-action/upload-sarif@v2 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,96 @@ | ||
#!/bin/sh | ||
|
||
# Checks if `string` contains `substring`. | ||
# | ||
# Arguments: | ||
# String to check. | ||
# | ||
# Returns: | ||
# 0 if `string` contains `substring`, otherwise 1. | ||
contains() { | ||
case "$1" in | ||
*$2*) return 0 ;; | ||
*) return 1 ;; | ||
esac | ||
} | ||
|
||
set -e | ||
|
||
# Declear ks client | ||
# Kubescape uses the client name to make a request for checking for updates | ||
export KS_CLIENT="github_actions" | ||
|
||
if [ ! -z "$INPUT_FRAMEWORKS" ] && [ ! -z "$INPUT_CONTROLS" ]; then | ||
echo "Framework and Control is specified. Please specify either one of them or neither" | ||
exit 1 | ||
if [ -n "${INPUT_FRAMEWORKS}" ] && [ -n "${INPUT_CONTROLS}" ]; then | ||
echo "Framework and Control is specified. Please specify either one of them or neither" | ||
exit 1 | ||
fi | ||
|
||
# Split the controls by comma and concatenate with quotes around each control | ||
if [ ! -z "$INPUT_CONTROLS" ]; then | ||
CONTROLS="" | ||
if [ -n "${INPUT_CONTROLS}" ]; then | ||
controls="" | ||
set -f; IFS=',' | ||
set -- $INPUT_CONTROLS | ||
set -- "${INPUT_CONTROLS}" | ||
set +f; unset IFS | ||
for control in "$@" | ||
do | ||
control=$(echo $control | xargs) # Remove leading/trailing whitespaces | ||
CONTROLS="$CONTROLS\"$control\"," | ||
control=$(echo "${control}" | xargs) # Remove leading/trailing whitespaces | ||
controls="${controls}\"${control}\"," | ||
done | ||
CONTROLS=$(echo "${CONTROLS%?}") | ||
controls=$(echo "${controls%?}") | ||
fi | ||
|
||
frameworks_cmd=$([ -n "${INPUT_FRAMEWORKS}" ] && echo "framework ${INPUT_FRAMEWORKS}" || echo "") | ||
controls_cmd=$([ -n "${INPUT_CONTROLS}" ] && echo control "${controls}" || echo "") | ||
|
||
files=$([ -n "${INPUT_FILES}" ] && echo "${INPUT_FILES}" || echo .) | ||
|
||
output_formats="${INPUT_FORMAT}" | ||
have_json_format="false" | ||
if [ -n "${output_formats}" ] && contains "${output_formats}" "json"; then | ||
have_json_format="true" | ||
fi | ||
|
||
# Subcommands | ||
ARTIFACTS_PATH="/home/ks/.kubescape" | ||
FRAMEWORKS_CMD=$([ ! -z "$INPUT_FRAMEWORKS" ] && echo "framework $INPUT_FRAMEWORKS" || echo "") | ||
CONTROLS_CMD=$([ ! -z "$INPUT_CONTROLS" ] && echo control $CONTROLS || echo "") | ||
should_fix_files="false" | ||
if [ "${INPUT_FIXFILES}" = "true" ]; then | ||
should_fix_files="true" | ||
fi | ||
|
||
# If a user requested Kubescape to fix their files, but forgot to ask for JSON | ||
# output, do it for them | ||
if [ "${should_fix_files}" = "true" ] && [ "${have_json_format}" != "true" ]; then | ||
output_formats="${output_formats},json" | ||
fi | ||
|
||
# Files to scan | ||
FILES=$([ ! -z "$INPUT_FILES" ] && echo "$INPUT_FILES" || echo .) | ||
output_file=$([ -n "${INPUT_OUTPUTFILE}" ] && echo "${INPUT_OUTPUTFILE}" || echo "results") | ||
|
||
# Output file name | ||
OUTPUT_FILE=$([ ! -z "$INPUT_OUTPUTFILE" ] && echo "$INPUT_OUTPUTFILE" || echo "results.out") | ||
account_opt=$([ -n "${INPUT_ACCOUNT}" ] && echo --account "${INPUT_ACCOUNT}" || echo "") | ||
|
||
# Command-line options | ||
ACCOUNT_OPT=$([ ! -z "$INPUT_ACCOUNT" ] && echo --account $INPUT_ACCOUNT || echo "") | ||
# If account ID is empty, we load artifacts from the local path, otherwise we | ||
# load from the cloud (this will enable custom framework support) | ||
artifacts_path="/home/ks/.kubescape" | ||
artifacts_opt=$([ -n "${INPUT_ACCOUNT}" ] && echo "" || echo --use-artifacts-from "${artifacts_path}") | ||
|
||
# If account ID is empty, we load artifacts from the local path, otherwise we load from the cloud (this will enable custom framework support) | ||
ARTIFACTS=$([ ! -z "$INPUT_ACCOUNT" ] && echo "" || echo --use-artifacts-from $ARTIFACTS_PATH) | ||
fail_threshold_opt=$([ -n "${INPUT_FAILEDTHRESHOLD}" ] && echo --fail-threshold "${INPUT_FAILEDTHRESHOLD}" || echo "") | ||
|
||
FAIL_THRESHOLD_OPT=$([ ! -z "$INPUT_FAILEDTHRESHOLD" ] && echo --fail-threshold $INPUT_FAILEDTHRESHOLD || echo "") | ||
SEVERITY_THRESHOLD_OPT=$([ ! -z "$INPUT_SEVERITYTHRESHOLD" ] && echo --severity-threshold $INPUT_SEVERITYTHRESHOLD || echo "") | ||
# When a user requests to fix files, the action should not fail because the | ||
# results exceed severity. This is subject to change in the future. | ||
severity_threshold_opt=$(\ | ||
[ -n "${INPUT_SEVERITYTHRESHOLD}" ] \ | ||
&& [ "${should_fix_files}" = "false" ] \ | ||
&& echo --severity-threshold "${INPUT_SEVERITYTHRESHOLD}" \ | ||
|| echo "" \ | ||
) | ||
|
||
COMMAND="kubescape scan $FRAMEWORKS_CMD $CONTROLS_CMD $FILES $ACCOUNT_OPT $FAIL_THRESHOLD_OPT $SEVERITY_THRESHOLD_OPT --format $INPUT_FORMAT --output $OUTPUT_FILE $ARTIFACTS" | ||
# The `kubescape fix` subcommand requires the latest "json" format version. | ||
# Other formats ignore this flag. | ||
format_version_opt="--format-version v2" | ||
|
||
eval $COMMAND | ||
# TODO: include artifacts_opt once https://github.com/kubescape/kubescape/issues/1040 is resolved | ||
scan_command="kubescape scan ${frameworks_cmd} ${controls_cmd} ${files} ${account_opt} ${fail_threshold_opt} ${severity_threshold_opt} --format ${output_formats} ${format_version_opt} --output ${output_file}" | ||
|
||
echo "${scan_command}" | ||
eval "${scan_command}" | ||
|
||
if [ "$should_fix_files" = "true" ]; then | ||
fix_command="kubescape fix --no-confirm ${output_file}.json" | ||
eval "${fix_command}" | ||
fi |