|
|
자 우리가 홈페이지를 만들어 회원 모집을 합니다.
그런데 여기서 아이디와 패스워드를 입력하여 가입을 하게 됩니다.
그럼 이게 어디에 저장이 될까요?
바로 mysql이나 ms-sql이라는 데이터베이스에 저장이 됩니다
그것만으로 시스템에 가입이 되는 것은 아닙니다.
그런데 웹호스팅 사업을 한다고 치죠...
웹에서 가입과 동시에 adduser나 useradd가 떨어져야 시스템에
가입이 되고 passwd나 shadow파일에 등록이 됩니다...
바로 호스팅 사업을 위해 알아두면 좋습니다....
좋습니다. **실제 Linux 서버에서 Apache/PHP(XAMPP) → 쉘 스크립트 → `adduser`**까지 연결되는 가장 단순한 형태로 만들어 보겠습니다.
이번 예제는 다음 3개 파일만 사용합니다.
```text
/opt/autoaccount/
├── index.php
├── create.php
└── create_user.sh
```
전체 구조는:
```text
웹 브라우저
↓
index.php
↓ POST
create.php
↓ sudo
create_user.sh
↓
adduser
↓
Linux 계정 생성
```
> 아래 예제는 **Linux에 XAMPP가 설치되어 Apache + PHP가 실행되는 경우**를 기준으로 합니다. Windows의 XAMPP에서 원격 Linux 서버의 계정을 만드는 구조라면 SSH 연결 부분이 추가로 필요합니다.
---
## 1. `index.php`
사용자가 아이디와 비밀번호를 입력하는 화면입니다.
```php
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Linux 자동 개통</title>
</head>
<body>
<h2>Linux 계정 자동 개통</h2>
<form method="post" action="create.php">
<p>
아이디<br>
<input type="text" name="username" required>
</p>
<p>
비밀번호<br>
<input type="password" name="password" required>
</p>
<p>
<input type="submit" value="계정 생성">
</p>
</form>
</body>
</html>
```
브라우저에서는 이렇게 보입니다.
```text
Linux 계정 자동 개통
아이디
[ hong ]
비밀번호
[ ******** ]
[ 계정 생성 ]
```
---
# 2. `create.php`
여기가 핵심입니다.
사용자가 입력한 값을 받아서 `create_user.sh`를 실행합니다.
```php
<?php
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$username = trim($username);
if ($username === '' || $password === '') {
exit('아이디와 비밀번호를 입력하세요.');
}
/*
* Linux 사용자 이름 검사
*
* 영문 소문자, 숫자, _, - 만 허용
*/
if (!preg_match('/^[a-z][a-z0-9_-]{2,31}$/', $username)) {
exit('사용자 아이디 형식이 잘못되었습니다.');
}
/*
* 쉘 스크립트 위치
*/
$script = '/opt/autoaccount/create_user.sh';
/*
* 비밀번호와 아이디를 쉘 스크립트의 표준입력으로 전달
*
* 비밀번호를 명령행 인자로 전달하지 않도록 합니다.
*/
$input = $username . PHP_EOL . $password . PHP_EOL;
/*
* sudo를 이용해서 쉘 스크립트 실행
*/
$command = 'sudo -n ' . escapeshellarg($script);
$descriptorspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'w')
);
$process = proc_open(
$command,
$descriptorspec,
$pipes
);
if (!is_resource($process)) {
exit('쉘 스크립트를 실행할 수 없습니다.');
}
/*
* 아이디 + 비밀번호 전달
*/
fwrite($pipes[0], $input);
fclose($pipes[0]);
/*
* 결과 읽기
*/
$output = stream_get_contents($pipes[1]);
$error = stream_get_contents($pipes[2]);
fclose($pipes[1]);
fclose($pipes[2]);
$return_code = proc_close($process);
if ($return_code === 0) {
echo "<h2>계정 생성 완료</h2>";
echo "<p>사용자 ID : " . htmlspecialchars($username) . "</p>";
echo "<p>" . nl2br(htmlspecialchars($output)) . "</p>";
} else {
echo "<h2>계정 생성 실패</h2>";
echo "<p>" . nl2br(htmlspecialchars($error)) . "</p>";
}
?>
```
중요한 부분은 이것입니다.
```php
$input = $username . PHP_EOL . $password . PHP_EOL;
```
PHP가 다음과 같이 쉘 스크립트에 전달합니다.
```text
hong
1234
```
---
# 3. `create_user.sh`
이 파일이 실제 Linux 계정을 만듭니다.
```bash
#!/bin/bash
# 아이디와 비밀번호를 입력받는다.
read USERNAME
read PASSWORD
# 아이디 형식 확인
if ! [[ "$USERNAME" =~ ^[a-z][a-z0-9_-]{2,31}$ ]]; then
echo "잘못된 사용자 이름입니다." >&2
exit 1
fi
# 이미 존재하는 사용자 확인
if id "$USERNAME" >/dev/null 2>&1; then
echo "이미 존재하는 사용자입니다." >&2
exit 2
fi
# Linux 계정 생성
/usr/sbin/useradd -m -s /bin/bash "$USERNAME"
if [ $? -ne 0 ]; then
echo "useradd 실행 실패" >&2
exit 3
fi
# 비밀번호 설정
echo "$USERNAME:$PASSWORD" | /usr/sbin/chpasswd
if [ $? -ne 0 ]; then
# 비밀번호 설정 실패 시 계정 삭제
/usr/sbin/userdel -r "$USERNAME" >/dev/null 2>&1
echo "비밀번호 설정 실패" >&2
exit 4
fi
echo "Linux 계정이 생성되었습니다."
echo "사용자 ID : $USERNAME"
exit 0
```
실행 권한을 줍니다.
```bash
sudo chmod 750 /opt/autoaccount/create_user.sh
```
---
# 4. 가장 중요한 부분 — sudo 설정
여기가 **PHP → root 권한 → useradd**를 연결하는 부분입니다.
PHP/Apache는 일반 사용자 권한으로 실행됩니다.
그런데:
```bash
useradd
```
는 일반적으로 root 권한이 필요합니다.
따라서 `sudo`를 사용합니다.
먼저 Apache를 실행하는 사용자를 확인합니다.
XAMPP라면 환경에 따라 다르지만 Linux에서 다음을 확인할 수 있습니다.
```bash
ps aux | grep httpd
```
예를 들어 Apache가 `daemon` 사용자로 실행되고 있다면:
```text
daemon
```
입니다.
그 다음 sudoers를 편집합니다.
```bash
sudo visudo
```
다음 한 줄을 추가합니다.
```text
daemon ALL=(root) NOPASSWD: /opt/autoaccount/create_user.sh
```
그러면 PHP에서:
```bash
sudo -n /opt/autoaccount/create_user.sh
```
를 실행할 수 있습니다.
**중요:** `NOPASSWD: ALL`처럼 전체 sudo 권한을 주면 안 됩니다.
오직:
```text
/opt/autoaccount/create_user.sh
```
하나만 허용하는 것입니다.
---
# 5. 디렉터리 구성
예를 들어:
```bash
sudo mkdir -p /opt/autoaccount
```
파일을 넣습니다.
```text
/opt/autoaccount/
│
├── index.php
├── create.php
└── create_user.sh
```
그리고:
```bash
sudo chown -R root:root /opt/autoaccount
```
권한을 설정합니다.
```bash
sudo chmod 755 /opt/autoaccount
sudo chmod 644 /opt/autoaccount/index.php
sudo chmod 644 /opt/autoaccount/create.php
sudo chmod 750 /opt/autoaccount/create_user.sh
```
---
# 6. XAMPP Apache에서 접근시키기
XAMPP의 웹 디렉터리를 이용한다면 예를 들어:
```text
/opt/lampp/htdocs/autoaccount/
```
로 만들 수도 있습니다.
그러면:
```text
/opt/lampp/htdocs/autoaccount/
│
├── index.php
├── create.php
└── create_user.sh
```
브라우저에서:
```text
http://localhost/autoaccount/
```
로 접속합니다.
다만 **쉘 스크립트는 웹에서 직접 다운로드되지 않도록** 권한과 웹 접근 경로를 별도로 관리하는 것을 권합니다. 더 안전한 구조는:
```text
/opt/lampp/htdocs/autoaccount/
├── index.php
└── create.php
/opt/autoaccount/
└── create_user.sh
```
입니다.
즉 **PHP는 웹 디렉터리에 있지만 `create_user.sh`는 웹 디렉터리 밖에 둡니다.**
---
# 7. 실제 동작
사용자가 브라우저에서:
```text
아이디 : test01
비밀번호 : 123456
```
를 입력하면,
```text
index.php
│
│ POST
▼
create.php
│
│ sudo -n
▼
create_user.sh
│
├── useradd -m test01
│
└── chpasswd
│
▼
Linux 계정 생성
```
그리고 Linux에서 확인하면:
```bash
id test01
```
결과:
```text
uid=1001(test01) gid=1001(test01) groups=1001(test01)
```
로그인 쉘도:
```bash
cat /etc/passwd | grep test01
```
로 확인할 수 있습니다.
---
## 중요한 점 하나
이 구조는 **"자동 개통 시스템의 핵심 원리"를 그대로 보여주는 예제**입니다.
즉 예전에 말씀하신
```text
HTML
↓
PHP
↓
Shell Script
↓
adduser
↓
Linux 계정
```
이라는 구조를 실제로 구현한 것입니다.
다만 실제 호스팅 업체처럼 인터넷에 공개하려면 다음 단계에서 **계정 중복 처리, 비밀번호 정책, CSRF 방어, 로그인/관리자 인증, 명령 실행 제한, 홈 디렉터리 생성, quota, Apache/Nginx VirtualHost 자동 생성, DNS, DB에 개통정보 저장** 등을 추가해야 합니다.
특히 **PHP가 `sudo`로 실행할 수 있는 명령을 `create_user.sh` 하나로 제한하는 것**이 이 시스템에서 가장 중요한 보안 구조입니다.
