Password Generation & Security Operations

Password Generation & Security Operations

Comprehensive guide to generating cryptographically secure passwords and secrets on Linux systems.

Quick Reference

# 32-char alphanumeric (most compatible)
openssl rand -base64 32 | tr -d '/+=' | head -c 32 && echo


# 24-char with symbols (high entropy)
openssl rand -base64 24

# Hex string (tokens, API keys)
openssl rand -hex 32

# UUID v4
uuidgen

# pass generate (stores automatically)
pass generate ARCANA/api/service-name 32

Password Generation Methods

OpenSSL provides cryptographically secure random bytes from /dev/urandom.

Alphanumeric Only
# 32 characters - clean, no special chars
openssl rand -base64 32 | tr -d '/+=' | head -c 32
# Output: 5kFxc5M6xuI6myLaSKWDX7tU8VRtujOU

# With length variable
LEN=24 && openssl rand -base64 $((LEN * 2)) | tr -d '/+=' | head -c $LEN
With Base64 Symbols (+, /, =)
# 32 characters including +/=
openssl rand -base64 24
# Output: R87D73kwd3WkmM4JOdgd+hYS/jon==

# Trim padding
openssl rand -base64 24 | tr -d '='
Hexadecimal
# 64 hex chars (32 bytes)
openssl rand -hex 32
# Output: a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890

# 32 hex chars (16 bytes) - for tokens
openssl rand -hex 16

2. /dev/urandom Direct

# Alphanumeric
< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 32

# With symbols
< /dev/urandom tr -dc 'A-Za-z0-9!@#$%^&*' | head -c 32

# Lowercase + numbers only
< /dev/urandom tr -dc 'a-z0-9' | head -c 32

3. UUID Generation

# UUID v4 (random)
uuidgen
# Output: f47ac10b-58cc-4372-a567-0e02b2c3d479

# Without dashes (32 hex chars)
uuidgen | tr -d '-'

# Lowercase
uuidgen | tr '[:upper:]' '[:lower:]'

4. Python One-Liners

# Secure random string
python3 -c "import secrets; print(secrets.token_urlsafe(24))"

# Hex token
python3 -c "import secrets; print(secrets.token_hex(16))"

# Custom alphabet
python3 -c "import secrets,string; print(''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(32)))"

5. pwgen (if installed)

# 32-char secure password
pwgen -s 32 1

# With symbols
pwgen -sy 32 1

# Multiple passwords
pwgen -s 32 5

Pass Integration

Generate and Store

# Generate 32-char password and store
pass generate ARCANA/api/ise-02 32

# Generate without symbols
pass generate -n ARCANA/api/ise-02 32

# Generate and copy to clipboard
pass generate -c ARCANA/api/ise-02 32

# Generate, don't print, copy to clipboard
pass generate -c -n ARCANA/api/ise-02 32

Insert with Metadata

# Generate password first
PASS=$(openssl rand -base64 32 | tr -d '/+=' | head -c 32)

# Insert with metadata using heredoc
pass insert -m ARCANA/api/ise-02 << EOF
${PASS}
---
type: cisco-ise-ers
node: ise-02
role: secondary-pan

connection:
  host: ise-02.inside.domusdigitalis.dev
  ip: 10.50.1.21
  port: 9060
  protocol: https
  endpoint: /ers/config

credentials:
  username: ersadmin
  auth: basic

meta:
  created: $(date +%Y-%m-%d)
  version: "3.2"
  notes: ERS API for automation scripts
EOF

Batch Password Generation Script

#!/bin/bash
# generate-pass-entry.sh - Generate password with metadata

CATEGORY="$1"
NAME="$2"
LENGTH="${3:-32}"

if [[ -z "$CATEGORY" || -z "$NAME" ]]; then
    echo "Usage: $0 <category> <name> [length]"
    echo "Example: $0 ARCANA/api ise-02 32"
    exit 1
fi

PASS=$(openssl rand -base64 $((LENGTH * 2)) | tr -d '/+=' | head -c "$LENGTH")
CREATED=$(date +%Y-%m-%d)

echo "Generated: $PASS"
echo "Path: $CATEGORY/$NAME"
echo ""

read -p "Add metadata? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    read -p "Service type: " SERVICE_TYPE
    read -p "Username: " USERNAME
    read -p "Host/Endpoint: " ENDPOINT
    read -p "Notes: " NOTES

    pass insert -m "$CATEGORY/$NAME" << EOF
${PASS}
---
type: ${SERVICE_TYPE}
credentials:
  username: ${USERNAME}
endpoint: ${ENDPOINT}
meta:
  created: ${CREATED}
  notes: ${NOTES}
EOF
else
    echo "$PASS" | pass insert -m "$CATEGORY/$NAME"
fi

echo "Stored at: $CATEGORY/$NAME"

Entropy Calculation

Understanding Password Strength

Character Set Pool Size Bits per Char

Numeric (0-9)

10

3.32

Lowercase (a-z)

26

4.70

Uppercase (A-Z)

26

4.70

Alphanumeric

62

5.95

+ Symbols (32)

94

6.55

Base64

64

6.00

Hex

16

4.00

Entropy Formula

Entropy (bits) = Length × log2(Pool Size)

Common Password Strengths

Length Alphanumeric With Symbols Hex

16

95 bits

105 bits

64 bits

24

143 bits

157 bits

96 bits

32

190 bits

210 bits

128 bits

64

381 bits

419 bits

256 bits

Quick Entropy Calculator

#!/bin/bash
# entropy.sh - Calculate password entropy

calc_entropy() {
    local password="$1"
    local length=${#password}
    local pool=0

    [[ "$password" =~ [0-9] ]] && ((pool += 10))
    [[ "$password" =~ [a-z] ]] && ((pool += 26))
    [[ "$password" =~ [A-Z] ]] && ((pool += 26))
    [[ "$password" =~ [^a-zA-Z0-9] ]] && ((pool += 32))

    # entropy = length * log2(pool)
    local entropy=$(echo "scale=2; $length * l($pool)/l(2)" | bc -l)

    echo "Length: $length"
    echo "Pool size: $pool"
    echo "Entropy: $entropy bits"

    if (( $(echo "$entropy >= 128" | bc -l) )); then
        echo "Strength: EXCELLENT"
    elif (( $(echo "$entropy >= 80" | bc -l) )); then
        echo "Strength: STRONG"
    elif (( $(echo "$entropy >= 60" | bc -l) )); then
        echo "Strength: MODERATE"
    else
        echo "Strength: WEAK"
    fi
}

calc_entropy "$1"

Device-Specific Requirements

Cisco ISE Password Policy

ISE enforces strict password requirements:

  • Minimum: 6 characters (default policy)

  • Must contain: uppercase, lowercase, number, special character

  • AVOID these characters in GUI passwords: $ " ' \' \

    • ISE web security filter blocks $ as potential injection

    • Quotes and backticks cause parsing issues

Safe special characters for ISE:

! @ # % ^ & * ( ) - _ = + [ ] { } | ; : , . < > ?

Quick ISE-safe password (one-liner):

< /dev/urandom tr -dc 'A-Za-z0-9!@#%^&*' | head -c 24 && echo
# ISE-compliant password function (GUI-safe characters only)
generate_ise_password() {
    local length=${1:-20}
    local password=""
    local safe_symbols='!@#%^&*()-_=+'

    # Ensure at least one of each required type
    password+=$(< /dev/urandom tr -dc 'A-Z' | head -c 1)
    password+=$(< /dev/urandom tr -dc 'a-z' | head -c 1)
    password+=$(< /dev/urandom tr -dc '0-9' | head -c 1)
    password+=$(< /dev/urandom tr -dc "$safe_symbols" | head -c 1)

    # Fill remaining with mixed chars (NO $ symbol)
    password+=$(< /dev/urandom tr -dc "A-Za-z0-9${safe_symbols}" | head -c $((length - 4)))

    # Shuffle the password
    echo "$password" | fold -w1 | shuf | tr -d '\n'
    echo
}

# Usage
generate_ise_password 24

Network Device Compatible

Many network devices have character restrictions:

# Safe for most network devices (no quotes, backslash, space, NO $)
< /dev/urandom tr -dc 'A-Za-z0-9!@#%^&*()-_=+' | head -c 24 && echo

API Token Format

# Bearer token style (base64url safe)
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='

# Hex API key (common format)
openssl rand -hex 32

Shell Functions

Add to ~/.bashrc or ~/.config/fish/functions/:

Bash

# ~/.bashrc

# Quick password generation
randpass() {
    local length=${1:-32}
    openssl rand -base64 $((length * 2)) | tr -d '/+=' | head -c "$length"
    echo
}

# With symbols
randpass-sym() {
    local length=${1:-32}
    openssl rand -base64 "$length"
}

# Hex token
randtoken() {
    local bytes=${1:-32}
    openssl rand -hex "$bytes"
}

# ISE-compliant (NO $ - ISE GUI blocks it)
randpass-ise() {
    local length=${1:-20}
    local p=""
    local safe='!@#%^&*()-_=+'
    p+=$(< /dev/urandom tr -dc 'A-Z' | head -c 1)
    p+=$(< /dev/urandom tr -dc 'a-z' | head -c 1)
    p+=$(< /dev/urandom tr -dc '0-9' | head -c 1)
    p+=$(< /dev/urandom tr -dc "$safe" | head -c 1)
    p+=$(< /dev/urandom tr -dc "A-Za-z0-9${safe}" | head -c $((length - 4)))
    echo "$p" | fold -w1 | shuf | tr -d '\n'
    echo
}

# Generate and copy to clipboard
randpass-clip() {
    local pass=$(randpass "${1:-32}")
    echo "$pass" | wl-copy
    echo "Copied to clipboard (32 chars)"
}

Fish

# ~/.config/fish/functions/randpass.fish

function randpass -d "Generate random password"
    set -l length $argv[1]
    test -z "$length"; and set length 32
    openssl rand -base64 (math "$length * 2") | tr -d '/+=' | head -c $length
    echo
end

function randtoken -d "Generate hex token"
    set -l bytes $argv[1]
    test -z "$bytes"; and set bytes 32
    openssl rand -hex $bytes
end

function randpass-clip -d "Generate and copy to clipboard"
    set -l pass (randpass $argv[1])
    echo $pass | wl-copy
    echo "Copied to clipboard"
end

Security Best Practices

DO

# Use cryptographically secure sources
openssl rand ...
/dev/urandom
python3 secrets module

# Use sufficient length
# Minimum 16 chars, recommended 24-32 chars

# Store securely
pass insert ...
age -e ...

# Clear clipboard after use
wl-copy --clear  # after 45 seconds by default with pass -c

DON’T

# Never use $RANDOM (predictable)
echo $RANDOM  # BAD

# Never use date-based seeds
date +%s | sha256sum  # BAD

# Never use /dev/random (blocks, not more secure)
< /dev/random  # Unnecessary, /dev/urandom is fine

# Never echo passwords to terminal logs
echo "password is $PASS"  # Logged in history

Secure Temporary Storage

# Use process substitution (no temp file)
pass insert mypass < <(openssl rand -base64 24)

# Or heredoc (also no temp file)
pass insert -m mypass << EOF
$(openssl rand -base64 24)
EOF

# If temp file needed, secure it
TMPFILE=$(mktemp)
chmod 600 "$TMPFILE"
openssl rand -base64 24 > "$TMPFILE"
# ... use file ...
shred -u "$TMPFILE"

Automation Scripts

Bulk Password Rotation

#!/bin/bash
# rotate-passwords.sh - Rotate multiple pass entries

ENTRIES=(
    "ARCANA/api/ise-01"
    "ARCANA/api/ise-02"
    "ARCANA/ssh/ise-01"
    "ARCANA/ssh/ise-02"
)

for entry in "${ENTRIES[@]}"; do
    echo "Rotating: $entry"

    # Backup old
    OLD=$(pass show "$entry" | head -1)
    echo "Old: ${OLD:0:4}****"

    # Generate new (keeps metadata if using pass generate with -i)
    pass generate -i "$entry" 32

    NEW=$(pass show "$entry" | head -1)
    echo "New: ${NEW:0:4}****"
    echo "---"
done

echo "Done. Don't forget to update actual services!"

Export for Ansible Vault

#!/bin/bash
# export-to-vault.sh - Export pass entries to Ansible vault format

OUTPUT="secrets.yml"

cat > "$OUTPUT" << 'HEADER'
---
# Ansible Vault Secrets
# Encrypted with: ansible-vault encrypt secrets.yml

HEADER

# Add entries
echo "ise_api_password: \"$(pass show ARCANA/api/ise-02 | head -1)\"" >> "$OUTPUT"
echo "ise_ssh_password: \"$(pass show ARCANA/ssh/ise-02 | head -1)\"" >> "$OUTPUT"

# Encrypt
ansible-vault encrypt "$OUTPUT"
echo "Created encrypted: $OUTPUT"

Quick Reference Card

+------------------------------------------------------------------+
|                    PASSWORD GENERATION                            |
+------------------------------------------------------------------+
| ALPHANUMERIC (32 chars)                                          |
|   openssl rand -base64 32 | tr -d '/+=' | head -c 32             |
|                                                                   |
| WITH SYMBOLS                                                      |
|   openssl rand -base64 24                                         |
|                                                                   |
| HEX TOKEN                                                         |
|   openssl rand -hex 32                                            |
|                                                                   |
| UUID                                                              |
|   uuidgen                                                         |
|                                                                   |
| PASS GENERATE                                                     |
|   pass generate PATH 32                                           |
|   pass generate -c PATH 32  # copy to clipboard                   |
|   pass generate -n PATH 32  # no symbols                          |
+------------------------------------------------------------------+
|                    ENTROPY TARGETS                                |
+------------------------------------------------------------------+
| 80+ bits   = Strong (16 alphanumeric)                            |
| 128+ bits  = Very Strong (22 alphanumeric)                       |
| 256+ bits  = Maximum (43 alphanumeric)                           |
+------------------------------------------------------------------+
|                    SHELL FUNCTIONS                                |
+------------------------------------------------------------------+
| randpass [len]      # alphanumeric                               |
| randpass-sym [len]  # with symbols                               |
| randtoken [bytes]   # hex token                                  |
| randpass-clip [len] # generate + copy                            |
+------------------------------------------------------------------+

Unsorted notes from experiences

Generate password

NEWPASS=$(< /dev/urandom tr -dc ‘A-Za-z0-9’ | head -c 32) echo “New password: $NEWPASS”

Create base64 token (replace ‘ersadmin’ with your username)

echo -n “ersadmin:$NEWPASS” | base64

Or all in one:

echo -n “ersadmin:$(< /dev/urandom tr -dc ‘A-Za-z0-9’ | head -c 32)” | base64

See Also

  • ARS-SECURITY-ENCRYPTION/2025-ENC-001-Encryption-Operations-Complete.md

  • OPS-PLAYBOOKS/2025-PLY-003-Custos-Clavium-Pass-Password-Manager.md

  • man openssl-rand

  • man pass