Skip to content

Commit afe39d3

Browse files
authored
Merge pull request #3 from panubo/add_tf_check_sensitive_output
Add TF check tf-check-sensitive-output
2 parents e00e2de + 2791ab6 commit afe39d3

File tree

2 files changed

+110
-0
lines changed

2 files changed

+110
-0
lines changed

.pre-commit-hooks.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,10 @@
6464
language: script
6565
files: \.tf$
6666
require_serial: true
67+
68+
- id: tf-sensitive-output-check
69+
name: TF sensitive outputs check
70+
description: Checks that sensitive outputs are set as sensitive in Terraform files.
71+
entry: bin/tf-check-sensitive-output.sh
72+
language: script
73+
files: \.tf$

bin/tf-check-sensitive-output.sh

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#!/usr/bin/env bash
2+
#
3+
# This script scans Terraform files (.tf) to ensure that any outputs
4+
# with potentially sensitive names are explicitly marked as 'sensitive = true'.
5+
#
6+
# It exits with status 0 if no issues are found.
7+
# It exits with status 1 if 'hcledit' is not installed or if any sensitive
8+
# outputs are found that are not properly marked.
9+
#
10+
# If files are passed to the script `./tf-check-sensitive-output.sh [FILE...]`
11+
# then only those files are checked. If no files are passed in all *.tf files are checked.
12+
#
13+
# False positives can be ignored (a WARNING will be reported) by setting "sensitive = false"
14+
15+
# Bash strict mode
16+
set -euo pipefail
17+
IFS=$'\n\t'
18+
19+
# --- Main Script ---
20+
21+
main() {
22+
# Check for the 'hcledit' dependency.
23+
if ! command -v hcledit &>/dev/null; then
24+
echo "ERROR: hcledit is not installed. Please install it to run this script." >&2
25+
echo "Installation instructions: https://github.com/minamijoyo/hcledit" >&2
26+
echo "Homebrew install: \`brew install minamijoyo/hcledit/hcledit\`" >&2
27+
exit 1
28+
fi
29+
30+
local error_found=0
31+
# Regex pattern for names that suggest sensitive content.
32+
# This is case-insensitive.
33+
local sensitive_pattern='pass|password|secret|key|private|token|cred|credential|conn_str'
34+
35+
# --- Helper function to process a single file ---
36+
process_file() {
37+
local file=$1
38+
39+
# When used with pre-commit, non-.tf files might be passed. Skip them.
40+
if ! [[ "$file" == *.tf ]]; then
41+
return
42+
fi
43+
44+
# Get all output block addresses (e.g., "output.my_secret") from the current file.
45+
# The '|| true' prevents the script from exiting if grep finds no matches.
46+
local sensitive_outputs
47+
sensitive_outputs=$(hcledit block list -f "$file" | grep -E '^output\.' | grep -iE "$sensitive_pattern" || true)
48+
49+
# If no sensitive outputs were found in this file, continue.
50+
if [[ -z "$sensitive_outputs" ]]; then
51+
return
52+
fi
53+
54+
# For each potentially sensitive output, check if it's marked as sensitive.
55+
while IFS= read -r output_address; do
56+
# Get the value of the 'sensitive' attribute for the output block.
57+
local is_sensitive
58+
is_sensitive=$(hcledit attribute get "${output_address}.sensitive" -f "$file" 2>/dev/null || true)
59+
60+
# Check the status of the 'sensitive' attribute and act accordingly.
61+
if [[ "$is_sensitive" == "true" ]]; then
62+
# Correct: The output is properly marked as sensitive.
63+
:
64+
elif [[ "$is_sensitive" == "false" ]]; then
65+
# Warn: The developer has explicitly marked this as not sensitive.
66+
echo "WARNING: Output '$output_address' in file '$file' is explicitly marked 'sensitive = false'. Please double-check this is intended." >&2
67+
else
68+
# Error: The 'sensitive' attribute is missing entirely.
69+
echo "ERROR: Output '$output_address' in file '$file' appears to be sensitive but is missing the 'sensitive = true' attribute. Set 'sensitive = false' to ignore." >&2
70+
error_found=1 # Modifies 'error_found' in the parent 'main' scope.
71+
fi
72+
done <<<"$sensitive_outputs"
73+
}
74+
75+
# --- Execution Logic ---
76+
77+
if [ "$#" -gt 0 ]; then
78+
# Case 1: Files are passed as arguments (pre-commit use case).
79+
echo "Scanning provided files..."
80+
for file in "$@"; do
81+
process_file "$file"
82+
done
83+
else
84+
# Case 2: No arguments. Find all '.tf' files to scan.
85+
echo "Scanning for sensitive outputs in all .tf files..."
86+
while IFS= read -r file; do
87+
process_file "$file"
88+
done < <(find . -type f -name "*.tf" -not -path "*.terraform*")
89+
fi
90+
91+
# After checking all files, exit with the appropriate status code.
92+
if [[ "$error_found" -ne 0 ]]; then
93+
echo ""
94+
echo "Scan complete. Found sensitive outputs that are not correctly marked." >&2
95+
exit 1
96+
fi
97+
98+
echo "Scan complete. No issues found."
99+
exit 0
100+
}
101+
102+
# Execute the main function, passing all script arguments to it.
103+
main "$@"

0 commit comments

Comments
 (0)