[Troubleshooting] - Symbolic link 로 인한 Command not found

청주는사과아님·2025년 1월 19일
0

Troubleshooting

목록 보기
5/7
post-thumbnail

최근 home-server 를 구축하던 중 symbolic link 의 잘못된 이해로 인한 트러블 슈팅을 경험하였고, 이를 기록하고 공유하고자 포스팅을 작성합니다.


🔖 배경 설명

구축하는 home-server 는 테스트용 API 서버 로 추후 프로젝트 진행을 위해 구축하는 서버입니다.

home-server 를 통해 다수의 프로젝트를 진행하고자 저는 현재 생성된 유저를 간단히 보여주는 shell script 를 만들었고, 이는 다음과 같습니다.

  • list-users-with-group.sh
#!/bin/bash

# Header for the output with extended widths
printf "%-25s %-25s %-10s %-10s\n" "USERNAME" "PRIORITY GROUP" "UID" "GID"

# Iterate through each user in the /etc/passwd file
while IFS=: read -r username _ uid gid _ _ _; do
  # Ignore system accounts with UID less than 1000
  if [ "$uid" -ge 1000 ]; then
    # Get the primary group name for the user
    group=$(getent group "$gid" | cut -d: -f1)

    # If the group name exists, print user, group, uid, and gid
    if [ -n "$group" ]; then
      printf "%-25s %-25s %-10s %-10s\n" "$username" "$group" "$uid" "$gid"
    fi
  fi
done < /etc/passwd
$ ./list-users-with-group.sh

USERNAME                  PRIORITY GROUP            UID        GID
nobody                    nogroup                   65534      65534
cheongju-admin            cheongju-admin            1000       1003
test-user-1               test-user-1               1001       1004
test-user-2               test-user-2               1002       1006

그리고 이와 연관된 심볼릭 링크를 /usr/bin 에 생성해, 다른 유저들도 실행 가능하도록 만들고자 하였습니다.

# /usr/bin 에 list-users-with-group.sh 와 연관된 심볼릭 파일을 생성
$ sudo ln -s /[생략]/list-users-with-group.sh /usr/bin/list-users

# 권한 설정
$ chmod o+rx list-users-with-group.sh && cd /usr/bin
$ sudo chmod o+rx list-users
# cheongju-admin 계정에서 확인
cheongju-admin@cheongju-raspi:~$ printf "command ---> $(which  list-users)\n\n" && list-users
# 잘 실행되는 모습
command ---> /usr/bin/list-users

USERNAME                  PRIORITY GROUP            UID        GID
nobody                    nogroup                   65534      65534
cheongju-admin            cheongju-admin            1000       1003
test-user-1               test-user-1               1001       1004
test-user-2               test-user-2               1002       1006

❗️ 문제 발견

list-users 가 작동하는 것으로 올바른 구성을 맞쳤다 생각했으나, 실제 다른 user 에서 확인하니 그렇지 않았습니다.

# test-user-1 에서 확인
test-user-1@cheongju-raspi:~$ list-users
list-users: command not found

분명히 /usr/bin/list-users 가 존재하고 list-users 의 권한도 풀어놨는데, 무엇이 문제였을까요?


📌 문제 원인

그 이유는 심볼릭 링크의 원본이 접근할 수 없는 곳에 위치해 있기 때문입니다.

사용자가 list-users 처럼 심볼릭 링크로 등록된 명령어를 실행할 때 다음처럼 작동합니다.

  1. 유저의 $PATH 에서 list-users 와 일치하는 목록을 탐색합니다.
  2. list-users 는 심볼릭 링크이므로, 그 원본 주소를 확인합니다.
  3. 원본 주소를 토대로 원본 스크립트를 실행합니다.

이 때 심볼릭 링크의 원본 주소에 접근할 수 없어 Command not found 가 발생합니다.

즉, 쉘 스크립트를 심볼릭 링크 명령어로 등록하기 위해선, 해당 파일까지 모든 경로가 접근 가능해야 합니다.

제가 등록한 list-users 명령어는 아래처럼 권한이 설정되어 있습니다.

$ namei -l list-users 
f: list-users
# 심볼릭 링크 자체
lrwxrwxrwx root           root           list-users -> /home/cheongju-admin/shell-scripts/show-info/list-users-with-group.sh

# 원본 파일의 재귀적 권한
drwxr-xr-x root           root             /
drwxr-xr-x root           root             home
drwxr-x--- cheongju-admin cheongju-admin   cheongju-admin
drwxr-x--- cheongju-admin cheongju-admin   shell-scripts
drwxr-x--- cheongju-admin cheongju-admin   show-info
-rwxr-xr-x cheongju-admin cheongju-admin   list-users-with-group.sh

list-users-with-group.sh 파일 자체는 실행 가능토록 만들었지만, 이를 찾아갈 수 없도록 만든 것입니다.

때문에 이를 해결하려면 list-users-with-group.sh 까지의 경로, cheongju-admin, shell-scripts, show-info 디렉토리를 외부 유저가 접근 가능토록 구성해야 합니다.

실제로 /usr/bin 에 존재하는 다른 심볼릭 링크 명령어를 보면 모두 완전히 접근 가능한 것을 볼 수 있습니다.

# 원본이 다른 곳에 존재하는 심볼릭 명령어 조회
$ ls -l /usr/bin | grep '\-> /' -m 5
lrwxrwxrwx 1 root root          25 Jan 13 12:47 animate -> /etc/alternatives/animate
lrwxrwxrwx 1 root root          29 Jan 13 12:47 animate-im6 -> /etc/alternatives/animate-im6
lrwxrwxrwx 1 root root          21 Sep 11 23:23 awk -> /etc/alternatives/awk
lrwxrwxrwx 1 root root          25 Jan 13 12:47 compare -> /etc/alternatives/compare
lrwxrwxrwx 1 root root          29 Jan 13 12:47 compare-im6 -> /etc/alternatives/compare-im6
# 재귀적 권환 조회
$ namei -l compare
# 모두 others 의 권한이 r-x 이상인 것을 확인 가능
f: compare
lrwxrwxrwx root root compare -> /etc/alternatives/compare
drwxr-xr-x root root   /
drwxr-xr-x root root   etc
drwxr-xr-x root root   alternatives
lrwxrwxrwx root root   compare -> /usr/bin/compare-im6.q16
drwxr-xr-x root root     /
drwxr-xr-x root root     usr
drwxr-xr-x root root     bin
-rwxr-xr-x root root     compare-im6.q16

✅ 문제 해결

이를 해결하는 방법은 크게 3 가지가 있습니다.

첫째로 이전에 언급했듯, list-users-with-group.sh 까지의 모든 경로를 외부 유저가 접근 가능토록 만드는 것입니다.

# 재귀적으로 chmod 실행
$ chmod o+rx -R /home/cheongju-admin

# 권환 확인
$ namei -l /usr/bin/list-users
f: /usr/bin/list-users
drwxr-xr-x root           root           /
drwxr-xr-x root           root           usr
drwxr-xr-x root           root           bin
lrwxrwxrwx root           root           list-users -> /home/cheongju-admin/shell-scripts/show-info/list-users-with-group.sh
drwxr-xr-x root           root             /
drwxr-xr-x root           root             home
drwxr-xr-x cheongju-admin cheongju-admin   cheongju-admin
drwxr-xr-x cheongju-admin cheongju-admin   shell-scripts
drwxr-xr-x cheongju-admin cheongju-admin   show-info
-rwxr-xr-x cheongju-admin cheongju-admin   list-users-with-group.sh

하지만 이는 새로운 스크립트를 만들때 마다 권한설정을 진행해야 하며, 무엇보다 유저의 home 디렉토리 권한을 개방 하는 단점이 존재합니다.
cheongju-admin 이 일반 계정이면 상관없을지 몰라도 저의 서버의 관리자 계정이기 때문에 이는 매우 적절치 못한 방법이라 판단했습니다.

둘째로 작성한 쉘 스크립트 자체를 /usr/bin 에 옮겨두는 것입니다.

# 파일 복사
$ sudo cp list-users-with-group.sh /usr/bin/list-users

# 권한 설정
$ sudo chmod o+rx /usr/bin/list-users

하지만 이는 스크립트를 수정할 때마다 cp 해야하므로 귀찮고 번거롭다 판다했습니다.

그래서 저는 세번째 방법으로 public 한 home 디렉토리를 구성 하는 것을 추천드립니다.

# 커스텀 쉘 스크립트 전용 디렉토리 구성
$ sudo mkdir /home/custom-shell-scripts

# 권한 open
$ sudo chmod o+rwx /home/custom-shell-scripts

# 파일 이동
$ mv list-users-with-group.sh /home/custom-shell-scripts/

# 심볼릭 명령어 생성
$ sudo ln -s /home/custom-shell-scripts/list-users-with-group.sh /usr/bin/list-users
# 재귀적 권한 조회
$ namei -l /usr/bin/list-users
f: /usr/bin/list-users
drwxr-xr-x root           root           /
drwxr-xr-x root           root           usr
drwxr-xr-x root           root           bin
lrwxrwxrwx root           root           list-users -> /home/custom-shell-scripts/list-users-with-group.sh
drwxr-xr-x root           root             /
drwxr-xr-x root           root             home
drwxr-xrwx root           root             custom-shell-scripts
-rwxr-xr-x cheongju-admin cheongju-admin   list-users-with-group.sh

/home/custom-shell-scripts 를 오직 쉘 스크립 전용 디렉토리로 구성함으로서 앞서 말한 단점을 모두 극복할 수 있습니다.

민감한 admin 디렉토리 권한을 열지 않으며, 스크립을 수정할 때마다 cp 하는 번거로움도 사라졌습니다.

또한 custom-shell-scripts 디렉토리의 소유 그룹 을 따로 지정해 쉘 스크립 담당자 를 부여할 수도 있게 되었습니다.

이제 처음으로 돌아가 test-user-1 에서 list-users 를 실행하면 아래처럼 정상 작동함을 확인할 수 있습니다.

$ test-user-1@cheongju-raspi:~$ printf "command ---> $(which  list-users)\n\n" && list-users
command ---> /usr/bin/list-users

USERNAME                  PRIORITY GROUP            UID        GID
nobody                    nogroup                   65534      65534
cheongju-admin            cheongju-admin            1000       1003
test-user-1               test-user-1               1001       1004
test-user-2               test-user-2               1002       1006

처음에는 심볼릭 명령어의 오해로부터 시작되었지만, 문제를 해결하고 개선하며 어떻게 구성하는 것이 linux 스러운지 느낄 수 있는 경험이었습니다.

앞으로도 home-server 를 구축하며 더욱 다양한 트러블 슈팅으로 뵙겠습니다.


profile
나 같은게... 취준?!

0개의 댓글