반복 작업을 좋아하는 사람은 별로 없다. 마우스를 싫어하고 단축키를 사랑하는 개발자들이라면 더욱 그러하다. 이 글은 한국신용데이터(이하 KCD)에서 개발자들의 반복 작업 중 하나였던 VPN 망 연결 및 전환을 AppleScript와 Hammerspoon을 이용해 자동화(원클릭 + 단축키 등록)하여 개선한 과정이다.
필자도 두 도구를 예전부터 사용해왔다거나, 잘 쓸줄 안다거나 하는 건 전혀 아니다. (원 필자인 김장환님은 좀 아시는듯하지만..) 어쨌든 문제 해결을 위해 노력한 결과를 공유하는 것이 목적이다. 비슷한 어려움을 겪고 있는 분들이 있다면, 또는 반복 업무를 자동화하는 데 관심이 있다면, 이 글과 코드를 참고하여 하루에 몇 초라도 절약할 수 있기를 기대한다.
0. 들어가며
KCD에서는 재택근무시 보안을 위해 VPN을 이용해야만 인터넷 접근이 가능하게 설정해 두었다. 일반적인 인터넷을 사용할 때는 외부망용(EXT), 코드 리뷰/배포 등 민감한 작업을 할 때는 외부 인터넷이 차단된 내부망용(INT) VPN을 쓴다.
VPN 연결에 쓰는 Pulse Secure는 설치시 메뉴 바로 VPN 연결을 할 수 있는데, 문제는 아래 두 가지다.
- 현재 EXT인지 INT인지 알기 어렵다.
- EXT와 INT를 오갈 때마다 메뉴바 클릭 + 마우스 움직임 + ID/PW 입력 등 많은 과정을 거쳐야 해서 번거롭다.
이 두 가지 문제를 자동화하여 업무 효율을 높여보자.
1. 망 접속 상태를 알아보자
우선 현재 어떤 네트워크에 접속해 있는지는 네트워크 IP 주소를 이용해 알아낼 수 있다.
이 IP 주소들은 사내 네트워크 구성이 변하지 않는 한 고정되어 있으므로, ifconfig 의 호출 결과로 현재 외부망인지 내부망인지를 알 수 있다:
☝️ 는 Hammerspoon이라는 OS X 자동화를 위한 Lua
기반 툴킷을 이용해, 1) 주기적으로 ifconfig를 호출해서 2. 그 결과값을 메뉴바에 표시해준 것이다. Hammerspoon의 사용 방법은 아래에서 천천히 알아보고, 맛보기로 VPN 상태를 감지해서 메뉴바를 업데이트하는 코드만 구경해보자:
-- query vpn connection
local function queryVpnConnection(callback)
logger.v('queryVpnConnection')
local test = hs.task.new("/sbin/ifconfig", function(exitCode, stdout, stderr)
local isExternal = string.find(stdout, 'xx.xx.3.')
local isInternal = string.find(stdout, 'xx.xx.4.')
--
local status = 0
if isExternal then
status = 1
elseif isInternal then
status = 2
else
status = 0
end
obj.status = status
callback(status)
end):start()
end
-- update the menu bar
local function updateMenuVpnStatus(status)
logger.v('updateMenuVpnStatus: %d', status)
if status == 1 then
obj.menu:setTitle('EXT')
elseif status == 2 then
obj.menu:setTitle(hs.styledtext.new('INT', {
font = hs.styledtext.boldSystem,
color = { hex = 'FF0000' }
}))
else
obj.menu:setTitle('')
end
end
2. EXT ↔ INT 변경을 쉽게 해보자
현재 어떤 상태인지 알고 있다면, 다른 특정 상태로 바꾸기 위해 어떤 단계를 거쳐야 하는지도 알 수 있다. 예를 들어 INT 상태에서 EXT 상태로 바꾸려면 다음 10단계를 수행해야 한다:
- Pulse Secure 메뉴바 아이콘 클릭
Employee_VPN
메뉴 클릭연결 해제
메뉴 클릭- Pulse Secure 메뉴바 아이콘 클릭
연결
메뉴 클릭- Employee_VPN 창에서
KCD_EXTVPN
선택 연결
버튼 클릭- ID와 PASSWORD 입력
연결
버튼 클릭- OTP PASSWORD 입력
그러면 이제 "메뉴바 클릭"이라든가, (PASSWORD는 위험하니 패스하더라도) "ID 타이핑" 같은 걸 프로그램으로 수행할 수만 있다면, 반복작업 자동화에 한 발 가까워질 것이다. 이를 할 수 있는 방법은 다양하겠지만 이 글에서는 MacOS 환경에 맞춰 AppleScript를 쓴다.
AppleScript는 애플이 만든 MacOS 상에서 애플리케이션과 통신할 수 있는 스크립트 언어다. OS X 가 나오기 전인 1993년부터 있었다.
예를 들어, AppleScript로 위의 6번과 7번(Employee_VPN 창에서 KCD_EXTVPN
선택 → 연결
버튼 클릭)을 수행하는 코드는 다음과 같다:
on click_connection_on_window(target)
global VPN_NAME
tell application "System Events" to tell process "PulseTray"
set vpnwin to first window whose name is VPN_NAME
tell first sheet of vpnwin
set realmRows to get every row of table 1 of scroll area 1
-- find & select row with target name
select (first item of realmRows whose value of static text 1 is target)
-- click "Connect"
click button CONNECT_NAME
end tell
end tell
end click_connection_on_window
참고로 AppleScript 파일은 .scpt
확장자를 가졌는데 일반적인 텍스트 에디터로는 편집이 안 되고, MacOS 기본 프로그램인 "스크립트 편집기"로 편집해야 한다.
스크립트 편집기에서 망치 모양 아이콘을 눌러 컴파일하고 나면, 아래와 같이 osascript(애플스크립트 파일을 실행할 수 있는 스크립트 언어) 파일을 만들어서 scpt
파일에 정의된 메서드를 실행할 수 있다. 아래는 Finder
앱의 경로를 현재 파일의 경로로 두고, kcd_vpn.scpt
에 정의된 connect_to_ext()
를 실행하여 외부망으로 연결 후 현재 상태를 메뉴바에 업데이트하는 코드다.
#!/usr/bin/osascript
tell application "Finder" to set cwd to container of (path to me) as string
set kcd_vpn to (load script file (cwd & "kcd_vpn.scpt" as alias))
run kcd_vpn
--
tell kcd_vpn
connect_to_ext()
delay 1
status()
end tell
3. Hammerspoon + AppleScript = ?
Hammerspoon은 menubar 아이콘과 상태를 표시하고, AppleScript는 각 메뉴를 눌렀을 때 정해진 명령을 실행한다. 열심히 삽질하고 실험해가며 코드를 짠 결과 이런 것들이 가능해졌다.
- 메뉴바 아이콘에 연결상태(EXT, INT) 표시
- 연결 상태에 따라 메뉴 제공
- disconnect 일 때:
connect...
: 연결창 열기connect to INT
: INT로 접속하기connect to EXT
: EXT로 접속하기status: disconnected
: 상태 표시 (비활성)Pulse Secure
: Pulse Secure 열기- EXT 일 때 (INT도 유사):
switch to INT
: INT로 재접속하기disconnect
: 연결 끊기status: connected to EXT
: 상태 표시 (비활성)Pulse Secure
: Pulse Secure 열기
4. Putting it all together
- 우선 Hammerspoon 홈페이지에 가서 다운로드 후 설치하면
~/.hammerspoon
디렉토리가 생성된다. - 안 생기면 직접 만들고, Hammerspoon 구동 파일인
init.lua
도 추가하자. - Hammerspoon 플러그인은
~/.hammerspoon/Spoons
에 넣으면 된다. 예제 저장소에서 받은KCDVpn.spoon
이 Hammerspoon 플러그인인데, Hammerspoon 앱으로 구동할 수 있는 모듈이자 디렉토리다. Spoons 디렉토리 안에 KCDVPN.spoon을 넣자. 디렉토리 구성물은 이렇다: init.lua
: hammerspoon 파일./scripts/*
: applescript 스크립트 파일들 및 bash 스크립트~/.hammerspoon/init.lua
를 아래처럼 편집해서 Hammerspoon 실행시 구동시킨다. 이리저리 바꿔가면서 자신에게 맞는 설정을 찾아보자.
-- Spoons/KCDVpn.spoon 디렉토리를 불러온다.
hs.loadSpoon('KCDVpn')
-- Spoon을 시작한다. 5초 단위로 ifconfig 를 질의하도록 한다.
spoon.KCDVpn:start({ interval = 5 })
-- 아래 코멘트를 해제하면 단축키를 지정할 수 있다.
--hs.hotkey.bind({'ctrl', 'option', 'v'}, 'i', function() spoon.KCDVpn:connectToInt() end)
--hs.hotkey.bind({"ctrl", "option", "v"}, "e", function() spoon.KCDVpn:connectToExt() end)
--hs.hotkey.bind({"ctrl", "option", "v"}, "t", function() spoon.KCDVpn:toggleVpnConnection() end)
scripts
디렉토리 안에는 애플스크립트 구동시 참조하는kcd_vpn.plist
파일이 있다. 이 파일을 자신의 환경에 맞게 설정을 해준다.- Profit!
KCD의 보안을 위하여 의도적으로 누락한 설명도 있으니 양해 부탁드리며, 서두에 적은 대로 이 글이 반복업무에 지친 여러분의 아픈 관절을 조금이라도 편하게 하는데 도움이 되길 바란다.