Home Born2beroot ④ 구현 과정 (Mandatory part)
Post
Cancel

Born2beroot ④ 구현 과정 (Mandatory part)

sudo 설정

visudo를 사용해 sudoers 파일의 아래 내용 편집

1
2
3
4
5
6
7
8
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
Defaults        authfail_message="Authenticate failed."
Defaults        badpass_message="Password failed."
Defaults        log_input
Defaults        log_output
Defaults        requiretty
Defaults        iolog_dir="/var/log/sudo/"
Defaults        passwd_tries=3
  • authfail_message : sudo 인증 실패 시 출력 메시지
  • badpads_message : sudo 인증에서 비밀번호 불일치 시 출력 메시지
  • log_input : log에 sudo로 사용한 input 내용 저장
  • log_output : log에 sudo로 출력된 output 내용 저장
  • requiretty : 현재 shell이 tty 인지 아닌지에 따라 sudo의 허가여부 결정
  • iolog_dir : sudo log 저장 경로 설정
  • passwd_tries : sudo 실행 횟수 설정

사용자 설정

유저 관리

1
2
3
4
5
sudo useradd -m [username] # 새유저 및 해당 홈디렉토리 생성
passwd [username] # 패스워드 설정
grep /bin/bash /etc/passwd | cut -f1 -d:# useradd로 추가했던 유저 목록
userdel [username] [groupname] # 유저를 해당 그룹에서 제거
userdel -r [username] # 유저의 모든 정보 삭제

그룹 관리

1
2
3
4
5
6
groupadd user42 # user42그룹을 추가
groupdel [groupname] # 그룹 삭제
usermod -G user42,sudo [username] # 유저를 user42, sudo그룹에 추가.(나머지 그룹에서는 제거)
usermod -aG user42,sudo [username] # 유저를 user42, sudo그룹에 추가. (나머지 그룹에서도 유지)
usermod -g user42 [username] # user42를 유저의 primary group으로 만듦.
id [username] # 유저의 그룹 정보를 보여줌
  • 계정을 sudo그룹에 넣으면 sudo 권한이 부여된다.

사용자 정보

/etc/passwd

  • 시스템 관리자가 유저를 생성할때마다 관련 정보를 저장
  • 각 필드별로 아래와 같은 의미를 가진다.
1
[user_account]:[user_pw]:[user_id]:[group_id]:[comment]:[home_dir]:[login_shell]

cut -f1 -d: /etc/passwd : 사용자 계정만 출력.
내가 생성하지 않았는데 보이는 다양한 계정(daemon, bin, sys, man 등) → 시스템 계정

  • 시스템 계정
    시스템의 필요에 의해 생성된 계정
    리눅스는 파일이나 프로세스 생성 시 반드시 소유자를 명시하게 되는데 모든 시스템에 대해 root 권한을 부여할 시에 생길 수 있는 시스템 손상의 문제를 시스템 계정을 통해 방지 할 수 있다.

호스트 정보

1
2
3
4
hostname # hostname 확인
hostname [new name] # 임시 hostname 변경
sudo hostnamectl set-hostname [new name] # static hostname 변경
sudo systemctl reboot # 시스템 reboot

패스워드 정책 설정

설정 1

sudo vim /etc/login.defs 로 아래 내용 수정

1
2
3
PASS_MAX_DAYS 30 # 최대 30일까지 사용
PASS_MIN_DAYS 2  # 최소 2일 이상 사용
PASS_WARN_AGE 7  # 7일전부터 경고 메시지 출력

설정 2

sudo apt install libpam-pwquality : 비밀번호 정책 설정을 위한 패키지 설치
sudo vim /etc/pam.d/common-password : 중간에 위치한 per-package modules를 아래와 같이 변경

1
password    requisite    pam_pwquality.so retry=3 minlen=10 difok=7 ucredit=-1 lcredit=-1 dcredit=-1 reject_username enforce_for_root maxrepeat=3

각 항목의 의미는 아래와 같다.

1
2
3
4
5
6
7
8
9
retry=3 # 비밀번호 최대 3회까지 입력 가능
minlen=10 # 최소 10자
difok=7 # 이전 비밀번호와 최소 7글자는 다르게 설정
ucredit=-1 # 대문자 최소 1자 이상
lcredit=-1 # 소문자 최소 1자 이상(이 조건이 있는 이유?)
dcredit=-1 # 숫자 최소 1자 이상
reject_username # username을 그대로 or 뒤집어서 암호로 사용 불가
enforce_for_root # 해당 비밀번호 정책을 root에도 적용
maxrepeat=3 # 3자까지 중복 가능

설정 적용

위의 두가지 설정은 모두 새로 생성되는 유저에 적용된다. 따라서 아래와 같이 추가적인 설정 적용 과정을 거쳐야 한다.

chage -m 2 -M 30 -W 7 [username] : 비밀번호 기간 적용(2~30일 유효, 7일전 경고)
passwd -e [username] : 다음 로그인시 비밀번호 변경
chage -l [username] : 유저별로 설정된 내용 확인
sudo vim /etc/shadow : 설정된 내용 한번에 확인

Untitled

위 내용 중 root와 username(taehooki)의 4, 5, 6번 필드(각각 2, 30, 7)를 보면 설정이 적용된 것을 알 수 있다.

AppArmor 설정

1
2
3
4
5
6
sudo apt --installed list apparmor # 설치 확인
apt install apparmor apparmor-profiles apparmor-utils # 설치
sudo apparmor_status # 상태 확인
aa-enabled # 활성화 여부 확인
sudo aa-status # 현재 상태 확인 가능(enforced, complain, unconfined)
ps auxZ | grep -v '^unconfined' # apparmor가 실행제한한 파일 확인
  • enforce 모드 : 허가되지 않은 파일에 접근을 거부한다.
  • complain 모드 : 어플리케이션이 해야 할 일이 아닌 일을 했을 때 로그를 기록한다.

SSH 설정

1
2
3
4
apt --installed list openssh-server # openssh 설치 확인(보통 설치되어있다.)
ssh -V # openssh 버전 확인
apt install openssh-server # openssh 설치(없다면)
sudo ufw allow 4242 # 4242 포트 ufw 허용
  • sudo vim /etc/ssh/sshd_config 내용 수정

    1
    2
    
      Port 4242 # SSH포트를 4242로 변경
      PermitRootLogin no # 외부에서 root로의 로그인 차단
    
  • 설정 적용

    1
    2
    3
    
      sudo systemctl restart ssh # 수정 후, 다시 시작해서 설정 적용
      systemctl status ssh # openssh 실행 상태 확인
      ss -tunpl # 포트번호 확인
    
  • systemctl : 서비스 관리 명령어

    1
    2
    3
    4
    5
    6
    7
    8
    
      systemctl start [서비스이름] # 시작
      systemctl stop [서비스이름] # 종료
      systemctl restart [서비스이름] # 재시작
      systemctl try-restart [서비스이름] # 재시작(시작된 서비스)
      systemctl reload [서비스이름] # 설정 reload
      systemctl status [서비스이름] # 상태 확인
      systemctl is-active [서비스이름] # 상태 확인(1)
      systemctl list-units --type service --all # 모든 서비스 상태확인
    
    • servicesystemctl의 차이
      service 명령어는 /etc/init.d 를 실행한다.
      systemctl 명령어는 /lib/systemd 의 파일을 실행하고 만약 없으면 위의 service의 경로의 파일을 실행한다.

UFW 설정

1
2
3
4
5
6
7
8
9
$ sudo apt install ufw # ufw 방화벽 설치
$ sudo ufw status verbose # 상태 확인(디폴트는 inactive)
$ sudo ufw enable # 부팅시 ufw 활성화 하기
$ sudo ufw disable # 비활성화
$ sudo ufw default deny # 기본 incoming deny
$ sudo ufw default allow # 기본 incomig allow
$ sudo ufw allow 4242 # 4242port로 ssh 연결 허용
$ sudo ufw status numbered # 규칙번호 확인
$ sudo ufw delete [규칙번호] # 해당 규칙 삭제

TTY로 VM 접근

tty

리눅스 디바이스 드라이버 중에서 콘솔이나 터미널을 의미
명칭은 과거에 사용하던 Teletypewriter에서 유래하였다.
여러 개의 터미널이 존재할 경우 tty0, tty1, …. , tty6로 번호를 붙혀 사용한다.

Port Forwarding

로컬에서 tty를 통해 가상머신에 접근하기 위해서는 포트 포워딩 작업이 추가적으로 필요하다.

sudo apt-get install net-tools : 넷툴즈 설치 (ifconfig 사용을 위해)

VirtualBox 설정
[Settings]-[Network]-[Advanced]-[Port Forwarding] 에서 Rule 추가하기

  • HOST IP : 127.0.0.1 (localhost, 자기 자신) 또는 ifconfig | grep inet의 값
  • HOST PORT : 5000 (임의의 값)
  • GuestIP : 10.0.2.15 (hostname -I의 값)
  • GUEST PORT : 4242
    • 호스트 포트 : 외부에서 연결할 때 이용하고자 하는 포트
    • 게스트 포트 : 내가 지정한 서비스의 포트

Untitled

cmd에서 아래 내용 입력해서 가상환경에 접속

1
ssh taehooki@127.0.0.1 -p 5000 # ssh [username]@[HOST IP] -p [HOST PORT]

VirtualBox의 포트 포워딩 설정에서 호스트 포트를 22(ssh 기본포트)로 지정했다면 ssh로 접속할 때 포트부분을 제외하고 ssh [username]@[HOST IP] 만 입력해도 된다.

Untitled

exit : 가상환경 접속 종료

Untitled

SSH를 사용해 접속할때 root로는 접속을 막았기 때문에 연결되지 않는다.

쉘 스크립트 작성

관련 명령어

  • OS 아키텍쳐, 커널 버전(Architecture)
    • uname -a
  • 물리 프로세서 개수(CPU physical)
    • cat /proc/cpuinfo(CPU 코어 개별적인 세부사항이 담겨있다.) 파일 참고
    • cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l
      • physical id : 0은 프로세서가 0개라는 의미가 아닌, 0번 id를 갖는 프로세서라는 의미이다.(0, 1, 2, … 으로 증가한다.)
      1. 해당 line을 추출한 뒤
      2. -u (unique) 옵션(정렬 후 중복된 내용을 제거)으로 정렬 후
      3. 행의 수를 세어 출력한다.
  • 가상 프로세서 개수(vCPU)
    • cat /proc/cpuinfo | grep processor | sort -u | wc -l
  • 현재 서버에 여유있는 RAM과 사용률(Memory Usage)
    • free : 메모리 사용량, 여유량과 캐싱으로 사용되는 메모리의 현황
      • [total] : 설치된 총 메모리 크기 / 설정된 스왑 총 크기
      • [used] : total에서 free, buff/cache를 뺀 사용중인 메모리. / 사용중인 스왑 크기
      • [free] : total에서 used와 buff/cahce를 뺀 실제 사용 가능한 여유 있는 메모리량 / 사용되지 않은 스왑 크기
      • [shared] : tmpfs(메모리 파일 시스템), ramfs 등으로 사용되는 메모리. 여러 프로세스에서 사용할 수 있는 공유 메모리
      • [buffers] : 커널 버퍼로 사용중인 메모리
      • [cache] : 페이지 캐시와 slab으로 사용중인 메모리
        • slab : 커널이 내부적으로 사용하는 영역
      • [buff/cache] : 버퍼와 캐시를 더한 사용중인 메모리
      • [available] : swapping 없이 새로운 프로세스에서 할당 가능한 메모리의 예상 크기. (예전의 -/+ buffers/cache이 사라지고 새로 생긴 컬럼)
    • free -m | grep Mem | awk '{printf "%d/%dMB (%.2f%%)", $3, $2, $3/$2*100}'
      1. free의 내용을 MB단위로 받아서
      2. Mem이 포함된 행의 내용을
      3. [used]/[total]MB ([used]/[total]x100%) 형태로 출력
  • 현재 서버에 여유있는 메모리와 사용률(Disk Usage)
    • df : 디스크메모리의 전체 현황
      • BM, BG: MB, GB로 결과 출력
    • df -BM | grep /dev/map | awk '{sum+=$3}END{print sum}' | tr -d
    • df -BM | grep /dev/map | awk '{sum+=$4}END{print sum}' | tr -d
  • 현재 프로세서의 사용률(CPU load)
    • mpstat: 사용가능한 CPU와 core별 사용률 현황
    • sudo apt-get install sysstat : mpstat 명령어가 포함된 패키지 설치
    • mpstat | grep all | awk '{printf "%.2f%%\n", 100-$NF}'
      • NF: 필드의 총 개수($NF=마지막 필드)
  • 마지막 reboot 일시(Last boot)
    • who : 호스트에 로그인한 사용자 정보를 /var/run/utmp 파일에서 가져옴
      • [b] : 마지막 시스템 부팅 시간
    • who -b | awk '{printf $3" "$4"\n"}'
  • LVM 활성화 여부(LVM use)
    • lsblk : 현재 디바이스의 스토리지 정보를 출력
    • 모든 블럭 장치에 대한 정보를 알 수 있다.
    • lsblk | grep LVM | wc -l | awk '{if($1>0) print "yes"; else print "no"}'
  • 활성화 된 연결의 수(Connections TCP)
    • ss : Socket Statistics. 네트워크 상태 확인 (netstat로도 가능)
      • [a] : 모든 포트 확인
      • [t] : TCP 포트 확인
      • [u] : UDP 포트 확인
      • [l] : LISTEN 상태 포트 확인
      • [p] : 프로세스명을 표시
      • [n] : 호스트 / 포트 / 사용자이름을 숫자로 표시
    • ss -t | grep ESTAB | wc -l | tr -d '\n'
      • ss : socket의 상태 확인(socket statistics)
        • ss를 옵션없이 사용하면 listening socket(서버)을 제외한 연결된 소켓만을 출력한다.
        • [t] : TCP socket 표시
      • tr : 문자 변환/삭제
      • 사용법 : tr [옵션][문자열1][문자열2]
        • [d] : 문자열1에서 특정 문자를 삭제
        • [s] : 문자열2에서 반복되는 문자를 삭제
        • [t] : 문자열 1을 문자열2의 길이로 자름
        • [옵션x] : 문자열1을 문자열2로 변경
  • 서버를 사용중인 유저의 수(User log)
    • who | wc -l
  • 서버의 IPv4 주소와 MAC주소(Network)
    • hostname -I : 서버의 IPv4 주소
    • ip link | grep link/ether | awk '{print "("$2")"}' : 서버의 MAC 주소
    • ifconfig | grep ether | awk '{print "("$2")"}'로도 MAC 주소 확인 가능
  • sudo를 통해 실행된 명령의 횟수(Sudo)
    • jounalctl : systemd의 서비스 로그를 찾는데 사용되는 명령
    • _EXE=, _COMM=, _KERNELDEVICE= 를 활용해 argument를 입력해 원하는 파일경로를 찾을 수 있다.(manpage 참고)
    • journalctl _COMM=sudo : 이렇게만 입력하면 아래와 같이 sudo명령이 아닌 행까지 모두 출력된다.

      Untitled

    • journalctl _COMM=sudo | grep COMMAND : 이렇게 COMMAND로 grep을 해야 원하는 결과를 얻을 수 있다.

      Untitled

monitoring.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/bin/bash

printf "#Architecture: "
uname -a

printf "#CPU physical : "
cat /proc/cpuinfo | grep "physical id" | sort -u | wc -l

printf "#vCPU : "
cat /proc/cpuinfo | grep processor | wc -l

printf "#Memory Usage: "
free -m | grep Mem |awk '{printf"%d/%dMB (%.2f%%)\n", $3, $2, $3/$2 * 100}'

printf "#Disk Usage: "
df -BM | grep /dev/map | awk '{sum+=$3}END{print sum}' | tr -d '\n'
printf "/"
df -BM | grep /dev/map | awk '{sum+=$4}END{print sum}' | tr -d '\n'
printf "MB ("
df -BM | grep /dev/map | awk '{sum1+=$3 ; sum2+=$4 }END{printf "%d", sum1 / sum2 * 100}' | tr -d '\n'
printf "%%)\n"

printf "#CPU load: "
mpstat | grep all | awk '{printf "%.2f%%\n", 100-$NF}'

printf "#Last boot: "
who -b | awk '{printf $3" "$4"\n"}'

printf "#LVM use: "
lsblk | grep LVM | wc -l | awk '{if($1>0) print "yes"; else print "no"}'

printf "#Connections TCP : "
ss -t | grep ESTAB | wc -l | tr -d '\n'
printf " ESTABLISHED\n"

printf "#User log: "
who | wc -l

printf "#Network: IP "
hostname -I | tr -d '\n'
ip link | grep link/ether | awk '{print "("$2")"}'

printf "#Sudo : "
journalctl _COMM=sudo | grep COMMAND | wc -l | tr -d '\n'
printf " cmd\n"

exit 0

cron

특정 시간에 특정 작업을 자동으로 수행하는 스케쥴러

crontab

cron 작업을 설정하고 수행하는 프로그램 /etc/crontab 파일에 기록된 내용대로 작업을 수행

기본 사용법

1
2
3
sudo crontab -e # crontab 편집
sudo crontab -l # crontab 작업내용 확인
sudo crontab -r # crontab 전체작업 삭제

사용 예시

1
2
3
4
5
6
7
8
9
10
11
0 * * * * {실행 명령} # 매시 정각
0 0 14 * * {실행 명령} # 매일 14시
0 0 * * 1 {실행 명령} # 매주 월요일 자정
0 0 2 * * {실행 명령} # 매달 2일 자정
20,50 * * * * {실행 명령} # 매시 20분, 50분
 */15 * * * * {실행 명령} # 15분 주기로
0 3 * * * {실행 명령} # 매일 3시
30 */6 * * * {실행 명령} # 매 6시간마다(00:30, 06:30, 12:30, 18:30)
30 1-23/6 * * * {실행 명령} # 1시 반부터 매 6시간마다
0 6 * * 1-5 {실행 명령} # 평일 6시
0 7 * * 6 {실행 명령} # 토요일 7시

crontab 설정

1
2
3
sudo chmod +x monitoring.sh # 실행권한 부여
sudo crontab -e # sudo를 사용해서 crontab 파일 수정
*/10 * * * * /root/monitoring.sh | wall # 10분마다 wall 실행
  • cron 30초마다 실행하는 법
    crontab 옵션은 최소 분단위이다. 초단위로 적용하고자 한다면 sleep을 사용하면 된다.
    (default가 1분이라 앞부분 시간설정은 안해도 된다.)

    1
    
      * * * * * /root/monitoring.sh | wall && sleep 30; /root/monitoring.sh | wall
    

관련 명령어

1
2
3
4
5
sudo service cron start # 시작
sudo service cron stop # 일시적 중단(재부팅하면 시작된다.)
sudo systemctl disable cron # 재부팅시 중단(아예 중단된다.)
sudo service cron restart # 재시작
sudo service cron status # 작동확인

Ref.

https://m.blog.naver.com/snazzy79/70148845500
https://bono915.tistory.com/entry/VirtualBox-Linux-포트포워딩-설정-및-ssh-연결-방법
https://www.whatap.io/ko/blog/37/
https://zidarn87.tistory.com/137
https://www.cyberciti.biz/tips/linux-investigate-sockets-network-connections.html
https://jdm.kr/blog/2

This post is licensed under CC BY 4.0 by the author.

Born2beroot ③ 배경 지식

Born2beroot ⑤ 구현 과정 (Bonus part)