Bash – Is it safe to use echo to pass sensitive data into chpasswd

bashpasswordSecurity

I am trying to mass set a few user account passwords using chpasswd. The passwords should be generated randomly and printed to stdout (I need to write them down or put them in a password store), and also passed into chpasswd.

Naively, I would do this like this

{
  echo student1:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
  echo student2:$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 13 ; echo '')
} | tee >(chpasswd)

However I worry about passing the new password as a commandline argument to echo, because arguments are usually visible to other users in ps -aux (although I never saw any echo line appear in ps).

Is there an alternative way of prepending a value to my returned password, and then passing it into chpasswd?

Best Answer

Your code should be safe as echo won't show up in the process table since it's a shell built-in.

Here's an alternative solution:

#!/bin/bash

n=20
paste -d : <( seq -f 'student%.0f' 1 "$n" ) \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

This creates your student names and passwords, n of them, without passing any passwords on any command line of any command.

The paste utility glues together several files as columns and inserts a delimiter in-between them. Here, we use : as the delimiter and give it two "files" (process substitutions). The first one contains the output of a seq command that creates 20 student usernames, and the second contains the output of a pipeline that creates 20 random strings of length 13.

If you have a file with usernames already generated:

#!/bin/bash

n=$(wc -l <usernames.txt)

paste -d : usernames.txt \
           <( tr -cd 'A-Za-z0-9' </dev/urandom | fold -w 13 | head -n "$n" ) |
tee secret.txt | chpasswd

These will save the passwords and usernames to the file secret.txt instead of showing the generated passwords in the terminal.