Secure User Password Disablement in Puppet: Best Practices for SSH Key-Only Environments


5 views

In SSH server configurations where public key authentication is exclusively used (with password authentication disabled), properly disabling user passwords during account creation becomes crucial. The standard Puppet user resource needs careful handling to ensure no accidental password vulnerabilities are introduced.

In Unix-like systems, the password field in /etc/shadow can contain several special values:

  • * - Account disabled (most secure)
  • ! - Account locked (alternative)
  • !! - Account never had a password

Using password => '*' in Puppet is indeed the correct and secure approach:

user { 'deploy_user':
    ensure     => 'present',
    comment    => 'Deployment Account',
    groups     => ['sudo'],
    home       => '/home/deploy_user',
    managehome => true,
    shell      => '/bin/bash',
    password   => '*',  # This properly disables password auth
    ssh_keys   => [
        'ssh-rsa AAAAB3Nza... deploy@ci-server'
    ]
}

The asterisk (*) is a reserved character that cannot be generated by any password hashing algorithm. When placed in the password field:

  • Prevents any password-based authentication attempts
  • Works consistently across all Unix variants
  • Is the method recommended by security auditors

While these might seem equivalent, they have subtle differences:

# Not recommended - '!' can sometimes be bypassed
password => '!'

# Problematic - may allow empty password on some systems
password => ''

Here's a full example combining password disablement with SSH key deployment:

user { 'admin_user':
    ensure     => 'present',
    comment    => 'Primary Admin',
    groups     => ['sudo', 'adm'],
    home       => '/home/admin_user',
    managehome => true,
    shell      => '/bin/bash',
    password   => '*',
    ssh_keys   => [
        'ssh-rsa AAAAB3Nza... admin@workstation',
        'ssh-ed25519 AAAAC3Nza... admin@mobile'
    ]
}

After Puppet runs, verify with:

sudo grep admin_user /etc/shadow

Should output something like:

admin_user:*:19476:0:99999:7:::

When configuring SSH servers for public key authentication only, properly disabling password authentication is critical. In Puppet, the password => '*' approach is actually the recommended method according to official documentation and common practices in the DevOps community.

The asterisk character in the password field has special meaning in Unix/Linux systems:

# This creates a user with disabled password
user { 'secure_user':
  ensure   => 'present',
  password => '*',
  # other attributes...
}

This method is secure because:

  • It sets an invalid encrypted password in /etc/shadow
  • Prevents any password-based authentication attempts
  • Maintains compatibility with all standard Unix tools
  • Is the documented method in Puppet's user resource type

While password => '*' is preferred, there are other valid approaches:

# Method 1: Using '!!' (also invalidates password)
user { 'backup_user':
  password => '!!',
}

# Method 2: Explicitly locking account
user { 'service_account':
  password => '!',
  shell    => '/usr/sbin/nologin',
}

Here's a comprehensive Puppet manifest for secure user management:

# SSH-only user with disabled password and proper permissions
user { 'devops_admin':
  ensure     => present,
  comment    => 'DevOps Team Member',
  groups     => ['sudo', 'ssh-access'],
  home       => '/home/devops_admin',
  managehome => true,
  shell      => '/bin/bash',
  password   => '*',
  ssh_keys   => [
    'ssh-rsa AAAAB3Nz... devops_admin@company',
    'ssh-ed25519 AAAAC3... devops_admin@laptop'
  ],
}

# Lock service account completely
user { 'ci_runner':
  ensure   => present,
  system   => true,
  password => '!',
  shell    => '/usr/sbin/nologin',
}

After applying your Puppet manifest, verify the configuration:

# Check shadow entry (should show '*' or '!')
sudo grep username /etc/shadow

# Attempt password login (should fail)
ssh username@localhost
  • Always combine password disabling with sshd_config hardening
  • Regularly audit user accounts with puppet resource user
  • Consider using centralized authentication for larger environments
  • Implement MFA for additional security layers