Skip to content
This repository has been archived by the owner on Sep 12, 2018. It is now read-only.

Commit

Permalink
Add doc, ssh-daemon.md
Browse files Browse the repository at this point in the history
  • Loading branch information
KOR-Believer authored and oh4851 committed Mar 17, 2015
1 parent e71e0ad commit 4249a85
Showing 1 changed file with 149 additions and 0 deletions.
149 changes: 149 additions & 0 deletions docs/ko/technical/ssh-daemon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
이 문서는 SSH 서버 데몬의 내부 동작 및 사용 방법을 설명한다.


SSH서버 데몬
--------------
Yobi의 SSH서버 데몬은 Git서비스를 SSH프로토콜로 이용할 수 있게 한다.
이를 위해 다음과 같은 기능을 지원한다.
- 사용자가 SSH키를 통해 인증할 수 있도록 한다.
- SSH키는 공개키-개인키로 이루어진 키쌍으로 인증 시 passphrase를 입력한다.
- 인증 된 사용자가 git-upload-pack, git-receive-pack명령을 기반으로 동작하는 clone, push, pull 등을 사용할 수 있도록 한다.
- Git저장소에 대한 권한관리는 HTTP방식과 동일하다. (인증을 성공해도 해당 저장소에 권한이 없으면 거절된다)
- 사용자가 git-upload-pack, git-receive-pack명령 이외의 명령을 서버에 전달할 수 없도록 한다.
- 사용자가 SSH를 통해 서버의 쉘에 직접 접근 할 수 없도록 한다.


데몬의 초기화 과정
--------------------
SshDaemon은 서버 실행 후 Global객체가 생성 될 때 Global객체 내부의 멤버 인스턴스로 생성된다.
Global객체의 onStart메서드가 실행 될 때, 이미 생성 되어 있는 SshDaemon인스턴스의 start메서드를 호출하여 데몬을 초기화하고 실행한다.
SSH가 사용하는 포트는 conf/application.conf의 ssh.port 값을 사용하되, 값이 정의되어있지 않다면 22000번을 사용한다.
데몬이 시작되면 사용자는 SSH프로토콜을 통해 Git저장소에 접근이 가능해 진다.
만약 데몬 시작에 실패했다면 Yobi의 프로젝트 홈 화면에서 SSH주소 복사 기능이 노출되지 않는다.


SSH서버의 SSH키 생성
----------------------
SshDaemon이 실행된 후 사용자가 최초로 SSH로 접근을 시도하면 `PEMGeneratorHostKeyProvider`를 통해 서버의 호스트 키(Host Key)가 생성된다.
`PEMGeneratorHostKeyProvider`는 MINA-SSHD에 구현되어 있는 기능으로 SSH 호스트 키(Host Key)를 생성한다.
이 객체의 생성자에는 호스트 키(Host Key)의 알고리즘, 키 사이즈 및 저장 할 디렉터리를 지정 할 수 있다.
생성된 호스트 키(Host Key)는 Yobi서버의 홈 디렉터리, 정확히는 자바 시스템 프로퍼티 `user.dir`가 가리키는 경로에 `yobihostkey.pem`파일로 저장된다.
PEM은 키 파일을 인코딩하는 방법으로, PEM 파일은 PEM Header, base64형식으로 인코딩 된 키 데이터, PEM Footer로 이루어져 있다.
Yobi의 호스트 키(Host Key)는 RSA알고리즘을 사용하며 저장되는 키 파일의 형식은 다음과 같다.
```
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAhTYBJi8JCu9qgVltGHErfrwQfQ2c7XvgrwZ6Fn23MpkSC8ZT
[...]
mlv58VeP6w83HM95Ux7ODZkhMlD+kXx+ZfQEzX+FCqgSVO/i5YLO
-----END RSA PRIVATE KEY-----
```
호스트 키(Host Key)가 한번 생성되면 다시 생성하지 않고 동일한 키를 사용하게 된다.
만약 서버의 키 파일이 변경됐다면 과거에 해당 서버에 접속했던 사용자는 다음과 같은 경고 메시지와 함께 접속을 거절당한다.
```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
[...]
Please contact your system administrator.
Add correct host key in ~/.ssh/known_hosts to get rid of this message.
Offending RSA key in ~/.ssh/known_hosts:1
RSA host key for localhost has changed and you have requested strict checking.
Host key verification failed.
```
이 경우 사용자는 ~/.ssh/known_hosts파일을 수정해야 접속이 가능하다.
- known_hosts파일은 사용자가 SSH로 접속을 시도했던 서버들의 공개키(Public Key) 정보를 담고 있다.

**known_hosts파일 수정 방법**
```
$ ssh-keygen -R "hostname or ip address"
위 명령은 known_hosts에서 hostname이나 ip address에 해당하는 공개키 정보를 삭제한다.
이 후 다시 SSH로 접속을 시도하면 다음과 같은 메시지와 함께 known_hosts에 새로운 키를 등록한다.
The authenticity of host 'localhost (127.0.0.1)' can't be established.
RSA key fingerprint is [...].
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
```


SSH주소 형식
--------------
Yobi에서 SSH를 통해 Git저장소에 접근할 때는 다음과 같이 ssh://로 시작하는 url을 사용한다.
```
ssh://username@server:port/owner/project
```
- **username** - SSH접근에 사용하는 계정명이다. 계정명은 "yobi"로 고정해 사용한다. 다른 계정명은 접근이 거절된다.
- **server** - SSH로 접근할 서버의 주소다. hostname(domain)이나 ip address를 사용한다.
- **:port** - SSH로 접근할 포트 번호다. 22번(well-known)포트를 사용할 경우 생략 가능하다.
- **owner** - 프로젝트(Git저장소)의 소유자명이다. 저장소의 소유자가 개인일 경우 개인의 계정명, 그룹일 경우 그룹명이된다.
- **project** - 프로젝트(Git저장소)의 이름이다.

따라서 항상 앞 부분은 `ssh://yobi@`로 시작하고 뒷 부분은 접근하려는 서버, 포트번호, 소유자, 프로젝트명에 따라 변할 수 있다.

**사용 예시**
- ex1) ssh://yobi@localhost:2200/group1/firstproject
- ex2) ssh://yobi@yobi.test.com/person1/myprivateproject
- ex3) ssh://yobi@127.0.0.1:22/person2/localproject


사용자의 인증 과정 [1]
------------------------
SSH사용자가 접근을 시도하면 데몬은 SshPublicKeyAuth를 통해 사용자가 제공한 공개키(Public Key)를 확인한다.
먼저, 사용자가 제공한 공개키와 일치하는 공개키가 데이터베이스에 존재하지 않을 경우는 다음과 같이 처리한다.
- 1. 서버는 클라이언트에게 실패했다는 정보 `SshConstants.SSH_MSG_USERAUTH_FAILURE (51)`를 담은 메시지를 전달한다.
- 2. 클라이언트는 이 메시지를 바탕으로 사용자의 터미널에 `Permission denied`를 출력하고 연결을 종료한다.

다음으로, 공개키가 일치하는 경우에는 다음과 같이 처리한다.
- 1. 서버는 클라이언트에게 공개키가 유효하다는 정보 `SshConstants.USERAUTH_PK_OK (60)`를 담은 메시지를 전달하고 응답을 기다린다.
- 2. 클라이언트는 공개키와 매치되는 개인키(Private Key)의 passphrase를 사용자에게 입력하도록 요구한다.
- 3-1. 만약, 사용자가 passphrase를 3회까지 틀릴 경우 더 이상 인증이 진행되지 않고 종료된다.
- 3-2. 반대로 passphrase를 정상적으로 입력했다면 클라이언트는 공개키-개인키 쌍이 성립한다는 정보(true)와, 암호화 알고리즘 방식을 서버에 전달한다.
- 4. 서버는 이를 바탕으로 응답확인 정보 `SshConstants.SSH_MSG_USERAUTH_REQUSET (50)`와 인증성공 정보 `SshConstants.SSH_MSG_USERAUTH_SUCCESS (52)`를 포함하는 메시지를 클라이언트에게 전달한다.


SSH Daemon의 요청 처리
------------------------
Yobi의 SSH데몬은 Git서비스를 위한 데몬이므로 Git저장소에 접근하는 목적 이외의 SSH요청은 제한되어야 한다.

SSH는 체널을 개설하고자 하는 측에서 Channel type을 명시하도록 되어 있다.[2]
그러므로 MINA-SSHD는 사용자의 요청이 도착하면 사용자의 요청에 명시된 Channel type을 확인한다.[3]

명시된 Channel type이 'shell'인 경우, 쉘 접속 요청으로 판단 SshShellFactory에서 처리된다.
Yobi의 SshShellFactory는 사용자가 쉘 접속을 시도 할 경우 쉘 사용이 불가능함을 안내하며 아래와 같이 출력된다.
```
$ ssh yobi@domain
Hi user1! You've successfully authenticated, but [Yobi] does not provide shell access.
```

명시된 Channel type이 'exec'인 경우 SshCommandFactory로 처리된다.
Git의 clone, push, pull 등의 명령은, 내부적으로 git-upload-pack이나 git-receive-pack명령으로 변환된다.
만약 SSH프로토콜을 통해 git clone명령이 실행되면 아래와 같이 동작한다.[4]
```
$git clone ssh://yobi@domain/owner/project
|
v
$ssh yobi@domain "git-upload-pack '/owner/project'"
```
Yobi의 SshCommandFactory는 git-upload-pack과 git-receive-pack명령을 처리하도록 작성되어 있다.
만약 이 두가지 이외의 명령이 전송된다면 UnknownCommand로 예외 처리한다.


사용자의 공개키 관리
----------------------
Yobi의 사용자는 설정 페이지의 SSH키 설정 메뉴를 통해 본인의 공개키를 관리 할 수 있다.
공개키는 사용자가 작성한 키 파일의 설명과 함께 등록이 가능하다.
등록된 키는 최초 등록일, 마지막 사용 날짜가 출력되며 만약 공개키가 도용되어 인증에 실패한 요청도 사용한 날짜로 간주하여 업데이트한다.
등록된 키는 사용자의 판단에 따라 삭제가 가능하다.


참고문헌
----------
[1] **rfc4252**(The Secure Shell (SSH) Authentication Protocol) - http://www.ietf.org/rfc/rfc4252.txt
[2] **rfc4254**(Opening a Channel) - http://tools.ietf.org/html/rfc4254#section-5
[3] https://github.com/apache/mina-sshd/blob/sshd-0.13.0/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java#L278
[4] **Packfile transfer protocols**(SSH Transport) - https://github.com/git/git/blob/master/Documentation/technical/pack-protocol.txt

0 comments on commit 4249a85

Please sign in to comment.