fcitx 한글 입력기 사용하기

Gnome 기본 IM(Input Method)인 IBus 입력기에 문제가 있어 fcitx로 입력기를 변경 했다.

Arch Linux

pacman -S fcitx5 fcitx5-hangul fcitx5-gtk fcitx5-qt fcitx5-configtool 

/etc/environment

GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
XMODIFIERS=@im=fcitx

시스템을 재시작 하면 fcitx가 자동 실행된다.

한글 입력 모드에서 태극 회오리 아이콘이 작업 표시줄에 표시된다. 변경 하려면 다음과 같이 실행한다.

sudo rm -f /usr/share/icons/hicolor/64x64/apps/fcitx-hangul.png
sudo wget https://raw.githubusercontent.com/PapirusDevelopmentTeam/papirus-icon-theme/master/Papirus/24x24/actions/fcitx-hangul.svg -O /usr/share/icons/hicolor/64x64/apps/fcitx-hangul.png

Ubuntu

sudo apt update
sudo apt install fcitx-hangul

설정 매뉴를 실행한 후 우측 설정 메뉴에서 Region & Language 을 선택한다.

설정 메뉴에서 Manage Installed Language 버튼을 클릭 한다.

Language Support 화면이 나타나면 하단의 Keyboard input method system 항목을 fcitx로 설정한다.

적용을 위해 시스템을 재시작한다.

상단 패널의 우측에 키보드 모양의 아이콘이 보이면 정상적으로 설치 된 것이다.

상단 패널의 기보트 아이콘을 클릭하여 설정 메뉴를 오픈한다.

Configure Current Input Method 메뉴를 실행한다.

Input Method 설정

  • Keyboard - English(US)

Input Method 설정

좌측 하단의 + 버튼을 클릭한다.

Search Input Method 항목에 Hangul을 입력 하여 검색한다.

Input Method 설정

검색 내용이 보이지 않으면 Only Show Current Language의 선택을 해제한다.

Input Method 설정

Hangul 을 선택 한 후 OK 버튼을 눌러 추가 한다.

Input Method 리스트에 다음과 같이 Hangul이 추가 되었다.

  • Keyboard - English(US)
  • Hangul

Input Method 설정

한/영 전환 키 설정

Global Config 탭을 선택 한다.

한/영 전환 설정

HotKey 항목의 첫 번째 항목인 Trigger Input Method 항목의 첫번째 항목이 Ctrl+Space로 설정 되어 있다. 두번째 항목을 클릭 하여 한/영 전환키를 입력 한다.

한/영 전환 설정

한/영 전환 키가 Ralt로 인식된다면 리눅스에서 한/영 전환키 사용하기를 참고 하여 한/영 전환키를 설정한다.

어떤 SHELL을 사용하고 있는지 확인해보자.

어러 쉘이 있다. sh(Bourne Shell)을 기반으로 하는 Bash(Bourne-again shell), zsh(Z shell) 등은 문법이 거의 똑같지만 완전히 같지는 않다. 쉘스크립트를 만들어 실행 하는 경우 #! 지시자로 사용할 쉘을 지정할 수 있기 때문에 크게 문제가 없지만 source 명령이나 dot(.) 명령으로 현재 환경(Current Environment Context)에서 스크립트를 실행하는 경우 사용중인 쉘의 종류에 따라 문법이 달라 문제가 발생 할 수 있다. 주의해서 처리 하도록 하자.

기본쉘을 Zsh 사용하기 시작하면서 겪은 문제다. 보통 리눅스에서 기본쉘은 Bash 이기 때문에 거의 모든 프로그램들이 Bash 위주로 구현되어 있기 때문에 발생 하는 문제이다.

대부분 다음과 같은 문제이다.

실행 스크립트의 파일 이름을 알고 싶을때 Bash에서는 $BASH_SOURCE를 사용한다. 하지만 이 변수는 Bash 에서만 지원됨으로 Zsh에서는 $0 변수를 사용해야 된다. Bash에서도 $0변수를 지원하지만 Bash에서 $0 변수를 사용하면 쉘의 정보((bash)가 표시된다.

쉘스크립트에서 $0 는 실행파일의 이름을 나타내는 변수 이다. Bash에서 $0 변수는 쉘이 시작할 때만 초기화 되지만 dot 명령은 새로운 쉘을 시작하는 것이 아니라 현재 쉘의 컨텍스트에서 실행 하는 것이므로 쉘에서 echo $0 를 실행한것과 같은 결과(즉, bash)가 출력된다. 그런데 Zsh 에서는 $0가 스크립트 이름으로 세팅된다.

구글링을 해보면 Zsh에서 Bash$BASH_SOURCE 와 가장 가까운 결과를 내는것은 ${(%):-%x} 라고 한다. 하지만 $0도 같은 결과는 내기 때문에 그냥 사용하기로 한다.

다음은 ./env 파일의 내용이다.

1
2
echo \$BASH_SOURCE = $BASH_SOURCE
echo \$0 = $0

각 SHELL에서 실행 해 보자

. ./env

다음과 같은 출력을 얻을 수 있다.

bash

$BASH_SOURCE = ./env
$0 = bash

zsh

$BASH_SOURCE =
$0 = ./env

따라서 실행 되는 스크립트의 이름 알기 위해서는 다음과 같이 쉘에 따라 다른 방식을 정용하여야 한다.

SH_NAME=$(basename $(readlink /proc/$$/exe))

case ${SH_NAME} in
	"zsh") SELF=$(realpath $0) ;;
	"bash") SELF=$(realpath ${BASH_SOURCE[0]}) ;;
	*) echo "Unknown SHELL $SH_NAME" && exit 0 ;;
esac

echo $SELF

Bash 또는 Zsh 만 사용한다면 다음과 같이 사용해도 같은 결과를 얻을 수 있다.

SELF=$(realpath ${BASH_SOURCE[0]:-$0})
echo $SELF

아래와 같이 env 파일을 만들고 dot command로 실행해보자

SELF=${BASH_SOURCE[0]:-$_}
echo $(basename $SELF) is located at $(realpath $SELF)

env 파일 실행

. ./env

Bash, Zsh 둘다 같은 결과를 얻을 수 있다.

env is located at /home/euikook/src/env

$SHELL

/etc/password 파일에 정의된 사용자에 할당된 SHELL 출력한다.

echo $SHELL

Cons

지정된 쉘 정보를 표시 하지만 현재 사용중인 SHELL 정보를 출력하지 않는다.

$ cat /etc/passwd | grep $USER
john:x:1000:1000::/home/john:/usr/bin/zsh

cat 명령으로 /etc/passwd 파일을 확인 결과 /usr/bin/zsh 가 쉘로 할당되어 있다.

아래와 같이 bash로 쉘을 변경 후 $SHELL$0 정보를 출력 해보자.

$ bash
$ echo echo User SHELL is $SHELL, Current SHELL is $0
User SHELL is /usr/bin/zsh, Current SHELL is bash

$0

쉘스크립트에서는 $0는 입력된 라인의 첫번째 단어를 나타낸지만 SHELL 상에서는 현재 SHELL의 이름을 표시한다.

echo $0

BASH 의 경우

bash

ZSH의 경우

/usr/bin/zsh

Cons

쉘스크립트에서는 사용할 수 없다.

아래와 같은 스크립트를 만들고 실행해 보자.

print-shell.sh

#!/usr/bin/env bash
echo $0

아래와 같이 스크립트의 첫번째 인자인 ./print-shell 이 출력된다.

$ ./print-shell
./print-shell.sh

/proc/$$/exe

현재 프로세서의 PID를 나타내는 $$ 변수를 이용한 방법이다.

리눅스에서는 각 프로세서의 정보가 /proc/<pid>/ 디렉터리에 있으며 /proc/<pid>/exe는 원본 실행 파일의 심볼릭 링크를 나타낸다. 따라서 쉘 스크립트 상에서 아래 명령을 실행 하면 현재 실행 중인 쉘의 정보를 확일 할 수 있다.

readlink /proc/$$/exe

Cons

가장 안정적으로 SHELL 정보를 가져올 수 있지만 리눅스에서만 사용할 수 있다.

ps Command

ps 명령을 활용하는 방법이 있다.

sh -c 'ps -p $$ -o ppid=' | xargs ps -o comm= -p
sh -c 'ps -p $$ -o ppid=' | xargs -I'{}' readlink -f '/proc/{}/exe'

sh -c ‘COMMAND’ vs COMMAND

sh -c 'COMMAND'와 COMMAND의 차이는 주어진 명령을 수행하기 위해 프로세서가 분기 될 때 전자의 경우 별도의 SHELL 프로세서에서 분기 되는 반면 후자의 경우에는 메인 SHELL 스크립트에서 분기 되는 것이다.

예를 들어 ps -p $$ 명령을 가각 실행 해 보자.

sh -c 'ps -p $$' 의 결과

$ $ sh -c 'ps -p $$'
    PID TTY          TIME CMD
1710512 pts/2    00:00:00 ps

PID 1710512에 대한 COMMAND가 ps 인것을 확인 할 수 있다.

ps 명령을 실행하기 위해 새로운 프로세서를 생성 하고 생성된 프로세서에서 ps $$ 명령을 수행 하여 $$ 변수가 생성된 프로세서의 PID로 대치 된 것을 알 수 있다.

ps -p $$의 결과

$ ps -p $$
    PID TTY          TIME CMD
1710370 pts/2    00:00:00 bash

현재 자신의 PID 1709311에 대한 COMMAND bash 인 것을 확인 할 수 있다.

반면 ps -p $$ 은 메인 쉘에서 분기 하여 실행 되었으며 ps 명령이 수행 되기 전에 $$ 변수가 메인 SHELL의 PID로 대치 된 것을 알 수 있다.

References

Shell에서의 Exit Status에 대하여

Exit Status에 대하여 알아보자.

요즘은 GUI를 많이 사용하지만 지금도DOS나 UNIX계열의 시스템에서는 쉘(SHELL)을 통해 프로그램을 실하고 프로그램의 출력을 통해 프로그램이 정상적으로 실행되었는지를 판단하한다.

전통적으로 UNIX 계열 프로그램은 침묵은 금이라는 유닉스의 설계 철학에 따라 ls와 같이 명시적으로 정보의 출력을 요구 하는 명령이 아닌경우 아무런 출력이 없으면 정상적으로 실행 된것이다.

Speech is silver, but silence is gold.

그렇다면 프로그램에서 다른 프로그램을 실행 하였을 때 자신이 실행한 프로그램이 정상적으로 수행되었는지 어떻게 판단 할까?

정답을 말하면 모든 명령은 종료될 때 Exit Status를 반환하는데 (명시적으로 지정하지 않을 경우 기본값을 반환한다.) 프로그램은 이 Exit Status를 가지고 자신의 실행한 프로그램이 정상적으로 종료 되었는지 판단 할 수 있다.

Exit Status는 O 에서 255 사이의 값을 가지고 쉘의 경우 125 이상의 값을 사용한다.

앞서도 설명 했듯이 침묵은 금이기 때문에 많은 프로그램이 아무런 문제 없이 정상 종료 되었다면 Exit Status 0을 반환한다.

사실 완전히 같은 의미는 아니지만 침묵은 금이라는 UNIX의 철학을 어느정도 따른다고 볼수 있다.

쉔에 요청한 명령이 존재 하지 않는 경우 Exit Status 127을 반환한다. 명령이 존재 하지만 실행 가능하지 않은 경우 126을 반환한다. 명령이 SIGINTSIGSEGV와 같은 Fatal Signal $N$에 의해 종료 된 경우 Exit Status는 $128 + N$ 이 된다.

그렇다며 이 0 ~ 125 까지의 Exit Status는 어떻게 정의 되는가? 많은 프로그램들이 POSIX에 정의된 errno.h를 따른다.

errno.h에는 자주 발생하는 에러를 정의해 놓았다. 프로그램이 비정상 적으로 종료 될때 errno.h를 참고 하여 반환값(Exit Status)을 결정 하도록 하자.

CC++ 개열의 함수도 마찬가지다. 함수의 수행 상태를 정수값으로 반환하는 함수의 경우 반환값을 errno.h를 참고 하여 반환 하도록 한다.

메모리 비교 함수인 memcmp와 문자열 비교함수인 strcmp 계열의 함수를 보자. C에서는 0 이 아닌 값이 참(TRUE) 이지만 위 함수들은 비교 대상이 일치 할때 0을 반환한다.

Shell Command(쉘 명령)

쉘 명령(Shell Command)명령(Command) 과 그에 따르는 공백 문자로 구분된 인자(Argument) 들로 구성된다.

사실 쉘에서 사용되는 상수, 문자열과 몇몇 예약어를 제외한 모든 특수 문자와 문자의 조합은 쉘에 내장된 명령또는 일발적은 명령이다.

심지어 test를 대신해서 쓰이는 [ 까지 Shell에 내장된 명령어이다.

아래 명령을 실행 해보자

which [

BASH의 경우 다음과 같은 출력을 얻을 수 있다.

/usr/bin/[

ZSH의 경우 다음과 같은 결과를 얻을 수 있다.

[: shell built-in command

errno

유닉스 계열 시스템을 사용한다면 errno 명령으로 확인 할 수 있다.

errno -l

아래는 위 명령의 출력중 일부를 나타낸 것이다.

EPERM 1 Operation not permitted
ENOENT 2 No such file or directory
ESRCH 3 No such process
EINTR 4 Interrupted system call
EIO 5 Input/output error
ENXIO 6 No such device or address
E2BIG 7 Argument list too long
ENOEXEC 8 Exec format error
EBADF 9 Bad file descriptor
ECHILD 10 No child processes
EAGAIN 11 Resource temporarily unavailable
ENOMEM 12 Cannot allocate memory
.
.
.

errno 명령은 moreutils의 일부 이므로 없다면 패키지를 설치 한다.

Debian 계열 (Debian, Ubunut, Mint…)

sudo apt install moreutils

Arch Linux 계열 (ArchLinux, Manjaro…)

sudo pacman -S moreutils

Redhat 계열 (Redhat, Fedora, Centos…)

sudo yum install moreutils
sudo dnf install moreutils

프로그래밍에서의 Exit Status, Return Code

아래와 같이 간단한 프로그램을 만든다고 가정해 보자. main() 함수에서 반환 하는 값이 Exit Status 가 되는데 앞서 설명 했듯이 0은 에러가 없는 상태를 나타내기 때문에 아래 예제에서는 0을 반환 하였다.

#include <stdio.h>

int main(int argc, char **argv)
{
    fprintf(stdout, "Hello!!");

    return 0;
}

하지만 프로그램 실행중 문제 가 발생하여 프로그램을 종료 해야 하는 경우 0을 반환 한하였다면 소스코드를 볼수 없는 프로그램 사용자들은 Exit Status0이기 때문에 프로램이 정상적으로 종료되었다고 착각 할 수 있다.

따라서 프로그램이나 쉘에서 수행되는 스크립트를 을 작성하는 경우 등으로 함수를 작성할때 반환되는 값을 POSIX에 정의된 errno를 참고하도록 하자.

리눅스에서 많이 사용되는 주요 프로그램들 대부분이 errno의 규칙을 따르지만 그렇지 않은 프로그램도 있다. 해당 프로그램의 매뉴얼을 읽어보자.(RTFM)

쉘에서의 Exit Status

쉘에서 실행한 명령의 종료 상태는 $? 변수에 저장된다.

아래 명령을 수행 해보자.

ls 
echo $?

화면에 0이 출력된다. ls 명령이 정상적으로 종료 된 것이다.

그렇다면 아래와 같이 ls 명령 다음에 존재 하지 않는 파일이나 디렉터리의 이름을 넣어 보자.

ls asdfasdfasdf
echo $?

화면에 2가 출력된다.

POSIX errno.h에는 errno 2ENOENT로 정의 되어 있으며 파일이나 디렉토리가 없을 경우 반환 하는 값니다.(No such file or directory)

Lists

리스트라는 개념이 있다. 우리가 알고 있는 리스트와는 조금 다르다. 아래는 BASH 메뉴얼에 있는 리스트에 대한 정의 이다.

A List is a sequence of one or more pipelines separated by one of the operators ;, &, &&, or ||‚ and optionally terminated by one of ;, &, or <newline>.

리스트는 ;, &, &&, 또는 || 연산자중 하나로 구분되고 선택적으로 ;, &, 또는 <newline> 으로 종료되는 하나 이상의 파이프라인 시퀀스다.

&& 연산자

Logical AND 연산과 같다.

command-one && command-two

command-one 이 참일 경우에만 command-two가 실행된다.

|| 연산자

Logical OR 와 같다.

command-one || command-two

command-one 이 거짓 일 경우에만 command-two가 실행된다.

&&|| 연산자를 활용하여 간단한 if else문과 같은 효과를 볼 수 있다.

디렉터리가 존재 할 경우 디렉터리를 삭제

[ -d /home/test/aaa ] && rm -rf /home/test/aaa

디렉터리가 존재하지 않을 경우 디렉터리를 생성

[ -d /home/test/aaa ] || mkdir -p /home/test/aaa

파일이 존재 하고 실행 권한이 있는 경우 파일을 실행

[ -x /bin/errno ] && errno -l

파일이 존재 하지 않을 경우 파일 생성

[ -f /home/test/aaa ] || touch /home/test/aaa

&& 연산자 사용시 주의점

[ -d /home/test/aaa ] && rm -rf /home/test/aaa

위 명령은 [ -d /home/test/aaa ] 이 참일 경우 rm -rf /home/test/aaa 명령을 실행하라는 뜻이다.

/home/test/aaa 디렉터리가 존재 하지 않을 경우 [ -d /home/test/aaa ] 명령이 거짓이 되어 rm -rf /home/test/aaa 명령이 실행 되지 않게 된다. 그리고 이 List의 Exit Status[ -d /home/test/aaa ]의 결과인 1 이 된다.

Makefile 등에서 이 명령을 사용하였을 때 Exit 가 참이 아니기 때문에 다음 명령이 수행되지 않는다.

/home/test/aaa 가 디렉토리 일 경우 이 디렉토리를 삭제하고 빈 파일 /home/test/aaa를 생성하고자 아래와 같이 Makefile을 작성 했다면


all:
    [ -d /home/test/aaa ] && rm -rf /home/test/aaa
    touch /home/test/aaa

[ -d /home/test/aaa ] && rm -rf /home/test/aaa의 결과가 거짓이기 때문에 다음 명령인 touch /home/test/aaa 수행 되지 않는다.

명령 다음에 || 연산자와 true 명령을 추가 하자.

true 명령은 Exit Code 0를 반환한다.

Makefile


all:
    [ -d /home/test/aaa ] && rm -rf /home/test/aaa || true
    touch /home/test/aaa

Windows 환경에서 사설 인증 기관 인증서(Private CA Certificate) 설치 하기

로컬 네트워크에서 사용할 목적으로 직접 서명(Self Signed)한 인증서를 가지고 서비스를 제공 하는 경우 인증서를 인증한 인증 기관의 공개키 인증서가 브라우저 또는 운영체제에 없기 때문에 신뢰할 수 없는 사이트 경고 메시지를 보게 된다. 경고 메시지를 없에려면 인증서를 인증한 사설 인증기관(CA)의 공개키 인증서(Public Key Certificate)를 브라우저 또는 운영체제에 설치 하여야 한다. 이 글에서는 Windows환경에서 사설 인증 기관 인증서를 설치 하는 벙법에 대하여 알아본다.

Windows는 운영체제 수준에서 CA 인증서를 관리 하기 때문에 운영체제의 CA 인증서 저장소에 인증서를 등록하면 특별한 경우를 제외 하면 거의 모든 프로그램에서 해당 인증서에 접근 할 수 있다.

MMC(Microsoft Management Console)를 이용하여 설치 하기

mmc를 입력 하고 Enter 키를 누른다.

시작 에서 실행을 검색하여 실행한다.

시작 > 실행

mmc 를 입력 하여 실행한다.

Run MMC

파일 > 스냅인 추가/제거를 선택한다.

스냅인 추가/제어

사용가능한 스냅인 목록에서 인증서를 선택하고 추가(A) > 버튼을 클릭한다.

인증서 추가

스냅인이 관리할 인증서 대상을 선택한다. 잘모르겠다면 그냥 마침 버튼을 클릭하여 스냅인을 추가한다.

관리 주체 설정

인증서 스냅인이 추가 되었다. 확인 버튼을 클릭하여 완료 한다.

스냅인 추가 완료

우측 트리 메뉴에서 인증서 - 현재사용자 > 신뢰할 수 있는 루트 인증 기관 을 차례대로 확장 한다.

인증서 > 신뢰할 수 있는 루트 인증 기관

인증서 - 현재사용자 > 신뢰할 수 있는 루트 인증 기관 > 인증서에 마우스 커서를 위치 시키고 마우스 오른쪽 버튼을 클릭하여 메뉴가 표시되게 한다. 모든 작업 > 가저오기를 선택한다.

모든 작업 > 가저오기

인증서 가저오기 마법사

인증서 가져오기 마법사가 시작 된다. 다음을 클릭하여 인증서 가져오기를 시작한다.

인증서 가져오기 마법사 시작

찾아보기 버튼을 클릭하여 가져올 인증서 파일을 선택한 후 다음 버튼을 클릭한다.

가져올 인증서 파일 선택

인증서 저장소 선택 메뉴가 나온다. 모든 인증서를 다음 저장소에 저장(P)를 선택한 후 찾아보기 버튼을 클릭 한다.

모든 인증서를 다음 저장소에 저장(P)

인증서 자장소 선택 착에서 신뢰할 수 있는 루트 인증 기관을 선택 한 후 확인 버튼을 클릭한다.

신뢰할 수 있는 루트 인증 기관

다음(N) 버튼을 눌러 다음으로 넘어간다.

인증서 저장소 선택

입력한 정보를 확인 하는 창이 나온다. 입력한 정보가 맞다면 마침 버튼을 클릭한다.

확인 후 마침

인증서 출처를 확인 할 수 없다는 경고 메시지가 뜬다. 예(Y) 버튼을 눌러 인증서를 가저온다.

설치 확인 / 예(Y)

인증서 가저오기 가 완료 되었다. 확인 버튼을 클릭한다.

가저오기 완료

인증서 리스트에서 가저온 인증서를 더블클릭 하여 인증서 정보를 확인해보자.

인증서 정보 확인

인증서파일을 통해 설치 하기

CA 인증서의 확장자에 따라서 인증서를 직접 설치 할 수도 있다.

탐색기에서 인증서 파일의 유형이 보안 인증서로 나온다면 인증서파일을 통해 설치 할 수 있다.

인증서를 더블 클릭하거나 인증서 파일에 마우스 커서를 위치 시키고 마우스 오른쪽 버튼을 클릭 하여 열기(O) 메뉴를 선택한다.

탐색기 - 인증서 파일

인증서 속성 - 일반

인증서 상태가

이 CA 루트 인장서가 신뢰할 수 있는 루트 인증 기관 저장소에 있지 않으므로 신뢰할 수 없습니다.

라고 나온다.

인증서 속성 - 인증 경로

인증서 설치

인증서 설치(I) 버튼을 클릭 하여 인증서 가저오기 마법사를 실행한다.

인증서 설치

또는 인증서 파일에 마우스 커서를 두고 마우스 오른쪽 버튼을 클릭하여 메뉴가 나오면 인증서 설치(I) 메뉴를 선택 하여 인증서 가져오기 마법사를 실행한다.

인증서 더블클릭

인증서 가져오기 마법사가 실행 되면 MMC를 이용한 설치 방법을 참고하여 인증서를 설치 한다.

Google Chrome

크롬에서도 인증서 가저오기 마법사를 실행 할 수 있다.

메뉴 > 설정 메뉴을 선택한다.

메뉴 > 설정

우측 메뉴에서 개인정보 및 보안 메뉴를 선택한다. 그 후 좌측 메뉴에서 개인정보 및 보안 > 보안 메뉴를 선택한다.

메뉴 > 설정

화면을 밑으로 내려 인증서 관리 메뉴을 클릭한다.

메뉴 > 설정

인증서 관리 창이 나타난다. 가져오기(I) 버튼을 클릭하여 가져오기 마법사를 실행한다.

메뉴 > 설정

인증서 가져오기 마법사가 실행된다. MMC를 이용한 설치 방법을 참고하여 인증서를 설치 한다.

인증서 설치 검증

인증서 설치 후 인증서 파일을 연어 정보를 확인하자.

인증서 속성 - 일반

인증서 경로 탭을 선택 하여 인증서 경로 정보를 확인해보자.

인증서 속성 - 인증 경로

인증서 상태에 올바른 인증서입니다. 라는 메시지가 나오면 인증서가 올바르게 설치 된 것이다.

리눅스에서 USB 설치 미디어 만들기

Prerequisite

어떤 설치 미디어나 라이브 디스크 라도 상관 없지만 이 글에서는 우분투를 기준으로 설명 하도록 한다.

설치 미디어 다운로드 및 검증

원하는 우분투 미러 사이트에서 설치 미디어를 다운로드 한다.

이글에서는 ubuntu-22.04.3-live-server-amd64.iso 파일을 기준으로 설명 한다.

파일의 검증을 위해 SHA256SUM 파일과 SHA256SUM.gpg 파일도 같이 다운로드 한다.

SHA256SUM 파일은 내려 받은 ubuntu-22.04.3-live-server-amd64.iso 파일이 손상 되거나 변조 되었을 우려가 있으므로 파일의 SHA256 해시가 저장되어 있어 파일의 무결성 검증에 사용된다. SHA256SUM.gpg 파일은 SHA256SUM에 GPG 서명으로 SHA256SUM 파일이 손상되거나 변조 되었을 경우 이를 인지 하기 위해 사용된다.

먼저 SHA256SUM.gpg 파일을 이용해 SHA256SUM 파일을 검증한다.

gpg --verify SHA256SUMS.gpg SHA256SUMS

아래와 같은 에러 메시지가 나온다면 키서버로 부터 공개키를 내려 받아야 한다.

$ gpg --verify SHA256SUMS.gpg SHA256SUMS
gpg: Signature made Fri 11 Aug 2023 03:33:07 AM KST
gpg:                using RSA key 843938DF228D22F7B3742BC0D94AA3F0EFE21092
gpg: Can't check signature: No public key

공개키의 ID 가 843938DF228D22F7B3742BC0D94AA3F0EFE21092 이라는 것을 알 수 있다.

gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 843938DF228D22F7B3742BC0D94AA3F0EFE21092

해당 키를 내려 받는다.

$ gpg --keyid-format long --keyserver hkp://keyserver.ubuntu.com --recv-keys 843938DF228D22F7B3742BC0D94AA3F0EFE21092
gpg: key D94AA3F0EFE21092: public key "Ubuntu CD Image Automatic Signing Key (2012) <[email protected]>" imported
gpg: Total number processed: 1
gpg:               imported: 1

공개키를 내려 받았음니 SHA256SUM 파일을 다시 검증해 보자.

$ gpg --verify SHA256SUMS.gpg SHA256SUMS
gpg: Signature made Fri 11 Aug 2023 03:33:07 AM KST
gpg:                using RSA key 843938DF228D22F7B3742BC0D94AA3F0EFE21092
gpg: Good signature from "Ubuntu CD Image Automatic Signing Key (2012) <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 8439 38DF 228D 22F7 B374  2BC0 D94A A3F0 EFE2 1092

gpg: Good signature from “Ubuntu CD Image Automatic Signing Key (2012) [email protected]” [unknown]

위와 같은 출력이 나온다면 SHA256SUMS 파일의 무결성은 확인 되었다.

이제 SHA256SUMS 파일을 이용하여 ubuntu-22.04.3-live-server-amd64.iso 파일의 무결성을 검증해보자.

SHA256SUMS 파일의 내용을 보면 sha256 해시와 파일 대상파일의 파일명이 같이 기술되어 있다.

a435f6f393dda581172490eda9f683c32e495158a780b5a1de422ee77d98e909 *ubuntu-22.04.3-desktop-amd64.iso
a4acfda10b18da50e2ec50ccaf860d7f20b389df8765611142305c0e911d16fd *ubuntu-22.04.3-live-server-amd64.iso

아래 명령을 이용하여 ubuntu-22.04.3-live-server-amd64.iso의 무결성을 검증한다.

SHA256SUMS 파일에는 2개의 파일이 기술되어 있지만 우리는 ubuntu-22.04.3-live-server-amd64.iso 파일만 다운로드 하였기 때문에 --ignore-missing 옵션을 이용하여 없는 파일은 무시 하도록 한다. 4

sha256sum --check --ignore-missing SHA256SUMS

아래와 같이 OK 가 나오면 iso 파일의 무결성은 검증이 완료 되었다.

$ sha256sum --check --ignore-missing SHA256SUMS
ubuntu-22.04.3-live-server-amd64.iso: OK

FAILED 가 나온다면 파일이 손상되었거나 변경되었다는 의미 이므로 다시 다운로드 하자.

설치 미디어 준비

자동 마운팅 기능이 활성화 되어 있거나 수동으로 마운팅 하여 USB저장 장치가 마운트 되어 있다면 마운트해제한다.

lsblk 명령으로 블럭 디바이스를 확인한다.

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0 953.9G  0 disk 
├─sda1        8:1    0   512M  0 part 
└─sda2        8:2    0 953.4G  0 part /home/data
sdc           8:32   1  14.3G  0 disk 
└─sdc1        8:33   1  14.3G  0 part /run/media/user/7AFC-CAE9
nvme0n1     259:0    0   1.9T  0 disk 
├─nvme0n1p1 259:1    0   512M  0 part /boot
├─nvme0n1p2 259:2    0    64G  0 part /
└─nvme0n1p3 259:3    0   1.8T  0 part /home

sda, sdc, nvme0n1 세개의 블럭 디바이스가 있다. 그중에 sdc가 USB 장치 이고 sdc1/run/media/user/7AFC-CAE9에 마운트 되어 있다.

마운트를 해제한다.

sudo umount /dev/sdc1

lsblk 명령으로 확인한다.

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda           8:0    0 953.9G  0 disk 
├─sda1        8:1    0   512M  0 part 
└─sda2        8:2    0 953.4G  0 part /home/data
sdc           8:16   1  14.3G  0 disk 
└─sdc1        8:33   1  14.3G  0 part 
nvme0n1     259:0    0   1.9T  0 disk 
├─nvme0n1p1 259:1    0   512M  0 part /boot
├─nvme0n1p2 259:2    0    64G  0 part /
└─nvme0n1p3 259:3    0   1.8T  0 part /home

Using dd command


dd bs=4M if=/path/to/iso-file of=/dev/sdX status=progress oflag=sync

다음은 Ubuntu 22.04.3 Server 설치용 ISO 파일을 가지고 USB 설치 미디어를 만는 예제이다.

.iso 파일을 USB로 복사한다.

sudo dd bs=4M if=/home/user/Downloads/ubuntu-22.04.3-live-server-amd64.iso of=/dev/sdc status=progress oflag=sync

예제 출력

877227008 bytes (2.9 GB, 2.7 GiB) copied, 257 s, 11.2 MB/s
685+1 records in
685+1 records out
2877227008 bytes (2.9 GB, 2.7 GiB) copied, 257.353 s, 11.2 MB/s

완료 되었으면 USB 저장 장치를 분리 한 후 다시 삽입한다.

lsblk 명령으로 확인 해보자.

NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sdc           8:16   1  14.3G  0 disk 
├─sdc1        8:17   1   2.7G  0 part /run/media/user/Ubuntu-Server 22.04.3 LTS amd64
└─sdc2        8:18   1   3.9M  0 part 

정상적으로 설치 미디어가 만들어졌다.

LD_LIBRARY_PATH vs LIBRARY_PATH

LD_LIBRARY_PATH vs LIBRARY_PATH

외부 C 라이브러리를 사용하는 Python 패키지를 빌드 하는데 참조하는 라이브러리가 표준 라이브러리 디렉터리에 있지 않아 검색할 라이브러리의 위치를 LD_LIBRARY_PATH 환경변수를 이용하여 지정하였으나 빌드가 계속 실패 한다.

/usr/bin/ld: cannot find -ltest

삽질을 좀 하다가 생각해보니 LD_LIBRARY_PATH는 런타임(실행시)에서 사용되고 실제 컴파일 시에는 -L 옵션을 했다는 것이 생각 난다.

다음과 같이 -L 옵션으로 라이브러리를 검색할 디렉터리를 지정할 수 있다. -l 옵션으로는 라이브러리 피일을 지정한다.

gcc -o test.o -L/path/to/custom/lib -ltest

빌드 설정파일을 변경하면 되지만 직접 관리하는 소스가 아닌경우 업데이트 시 매번 같은 작업을 해주어야 하기 때문에 환경 변수로 라이브러리 경로를 설정 하는 방법이 있으면 좋을 것 같다. GCC manual 페이지를 읽어 보니 컴파일 타임에 라이브러리(링커 파일)검색 할 때는 LIBRARY_PATH 변수를 설정해 주면 된다. -L 옵션에서 지정한 디렉터리가 우선순위를 갖는다.

LD_LIBRARY_PATH

LD_LIBRARY_PATH는 프로그램 실행 타임에 동적 링커가 라이브러리를 조회 할때 사용된다.

A list of directories in which to search for ELF libraries at execution time. The items in the list are separated by either colons or semicolons, and there is no support for escaping either separator. A zero-length directory name indicates the current working directory.

LIBRARY_PATH

컴파일 타임에서 라이브러랴(링커 파일) 검색 하기 위해 사용된다.

The value of LIBRARY_PATH is a colon-separated list of directories, much like PATH . When configured as a native compiler, GCC tries the directories thus specified when searching for special linker files, if it can’t find them using GCC_EXEC_PREFIX . Linking using GCC also uses these directories when searching for ordinary libraries for the -l option (but directories specified with -L come first).

GPG를 이용하여 Git 커밋에 서명하기

커밋에 서명이 필요한 이유

Git은 분산형 버전관리 시스템(VCS, Version Control System)이기 때문에 가지고 있는 태생적인 문제가 있다. Subversion과 같은 중앙 집중형 버전관리 시스템은 모든 수정 사항이 중앙(버전관리서버)에서 관리 되기 때문에 사용자가 자신의 수정 사항을 소스 트리에 저장하고 싶으면 중앙에 있는 버전관리 시스템으로 커밋(서브버전 기준)하여야 한다. 인증 이 필요한 원격의 저장소를 사용한다고 가정하면 커밋할때 마다 매번 인증을 받아야 하고 인증이 정상적으로 완료 되어야 Commit이 반영되기 때문에 인증 정보를 도용당하지 않는 이상 기여자의 정보가 부정(도용) 사용될 경우는 거의 없다.

하지만 Git와 같은 분산형 버전관리 시스템의 경우 로컬에서 자신만의 소스트리의 관리가 가능하고 커밋에 저장되는 커밋의 작성자(Author) 커밋터(Committer)정보가 커밋을 하고자 하는 사람(또는 장치)가 제공하는 정보에 의존하기 때문에 기여자의 정보가 부정(도용) 사용 될 우려가 있다.

최근 나오는 치팅의 대부분은 권위있는 사람이나 사이트 또는 단체로 가장하여 사용자의 결제 정보를 포함한 개인 정보를 탈취하는 것이다.

프로젝트의 관리자가 Pull Request를 받았다고 가정하자. 가장 이상적인 관리 방법은 관리자가 모든 코드를 리뷰 하고 문제가 없을 경우에만 해당 요청을 승인 하는것이지만 관리자가 모든 코드를 리뷰 하지 못하는 경우 앞서 학습된 기여자의 평판에 의존 하여 승인 여부를 결정 할 수 있다. 공격자는 관리자가 신뢰할 만한 기여자의 이름을 도용하여 Pull Request를 하면 관리자는 도용된 기여자의 평판을 기반으로 승인 여부를 결정할 수 있기 때문에 문제가 발생할 수 있다. 그렇다면 이러한 명의의 도용을 막는 방법은 무엇이 있을까?

도용을 막기 위한 방법은 무엇이 있을까?

Git에서는 인터넷에서 가저온 커밋이 실뢰할 수 있는 출처에서 온것인지 확인하는 방법으로 GPG를 사용하여 커밋에 서명하는 기능을 제공한다.

커밋에대한 서명은 Git v1.7.9 또는 그 이상에서만 제공된다.

GPG(GNU Privacy Cuard)는 GNU에서 제공하는 OpenPGP(RFC4880)의 오픈소스 구현이다.

GPG의 사용법은 GPG(GnuPG) 사용하기를 참고 한다.

커밋에 서명하기

GPG Key Pair가 없는 경우 --full-gen-key 옵션으로 키를 생성한다.

gpg --full-gen-key

Key Pair 생성에 대한 자세한 방법은 GPG(GnuPG) 사용하기/Key Pair 생성을 참고 한다.

아래와 같이 개인 키의 리스트 중에 사용할 개인 키의 ID를 복사 한다.

gpg --list-secret-keys --keyid-format LONG 

아래는 [email protected]의 개인 키에 대한 예제 출력이다.

sec   rsa4096/70278B7766602624 2021-03-17 [SC] [expires: 2023-03-17]
      4D4E4059E7068A5C703C898E70278B7766602624
uid                 [ultimate] John Doe (ACME Inc.) <[email protected]>
ssb   rsa4096/EC736BC8E36D823D 2021-03-17 [E] [expires: 2023-03-17]

위 출력에서 첫 번째 라인의 70278B7766602624가 GPG key ID 이다.

git config 명령으로 user.signingkey 옵션을 설정한다.

git config user.signingkey 70278B7766602624

계정의 기본 옵션을 설정 하려면 --global 옵션을 사용한다.

git config --global user.signingkey 70278B7766602624

이제 커밋에 서명을 해보자. 수정 사항을 스테이징 하고 커밋 한다. --gpg-sign -S 옵션을 사용하면 커밋이 개인키로 서명된다.

git commit -S -m "My first signed commit"

--show-signature 옵션으로 서명 정보를 볼 수 있다.

git log --show-signature -1
commit 20872c5f0673a47a78a8fafa0c8b9ccba4d766b6 (HEAD -> master, origin/master)
gpg: Signature made Wed 17 Mar 2021 09:25:04 PM KST
gpg:                using RSA key 4D4E4059E7068A5C703C898E70278B7766602624
gpg: Good signature from "euikook <[email protected]>" [ultimate]
Author: John Doe <[email protected]>
Date:   Wed Mar 17 21:25:04 2021 +0900

    My first signed commit

Github에 GPG 공개키 등록 하기

다음 명령으로 공개키 리스트를 확인하고 서명한 키에 대응되는 공개키의 Key ID를 복사한다.

gpg --list-key
pub   rsa4096 2021-03-17 [SC] [expires: 2023-03-17]
      4D4E4059E7068A5C703C898E70278B7766602624
uid           [ultimate] John Doe (ACME Inc.) <[email protected]>
sub   rsa4096 2021-03-17 [E] [expires: 2023-03-17]

Key ID 가 4D4E4059E7068A5C703C898E70278B7766602624 이다.

--export 옵션과 --armor 옵션을 사용하여 공개키를 내보낸다.

gpg --export --armor  4D4E4059E7068A5C703C898E70278B7766602624

아래는 [email protected]의 공개 키(4D4E4059E7068A5C703C898E70278B7766602624)를 내보내기 한 결과이다.

안전한 곳에 복사해 둔다.

-----BEGIN PGP PUBLIC KEY BLOCK-----

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
NwHPf0tX2G2Mz2KR
=y3/s
-----END PGP PUBLIC KEY BLOCK-----

Github에 수정사항을 푸쉬하기 전에 서명한 키에 대응되는 공개키를 Github에 등록 하여야 한다.

Github에 접속하 로그인 하자. 우측 상단의 아바타를 클릭 하여 설정(Setting) 화면으로 이동한다.

Github - Settings

우측의 메뉴 중 SSH and GPG Keys를 선택 한다.

Github - Settings

New PGP Key 버튼을 클릭한다.

Github - Settings

앞서 복사한 공개 키를 붙여 넣고 Add GPG Key 버튼을 눌러 키를 등록한다.

Github - Settings

비밀번호를 입력하여 키를 등록한다.

Github - Settings

[email protected] 에 대한 공개키가 등록 되었다. 뒤에 Unverified 배지는 메일주소 [email protected]가 내 계정에 등록된 메일주소가 아니기 때문이다.

Github - Settings

그림과 같이 Setting / Emails에 등록된 이메일에 대한 키를 등록하면 된다.

Github - Settings

그림의 [email protected] 에 대한 GPG Key는 Unverified 배지가 없다.

커밋 올리기

Github에 서명된 커밋을 Push 한다.

git push

Push 후 해당 저장소의 커밋 정보를 열람 해보자.

이래와 같이 Verified 베지가 붙어 있다. 바르게 서명 되었고 Github에서 서명을 등록한 공개키로 검증 한 것이다.

Github GPG Signed Commit

euikook/gpg-sign-test

GPG(GnuPG) 사용하기

OpenPGP의 GNU 구현인 GPG(GnuPG)와 그 사용법에 대하여 알아보자.

GPG란?

GPG(GNU Privacy Cuard)는 GNU에서 제공하는 OpenPGP(RFC4880)의 오픈소스 구현이다.

개인간, 장비간 또는 개인 - 장비간에 교환되는 메시지나 파일을 암호화여 기밀성을 보장하거나 디지털 서명을 통해 무결성을 식별할 수 있게 해주는 도구다.

기본적으로 RSA와 같은 공개 키 암호화 방식을 사용하여 종단간 파일이나 메시지를 암호화 하거나 서명 하는 기능을 제공한다.

GnuPG에 대한 자세한 내용은 나무위키/GnuPG 또는 위키피디아/GNU 프라이버시 가드를 참고 한다.

PGP에 대한 내용은 나무위키/PGP 또는 위키피디아/PGP를 참고 한다.

이 문서에서는 GPG의 사용법에 대하여 설명 하도록 한다.

공개 키 암호화 방식에 관한 내용은 공개 키 암호화 방식이란?을 참조한다.

GPG 사용하기

Key Pair 생성

gpg --full-gen-key
  • Please select what kind of key you want: 1
  • What keysize do you want? 4096
  • Key is valid for? 2y
  • Is this correct? (y/N) y
  • Real name: John Doe
  • Email address: [email protected]
  • Comment: N/A
  • Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O

추가 정보

  • Real Name은 개인, 회사 또는 제품의 이름으로 설정한다.
  • Email address는 키의 관리자의 이메일 주를 입력 한다.
  • Comment는 선택 적이며 회사, 부서, 키의 용도 또는 버전을 입력 하도록 한다.

정보 확인 후 개인 키를 보호할 목적으로 passphrase(암호)를 입력하라는 프롬프트가 뜬다. 암호를 입력하고(또는 입력하지 않고) OK를 선택한다. Gnome과 같은 GUI를 사용하고 있다면 GUI 팝업이 뜰 수 있다.

암호를 입력 하지 않으면 입호 입력을 권하는 경고 메시지가 뜬다. 암호 없이 키를 생성 하려면 Yes, protection is not nedded를 선택한다.

경우에 따라서 암호 없기 키를 만들 수 없는 경우가 있다. 적당한 암호를 입력 하여 키를 생성하자 나중에 키에서 암호를 제거할 수 있다.

아래는 키 생성에 대한 전체 예제이다.

$ gpg --full-gen-key
gpg (GnuPG) 2.2.27; Copyright (C) 2021 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
  (14) Existing key from card
Your selection? 1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072) 4096
Requested keysize is 4096 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0) 2y
Key expires at Thu 16 Mar 2023 11:12:08 AM KST
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: John Doe
Email address: [email protected]
Comment: ACME Inc.
You selected this USER-ID:
    "John Doe (ACME Inc.) <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key B821C2E8600096BE marked as ultimately trusted
gpg: revocation certificate stored as '/home/euikook/.gnupg/openpgp-revocs.d/EFD634321C5A23B17A74AB6DB821C2E8600096BE.rev'
public and secret key created and signed.

pub   rsa4096 2021-03-16 [SC] [expires: 2023-03-16]
      EFD634321C5A23B17A74AB6DB821C2E8600096BE
uid                      John Doe (ACME Inc.) <[email protected]>
sub   rsa4096 2021-03-16 [E] [expires: 2023-03-16]

키 확인 하기

gpg --list-key
gpg --list-keys
gpg: checking the trustdb
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2u
gpg: next trustdb check due at 2023-03-16
/home/euikook/.gnupg/pubring.kbx
--------------------------------
pub   rsa4096 2021-03-16 [SC] [expires: 2023-03-16]
      EFD634321C5A23B17A74AB6DB821C2E8600096BE
uid           [ultimate] John Doe (ACME Inc.) <[email protected]>
sub   rsa4096 2021-03-16 [E] [expires: 2023-03-16]

Key에 서명하기

gpg --sign-key [email protected]

GPG 키 편집

--edit-key 옵션으로 생성된 키의 정보를 수정할 수 있다.

gpg --edit-key [email protected]

위 명령을 수행 하면 gpg> 프롬프트가 뜬다. ? 입력하면 입력 가능한 명령이 나온다.

adduid 명령으로 uid를 추가 할 수 있다.

편집이 완료 되었으면 quit 명령으로 프로그램을 종료 한다.

개인 키에서 암호 변경/제거하기

gpg --list-keys
/home/john/.gnupg/pubring.kbx
--------------------------------
pub   rsa3072 2021-03-16 [SC]
      AA1AC070A86C0523A867C0261D3E87647AD3517E
uid           [ultimate] John Doe <[email protected]>
sub   rsa3072 2021-03-16 [E]
gpg --edit-key AA1AC070A86C0523A867C0261D3E87647AD3517E

gpg> 프롬프트가 뜨면 passwd를 입력하여 비밀번호를 변경한다.

기존 비밀번호를 입력 하고 새로운 비밀번호를 입력한다. 암호를 제거 하려면 암호를 입력 하지 않고 OK를 선택한다.

암호를 입력 하지 않으면 입호 입력을 권하는 경고 메시지가 뜬다. 암호 없이 키를 생성 하려면 Yes, protection is not nedded를 선택한다.

GPG 폐기 인증서(Revocation Certificate) 생성

Key Pair를 생성한 후 폐기 인증서를 만들어야 한다. 명시적으로 키를 폐기 하고자 할때 만들어도 되지만 개인 키가 손상되었거나 분실하였을 경우 폐기 인증서를 만들 수 없기 때문에 미리 만들어서 안전한 곳에 보관한다.

폐기 인증서는 언제 만든어야 할까? 키 생성 후 바로 생성 하는 것이 좋은 방법이다. 폐기 인증서를 만든다고 키가 바로 폐기 되는것이 아니기 때문이다. 이렇게 만들어 놓은 폐기 인증서는 암호를 잊어 버리거나, 키를 분실한 경우 키를 안전하게 폐기 할 수 있는 방법을 제공한다.

gpg --output john.revoke.asc --gen-revoke [email protected]

아래는 폐기 인증서를 만든 전체 과정이다.

gpg --output euikook.revoke.asc --gen-revoke [email protected]

sec  rsa4096/B821C2E8600096BE 2021-03-16 John Doe (ACME Inc.) <[email protected]>

Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
  0 = No reason specified
  1 = Key has been compromised
  2 = Key is superseded
  3 = Key is no longer used
  Q = Cancel
(Probably you want to select 1 here)
Your decision? 0
Enter an optional description; end it with an empty line:
> 
Reason for revocation: No reason specified
(No description given)
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.

Please move it to a medium which you can hide away; if Mallory gets
access to this certificate he can use it to make your key unusable.
It is smart to print this certificate and store it away, just in case
your media become unreadable.  But have some caution:  The print system of
your machine might store the data and make it available to others!

폐기 인증서만 있다면 누구든지 공개키를 폐기할 수 있으므로 안전한 곳에 보관 하여야 한다.

키를 폐기 하는 방법은 키 폐기(Revocation) 하기를 참고한다.

공개 키 내보내기

타인에게 공개할 공개 키를 공유 하기 위해서는 키를 내보야 한다. --export 옵션을 사용하여 키를 내보낸다. 기본적으로 키를 바이너리 형식으로 내보내지만 이를 공유 할 때 불편할 수 있다. --armor 옵션을 사용하여 키를 ASCII형식으로 출력한다.

gpg --export --armor --output john.pub [email protected]

다른 사람들이 공개 키를 검증 하는 것을 허용 하려면 공개 키의 지문(fingerprint)도 같이 공유 한다.

gpg --fingerprint [email protected]

다른 사람의 공개 키 가져오기

공유 받은 공개 키를 가져온다.

gpg --import john.pub

출력되는 정보와 가져오기한 키의 정보가 맞는지 확인한다.

gpg: key B821C2E8600096BE: 1 signature not checked due to a missing key
gpg: key B821C2E8600096BE: public key "John Doe (ACME Inc.) <[email protected]>" imported
gpg: Total number processed: 1
gpg:               imported: 1
gpg: no ultimately trusted keys found

--list-keys 옵션으로 확인하자.

gpg --list-keys
/home/jane/.gnupg/pubring.kbx
--------------------------------
pub   rsa4096 2021-03-16 [SC] [expires: 2023-03-16]
      EFD634321C5A23B17A74AB6DB821C2E8600096BE
uid           [ unknown] John Doe (ACME Inc.) <[email protected]>
sub   rsa4096 2021-03-16 [E] [expires: 2023-03-16]

개인 키(비밀 키) 내보내기/가저오기

여러대의 머신에서 같은 개인키를 사용하고 싶거나 개인 키를 생성한 다음 백업 하고자 하는 경우 개인 키를 내보내야 한다.

--export-secret-key 옵션을 이용하여 키를 내보내자.

--export-options export-backup을 사용하여 키를 복원하는데 필요한 다른 정보도 같이 내보내자.

gpg --output john.secret.gpg --armor \
--export-secret-key --export-options export-backup [email protected]

다른 PC로 john.secret.gpg 파일을 복사 한후 --import 옵션으로 가저오자.

개인 키는 유출되면 치명적이므로 안전하게 보관하자.

gpg --import john.secret.gpg

개인 키는 유출되면 치명적이므로 가저오기 이후 바로 안전하게 삭제한다.

shred 명령을 사용하여 안전하게 삭제한다.

shred -zvu -n  5 john.secret.gpg

아래는 예제 출력이다.

shred: john.secret.gpg: pass 1/6 (random)...
shred: john.secret.gpg: pass 2/6 (000000)...
shred: john.secret.gpg: pass 3/6 (random)...
shred: john.secret.gpg: pass 4/6 (ffffff)...
shred: john.secret.gpg: pass 5/6 (random)...
shred: john.secret.gpg: pass 6/6 (000000)...
shred: john.secret.gpg: removing
shred: john.secret.gpg: renamed to 000000000000000
shred: 000000000000000: renamed to 00000000000000
shred: 00000000000000: renamed to 0000000000000
shred: 0000000000000: renamed to 000000000000
shred: 000000000000: renamed to 00000000000
shred: 00000000000: renamed to 0000000000
shred: 0000000000: renamed to 000000000
shred: 000000000: renamed to 00000000
shred: 00000000: renamed to 0000000
shred: 0000000: renamed to 000000
shred: 000000: renamed to 00000
shred: 00000: renamed to 0000
shred: 0000: renamed to 000
shred: 000: renamed to 00
shred: 00: renamed to 0
shred: john.secret.gpg: removed

또는 wipe 먕량을 사용한다.

wipe -rfiv john.secret.gpg

아래는 예제 출력이다.

wipe: destroy file `john.secret.gpg'? y
john.secret.gpg: 100%

wipe 명령이 없으면 설치 한다.

Debian 기반인 경우

sudo apt-get install wipe 

Redhat 기반인 경우

sudo yum install wipe

ArchLinux 기반인 경우

sudo pacman -S wipe

암호화 하기

암호화 할 파일을 생성한다.

echo "This is plan text" > doc.txt

doc.txt 을 암호화 한다.

gpg --encrypt --output doc.txt.gpg --armor --recipient [email protected] doc.txt

doc.txt 을 개인 키로 서명하고 암호화 한다. 서명에 사용될 키를 지정 해주지 않으면 기본 개인 키가 사용된다.

개인 키가 없으면 에러가 발생한다. Key Pair 생성를 참조 하여 키 쌍을 생성한다.

gpg --encrypt --sign --output doc.txt.sign.gpg --armor --recipient [email protected] doc.txt
  • --encrypt 옵션을 이용하여 암호화 한다. -e로 축약할 수 있다.
  • --sign 옵션으로 signature를 생성한다. 자신의 개인 키로 서명을 한다. 복호화를 위해서는 서명에 사용한 개인 키에 대응되는 공개 키카 설치 되어야 한다. -s로 축약할 수 있다.
  • --output 옵션을 이용하여 암호화된 결과물이 저장될 파일의 이름을 지정한다. -o로 축약 할 수 있다.
  • --armor 옵션을 이용하여 ASCII 형식으로 내보낸다. -a로 축약할 수 있다.
  • --recipient 옵션으로 암호화에 사용될 공개 키를 지정한다. -r로 축약할 수 있다.
  • doc.txt 암호화 하고자 하는 파일을 지정한다.

평문인 doc.txt 파일은 다음과 같다.

This is plan text

암호화 된 파일인 doc.txt.gpg의 내용은 아래와 같다.

-----BEGIN PGP MESSAGE-----

hQIMA21mHEvqjR9LARAAnqRsoDWnEvpMGzaLxW9Jp5ytSW6V8uimJo0TboUh5Ur6
PuNRAyQS3Dvll2CmIXg9i7yNjd4ameCm1eQSfL7b/D5yJcTrfRJX6D8clgFs2QIb
oqz3SGhzgx+bdAtY4yvO89+yhNHEFBQZHSE9tlh6lS4zXuZE745HWk+sECBKA1pm
Xz6XpvN7NUtF655lmvNlSE/fQ3yxptq6c5KHC29cJmc2VpHBuPs/42qt/rxWjTUd
FbWY1+IbroJq8VkEbPR9G/sHmaRyu+YhS0bud6orkJfeP0dMgexJBAxf8abXShIl
5xBcGW2NvoSSTqP6GoJXOnzcc+XXAhosun83uFdwx7Uv+qmqn4iN6HSeAujnsqCG
c+ZCKBPHCOig2qWBsj3CH3CLL7gjANuoJgS2W92KYmaUcbsDX5hZiIdmNEWjgQbV
eDW1TifqlVVLVo/r2h/cawHsYqLwhH+tJeziIqyROQaYYdrDc+SWyUd//eIQQfDn
QGJrAaf+qKvSW8h6GGmv4LztIYPqxpF2+zwu06lQIHg7VWUOhAZO00yxAlwh/scV
6sZjuXgWb5aJTmpVVexAaW6VJsGt92Uij5pVajmEkrgnBK2kvaBbl4ykRJ9w6FTv
BVgTS+tQFr1KS0NAaL7hV/VrPvgceR1bo62p9E7MqgPICTu7dvOBst9z/M15t9vS
UgGQsLcBmr73MIkaXFsEt1kOEm6iY/BSOvcp2FC5U7FD6yyyMLNaeKX9wnP1sA8M
phFmKzRpw7UG5lh3fesRE/z0ZboCxjSHEmbDMW7hnEo8fn0=
=3TXR
-----END PGP MESSAGE-----

서명후 암호화된 파일인 doc.txt.sign.gpg의 내용은 아래와 같다. (개인 키로)서명된 파일을 암호화 했기 때문에) 더 길다.

-----BEGIN PGP MESSAGE-----

hQIMA21mHEvqjR9LAQ/+Kn9oWh+Bcq4LOU3jAA2rgE0R4+i8yzTR6oh+VmjFkzbQ
ja1frjoqGoIEqnMiYGP13tDvg1LpAceX9JFB0OnihRTTjzrsqCK9WqbrZoXVn6UG
Dz4CbRjG+fe9+pNMS9rdkgRMLF0UBMSrhDWBcQwR5B8C9nvm1f8h/CTNfFM/4hvW
OewlXpMhylwrfXLY9Bf7cxBzWMpnC+Gxbukp1ORHKUsN46b/4SRZ7NzFbKP+TNWb
dOBe98j3dTPbhavPj/JlFcB/gfFdNmpIhLIiDKGJeZJrpQA8R/mekhgM9/mXrxhU
HUnKbUCqeGFE1foiizhAbs6PpksW5YoEQv/wjXJxE/YLNjgOrL+7JLif1+8jBhLO
lzc/wW4tpaIuc3aJZIqGUYJzgzlDnCihMb8jD9kWzdweUQAN0HTnP/PC9kAnQ98v
uHyORW53Ie/fhrGTSAObspkXqQ+1b5jgcLlk9LmK6tlyOMWvFHxjDeP0WrjPCWaA
zpQlNUmnn3SlWNXQEkKo53FqJkcDPujxW//nsiPreCuj995o+UeE9k0UPXsLCob+
RpA54rX3aTCRVKjF6H2yoXr8HWaL7MfDI8amA4aDRDnSWdNnr0DAplbn5dZJTLPj
vdxagGS759tEPZalrduP0R0lVyw3Ds6E4J9+hVstqlFnxbOroiGEZqzx1v7ArxvS
6QFtKoV5dLR9B9lr6ykoTgYQ79qB1h2OT9Y33IhfvyliGve49mCW3ScXBZxXGlmp
7om0xpWVymxbL6ReWUeBKlVGoOK/GexVFHUTyCTiO4XVMV+ueS+VP4cfWvXe7cGv
lyRvuE+s+hiz1Apv9xZ/mv/Z13kRWi55JDfYmxEBs8dI1I9albvXPSnZW3wjfRkZ
DpUj7hi2YAp8zYHFmrhPLRlVOZZPcNYjiQASY+DkKkxIPXoUrMvz6SboZzHhnLv2
wtVEAFBXza2uVSmD+Eflj6X3LWjUAMFke2UGzaXzbYhJXK/pu0UMCLwKfd9SI8hi
3DdmdG1OtqDPsXYF90zdI1IljyRvBWJZg27LGqieQB7xWFiZ5FKz9fYgmU3BTPRW
wN6S2DUbu1NjUjGtJN65KoRKbPs/k5RCHxbUAJkgS7vveWpy8zXFDngkvbIlldf/
sGNWdDPIh/Kb+2NUOKW4x/HfBW1J5J24mIjN+y2e1TXWdzN8Yn6wggxoM9i5rU9i
MrVPtXBHxFcxgBKGZRYf5L3a8zgwP72CcNkE7u09jktSOXz92tq+IgYwb/vYJJdV
fnZQ7WeUYN/LwkD7WG9bDhIzOd4G+hf6YpFz7ApZedO3QQCq6OOchZwwvNEUFTBx
8MeP+XT7fUOlSpUK2I89GyPKMXvNTuTPcpWJrHM54iX2nKl2tf43fCJM7HYxTP9C
SPpviIMr0EOPl/Ff5LM7PvYiiMWoQR6ZikxmS7ESMQEkvAGc3k9mGXBzJh+VexFX
DbCzidT/sbbAHY8N3aP66SH5c8OounCZip+5w08+c/r09JmDlWdM0qnlpdGPE9FT
A1MitGPxdZXk5+ihKyVuul5IlaJ8PcMAkZcodsyIbfe59BrwM5XHCoHP4CeBQg==
=KSvJ
-----END PGP MESSAGE-----

암호화(Encryption)서명(Signing)

암호화(Encryption)서명(Signing) 에 대한 정리를 하고 넘어갈 필요가 있다.

GPG(GnuPG)에서는 암호화(Encryption)서명(Signing) 이라는 두가지 용어를 사용하는 데 암호화 는 공개 키를 이용하여 암호화 하는 방법이고, 서명(Signing) 은 개인 키를 이용하여 암호화 하는 방식이다.

암호화(暗號化) 또는 엔크립션(Encryption)은 특별한 지식을 소유한 사람들을 제외하고는 누구든지 읽어볼 수 없도록 알고리즘을 이용하여 정보(평문을 가리킴)를 전달하는 과정이다. (출처 - 위키피디아)

공개 키를 이용하여 암호화 하였을 경우 암호화에 사용된 (공개 키에 대응되는) 개인 키를 가진 사람만이 정보를 열람 할 수 있다. 개인 키를 소유한 사람만 정보를 열람 할 수 있으므로 암호화(Encryption) 한다.

서명(署名, signature) 또는 사인(영어: sign)은 누군가의 이름, 가명, 또는 누군가가 문서에 기록했다는 증거, 자기 동일성을 위한 표시를 하기위해 쓴 것을 말한다. (출저 - 위키피디아)

그에 반해 개인 키를 이용하여 암호화는 공개 키를 가진 모든 사람(공개 키가 키 서버에 공개 되어 있다면 잠재적으로 누구든지)이 해당 정보를 열람 할 수 있으므로 암호화(Encryption) 의 정의와는 맞지 않는다. 개인 키를 통하여 암호화된 정보가 (개인 키에 대응되는) 공개 키로 복호화 된다는 것은 해당 정보의 출처가 (이 정보에 서명(Signing) 한 개인 키에 대응되는) 공개 키를 공개한 사람 이라는 것과 - 개인 키는 정보에 서명한 사람만 소유하고 있기 때문이다. - 데이터가 (작성자가 서명한 이후)변조 되않았다는 것을 증명한다. 따라서 개인 키로 암호화 하는 것을 서명(Signing) 이라고 한다.

따라서 --sign옵션을 사용하면 개인키로 암호화(Encrypt) 서명(Signing) 한 다음 받는사람(Recipient) 의 공개 키로 한번 더 암호화(Encryption) 하는 것이다.

참고 - stackoverflow: how to encrypt a file using private key in gpg

--list-packets 옵션으로 암호회된 데이터의 순서를 보면 암호화가 먼저 되었는지 서명이 먼저 되었는지 확일 할 수 있다.

머신에 [email protected] 의 개인 키와 공개키가 모두 있다면 아래와 같이 실행 해보자.

echo 'this is plain text' | gpg -r [email protected] --encrypt --sign   | gpg --list-packets

다음은 예제 출력이다.

gpg: encrypted with 4096-bit RSA key, ID EC736BC8E36D823D, created 2021-03-17
      "John Doe (ACME Inc.) <[email protected]>"
# off=0 ctb=85 tag=1 hlen=3 plen=524
:pubkey enc packet: version 3, algo 1, keyid EC736BC8E36D823D
	data: [4093 bits]
# off=527 ctb=d2 tag=18 hlen=2 plen=0 partial new-ctb
:encrypted data packet:
	length: unknown
	mdc_method: 2
# off=548 ctb=a3 tag=8 hlen=1 plen=0 indeterminate
:compressed packet: algo=2
# off=550 ctb=90 tag=4 hlen=2 plen=13
:onepass_sig packet: keyid 70278B7766602624
	version 3, sigclass 0x00, digest 10, pubkey 1, last=1
# off=565 ctb=cb tag=11 hlen=2 plen=25 new-ctb
:literal data packet:
	mode b (62), created 1615965739, name="",
	raw data: 19 bytes
# off=592 ctb=89 tag=2 hlen=3 plen=578
:signature packet: algo 1, keyid 70278B7766602624
	version 4, created 1615965739, md5len 0, sigclass 0x00
	digest algo 10, begin of digest 9e d9
	hashed subpkt 33 len 21 (issuer fpr v4 4D4E4059E7068A5C703C898E70278B7766602624)
	hashed subpkt 2 len 4 (sig created 2021-03-17)
	hashed subpkt 28 len 13 (signer's user ID)
	subpkt 16 len 8 (issuer key ID 70278B7766602624)
	data: [4095 bits]

가장 처음이 gpg: encrypted with 4096-bit RSA key시작 하는것으로 보아 서명된 파일이 암호화 되었다는 것을 알 수 있다.

개인 키가 여러개여서 기본으로 지정된 개인 키가 아니라 특정 개인 키를 지정 하고 싶다면 --local-user 옵션으로 서명에 사용될 USER-ID나 개인 키의 KEY-ID를 지정할 수 있다.

서명에 사용될 USER-ID를 지정하지 않으면 secret keyring에서(--list-secret-keys 옵션을 사용했을 때) 가정 먼저 나오는 USER-ID가 선택된다.

복호화 하기

gpg --decrypt --output doc.txt.dec doc.txt.gpg
gpg --decrypt --output doc.txt.sign.dec doc.txt.sign.gpg
  • --decrypt 옵션을 이용하여 복호화 한다. -d로 축약할 수 있다.
  • -output 옵션을 이용하여 복호화된 결과물이 저장될 파일의 이름을 지정한다. -o로 축약할 수 있다.
  • doc.txt.gpg | doc.txt.sign.gpg 복호화할 암호화 된 파일을 지정한다.

서명이된 암호화 파일의 경우 서명한 사람의 공개 키가 설치 되어 있어야 정상적으로 복호화가 된다.

복호화 제대로 되었는지 확인한다. 결과는 아래와 같다.

This is plan text

공개 키 서버 사용하기

이메일 주소를 기반으로 공개 키를 등록하고 받게 해주는 공개 키 서버가 있다.

아래는 대표적인 키 서버 목록이다.

예제에서는 OpenPGP Key Server를 사용한다.

키서버에 올리기

gpg --send-keys --keyserver keys.openpgp.org EFD634321C5A23B17A74AB6DB821C2E8600096BE

키를 등록하면 키 생성 시 입력한 메일 주소로 확인 메일이 온다. 설명에 따라 인증을 수행한다.

키서버에서 공개 키 가저오기

gpg --keyserver pgp.mit.edu --search-keys [email protected]

아래는 키를 받는 예제이다.

gpg --keyserver keys.openpgp.org --search-keys [email protected]

위 명령을 수행하면 [email protected] 와 관련된 공개 키 리스트가 나오고 키를 선택 하라는 프롬프트가 뜬다.

Keys 1-1 of 1 for "[email protected]".  Enter number(s), N)ext, or Q)uit >

내려받고 싶은 키의 번호를 입력하면 키를 내려받아 키 저장소에 추가된다.

아래는 [email protected] 으로 키를 검색하여 내려 받는 예제이다.

$ gpg --keyserver keys.openpgp.org --search-keys [email protected]
gpg: data source: http://keys.openpgp.org:11371
(1)	euikook <[email protected]>
	  4096 bit RSA key 6FE1162F829A61EE, created: 2021-03-16
Keys 1-1 of 1 for "[email protected]".  Enter number(s), N)ext, or Q)uit > 1
gpg: key 6FE1162F829A61EE: public key "euikook <[email protected]>" imported
gpg: Total number processed: 1
gpg:               imported: 1

키 폐기(Revocation) 하기

키 서버에서 키를 삭제 하기 위해서는 폐기 인증서(Revocation Certificate)를 먼저 만들어야 한다.

키를 폐기 하더라도 폐기 전에 했던 서명들은 유효하다. 마찬가지로 폐기된 비밀키에 접근 가능하다면 폐기 전 수신했던 폐기된 공개키로 암호화 된 메시지도 복호화 할 수 있다.

--import 옵션으로 폐기 인증서를 가저 온다.

gpg --import john.revoke.asc 
gpg: key B821C2E8600096BE: "John Doe (ACME Inc.) <[email protected]>" revocation certificate imported
gpg: Total number processed: 1
gpg:    new key revocations: 1
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: depth: 0  valid:   3  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 3u
gpg: next trustdb check due at 2023-03-16

정상적으로 폐기 되었다.

--list-keys--list-secret-keys 옵션으로 키가 정상적으로 폐기 되었는지 확인한다.

gpg --list-keys
pub   rsa4096 2021-03-16 [SC] [revoked: 2021-03-16]
      EFD634321C5A23B17A74AB6DB821C2E8600096BE
uid           [ revoked] John Doe (ACME Inc.) <[email protected]>

pub rsa4096 2021-03-16 [SC] [revoked: 2021-03-16]

gpg --list-secret-keys
sec   rsa4096 2021-03-16 [SC] [revoked: 2021-03-16]
      EFD634321C5A23B17A74AB6DB821C2E8600096BE
uid           [ revoked] John Doe (ACME Inc.) <[email protected]>

uid [ revoked] John Doe (ACME Inc.) <[email protected]>

이제 공개키가 폐기 되었다는 것을 다른 사람에게 알릴 필요가 있다. 패기 인증서를 공개키를 공유한 사람에게 전송한다.

공개키 서버에 폐기된 공개 키 보내기

--send-keys 옵션으로 키가 폐기 되었다는 것을 알린다.

gpg --send-keys --keyserver keys.openpgp.org EFD634321C5A23B17A74AB6DB821C2E8600096BE

폐기 후 키를 다시 생성 하고 공개키를 키서버에 올리자.

키서버에서 키 갱신 하기

서명된 파일을 받았는데 폐기된 키를 가지고 있어 검증 할 수 없는 경우 보낸 사람에서 새로운 공개 키를 공유 받거나 키 서버에서 키를 갱신 하여야 한다.

--refresh-key 옵션으로 키를 갱신한다. --key-server 옵션으로 키 서버를 지정할 수 있다.

gpg --refresh-keys --key-server keys.openpgp.org

Insync Moving to new computer without re-syncing

이 글에서는 Insync을 사용중 PC를 옯기거나 OS를 재설치 하여야 하는 경우 재 동기화 없이 데이터를 옮기는 방법에 대하여 설명한다.

Insync: Google Drive Syncing Application for Linux

Insync: 리눅스를 위한 Google Drive 동기화 어플리케이션

Insync 종료

PC를 Apple에서 Banana로 옯기는 경우 Apple PC와 Bnana PC에서 Insync를 종료 한다. OS를 다시 설치 하는 경우 해당 PC의 Insync만 종료 한다.

insync quite
insync-headless quite

Data 디렉터리 백업 또는 이동

다른 컴퓨터로 이동

Insync의 동기화 폴더를 Apple에서 Banana로 이동한다.

리눅스의 경우 rsync로 동기화 할 수 있다. 이동 하고자 하는 Banana에 접속 하여 아래 명령을 수행한다.

실제 명령 입력 시 Apple은 자신의 기존 컴퓨터의 호스트네임으로 변경한다.

AppleBanana의 동기화 디렉터리는 경로가 같아야 한다.

OS 재설치

OS를 다시 설치 하는 경우 해당 PC의 동기화 폴더를 백업한다.

리눅스의 경우 별도의 저장 장치에 저장하거나 OS를 재설치 하더라도 지워지지 않는 디렉터리에 저장한다.

예제에서는 /mnt/backup/ 디렉터리에 Insync.data.tar라는 이름으로 백업한다.

tar cvf ~/mnt/backup/Insync.data.tar ~/Insync

재설치 후 백업된 데이터를 복구 한다.

OS 재설치 후 Insync를 설치 하고 실행 않은 상태에서 데이터를 복원한다. 이미 설치 하여 ~/Insync 디렉터리가 존재 할 경우 삭제 복구 한다.

rm -rf ~/Insync

백업 데이터를 복구한다.

tar xvf ~/mnt/backup/Insync.data.tar -C ~/

재설치 후 재설치전 동기화 디렉터리와 같은 경로에 데이터를 복구 해야 한다.

설정 파일 백업 또는 이동

Insync의 설정 데이터와 인증 정보와 같은 설정 동기화 정보의 위치는 아래와 같다.

해당 디렉터리를 이동하거나 백업 한다.

  • Windows

    • C:\Users\[Username]\AppData\Roaming\Insync
    • C:\Users\[Username]\AppData\Roaming\Insync-headless
  • Mac OS:

    • ~/Library/Application Support/Insync
    • ~/Library/Application Support/Insync-headless
  • Linux

    • ~/.config/Insync
    • ~/.config/Insync-headless

다른 컴퓨터로 이동

Insync의 동기화 폴더를 Apple에서 Banana로 이동한다.

리눅스의 경우 rsync로 동기화 할 수 있다. 이동 하고자 하는 Banana에 접속 하여 아래 명령을 수행한다.

Headless 버전의 경우 ~/.config/Insync~/.config/Insync-headless로 변경한다.

실제 명령 입력 시 Apple은 자신의 기존 컴퓨터의 호스트네임으로 변경한다.

OS 재설치

OS를 다시 설치 하는 경우 해당 PC의 동기화 폴더를 백업한다.

리눅스의 경우 별도의 저장 장치에 저장하거나 OS를 재설치 하더라도 지워지지 않는 디렉터리에 저장한다.

예제에서는 /mnt/backup/ 디렉터리에 Insync.config.tar라는 이름으로 백업한다.

tar cvf ~/mnt/backup/Insync.config.tar ~/.config/Insync

재설치 후 백업된 데이터를 복구 한다.

OS 재설치 후 Insync를 설치 하고 실행 않은 상태에서 데이터를 복원한다. 이미 설치 하여 ~/config/Insync 디렉터리가 존재 할 경우 삭제 복구 한다.

rm -rf ~/.config/Insync

복구한다.

tar xvf ~/mnt/backup/Insync.config.tar -C ~/

OS 재설치 후 Insync를 설치 하고 실행 않은 상태에서 데이터를 복원한다.

Insync 시작 및 확인

insync start

headless 버전의 경우 아래 명령을 실행한다.

insync-headless start

아래 명령으로 Insync의 상태를 확인한다.

insync show

headless 버전의 경우 아래 명령을 실행한다.

insync-headless status

Insync 3.x auto start with systemctl

Desktop 라이센스로 같이 사용할 수 있을 줄 알았는데. 서버용 라이센스를 별도로 구매 해야 된다. WTF 그것도 일년에 39.99 달러, 거기다 나처럼 Google Workspace를 사용하여 gmail.com 이 아닌 커스텀 도메인 을 사용하는 사람은 일년에 159.99 달러다. 돈이 썩어 나는구나. 다음글을 참고 하여 Insync Desktop 버젼을 자동실행 하는 방법을 사용하자. Insync 3.x auto start with xvfb and systemctl. 굳이 연간 39.99 달러나 159.99 달러를 내면서 headless 버젼을 사용하고 싶으신 분은 다음글을 참고 하기 바란다.

그냥 GoodSync로 갈아 타 버릴까?

이 글에서는 Google Drive 와 One Drive의 third-party 동기화 유틸인 Insync의 headless 버전을 설치 하고 자동 실행 하는 방법에 대하여 알아본다.

Insync: Google Drive Syncing Application for Linux

Insync: 리눅스를 위한 Google Drive 동기화 어플리케이션

Insync가 3.x 버전으로 판올림 되면서 headless 버전이 사라지는 바람에 xvfb를 통해 우회 실행 하는 방법에 대하여 설멍한 적이 있다.

하지만 Insync 3.x 대한 headless 버전이 릴리즈 되었기 때문에 이런 번거로운 작업이 필요 없어 졌다.

잘 돌아가는 Insync를 headless 버전으로 바꾸기 귀찮아서 미루고 있었는데 이번에 Ubuntu Box를 Bionic에서 Focal로 판올림 하는 김에 시간을 내서 headless 버전으로 변경 하였다.

Prerequisites

  • insync-headless

Insync headless 설치

Insync의 설치 방법은 Insync - Linux에서 Google Drive Desktop Client 사용하기를 참고 한다.

Stop and Remove Insync with xvfb version

이전에 [xvfb 버전]((/posts/insync-3.x-auto-start-with-xvfb-and-systemctl)문서를 참고 하여 설정 하였다면 xvfb와 insync 서비스를 삭제 하자.

systemctl --user stop insync.service
systemctl --user stop xvfb.service
rm -f /home/$USER/.config/systemd/user/xvfb.service
rm -f /home/$USER/.config/systemd/user/insync.service

UI 버전에서 Headless 버젼으로 변경 시 유의 사항

각 설정 과 데이터베이스 파일의 구조는 크게 변하지 않은 것 같으나 위치가 변경 되었다.

  • UI Version의 경우 ~/.config/Insync
  • Headless 버젼의 경우 ~/.config/Insync-headless

따라서 UI 버젼에서 Headless 버젼으로 변경하고 Insync를 실행하면 UI 버전에서 사용하던 계정 등의 설정 정보를 같이 로드 되지 않는다.

~/.config/Insync 디렉터리를 ~/.config/Insync-headless로 복사한다.

cp -ap ~/.config/Insync ~/.config/Insync-headless

UI 버전과 Headless 버젼의 설정 파일 구조가 언제 바뀔지 모르기 때문에 Symbolic Link 보다는 Hard Link링크로 복사하여 Headless 버젼을 실행 해 보고 문제가 발생하면 해당 디렉터리를 삭제 후 다시 설정하자.

Headless 버전에서 UI 버젼으로 바꾸는 경우에는 반대로 수행하면 된다.

Systemctl script

Insync headless

Create a file /home/$USER/.config/systemd/user/insync-headless.service

Enable unit file

systemctl --user enable insync-headless.service

Enable Lingering

loginctl enable-linger ${USER}
loginctl show-user ${USER} | grep Linger

Post reboot

systemctl --user status insync-headless.service
ps ef |grep insync-headless