stunnel에서 SSH over SSL (forward proxy를 통해 가능)

SSH하고 싶은데 할 수없는, 그런 때



방화벽으로 제한되는 등의 이유로 외부로 ssh 할 수 없는 경우가 있다.
직접 통신은 NG로 HTTP 프록시 서버(forward proxy) 경유의 통신 밖에 통과할 경우도 있다.

많은 환경에서는 HTTPS를 통해서 의도에 tcp/443의 SSL은 통과한다.
그 경우는 stunnel 를 사용하면 SSL 위에서 SSH 할 수 있다. (forward proxy를 통해서도 가능)

주의점



SSH는 TCP 핸드 셰이크 후에 서버 측에서 시작하는 프로토콜이므로 스캔되면 그 앞에서 SSH를 기다리고 있음을 즉시 알 수 있습니다.

여기에서는 오레올레 CA라이크인 증명서와 그 아래에 서버 증명서·클라이언트 증명서를 준비해, 클라이언트 증명서 검증을 필수로 하는 것으로 스캔해도 보통의 SSL인 것 밖에 모른다.
(검증 결과가 NG이면 SSL 레이어에서 오류가 발생하여 sshd에 전달되지 않음)

인증서의 revoke나 CRL 등, 괜찮은 CA의 작업은 취급하지 않는다.

환경



CentOS에서 server로 stunnel을 이동하고,
Cygwin에서 client로 stunnel을 이동하여 CentOS로 SSH합니다.
stunnel 사이에 프록시가 있어도 문제 없다.
┃ クライアントマシン(Cygwin) ┃          ┃   サーバマシン (CentOS)      ┃
┃ ssh =(SSH)=> stunnel:9999 ===(SSL)==> stunnel:443 =(SSH)=> sshd:22 ┃



설치



CentOS라면 EPEL 리포지토리에서 yum으로 설치할 수 있고,
Cygwin은 setup.exe로 설치할 수 있습니다.

stunnel 설정



인증서 등 준비


CA(Root) ┳ サーバ証明書
         ┗ クライアント証明書

중간 CA 없음 2계층만.
KeyUsage라든지, 그 외 세세한 것은 말하지 않는다.
$# CA 証明書
$ openssl genrsa -aes256 -out ca.key 2048
$ openssl req -new -key ca.key -out ca.csr -subj "/CN=TestCA"
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 7300

$# サーバ証明書 (サーバ証明書の CN は検証していないようだが、FQDN にしておく)
$ openssl genrsa -aes256 -out server.key 2048
$ openssl req -new -key server.key -out server.csr -subj "/CN=example.com"
$ openssl x509 -req -CA ca.crt -CAkey ca.key -set_serial 1 -in server.csr -out server.crt -days 3650

$# クライアント証明書
$ openssl genrsa -aes256 -out client.key 2048
$ openssl req -new -key client.key -out client.csr -subj "/CN=TestClient"
$ openssl x509 -req -CA ca.crt -CAkey ca.key -set_serial 2 -in client.csr -out client.crt -days 3650


서버 설정(CentOS)



iptables 를 설정하고 있는 경우는 tcp/443 을 받아들이도록(듯이) 할 필요가 있다.
(이 방법으로 SSH 하는 경우는) tcp/22 는 localhost 로부터만 허가하면 되고, 외부로부터 받아들일 필요는 없다.

yum 설치해도 기동 스크립트는 부속되어 있지 않으므로, 필요하다면 스스로 쓴다.
## 事前に用意した CA証明書, サーバ証明書とその秘密鍵を設置
## 秘密鍵は mode を 400 にしておく
# ls /etc/stunnel
ca.crt  server.crt  server.key

## パスフレーズは解除しておく
# openssl rsa -in server.key -out server-nopass.key

## 設定ファイルを作成
# vi /etc/stunnel/stunnel.conf
cert = /etc/stunnel/server.crt
key = /etc/stunnel/server-nopass.key
sslVersion = TLSv1
chroot = /var/run/stunnel
setuid = nobody
setgid = nobody
pid = /stunnel.pid
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
compression = zlib
verify = 2
CAfile = /etc/stunnel/ca.crt
debug = authpriv.info
[ssh over ssl]
accept  = 443
connect = 22
TIMEOUTclose = 0

## chroot の準備
# mkdir /var/run/stunnel
# chown nobody:nobody /var/run/stunnel

## stunnel を起動
# stunnel /etc/stunnel/stunnel.conf

클라이언트 설정(Cygwin)


$# 事前に用意した CA証明書, クライアント証明書とその秘密鍵を設置
$# 秘密鍵は mode を 400 にしておく
$ ls /etc/stunnel
ca.crt  client.crt client.key

$# 設定ファイルを作成
$ vi /etc/stunnel/stunnel.conf
debug = info
output = /var/log/stunnel.log
cert = /etc/stunnel/client.crt
key = /etc/stunnel/client.key
verify = 2
CAfile = /etc/stunnel/ca.crt
options = NO_SSLv2
[ssh_over_ssl]
client = yes
accept = 9999
connect = example.com:443

forward proxy를 통과하는 경우



proxy가 httpproxy라는 이름으로 액세스 할 수 있고 8888을 Listen하고 있다고 가정합니다.
[ssh_over_ssl]의 부분을 다음과 같이 한다
[ssh_over_ssl]
client = yes
accept = 9999
protocol = connect
protocolHost = example.com:443
connect = httpproxy:8888

SSH over SSL로 로그인


$ stunnel /etc/stunnel/stunnel.conf
$ ssh -p 9999 localhost

좀 더 동작 테스트



연결되었기 때문에 끝나고 하면 아픈 눈을 볼지도 모른다.

증명서의 준비로 한 것을 다른 파일명으로 한가지 실시해,
다른 체인 CA, 서버, 클라이언트 인증서를 만듭니다.

stunnel 서버와 클라이언트에는 별도의 체인의 증명서를 설정해 연결되어 있지 않은 것을 확인한다.

Wireshark의 화면 캡처는 192.168.37.7이 클라이언트로 192.168.37.250이 서버.

클라이언트 인증 확인


  • 적절한 클라이언트 인증서로 연결할 수 없는지 확인

  • 이전 openssl s_server 에서 verify 옵션 붙여도 절단해 주지 않았던 추억이 있으므로, 절단까지 확인한다.



    서버측이 Fatal인 Alert Protocol을 던지고 RST도 던지고 있다.
    stunnel.conf에서 verify를 주석 처리하면 인증 할 수 없어도 연결되었습니다.

    서버 인증 확인


  • 적절한 서버 인증서라면 연결하지 마십시오.



  • RST는 서버 측이 먼저였지만 Fatal Alert Protocol은 클라이언트에서 던지고 있기 때문에 아마 괜찮습니다.
    stunnel.conf에서 verify를 주석 처리하면 인증 할 수 없어도 연결되었습니다.

    그건 그렇고 ...



    패킷을보고 기억했지만 핸드 셰이크 중에 루트 CA 인증서도 보내는 것이 일반적입니다.
    세상 일반 서버에서도 그러한 거동을 잘 볼 수 있다고 생각한다.

    클라이언트는 수신해도 그것을 신뢰해서는 안 되고, 송신하는 것 자체가 쓸데없는 생각이 들지만, 무엇인가 송신해야 할 이유가 있는 것일까.

    좋은 웹페이지 즐겨찾기