133 lines
5.3 KiB
YAML
133 lines
5.3 KiB
YAML
name: Kube-bench CIS scan
|
|
|
|
on:
|
|
pull_request:
|
|
push:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
kube-bench:
|
|
name: Scan ephemeral K3s cluster
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 15
|
|
|
|
steps:
|
|
- name: Check out repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install k3d
|
|
run: curl -sfL https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
|
|
|
|
- name: Install kubectl
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
kubectl_version=v1.35.5
|
|
temp_dir="$(mktemp -d)"
|
|
trap 'rm -rf "$temp_dir"' EXIT
|
|
curl --fail --location --retry 3 \
|
|
--output "$temp_dir/kubectl" \
|
|
"https://dl.k8s.io/release/${kubectl_version}/bin/linux/amd64/kubectl"
|
|
curl --fail --location --retry 3 \
|
|
--output "$temp_dir/kubectl.sha256" \
|
|
"https://dl.k8s.io/release/${kubectl_version}/bin/linux/amd64/kubectl.sha256"
|
|
printf '%s %s\n' "$(cat "$temp_dir/kubectl.sha256")" "$temp_dir/kubectl" | sha256sum --check --strict -
|
|
install -m 0755 "$temp_dir/kubectl" /usr/local/bin/kubectl
|
|
kubectl version --client
|
|
|
|
- name: Install jq
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
jq_version=1.8.2
|
|
jq_sha256=b1c22172dd303f3be49e935aa56aa48a8b7a46e0bc838b4997d3bb451495870f
|
|
temp_dir="$(mktemp -d)"
|
|
trap 'rm -rf "$temp_dir"' EXIT
|
|
curl --fail --location --retry 3 \
|
|
--output "$temp_dir/jq" \
|
|
"https://github.com/jqlang/jq/releases/download/jq-${jq_version}/jq-linux-amd64"
|
|
printf '%s %s\n' "$jq_sha256" "$temp_dir/jq" | sha256sum --check --strict -
|
|
install -m 0755 "$temp_dir/jq" /usr/local/bin/jq
|
|
jq --version
|
|
|
|
- name: Create ephemeral K3s cluster
|
|
run: |
|
|
k3d cluster delete security-baseline-ci >/dev/null 2>&1 || true
|
|
k3d cluster create --config ci/k3d-ci-cluster-config.yaml
|
|
mkdir -p "$HOME/.kube"
|
|
k3d kubeconfig get security-baseline-ci > "$HOME/.kube/config"
|
|
api_host=127.0.0.1
|
|
if getent hosts host.docker.internal >/dev/null 2>&1; then
|
|
api_host=host.docker.internal
|
|
elif command -v docker >/dev/null 2>&1; then
|
|
docker_gateway="$(docker network inspect bridge --format '{{(index .IPAM.Config 0).Gateway}}' 2>/dev/null || true)"
|
|
if [[ -n "$docker_gateway" ]]; then
|
|
api_host="$docker_gateway"
|
|
fi
|
|
fi
|
|
if [[ "$api_host" == 127.0.0.1 && -r /proc/net/route ]]; then
|
|
gateway_hex="$(awk '$2 == "00000000" {print $3; exit}' /proc/net/route)"
|
|
if [[ "$gateway_hex" =~ ^[0-9A-Fa-f]{8}$ ]]; then
|
|
api_host="$((16#${gateway_hex:6:2})).$((16#${gateway_hex:4:2})).$((16#${gateway_hex:2:2})).$((16#${gateway_hex:0:2}))"
|
|
fi
|
|
fi
|
|
sed -i -E "s#https://0\.0\.0\.0:#https://${api_host}:#" "$HOME/.kube/config"
|
|
kubectl config set-cluster k3d-security-baseline-ci --tls-server-name 0.0.0.0 >/dev/null
|
|
kubectl wait --for=condition=Ready nodes --all --timeout=180s
|
|
kubectl get nodes -o wide
|
|
|
|
- name: Run kube-bench
|
|
id: scan
|
|
shell: bash
|
|
run: |
|
|
set +e
|
|
mkdir -p artifacts
|
|
kubectl create namespace kube-bench --dry-run=client -o yaml | kubectl apply -f -
|
|
kubectl apply -f ci/kube-bench-k3s-job.yaml
|
|
kubectl wait --for=condition=complete job/kube-bench -n kube-bench --timeout=180s
|
|
job_rc=$?
|
|
kubectl logs -n kube-bench job/kube-bench > artifacts/kube-bench-k3s-cis-1.7.json || true
|
|
|
|
if ! jq -e . artifacts/kube-bench-k3s-cis-1.7.json >/dev/null; then
|
|
echo "kube-bench did not produce valid JSON" >&2
|
|
cat artifacts/kube-bench-k3s-cis-1.7.json
|
|
exit 1
|
|
fi
|
|
|
|
pass_count=$(jq '[.. | objects | select(has("total_pass")) | .total_pass] | add // 0' artifacts/kube-bench-k3s-cis-1.7.json)
|
|
warn_count=$(jq '[.. | objects | select(has("total_warn")) | .total_warn] | add // 0' artifacts/kube-bench-k3s-cis-1.7.json)
|
|
fail_count=$(jq '[.. | objects | select(has("total_fail")) | .total_fail] | add // 0' artifacts/kube-bench-k3s-cis-1.7.json)
|
|
|
|
{
|
|
echo "## kube-bench CIS K3s 1.7"
|
|
echo
|
|
echo "| Result | Count |"
|
|
echo "| --- | ---: |"
|
|
echo "| Pass | ${pass_count} |"
|
|
echo "| Warn | ${warn_count} |"
|
|
echo "| Fail | ${fail_count} |"
|
|
echo
|
|
echo "Findings are reported as an artifact. The disposable K3d baseline is not a merge gate yet."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
# The report is intentionally informational until selected controls
|
|
# become merge gates in a later hardening phase.
|
|
exit 0
|
|
|
|
- name: Upload kube-bench report
|
|
if: always()
|
|
# Upstream v4 rejects Gitea because it identifies as GHES.
|
|
# This compatible fork retains the v4 interface on both forges.
|
|
uses: christopherHX/gitea-upload-artifact@v4
|
|
with:
|
|
name: kube-bench-k3s-cis-1.7
|
|
path: artifacts/kube-bench-k3s-cis-1.7.json
|
|
if-no-files-found: warn
|
|
|
|
- name: Delete ephemeral cluster
|
|
if: always()
|
|
run: k3d cluster delete security-baseline-ci
|