What is Ansible no_log?

no_log: true prevents Ansible from displaying task input and output in the console and logs. Use it whenever a task handles passwords, API keys, tokens, or any sensitive data that shouldn't appear in plain text.

Basic Usage

# Without no_log — password visible in output!
- name: Set user password
  ansible.builtin.user:
    name: deploy
    password: "{{ vault_password | password_hash('sha512') }}"
  # Output shows: "password": "$6$abc..."

# With no_log — output censored
- name: Set user password
  ansible.builtin.user:
    name: deploy
    password: "{{ vault_password | password_hash('sha512') }}"
  no_log: true
  # Output shows: "censored": "the output has been hidden due to the fact that 'no_log: true' was set"

When to Use no_log

# ✅ Passwords
- name: Set database password
  ansible.builtin.mysql_user:
    name: app
    password: "{{ db_password }}"
  no_log: true

# ✅ API keys and tokens
- name: Call API with token
  ansible.builtin.uri:
    url: https://api.example.com/deploy
    headers:
      Authorization: "Bearer {{ api_token }}"
    body_format: json
    body:
      version: "{{ app_version }}"
  no_log: true

# ✅ Environment variables with secrets
- name: Run app with secrets
  ansible.builtin.shell: /opt/myapp/start.sh
  environment:
    DB_PASSWORD: "{{ vault_db_password }}"
    API_KEY: "{{ vault_api_key }}"
  no_log: true

# ✅ Writing secrets to files
- name: Create .env file
  ansible.builtin.copy:
    content: |
      SECRET_KEY={{ vault_secret_key }}
      DB_URL=postgres://user:{{ vault_db_password }}@localhost/myapp
    dest: /opt/myapp/.env
    mode: "0600"
  no_log: true

Conditional no_log

# Log in development, hide in production
- name: Deploy with credentials
  ansible.builtin.uri:
    url: "{{ deploy_url }}"
    headers:
      Authorization: "Bearer {{ deploy_token }}"
  no_log: "{{ env == 'production' }}"

# Disable no_log for debugging
- name: Set password
  ansible.builtin.user:
    name: deploy
    password: "{{ vault_password | password_hash('sha512') }}"
  no_log: "{{ not debug_mode | default(true) }}"

no_log on Variables

# Mark variable as no_log at set_fact level
- name: Store secret
  ansible.builtin.set_fact:
    api_response: "{{ result.json }}"
  no_log: true

# In vars
vars:
  db_connection:
    host: db.example.com
    password: "{{ vault_db_pass }}"

For platform & security teams

Handling secrets across shared automation?

no_log reduces accidental output, but production automation also needs credential boundaries, Vault/controller integration, auditability, and repository controls.

Fixed-scope review · typically €1,500–€3,000 · prioritized findings and a remediation plan.

Review your automation security

Block-Level no_log

# Apply to entire block
- block:
    - name: Create service account
      ansible.builtin.user:
        name: svc_myapp
        password: "{{ vault_svc_password | password_hash('sha512') }}"

    - name: Write credentials
      ansible.builtin.copy:
        content: "{{ vault_credentials }}"
        dest: /etc/myapp/credentials
        mode: "0600"

    - name: Configure API key
      ansible.builtin.lineinfile:
        path: /etc/myapp/config.yml
        line: "api_key: {{ vault_api_key }}"
  no_log: true

Debug with no_log

When no_log: true hides errors, temporarily disable it:

# Can't see what went wrong!
- name: API call
  uri:
    url: https://api.example.com
    body: "{{ secret_payload }}"
  no_log: true    # Change to false to debug

# Or use environment variable
# ANSIBLE_NO_LOG=false ansible-playbook site.yml

What no_log Hides

HiddenNot Hidden
Task arguments (input)Task name
Task output (stdout/stderr)Host name
Registered variablesChanged/OK status
Loop itemsTask duration
Callback plugin dataPlay name
TASK [Set password] ***************
ok: [web-01] => {"censored": "the output has been hidden due to the fact that 'no_log: true' was set", "changed": false}

Common Mistakes

Forgetting no_log on Debug

# ❌ BAD — exposes secret in output
- debug:
    msg: "Password is {{ vault_password }}"

# ✅ GOOD — hide the debug output
- debug:
    msg: "Password is {{ vault_password }}"
  no_log: true

# ✅ BETTER — don't debug secrets at all
- debug:
    msg: "Password has been set for {{ username }}"

Loop Items Visible

# ❌ Loop items shown even with registered var
- name: Create users
  ansible.builtin.user:
    name: "{{ item.name }}"
    password: "{{ item.pass | password_hash('sha512') }}"
  loop:
    - { name: alice, pass: "{{ vault_alice_pass }}" }
    - { name: bob, pass: "{{ vault_bob_pass }}" }
  no_log: true    # ← Must add this

Registered Result Leaks

# ❌ The register captures the secret
- name: Get API token
  uri:
    url: https://auth.example.com/token
    body: "client_secret={{ vault_secret }}"
  register: auth_result
  no_log: true

# ❌ Then debug exposes it
- debug: var=auth_result    # Shows the token!

# ✅ Only show non-sensitive parts
- debug:
    msg: "Auth status: {{ auth_result.status }}"

ansible-lint Rule

ansible-lint warns when no_log is missing on tasks that appear to handle secrets:

WARNING  no-log-password: task uses password without no_log

Fix: add no_log: true to any task with password parameters.

Conclusion

Use no_log: true on every task that handles passwords, tokens, API keys, or sensitive data. Apply it to blocks for groups of sensitive tasks. Use conditional no_log to enable logging in dev but hide in production. Remember that registered variables can leak secrets — don't debug them. Combine no_log with Ansible Vault for end-to-end secret protection. The rule is simple: if the output could contain a secret, add no_log: true.