Wave Spread...

Linux 下的用户管理策略

分类:Linux 评论: 0

多用户态是 GNU/Linux 的一个创举,引入了多用户、多任务的概念,任何操作都需要建立在用户的基础上。

用户系统一方面可以帮助系统管理员对使用系统的用户进行跟踪,并控制用户对系统资源的访问;另一方面也可以帮助用户组织文件,并为用户提供安全性保护。

用户的管理

Linux 下的用户系统引入了用户与用户组的概念,用户组可以提高此系统的灵活度,可将部分用户划分为组,使得组内资源可以共享。

用户及组添加

使用 useradd 命令即可添加系统用户。

# useradd [options] LOGIN
常用参数 长参数 作用及描述 注意事项
-c --comment 指定用户的描述 非必要
-d --home-dir 指定用户的家目录 /
-D --default 修改默认参数 /
-e --expiredate 指定用户的过期时间 时间格式必须为 YYYY-MM-DD
-f --inactive 指定用户密码过期后的禁用时间 /
-g --gid 指定用户的所属用户组 /
-G --groups 指定用户的所属用户组群 使用此参数可将用户添加至多个用户组
-m --create-home 自动为用户创建用户家目录 默认为 /home/用户名
-M --no-create-home 不创建用户家目录 /
-u --uid 指定用户的UID /
-s --shell 指定用户登陆的命令解释器 /
-r --system 指定用户为系统账户 可使用 UID 1000 以内
-p --password 指定用户密码 /

使用 groupadd 命令即可添加用户组

# groupadd [options] group
常用参数 长参数 作用及描述 注意事项
-f --force 强制添加用户组 若用户组已经存在,则会随机分配另一个 GID
-g --gid 指定用户的 GID /
-r --system 指定用户组系统用户组 /

举个例子:

例一:建立一个不允许登陆,且不创建家目录的用户 www-data(常用来给服务使用)

# useradd -s /sbin/nologin -M www-data

例二:建立一个 UID 为 666,且 GID 为 666 的用户 www-data

# groupadd -g 666 www-data
# useradd -u 666 -g www-data www-data

用户及组删除

使用 userdel 命令即可删除用户

# userdel [options] LOGIN
常用参数 长参数 作用及描述 注意事项
-f --force 强制删除用户 用户登陆中也可删除
-r --remove 同时删除用户的家目录 /

使用 groupdel 命令即可删除用户组

# groupdel [options] GROUP

用户信息修改

使用 usermod 命令即可删除用户

# usermod [options] LOGIN
常用参数 长参数 作用及描述 注意事项
-c --comment 修改用户的描述 非必要
-d --home-dir 修改用户的家目录 /
-g --gid 修改用户的所属用户组 /
-G --groups 修改用户的所属用户组群 /
-u --uid 修改用户的UID /
-s --shell 修改用户登陆的命令解释器 /

例三:将用户 kane 的命令解释器修改为 ksh ,家目录改为 /var/lib ,用户组改为 root

# usermod -s /bin/ksh -d /var/lib -g root kane

例四:将一个已有用户 nginx 增加到一个已有用户组 www-data 中

将一个已有用户增加到一个已有用户组中,使此用户组成为该用户的附加用户组,可以使用带 -a 参数的 usermod 指令。-a 代表 append,也就是将用户添加到新用户组中而不必离开原有的其他用户组。不过需要与 -G 选项配合使用。

# usermod -a -G www-data nginx

如果要同时将 nginx 的主要用户组改为 www-data,则直接使用 -g 选项。

# usermod -g www-data nginx

将一个用户从某个组中移除。

# gpasswd -d user group

注意:使用此命令需要保证 group 不是 user 的主组。

用户密码设置

使用 passwd 命令即可修改用户密码

# passwd [options] LOGIN
常用参数 长参数 作用及描述 注意事项
-k --keep 用户密码只能在过期后才能重置
-l --lock 锁定用户 /
-u --unlock 解锁用户 /
-d --delete 删除用户密码 /
-f --force 强制指定的操作 /
--stdin / 从标准输入内获取密码 /

例五:无交互式地修改用户 kane 的密码

# echo "centos" | passwd --stdin kane

登陆用户查询及清理

Linux 为多用户系统,可以多人同时登陆,因此需要得知系统有多少用户登陆。及清理掉未知的登陆用户,保护系统安全。

使用 w 命令即可查询用户登陆状态

# w
 10:19:12 up 19 days, 27 min,  1 user,  load average: 0.00, 0.01, 0.05
 USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
 root     pts/0    192.168.1.215    09:40    0.00s  0.01s  0.00s w
项目名 说明
USER 登陆用户
TTY 终端
FROM 来源
LOGIN@ 登陆时间
IDLE 用户空闲时间(从上一任务结束后开始计算)
JCPU 此终端的相关的进程所耗费的CPU时间
PCPU 指WHAT域的任务执行后耗费的CPU时间
WHAT 表示当前执行的任务

小贴士:使用 w 命令可以仅仅查看某个用户的状态,使用 w 后加用户名即可。

使用 who 命令也可查询系统登陆的用户

# who

踢掉某个用户可以使用 pkill

# pkill -kill -t pts

注意:后面接 TTY 字段的名称。

示例脚本

需求:批量添加用户并设置密码

Shell 实现

#!/bin/bash
# 批量添加指定数量的用户
# 创建用户默认名
# 配置默认密码

# 输入用户名,输入信息存入name变量中,限制30s的输入时间
read -p "Please input user name:" -t 30 name
# 输入需要创建的用户数量,存入num中,限制30s输入时间
read -p "Please input the number of users:" -t 30 num
# 输入需要创建的默认密码,存入pass中,限制30s输入时间
read -p "Please input the password of users:" -t 30 pass

# 用户名、用户数量、默认密码都输入成功之后
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
    then
# 输入的num变量为数值类型
    y=$(echo $num | sed 's/[0-9]//g')
    if [ -z "$y"]
        then
# 创建用户
    for (( i=1;i<=$num;i=i+1))
        do
        # 用户名以输入用户名+序号组成 
        /usr/sbin/useradd $name$i &> /dev/null
        # 创建默认密码
        echo $pass | /usr/bin/passwd --stdin $name$i &> /dev/null
        done
    fi
fi

改进可以引用随机密码的方式优化脚本,并记录到文件中。

Linux 的生成随机字符串的方式有很多,比如要产生一个 16 位的字母和数字混合的随机密码,可以这样:

方式1:

$ cat /dev/urandom | head -1 | md5sum | head -c 16

在 Linux 中有一个特殊的虚拟设备 /dev/urandom 是用来产生随机数序列的。利用该设备可以根据需要生成随机字符串。

方式2:

$ date +%s | sha256sum | base64 | head -c 16

可以先获取当前时间戳,然后对其进行加密(校验)用 md5sum 也行,然后取前 16 位。

方式3:

$ openssl rand 100 | base64 | head -c 16

使用 openssl 套件生成随机字符串,然后进行加密,再取前 16 位。

方式4:

#!/bin/bash
a=(a b c d e A B C D E F @ $ % ^ 0 1 2 3 4 5 6 7 8 9)
for ((i=0;i<10;i++)); do
    echo -n ${a[$RANDOM % ${#a[@]}]}
done
echo

Python 实现

#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import random
import time
import io

def deluser(nums):
    '''删除用户测试用户'''
    for i in range(nums):
        username = 'stu' + str(i)
        linux_cmd = 'userdel -r {username}'.format(username=username)
        cmd_stat = os.system(linux_cmd)
        if cmd_stat == 0:
            print(username + " userdel: OK")
        else:
            print(username + " userdel: FAIL")

def create_user(nums, record_adduser):
    '''添加用户测试用户'''
    if isinstance(nums, str):
        nums = int(nums)
    symbol = '1234567890'
    if not os.path.exists(os.path.dirname(record_adduser)):
        # 没有这个目录创建
        os.mkdir(os.path.dirname(record_adduser))
    # 这个文件直接打开,没有就创建
    f = io.open(record_adduser, 'a+', encoding='utf-8')
    for i in range(nums):
        passwd = ''.join(random.sample(symbol, 6))
        username = 'stu' + str(i)
        linux_cmd = 'useradd {username} && echo "{passwd}" | passwd {username} --stdin{linesep}'.format(username=username,
                                                                                               passwd=passwd, linesep=os.linesep)
        current_user = os.popen('whoami').read().strip()
        cmd_stat = os.system(linux_cmd)
        tmp = str(time.strftime('%Y-%m-%d %H:%M ', time.localtime()) + \
                  ' ' + current_user + ' ' + linux_cmd + ' {stat}')
        if cmd_stat == 0:
            print(username + " useradd: OK")
            tmp = tmp.format(stat='OK').decode('utf-8')
            # 创建成功写一句
            f.write(tmp)
        else:
            print(username + " useradd: FAIL")
            tmp = tmp.format(stat='FAIL').decode('utf-8')
            f.write(tmp)
        # f.flush()
    f.close()

if __name__ == '__main__':
    record_adduser = '/root/adduser{sep}useradd.log'.format(sep=os.path.sep)
    create_user(10, record_adduser)
    # deluser(10)

# python 2 下,str 是 bytes类型,文件通过 io模块打开

参考链接

回复