Steampunk Spotter

Spotter Custom Policies 103: Preventing PII Leaks in Ansible Playbooks

February 6, 2025 - Words by  Nejc Slabe - 4 min read

Card image caption

We’ve followed Sarah, a security compliance officer at a global enterprise, on her journey to securing Ansible Playbooks in previous posts. She tackled key security risks in Custom Policies 101: Preventing Sensitive Information Leakage in Your Playbooks and advanced her approach in Spotter Custom Policies 102: Detecting Sensitive Data in Variables and Beyond .

Now, Sarah is facing a new challenge: ensuring that sensitive parameters in playbooks, such as full names, passwords, and API keys, are always protected. As she reviewed logs and configurations, Sarah discovered a worrying trend—sensitive personal data was being inadvertently leaked into logs, posing a major compliance and security risk. With regulatory pressures mounting, including GDPR and internal security policies, she needed a way to proactively detect and prevent these leaks before they reached production.

Steampunk Spotter’s Custom Policies to the rescue, again — a solution that had already helped Sarah make significant progress in securing playbooks. But to further strengthen security, she needed to expand her approach, refining custom policies to not just detect issues but enforce best practices across her organization.

The Hidden Risk: Personally Identifiable Information exposure in Ansible Playbooks

In cybersecurity, preventing data exposure is a top priority—especially in industries like finance, healthcare, and government. Sarah knew that misconfigured automation could accidentally expose full names, passwords, or other PII in logs, violating compliance policies and putting sensitive customer data at risk.

Her biggest concern? Ansible’s no_log parameter, which, when misused, allows sensitive data to appear in logs. If someone wrote a playbook without setting no_log: true for tasks handling user credentials or full names, it could lead to a security breach.

To illustrate the issue, here’s an example of a problematic playbook Sarah encountered:

---
- hosts: all
  connection: local
  gather_facts: false

  tasks:
    - name: Ensure user Bob is present
      ansible.windows.win_user:
        name: MSbob
        fullname: Bob Something
        password: "{{ bob_password }}"
        password_expired: false
        password_never_expires: true
        state: present
        groups:  
          - Users
      no_log: false  # Incorrect - PII is exposed!

Sarah also checked offical Ansible documentation and saw that she needed a way to automatically detect and fix this issue at scale.

Why Spotter’s Custom Policies Were the Perfect Fit

Sarah had tried basic linting tools, but they weren’t enough. She needed deeper playbook analysis to catch security misconfigurations. That’s where Steampunk Spotter came in.

Spotter’s custom policies feature allows security teams to:

  • Define security rules tailored to their organization’s needs.

  • Prevent common misconfigurations like improper use of no_log.

  • Ensure compliance with GDPR, NIST, and other security frameworks.

  • Automate security scanning within CI/CD pipelines.

By writing a custom security policy, Sarah could ensure that every Ansible Playbook followed best practices, reducing manual code reviews and eliminating human error.

Step-by-Step: Creating a Custom Policy to Prevent PII Leaks

To stop full name leakage, Sarah wrote a Rego policy—the language used by Spotter’s Open Policy Agent (OPA) engine.


Step 1: Writing the Custom Policy

She created a Rego policy to enforce no_log: true when handling fullname in playbooks:

package Play

SpotterPolicy[result] { 
    task := input.tasks[i] 
    task_args := task.task_args 
    task_args[key] 
    task_args[key][sub_key] 
    regex.match("^fullname$", sub_key)
    task_args.no_log = false  # If no_log is false, we flag an error!

    result := { 
        "correlation_id": task.task_id, 
        "check_type": "TASK", 
        "subcode": "NoLogFullName", 
        "message": "When using 'fullname', ensure 'no_log' is set to true.", 
    } 
} 

Step 2: Uploading the Policy to Spotter

Sarah uploaded the custom policy into Spotter with:

spotter policies set custom_no_log_policy.rego

Or through the Spotter APP, like in the first blog post -> Spotter Custom Policies 101: A Beginner’s Guide to Tailored Automation Checks .


Step 3: Scanning the Playbooks

Now, whenever a developer wrote a non-compliant playbook, Spotter automatically flagged the issue:

spotter scan playbook.yml

Scan Summary:

playbook.yml:7:7: ERROR: [E2300::NoLogFullName] When using 'fullname', ensure 'no_log' is set to true.

Step 4: Fixing the Playbook

After Spotter’s recommendation, Sarah’s team updated the playbook:

---
- hosts: all
  connection: local
  gather_facts: false

  tasks:
    - name: Ensure user Bob is present
      ansible.windows.win_user:
        name: MSbob
        fullname: Bob Something
        password: "{{ bob_password }}"
        password_expired: false
        password_never_expires: true
        state: present
        groups:  
          - Users
      no_log: true  #  Now correctly preventing PII leaks

After running another Spotter scan, the errors were gone! 🎉

Beyond MVP: Extended Rego Policy for Detecting Sensitive Parameters

To enhance the security further, Sarah implemented an extended Rego policy that not only detects various sensitive parameters but also ensures that no_log is both present and set to true.


Extended Rego Policy

package Play

SpotterPolicy[result] {
    task := input.tasks[_]
    task_args := task.task_args

    regexes := ["fullname", "password", "secret_key", "access_key", "token", "api_key"]
    candidate := regexes[_]

    [path, _] := walk(task_args[key])
    subpath := array.reverse(path)[0]
    regex.match(sprintf(".*%s.*$", [candidate]), subpath)
    
    not task_args.no_log
    task_args.no_log != true

    result := {
        "correlation_id": task.task_id,
        "check_type": "TASK",
        "subcode": "NoLogFullName",
        "message": sprintf("When using a parameter '%s', ensure that the Ansible task is run with parameter no_log and its value is set to true.", [subpath]),
        "test": subpath,
    }
}

This updated policy ensures that all sensitive parameters are flagged and that no_log is explicitly enforced, reducing the risk of accidental data exposure in logs. This policy and many more can be found in our public examples .

Beyond Security: Automating Compliance in CI/CD

With Spotter integrated into GitHub Actions and GitLab CI/CD , Sarah ensured every playbook was automatically scanned for security risks before deployment.

Here’s how she set up GitHub Actions for automated checks:

name: Test with Steampunk Spotter
on: push
jobs:
  run:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@master

      - name: Scan Ansible content
        uses: xlab-steampunk/[email protected]
        with:
          sarif_file: example.sarif
        continue-on-error: true
        env:
          SPOTTER_API_TOKEN: ${{ secrets.SPOTTER_TOKEN }}

      - name: Read SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: example.sarif

More about how you can set up Spotter in your CI/CD pipeline . The start is important, but to get to trustable automation, we need to validate code on complete organization level and every code change.

Secure Your Playbooks with Spotter Today!

Want to enhance security and prevent PII leaks in Ansible? Try Steampunk Spotter!


Found this post useful?

Get our monthly newsletter.

Thank you for subscribing!

Please wait

Processing, please wait...

Keep up with what we do on our social media.