Post

HAproxy ssl key log

목차


개요

HAProxy에서 sslkeylog를 설정하지 않으니 암호화된 TLS 패킷이 제대로 흐르는지 분석이 어려웠다. 이를 위해 HAProxy에서 SSL Key Log를 설정하는 방법을 알아보자.

방법

HAProxy 스펙 확인

HAProxy에서 LUA를 지원해야 한다.
아래 명령어로 LUA 스크립트를 지원하는지 확인할 수 있다.

1
haproxy -vv

출력 결과에 +LUA가 포함되어 있으면 OK.

1
/usr/sbin/haproxy -vv | grep "LUA"
1
2
3
4
5
6
Feature list : +EPOLL -KQUEUE +NETFILTER +PCRE +PCRE_JIT -PCRE2 -PCRE2_JIT
+POLL -PRIVATE_CACHE +THREAD -PTHREAD_PSHARED +BACKTRACE -STATIC_PCRE
-STATIC_PCRE2 +TPROXY +LINUX_TPROXY +LINUX_SPLICE +LIBCRYPT +CRYPT_H
+GETADDRINFO +OPENSSL +LUA +FUTEX +ACCEPT4 -CLOSEFROM +ZLIB -SLZ
+CPU_AFFINITY +TFO +NS +DL +RT -DEVICEATLAS -51DEGREES -WURFL +SYSTEMD
-OBSOLETE_LINKER +PRCTL +THREAD_DUMP -EVPORTS

LUA가 포함되어 있으면 본 방법을 적용할 수 있다.
그렇지 않을 경우 LUA 옵션을 포함시켜 재컴파일을 진행해야 한다.

sslkeylog 루아 스크립트 다운로드

소스 내용

소스 내용은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
--[[
    This script can be used to decipher SSL traffic coming through haproxy. It
    must first be loaded in the global section of haproxy configuration with
    TLS keys logging activated :

      tune.ssl.keylog on
      lua-load sslkeylogger.lua

    Then a http-request rule can be inserted for the desired frontend :
      http-request lua.sslkeylog <path_to_keylog_file>

    The generated keylog file can then be injected into wireshark to decipher a
    network capture.
]]

local function sslkeylog(txn, filename)
	local fields = {
		CLIENT_EARLY_TRAFFIC_SECRET     = function() return txn.f:ssl_fc_client_early_traffic_secret()     end,
		CLIENT_HANDSHAKE_TRAFFIC_SECRET = function() return txn.f:ssl_fc_client_handshake_traffic_secret() end,
		SERVER_HANDSHAKE_TRAFFIC_SECRET = function() return txn.f:ssl_fc_server_handshake_traffic_secret() end,
		CLIENT_TRAFFIC_SECRET_0         = function() return txn.f:ssl_fc_client_traffic_secret_0()         end,
		SERVER_TRAFFIC_SECRET_0         = function() return txn.f:ssl_fc_server_traffic_secret_0()         end,
		EXPORTER_SECRET                 = function() return txn.f:ssl_fc_exporter_secret()                 end,
		EARLY_EXPORTER_SECRET           = function() return txn.f:ssl_fc_early_exporter_secret()           end
	}

	local client_random = txn.c:hex(txn.f:ssl_fc_client_random())

	-- ensure that a key is written only once by using a session variable
	if not txn:get_var('sess.sslkeylogdone') then
		local file, err = io.open(filename, 'a')
		if file then
			for fieldname, fetch in pairs(fields) do
				if fetch() then
					file:write(string.format('%s %s %s\n', fieldname, client_random, fetch()))
				end
			end
			file:close()
		else
			core.Warning("Cannot open SSL log file: " .. err .. ".")
		end

		txn:set_var('sess.sslkeylogdone', true)
	end
end

core.register_action('sslkeylog', { 'http-req' }, sslkeylog, 1)

본 소스를 다운받아 /etc/haproxy/sslkeylogger.lua 경로에 위치시킨다.

그리고 /etc/haproxysslkeylog.log 빈 파일을 생성한다.

HAProxy 설정 및 스크립트 적용

1
touch /etc/haproxy/sslkeylog.log

HAProxy 설정 파일의 global 섹션에 다음 내용을 추가한다.

1
2
3
4
5
global
  # ... 내용 생략 ...
  tune.ssl.keylog on
  lua-load /etc/haproxy/sslkeylogger.lua
  # ... 내용 생략 ...

이후 HAProxy 설정 파일의 frontend 섹션에 다음 내용을 추가한다.

1
2
3
4
frontend test
  # ... 내용 생략 ...
  http-request use-service lua.sslkeylog /etc/haproxy/sslkeylog.log
  # ... 내용 생략 ...

config 파일이 맞는지 확인한다.

1
/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c

이후 HAProxy를 재시작한다.

/etc/haproxy/sslkeylog.log 파일에 SSL Key Log가 기록된다.

이후 해당 파일을 이용해 Wireshark에서 SSL Key Log를 적용하면 암호화된 패킷을 해독할 수 있다.

This post is licensed under CC BY 4.0 by the author.