코딩마을방범대

자바를 통해 서버의 sh 실행 제어하기 본문

💡 백엔드/Java

자바를 통해 서버의 sh 실행 제어하기

신짱구 5세 2024. 1. 19. 11:31

 

 

 

자바를 이용해 ssh 에 접속하여 command를 수행할 수 있다.

더불어 파일 업로드, 다운로드도 가능하다!

이번 포스팅에선 ssh에 접속해서 sh파일을 실행하는 로직을 구상해볼 것이다!

 

 


 

 

사용하기

 

1. 같은 서버 내에서 SH파일만 실행하기

 

다른 서버로는 접근이 불가하고, war 를 구동시킨 현재 서버에만 접근이 가능한 로직이다.

아래 로직은 프로세스 실행 후 출력값을 반환한다.

public String serviceShControl(String path, String status) throws IOException {
	// path엔 "/home/shin/service.sh" 등의 sh 파일 위치를, 
	// status는 start 등의 sh에 존재하는 명령어를 적어주면 된다.
	ProcessBuilder pb = new ProcessBuilder(path, status);

	Process process = pb.start();

	StringBuilder output = new StringBuilder();
	BufferedReader reader = new BufferedReader(
			new InputStreamReader(process.getInputStream()));

	String line;
	while ((line = reader.readLine()) != null) {
		output.append(line);
	}
	return output.toString()
}

 

 

 

 

 


 

 

 

 

 

2. ssh 서비스를 이용해서 직접 명령문으로 실행하기

 

JSch 를 사용하기 위해 아래 의존성을 추가해준다.

dependencies {
	implementation 'com.jcraft:jsch:0.1.55'
}
JSch
SSH (Secure Shell) 프로토콜을 사용할 수 있게 해주는 순수 자바 라이브러리

 

 

첫 번째로, getSession 메소드를 실행해서 ssh에 연결할 세션을 받아온다.

 

두 번째로, serviceControl  메소드를 실행해서 명령문을 실행해준다.

 

cd 를 통해 sh 파일이 존재하는 위치로 이동하지 않을 경우 ssh 에 접속했을 때의 home 위치에서 실행시키게 되어,

log 등이 home 위치에 쌓이게 된다.

 

public Session getSession(String host, String id, String password) throws JSchException {
	JSch jsch = new JSch();
	Session session = jsch.getSession(id, host, 22);
	session.setPassword(password);

	java.util.Properties config = new java.util.Properties();
    
    // no = JSch를 통한 SSH 연결 시 호스트 키 검사를 무시하고, 어떤 호스트 키라도 수락하도록 설정하는 것을 의미
	config.put("StrictHostKeyChecking", "no");
	session.setConfig(config);

	session.connect();
	return session;
}

public String serviceControl(Session session, String path, String shFileName, String status) throws Exception {
	// 'exec' 채널은 주로 원격 서버에서 단일 명령어를 실행할 때 사용
	ChannelExec channel = (ChannelExec) session.openChannel("exec");

	String command = "cd " + path;
	command += " && ./" + shFileName + " " + status;

	channel.setCommand(command);

	// 원격 서버로 부터 데이터를 입력받지 않겠다는 의미
	channel.setInputStream(null);
    
	// 에러 발생 시, 에러 메시지는 System.err에 출력됨
	// 에러 출력 스트림을 저장
	ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
	channel.setErrStream(errorStream);
	// 명령어 실행 결과를 저장
	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	channel.setOutputStream(outputStream);

	channel.connect();

	while (channel.isConnected()) {
		Thread.sleep(100);
	}

	String errorMsg = new String(errorStream.toByteArray());
	String resultMsg = new String(outputStream.toByteArray());
	if (!errorMsg.trim().isEmpty()) {
		log.error("Error Message : {}", errorMsg);
        return errorMsg;
	}

	channel.disconnect();
	session.disconnect();

	return resultMsg;
}

 

 

 


 

 

 

💡 명령어가 제대로 실행됐는지 확인하는 방법

 

아래 명령어 두 개를 통해 SSH 접속 로그를 확인할 수 있다.

sudo tail -1000f /var/log/auth.log

sudo tail -1000f /var/log/secure

 

 

 

 

 

 

 


 

 

 

 

 

 

 

오류 발생

 

 

1. Permission denied

 

sudo 권한으로 실행했지만 발생하는 퍼미션 디나인 문제는 대부분이 파일 권한의 문제이다.

아래 명령어를 통해 sh 파일 등의 파일 권한을 변경해주면 된다.

 

sudo chmod 755 파일명

 

 

 

 

 


 

 

 

 

 

2. This service allows sftp connections only

 

2번 방법으로 실행 후 아래와 같은 리턴 메시지를 받았다!

 

This service allows sftp connections only;/n

 

ssh 서버가 SFTP(Secure File Transfer Protocol)를 통한 연결만을 허용하고, 다른 연결 방식(예를 들어, 일반 FTP, HTTP 등)은 허용하지 않는다는 것을 의미한다.

 

따라서 서버의 세팅 정보를 변경해줘야 한다.

 

파일 전송 프로토콜 종류 설명
FTP (File Transfer Protocol) 가장 기본적인 파일 전송 방식이지만, 암호화되지 않아 보안에 취약
SFTP (SSH File Transfer Protocol) SSH를 통해 파일을 전송하며, 모든 전송이 암호화되어 보안 강화
FTPS (FTP over SSL/TLS) FTP에 SSL 또는 TLS 보안 계층을 추가한 것으로, 데이터 전송 시 보안을 제공

 

 

 

 

1. ssh conf 파일 수정

sudo vi /etc/ssh/sshd_config

 

위 명령어를 통해 ssh conf 파일을 실행시켜 아래로 스크롤해보면 아래 부분을 확인할 수 있다.

여기서 ForceCommand internal-sftp 부분을 주석 처리해줘야한다. (# 추가)

 

 

 

 

2. 저장 완료 후 시스템 재실행

sudo systemctl restart sshd

 

 

 

 

 

 


 

 

 

 

 

3. fatal: bad ownership or modes for chroot directory component "/home/사용자명/"

 

2번의 방법으로 접속하였을 때 아래 명령어를 실행해 로그를 확인해보니 오류가 발생한 것을 확인할 수 있었다.

 

sudo tail -1000f /var/log/auth.log
Jan 24 08:13:17 ip-10-0-18-144 systemd-logind[375]: New session 217 of user 사용자명.
Jan 24 08:13:18 ip-10-0-18-144 sshd[666954]: fatal: bad ownership or modes for chroot directory component "/home/사용자명/"
Jan 24 08:13:18 ip-10-0-18-144 sshd[666909]: pam_unix(sshd:session): session closed for user 사용자명
Jan 24 08:13:18 ip-10-0-18-144 systemd-logind[375]: Session 217 logged out. Waiting for processes to exit.
Jan 24 08:13:18 ip-10-0-18-144 systemd-logind[375]: Removed session 217.

 

 

위 오류는 사용자의 홈디렉토리가 root의 소유가 아닌 다른 사용자의 소유로 설정되어 오류가 발생하는 것이다.

홈디렉토리 내의 폴더나 파일은 사용자가 권한을 가질 수 있지만, 홈디렉토리는 root 소유여야 하고, 이 디렉토리는 다른 사용자에게 쓰기 권한이 없어야 한다.

 

아래 명령어를 실행해 디렉토리의 소유자를 root로 변경하고, 그룹 사용자와 다른 사용자에게 쓰기 권한을 제거한다.

 

sudo chown root:root /home/사용자명
sudo chmod go-w /home/사용자명

 

 

 

SMALL