Steampunk Spotter
Spotter Custom Policies 102: Detecting Sensitive Data in Variables and Beyond
January 22, 2025 - Words by Nejc Slabe - 6 min read
In our first post, Spotter Custom Policies 101 , we explored how Steampunk Spotter’s custom policies empower teams to tailor their automation checks. Today, we’re diving deeper into a critical use case—detecting potential sensitive data across not just playbooks, but also variable files, and other related content.
Modern IT environments are rich with automation, but they also pose unique security challenges. Ansible, as powerful as it is, doesn’t inherently prevent sensitive information from slipping into places it shouldn’t. Enter Spotter, with its ability to catch these vulnerabilities before they reach production.
A Story of Automation Excellence: Meet Sarah
Sarah, a security compliance officer at a global enterprise, was tasked with auditing logs and preventing misconfigurations across the company’s infrastructure. One of Sarah’s focus areas was ensuring Ansible playbooks adhered to strict compliance and security standards. While the company used tools with pre-built checks, they weren’t sufficient to address the specific compliance needs of Sarah’s organization. When Sarah discovered the power of custom policies in Steampunk Spotter, her workflow transformed.
This series follows Sarah’s journey as she harnesses the potential of custom policies to tackle misconfigurations and compliance challenges head-on.
Why Sensitive Data Detection Matters
Sarah’s team relies heavily on automation to manage their infrastructure, but during a routine review, she noticed something alarming—a sensitive API key had been hardcoded into a variable file and committed to their repository. It was a wake-up call.
Despite the robust automation tools at her disposal, Sarah realized they lacked a mechanism to catch such oversights. By creating a tailored sensitive data detection policy, Sarah was able to proactively safeguard her team’s automation workflows and prevent future incidents.
Imagine this: a company name, API key, or password inadvertently makes its way into a variable file. It’s not in the playbook itself, so conventional Ansible linting or scanning tools miss it. Now it’s exposed to anyone who accesses your automation. The risk? Unauthorized access, compliance violations, or even reputational damage.
With Spotter’s custom policies, you can proactively scan for sensitive data in all ansible-related content—not just playbooks.
AWS Compliance examples
Here we have an Playbook example that will create a Security Group on AWS and spin up and EC2 instance, then with the help of two custom policies we will check the Playbook if there are some potencial security issues inside.
---
- hosts: all
connection: local
gather_facts: false
tasks:
- name: Create security group.
amazon.aws.ec2_security_group:
name: "web-app-sec"
description: "Sec group for app web-app"
region: "eu-west-1"
access_key: "sdafrgeg3wfw" ## Acess Key as plaintext
rules:
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: 0.0.0.0/0
- proto: tcp
to_port: 80
cidr_ip: 0.0.0.0/0
register: result_sec_group
- name: EC2 instance create.
amazon.aws.ec2_instance:
name: "VM_for_demo"
vpc_subnet_id: subnet-5ca1ab1e
instance_type: t2.micro
key_name: "prod-ssh-key"
security_group: "default" ## Default Security Group
volumes:
- device_name: /dev/sda1
ebs:
volume_size: 64
delete_on_termination: true
image_id: ami-08c947c038321a605
network:
assign_public_ip: true
tags:
demo: VM
Access key as plaintext detection for AWS
package Spotter
# Check if the access key is not written as plain text.
SpotterPolicy[result] {
task := input.tasks[i]
task_args := task.task_args["amazon.aws.ec2_security_group"].access_key
regex.match("{{.*}}", task_args) == false # Regex to check if there is a variable structure.
result := {
"correlation_id": task.task_id,
"check_type": "TASK",
"subcode": "PlainText_Variable",
"message": "Access key should be written as a variable, not plain text! Use Ansible Vault insted."
}
}
This policy ensures access keys are stored securely as variables or vault entries instead of being hardcoded. Spotter not only flags the issue but also provides actionable recommendations to remediate these security gaps, helping teams protect sensitive credentials from potential exposure.
AWS EC2 instance in DEFAULT security group
package Spotter
# Check if value of Security group for EC2 instance is not set to default.
SpotterPolicy[result] {
task := input.tasks[i]
task_args := task.task_args["amazon.aws.ec2_instance"].security_group
task_args = "default"
result := {
"correlation_id": task.task_id,
"check_type": "TASK",
"subcode": "DefaultSecurityGroup",
"message": "Instances shouldn't be in default security groups."
}
}
This policy helps enforce best practices by ensuring instances are assigned to custom security groups with well-defined access rules. Spotter identifies these issues early, giving teams the opportunity to adjust configurations and prevent security oversights.
Spotter output
After running spotter scan playbook.yml on a playbook, the following output was generated:
(venv) nejcslabe@ns-ubuntu:~.../spotter-examples$ spotter scan playbook.yml
Scanning...success. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
Check results:
playbook.yml:2:3: HINT: [H1601] Plays should always be named using the name parameter.
playbook.yml:7:7: ERROR: [E2300::PlainText_Variable] Access key should be written as a variable, not plain text!.
playbook.yml:23:7: ERROR: [E2300::DefaultSecurityGroup] Instances shouldn't be in default security groups.
Quite nice if you ask me :) Now lets tackle Sarah’s problem.
Creating a Sensitive Data Policy
Let’s look at how we can create a policy to detect sensitive data, such as a company name, in variable files, Play’s, taks’s or other configurations.
Example Ansible Playbook
Sensitive information can often appear in unexpected places, such as variable in var files. For example, consider the following var:
xlab_public_ip: 54.32.31.117
In this example, the term “xlab” is used which could inadvertently expose sensitive or internal information. With Steampunk Spotter’s custom policies, you can detect and flag the use of such terms.
Policy for checking sensitive data
Here’s a sample Rego policy you can implement:
package sensitive_data
import rego.v1
# list of sensitive keywords that one wants to check for
volatile_words := ["xlab", "spotter", "my_company_name"]
# helper functions
_is_volatile_word(volatile_keyword, value) := volatile_keyword if {
is_string(value)
escaped = sprintf("(?i)%s", [volatile_keyword])
regex.match(escaped, value)
}
_is_volatile_value(volatile_keyword, path, value) := result if {
volatile_word = _is_volatile_word(volatile_keyword, value)
full_path = concat(".", path)
result = [full_path, volatile_word]
}
_is_volatile_key(volatile_keyword, path) := result if {
value = array.reverse(path)[0]
volatile_word = _is_volatile_word(volatile_keyword, value)
full_path = concat(".", path)
result = [full_path, volatile_word]
}
_generate_result(check_type, subcode, correlation_id, message) := {
"check_type": check_type,
"subcode": subcode,
"correlation_id": correlation_id,
"message": message,
}
_unpack_item(item, args, correlation_id, check_type) := {
"args": item[args],
"correlation_id": item[correlation_id],
"file": item.spotter_metadata.file,
"check_type": check_type,
}
# Rules for var keys or values
check_var_values contains result if {
item = _unpack_item(input.variables[_], "variable_args", "variable_id", "VAR")
[path, value] := walk(item.args) # The "walk" function returns all key-paths and their associated values from "item.args".
[full_path, volatile_word] := _is_volatile_value(volatile_words[_], path, value)
message = sprintf("Insecure keyword '%s' used inside %s '%s'.", [volatile_word, "variable", full_path])
result = _generate_result(item.check_type, "VOLATILE_VALUE", item.correlation_id, message)
}
check_var_keys contains result if {
item = _unpack_item(input.variables[_], "variable_args", "variable_id", "VAR")
[path, _] := walk(item.args)
[full_path, volatile_word] := _is_volatile_key(volatile_words[_], path)
message = sprintf("Insecure keyword '%s' used inside %s '%s'.", [volatile_word, "variable_name", full_path])
result = _generate_result(item.check_type, "VOLATILE_KEY", item.correlation_id, message)
}
This policy demonstrates how you can configure Spotter to identify sensitive keywords—whether in a variable name, a value. But we have an extended version of this policy, in our public custom policies library .
Including Ansible variables
Ansible automation encourages reuse of playbooks through allowing to bring variables out of playbooks and storing them in variable files. Use the --include-vars
CLI option to include these files in scans of your projects and to send the variables and their values to the Steampunk Spotter backend server.
Use Spotter --include-variables
spotter scan path/to/folder --include-variables
Link to the Docs .
Real-World Applications
1. Project Variable Auditing
Using this custom policy, Spotter can scan variable files for sensitive terms. No more accidental API key or other sensitive data leaks!
2. Variable File Compliance
Many teams maintain Ansible variables in separate YAML files. Spotter ensures that these files don’t include hardcoded sensitive data.
3. CI/CD Pipeline Integration
Extend this policy into your CI/CD workflows to block risky commits at the gate, maintaining security hygiene at every step.
Proactive Security with Spotter
Detecting sensitive data isn’t just about avoiding mistakes — it’s about building trust. With Spotter, you can rest easy knowing your Ansible environment is protected by robust, customizable checks that adapt to your organization’s needs.
Want to try this out? Start by defining your own sensitive keywords. Then, implement the policy in Spotter and see how it elevates your automation security.
Did you miss the first post in this series? Read it here . Ready to take the next step? Get started with Spotter .
Additional Resources
For more details on how to create and manage custom policies in Spotter, check out the following resources: