---
title: Enable PAM
description: Datadog, the leading service for cloud-scale monitoring.
breadcrumbs: Docs > Datadog Security > OOTB Rules > Enable PAM
---

> For the complete documentation index, see [llms.txt](https://docs.datadoghq.com/llms.txt).

# Enable PAM
 
## Description{% #description %}

UsePAM Enables the Pluggable Authentication Module interface. If set to "yes" this will enable PAM authentication using ChallengeResponseAuthentication and PasswordAuthentication in addition to PAM account and session module processing for all authentication types. To enable PAM authentication, add or correct the following line in `/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf`:

```
UsePAM yes
```

## Rationale{% #rationale %}

When UsePAM is set to yes, PAM runs through account and session types properly. This is important if you want to restrict access to services based off of IP, time or other factors of the account. Additionally, you can make sure users inherit certain environment variables on login or disallow access to the server.

## Remediation{% #remediation %}

### Shell script{% #shell-script %}

The following script can be run on the host to remediate the issue.

```bash
#!/bin/bash

# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}' 'linux-base' 2>/dev/null | grep -q '^installed$'; then

mkdir -p /etc/ssh/sshd_config.d
chmod 0700 /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
# sshd reads /etc/ssh/sshd_config.d through an Include line of /etc/ssh/sshd_config.
if grep -Eiqs '^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf' /etc/ssh/sshd_config; then
    if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
        LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    else
        touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
        chmod 0644 "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

    cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
    # Insert at the beginning of the file
    printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
else
    if [ -e "/etc/ssh/sshd_config" ] ; then
        LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config"
    else
        touch "/etc/ssh/sshd_config"
        chmod 0600 "/etc/ssh/sshd_config"
    fi
    # make sure file has newline at the end
    sed -i -e '$a\' "/etc/ssh/sshd_config"

    cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
    # Insert at the beginning of the file
    printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config"
    cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
    # Clean up after ourselves.
    rm "/etc/ssh/sshd_config.bak"
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
```

### Ansible playbook{% #ansible-playbook %}

The following playbook can be run with Ansible to remediate the issue.

```go
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Find if a Match block of /etc/ssh/sshd_config sets the parameter
    UsePAM
  ansible.builtin.find:
    paths:
    - /etc/ssh
    patterns: sshd_config
    contains: (?ims)^[ \t]*Match[ \t].*^[ \t]*UsePAM[ \t]
    read_whole_file: true
  register: _sshd_main_config_match_sets_parameter
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Remove the parameter UsePAM from the Match blocks of /etc/ssh/sshd_config
  ansible.builtin.replace:
    path: '{{ item.path }}'
    after: (?im)^[ \t]*Match[ \t]
    regexp: (?i)^[ \t]*UsePAM[ \t].*\n?
    replace: ''
  loop: '{{ _sshd_main_config_match_sets_parameter.files }}'
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Find the files of /etc/ssh/sshd_config.d where a Match block
    sets the parameter UsePAM
  ansible.builtin.find:
    paths:
    - /etc/ssh/sshd_config.d
    patterns: '*.conf'
    contains: (?ims)^[ \t]*Match[ \t].*^[ \t]*UsePAM[ \t]
    read_whole_file: true
  register: _sshd_config_dir_match_sets_parameter
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Remove the parameter UsePAM from the Match blocks of the files
    of /etc/ssh/sshd_config.d
  ansible.builtin.replace:
    path: '{{ item.path }}'
    after: (?im)^[ \t]*Match[ \t]
    regexp: (?i)^[ \t]*UsePAM[ \t].*\n?
    replace: ''
  loop: '{{ _sshd_config_dir_match_sets_parameter.files }}'
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Check if /etc/ssh/sshd_config includes /etc/ssh/sshd_config.d
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: (?i)^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf
    state: absent
  check_mode: true
  changed_when: false
  failed_when: false
  register: _sshd_config_includes_config_dir
  when: '"linux-base" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Set the parameter UsePAM in /etc/ssh/sshd_config.d
  block:

  - name: Enable PAM - Check if the parameter UsePAM is configured in /etc/ssh/sshd_config
    ansible.builtin.lineinfile:
      path: /etc/ssh/sshd_config
      regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
      state: absent
    check_mode: true
    changed_when: false
    register: _config_file_has_parameter

  - name: Enable PAM - Check if the parameter UsePAM is configured in /etc/ssh/sshd_config.d
    ansible.builtin.find:
      paths:
      - /etc/ssh/sshd_config.d
      contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
      patterns: '*.conf'
    register: _config_dir_has_parameter

  - name: Enable PAM - Count the lines that configure the parameter UsePAM in /etc/ssh/sshd_config.d
    ansible.builtin.lineinfile:
      path: '{{ item.path }}'
      regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
      state: absent
    check_mode: true
    changed_when: false
    loop: '{{ _config_dir_has_parameter.files }}'
    register: _config_dir_parameter_lines

  - name: Enable PAM - Check if /etc/ssh/sshd_config exists
    ansible.builtin.stat:
      path: /etc/ssh/sshd_config
    register: _config_file_exists

  - name: Enable PAM - Check if the parameter UsePAM is configured correctly in /etc/ssh/sshd_config
    ansible.builtin.lineinfile:
      path: /etc/ssh/sshd_config
      regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+yes$
      state: absent
    check_mode: true
    changed_when: false
    register: _config_file_correctly
    when: _config_file_exists.stat.exists

  - name: Enable PAM - Check if the parameter UsePAM is configured correctly in /etc/ssh/sshd_config.d
    ansible.builtin.find:
      paths:
      - /etc/ssh/sshd_config.d
      contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+yes$
      patterns: '*.conf'
    register: _config_dir_correctly

  - name: Enable PAM
    block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+
        mode: '0600'
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      ansible.builtin.stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter UsePAM is present in /etc/ssh/sshd_config.d
      ansible.builtin.find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
        patterns: '*.conf'
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      ansible.builtin.lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+
        mode: '0600'
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files | default([]) }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched > 0

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+
        mode: '0600'
        line: UsePAM yes
        state: present
        insertbefore: BOF
        validate: /usr/sbin/sshd -t -f %s
    when:
    - _config_file_correctly is not skipped
    - (_config_file_correctly.found == 0 and _config_dir_correctly.matched == 0) or
      ((_config_file_has_parameter.found | int) + (_config_dir_parameter_lines.results
      | map(attribute='found') | map('int') | sum)) != 1

  - name: Enable PAM - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
    ansible.builtin.file:
      path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      mode: '0600'
      state: touch
      modification_time: preserve
      access_time: preserve
  when:
  - '"linux-base" in ansible_facts.packages'
  - (_sshd_config_includes_config_dir.found | default(0) | int) > 0
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam

- name: Enable PAM - Set the parameter UsePAM in /etc/ssh/sshd_config
  block:

  - name: Enable PAM - Find the files of /etc/ssh/sshd_config.d that set the parameter
      UsePAM
    ansible.builtin.find:
      paths:
      - /etc/ssh/sshd_config.d
      patterns: '*.conf'
      contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
    register: _sshd_config_dir_sets_parameter

  - name: Enable PAM - Remove the parameter UsePAM from the files of /etc/ssh/sshd_config.d
    ansible.builtin.lineinfile:
      path: '{{ item.path }}'
      regexp: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+
      state: absent
    loop: '{{ _sshd_config_dir_sets_parameter.files }}'

  - name: Enable PAM
    block:

    - name: Check for duplicate values
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)(?i)^\s*UsePAM\s+
        mode: '0600'
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)(?i)^\s*UsePAM\s+
        mode: '0600'
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)(?i)^\s*UsePAM\s+
        mode: '0600'
        line: UsePAM yes
        state: present
        insertbefore: BOF
        validate: /usr/sbin/sshd -t -f %s
  when:
  - '"linux-base" in ansible_facts.packages'
  - (_sshd_config_includes_config_dir.found | default(0) | int) == 0
  tags:
  - DISA-STIG-UBTU-22-255065
  - PCI-DSSv4-2.2
  - PCI-DSSv4-2.2.6
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
  - sshd_enable_pam
```
