curl 사용법을 정리해 본다. curl 사용법을 정리하는 이유는 쿠버네티스(Kubernetes) 를 사용하면서 테스트를 위해서 많이 사용할 명령어이기 때문이다. 쿠버네티스에서 주로 사용하는 방법은 인증서를 지정해 인증을 받아 실행시키는 API 호출이다.
–cacert
TLS 연결을 위해 인증서 파일을 지정하는데 사용 한다. 이 파일은 다중 CA 인증서를 포함할 수 있다. 여기서 ‘다중 CA 인증서’ 는 인증서 체인(Certification Chain) 을 말한다. 인증서는 반드시 PEM 포맷이여야 한다.
–cert
TLS 연결을 위한 클라이언트 인증서 파일을 지정하는데 사용 한다. 인증서는 보안 전송(Secure Transport) 를 위해서는 PKCS#12 포맷을 다른 엔진을 위해서는 PEM 포맷을 사용이여야 한다. 이 옵션은 개인 키와 클라이언트 인증서가 연결된 인증서 파일로 가정 한다.
–key
개인 키 파일 이름
쿠버네티스 테스트
현재 쿠버네티스를 KVM 에 Hardway 로 설치를 했다. controller-manager, etcd, apiserver 등을 OS 프로세스등으로 작동한다. 이러다보니 이 서버에 연결을 위해서는 인증을 해야 하는데, 인증서가 필요한데 테스트를 다음과 같이 할 수 있다.
컴퓨터를 다룬다는 건 쉬운게 아니다. 컴퓨터 자체는 공학 개념이지만 그 컴퓨터에서 작동하는 수 많은 일들은 과학에 속한다. 이러한 컴퓨터 과학분야는 매우 다양해서 대충이라도 알고 있는 것과 모르는 것의 차이는 시간이 갈 수록 커질 수 밖에 없다.
그 대충이라도 알아야하는 것중에 하나가 암호화다. 컴퓨터 네트워크를 위해서 필요한 보안을 가능하게 해주는 암호화. 개인 정보의 중요성을 가져오지 않아도 과거부터 컴퓨터 네트워크에서 암호화는 필요 이상이였다.
암호화 방법에서 데이터를 암호화 하는 키가 어떤건지를 말하는 것으로 대칭키, 비대칭키라는 말이 있다. 오늘은 암호화의 기초, 용어에 대해서 알아본다.
대칭키(Symmetric Key)
대칭키는 영어로 Symmetric Key 라고 하는데, 직역 그 자체로 ‘대칭’ 이다. ‘대칭’ 이라는 용어의 사용은 동일한 형상이 상반된 위상에 존재하는 것을 말한다. 대칭은 자연상태에서 가장 많이 발견된다. 식물의 꽃의 경우 반으로 접었을때에 포개지는 것이 대표적이다. 자연이 가장 안전적인 상태가 대칭이라는 말이 있을 정도로 자연에서의 대칭은 흔하다.
암호화는 복호화도 포함한다. 어떤 평문을 암호화 했다면 반드시 해독이 가능하도록 평문으로 되돌릴 수 있어야 한다. 이를 복호화라고 하는데, 암호화 할때 사용하는 암호화 키와 복호화 할때 사용하는 복호화 키가 모두 동일한 경우를 대칭키 암호화라고 한다.
암호화 과정과 복호화 과정을 포개면 동일한 키가 딱 들어맞고 찾을 수 있다해서 대칭키라고 이름을 붙인 것으로 보인다. (이건 추정이다. 하지만 이름 하나는 딱 맞게 잘 지은 거 같다)
대칭키 암호화는 암호화, 복호화에 모두 동일한 키를 사용하기 때문에 복호화를 하는 사람도 결국 같은 키를 가지고 있어야 한다. 암호전문을 전송, 수신하는 양측 모두 같은 암호키를 가지고 있어야지만 암호화전문을 보내고 복호화해서 평문으로 내용을 확인할 수 있으니까..
암호화의 발전은 전쟁으로 인한 것이 였다. 1,2차 대전때에 전문통신을 암호화 해야할 필요가 있었는데, 이때 암호화를 위한 키 스트링을 사용했었다. 다시 복호화를 하기 위해서는 암호화 과정에서 사용했던 동일한 키 스트링을 이용해야만 했다. 대칭키 암호화를 활용한 것이다.
이러다보니 적군에게 스파이를 파견해 하는 일중에 최우선은 이 암호화 하는데 이용하는 키 스트링을 훔쳐오는 것이다. 그 키 스트링만 알면 적군의 암호전문통신을 중간에서 가로채서 해독할 수 있고 작전을 모두 알 수 있었기 때문이다.
이것은 결과적으로 대칭키 암호화에서 암호화 한 전문 보다는 암호화를 하는데 사용한 대칭키를 어떻게 보관하고 상대방에게 전달해야 하느냐 하는 문제로 이어진다.
컴퓨터 분야에서도 대칭키 암호화를 활용한적있다. 대표적으로 DES 암호화 알고리즘이 그것이다. DES 암호화 알고리즘은 IBM 이 만들어서 미국 NIST 에 제안해 채택되었다. 하지만 1998년에 대칭키를 몰라도 수학적으로 해독이 가능하다는 것이 증명됨에 따라 사용하지 않고 있다.
비대칭키(Asymmetric Key)
비대칭키 암호화는 암호화 하는데 사용하는 암호화 키와 복호화 하는데 사용하는 복호화 키가 다르다. 어떻게 암호화 키와 복호화 키가 다른데, 평문을 암호화도 되고 더군다나 그 암호화된 문장이 평문으로 복호화가 되나? 하겠지만, 매우 잘 된다.
비대칭키 암호화의 핵심은 복호화와 전달에 있다. 정확하게 말하면 암호화, 복호화 전체과정에서 가장 중요하게 보는 부분이 복호화일 뿐이다.
암호화를 하는 이유는 보안을 위한 것이다. 그 보안이라는 것은 타인이 내가 봐야하는 뭔가 은밀한 기밀을 들키지 않고 유지 하는 것을 말한다. 결국 그 은밀한 기밀은 나만 보아야 한다는 전제가 깔린 것이다.
비대칭키 암호화에서 가장 중요하게 보는 것은 복호화다. 암호화는 아무나 다 해도 된다. 하지만 그것을 볼 수 있는 사람은 오직 나 혼자여야 한다. 따라서 복호화를 위한 키는 나만 가지고 있으면 된다.
암호화를 하는 이유는 타인에게 정보를 전달하기 위한 것이다. 타인에게 정보를 전달도 하지 않을 거라면 나 혼자 아는 암호화 키로 암호화하고 보관하면 된다. 나만 알고 있는 키이기 때문에 다른 사람에게 유출될 일도 없다. 하지만 타인에게 정보를 전달하는 거라면 대칭키 암호화에서처럼 상대방도 내 암호화 키를 알고 있어야 하고 이 키를 전달하는데 많은 보안을 유지해야 한다.
하지만 암호화 된 전문을 나만 아는 키로 해독이 가능하면 대칭키 암호화 키 전달을 위한 추가적인 보안이 필요 없다.
비대칭키 암호화는 그 누구나 암호화를 할 수 있는 키가 존재하고 나만 복호화 할 수 있는 복호화 키, 이렇게 두가지로 존재한다. 이를 공개 키(Public Key), 개인 키(Private Key) 라고 부른다.
비대칭키 암호화를 사용하기 위해서 나는 공개 키와 개인 키 두개를 만든다. 그리고 공개 키를 세상에 그냥 뿌린다. 인터넷에 그냥 올려놔도 된다. 지구상에 모든 사람이 공개 키를 알아도 된다. 왜냐하면 공개 키로 암호화 한 전문은 오로지 나 혼자 가지고 있는 개인 키로만 평문으로 복호화가 가능하니까.
비대칭키 암호화에 대표는 RSA 이다. 론 리베스트(Ron Rivest), 아디 샤미르(Adi Shamir), 레오나르드 애들만(Leonard Adleman) 3명의 수학자의 앞 글자를 따서 지은 것이다.
이 3명의 수학자는 MIT 컴퓨터 사이언스 실험실 8층에서 함께 암호화 알고리즘 연구를 진행하던 중에 디피와 헬만이 발표한 비대칭키 암호화 알고리즘을 듣게 된다. 그리고 그들도 이 암호화 알고리즘 개발에 착수하는데, 1977년 4월에 론 리베스트가 수학 교과서를 읽다가 갑자기 아이디어가 떠올랐다고 한다. 그는 전광석화처럼 그날 밤에 논문을 작성하고 마쳤는데, 논문에 마지막에 자신을 포함한 연구실 사람 이름을 올렸다고 한다. 그래서 RSA 라고 부르게 되었다는 것.
SSH 키 접속
어느날 한번쯤은 ‘SSH 키 접속’ 이라는 것을 들어보거나 검색을 해봤을 것이다. SSH 는 서버에 접속을 위한 프로그램으로 SSH 서버에 접속을 위해서는 ID/Password 입력해 접속을 한다. 하지만 SSH 는 Key 방식으로 접속을 지원한다. 이때 SSH가 사용하는 Key 방식이 RSA 키 방식이다.
SSH 키 접속을 위해서는 암호화 키를 생성해야 하는데, 대충 다음과 같은 명령어로 생성이 된다.
SSH RSA 키 생성
ZSH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ssh-keygen-tRSA
Generating public/privateRSA key pair.
Enter file inwhich tosave the key(/home/systemv/.ssh/id_rsa):
Enter passphrase(empty forno passphrase):
Enter same passphrase again:
Your identification has been saved in/home/systemv/.ssh/id_rsa
Your publickey has been saved in/home/systemv/.ssh/id_rsa.pub
Ansible 을 사용할때에 특정 동작에 대해서 대기한 후에 진행하도록 해야할 필요가 있다. 대표적인 것이 Tomcat 과 같은 경우인데, Tomcat 이 시작을 하게 되면 애플리케이션이 동작하기까지 몇 초의 시간이 더 걸린다. 웹 애플리케이션이 정상적으로 접속을 받기 전에 또 다른 작업을 하게 될 경우에 문제가 된다.
wait_for
Ansible 에서는 위와같은 경우를 위해서 wait_for 라는 것을 지원한다. 예제를 보면 단번에 이해할 수 있다.
vim 은 리눅스의 기본 에디터이다. 많은 기능을 제공하지만 이 기능을 사용하기 위해서는 설정을 해야 한다. 그런데, 이런 설정을 하나하나 하기 보다는 간단하게 Plugin 형태로 제공해 네트워크를 통해서 설치를 도와주는 플러그인 프로그램이 있다. 이것을 이용해서 기본적인 세팅을 해보자.
VIM 세팅을 위해서 git 명령어가 설치되어 있어야 한다. 그리고 기본적으로 시스템 계정 홈디렉토리를 기본으로 한다.
또, 반드시 네트워크가 연결되어 있어야 한다. 443 이나 80 포트가 OutBound 로 열려 있어야 한다.
Vundle
VIM 플러그인 설치를 도와준다. 네트워크를 통해서 설치하고 픈 플러그인을 지정해주면 설치를 해준다. 플러그인에 대한 설정은 여전히 사용자가 해줘야 하지만 하나하나 찾아서 해주는 것보다는 낫다.
2021년에 아직도 Trac 을 사용하는 사람이 있을지 모르겠다. 하지만 프리랜서로 많은 프로젝트를 하는데 있어서 Trac 만큼 간단하면서도 필요한 기능이 다 있는 툴은 찾기가 힘들다. 프로젝트에 투입되면 Windows 10에 Trac 을 설치하고 프로젝트를 위한 여러가지 작업을 Trac 으로 하게 된다. Trac 을 이용하는 기능은 다음과 같다.
Wiki
Ticket
Calendar
Gant Calendar
문서도 작성하고 요청한 사항들을 정리하고 일정을 확인하는데, 그것도 로컬 컴퓨터에서 Python 으로 아주 가볍게 동작하는 툴을 본적이 없다. Jira 와 같은 협업툴이 많이 나왔지만, 프리랜서로서 자신만의 뭔가를 정리하려고할때 이만한 게 없다.
Trac 1.2
현재 Trac 은 죽어가는 프로젝트다. 조만간에 아카이빙을 해야할 정도라고 해도 된다. 그도 그럴것이 현재 Python 2 버전에서만 작동된다. Python3 이 새롭게 나왔는데 이것으로 바꿀 생각이 없어 보인다. 그래서 이 문서는 (아마도) Trac 1.2 버전에 관해 마지막 설치 문서가 될 것이다.
Trac 1.2 버전이 많은 플러그인들을 지원한다. 최신버전의 경우에 개발이 중단된 플러그인들을 제대로 인식하지 못한다. 내부적으로 바뀐부분도 많아서 고칠려면 꽤 손이 가는 일이라 안하는게 낫다.
Trac 은 Python 프로젝트이기 때문에 Python 이 있어야 하고 그것도 2.x 버전을 필요로 한다.
Python 2.7 설치하기
Windows 용 Python 을 다운받아서 설치해야 하는데, 2021년 현재 2.7.18 이 마지막 버전이며 MSI 인스톨러를 파일을 다운받을 수 있다. 다운로드 받은 파일을 더블클릭해 설치해주는데, 설치 디렉토리를 나의 경우에 F:\Python27 로 해줬다.
pip.exe 를 이용한 의존성 설치
Trac 은 Python 으로 제작되었지만, 여러가지 의존성 라이브리를 필요로 한다. 이를 설치하기 위해서는 pip 프로그램을 이용하는게 가장 쉽다. pip.exe 는 Python 설치 디렉토리에 Scripts 폴더에 존재한다.
한가지, 데이터 저장소로 데이터베이스를 선택하지 않았다. 기본적으로 Trac 은 데이터저장소로 sqlite3 을 사용하는데, Python 2.7 에 기본 포함되어 있어 별도의 의존성을 설치할 필요가 없다.
Genshi, version > 0.6
Genshi 를 설치해 줘야 한다. pip 를 이용해서 설치 한다.
Genshi 설치
ZSH
1
2
3
4
5
6
7
8
9
10
11
12
F:\Python27\Scripts>pip.exeinstall genshi
DEPRECATION:Python2.7reached the endof its life on January1st,2020.Please upgrade your Python asPython2.7isno longer maintained.pip21.0will drop support forPython2.7inJanuary2021.More details about Python2support inpip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will
Using legacy'setup.py install'forgenshi,since package'wheel'isnotinstalled.
Installing collected packages:six,genshi
Running setup.pyinstall forgenshi...done
Successfully installed genshi-0.7.5six-1.16.0
Babel, version 0.9.6 or ≥ 1.3, needed for localization support
지역화 번역을 사용하기 위해서 필요하다고 한다.
Babel 설치
ZSH
1
2
3
4
5
6
7
8
9
10
11
12
13
F:\Python27\Scripts>pip.exeinstall babel
DEPRECATION:Python2.7reached the endof its life on January1st,2020.Please upgrade your Python asPython2.7i7 won'tbe maintained after that date.Afuture vs no longer maintained.pip21.0will drop support forPython2.7inJanuary2021.More details about Python2suppo/pip.pypa.io/en/latest/development/release-procesrt inpip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will
docutils, version ≥ 0.3.9 for WikiRestructuredText.
Wiki 기능을 위해서 설치해 준다.
docutils 설치
ZSH
1
2
3
4
5
6
7
8
F:\Python27\Scripts>pip.exeinstall docutils
DEPRECATION:Python2.7reached the endof its life on January1st,2020.Please upgrade your Python asPython2.7i7 won'tbe maintained after that date.Afuture vs no longer maintained.pip21.0will drop support forPython2.7inJanuary2021.More details about Python2suppo/pip.pypa.io/en/latest/development/release-procesrt inpip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will
DEPRECATION:Python2.7reached the endof its life on January1st,2020.Please upgrade your Python asPython2.7i7 won'tbe maintained after that date.Afuture vs no longer maintained.pip21.0will drop support forPython2.7inJanuary2021.More details about Python2suppo/pip.pypa.io/en/latest/development/release-procesrt inpip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will
Trac 설치는 1.2.6 버전을 설치해야 한다. pip 를 이용해서 설치해야 하는데, 특정 버전을 설치하기 위해서는 반드시 버전을 명시해줘야 한다. 그렇지 않으면 최신버전을 설치하게 되는데, 현 시점에서(2021.08.27) Trac 1.4 가 최신 버전이다.
Trac 1.2.6 설치
ZSH
1
2
3
4
5
6
7
8
9
10
11
12
13
F:\Python27\Scripts>pip.exeinstall trac==1.2.6
DEPRECATION:Python2.7reached the endof its life on January1st,2020.Please upgrade your Python asPython2.7i7 won'tbe maintained after that date.Afuture vs no longer maintained.pip21.0will drop support forPython2.7inJanuary2021.More details about Python2suppo/pip.pypa.io/en/latest/development/release-procesrt inpip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will
이제 Trac 프로젝트를 만들어야 한다. Trac 은 원래 멀티 프로젝트를 지원하지 않는다. 대신 Trac 프로젝트라고 해서, 비유를 하자면 웹 서버 가상호스팅 처럼 여러 시스템 계정을 가상 호스팅 루트로 서빙하듯이 여러 프로젝트 디렉토리를 생성해서 이를 루트로 인식시켜 작동하도록 했다.
Trac 프로젝트를 만들기 위해서는 trac-admin.exe 를 이용하며 프로젝트 디렉토리를 지정해 주면 생성 된다.
DEPRECATION:Python2.7reached the endof its life on January1st,2020.Please upgrade your Python asPython2.7isno longer maintained.pip21.0will drop support forPython2.7inJanuary2021.More details about Python2support inpip can be found at
https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
admin 이라는 ID 로 로그인 인증을 위해서는 인증을 위한 방법을 먼저 정의해야 한다. 인증 방법에는 다음과 같이 두가지 방법이 있다.
Basic Auth by HTTP
Htdigest
나의 경우에는 Htdigest 방법을 사용한다. 이를 위해서 AccountManager 플러그인을 설치했다. 그리고 Htdigest 인증 파일을 작성해줘야 한다. 이를 위해서 다음과 같이 Htdigest 인증 파일을 만들어주는 trac-digest.py 파일을 이용한다.
이렇게 설정한 후에 Trac 프로젝트를 재 시작 해준다. 그러면 새로운 티켓 생성하기에서 다음과 같이 시작날짜와 만료날짜 Completed 가 나타난다.
이제 필요한 플러그인은 모두 설치가 되었다.
우선순위 번역
관리 페이지에 우선순위가 있다. 영문으로 되어 있는데 다음과 같이 번역을 해준다.
해결방법 번역
관리 페이지에 해결방법이 있다. 영문으로 되어 있는데 다음과 같이 번역을 해준다.
티켓 종류 번역
관리 페이지에 티켓 종류가 있다. 영문으로 되어 있는데 다음과 같이 번역을 해준다.
이렇게 모든 설치와 설정은 끝났다.
결론
이제는 팀 협업을 위한 툴들이 아주 많다. 굳이 Trac 을 사용할 필요도 없으면 협업툴을 익히는 것이 직장생활(?)을 오래하는 방법이기도 하다. 하지만 프리랜서로서 일을 할때에 협업툴도 사용을 하겠지만 개인적인 업무를 기록하고 업무요청을 Ticket으로 기록하는 것 만큼 좋은 방법은 없다고 생각하는데 Trac 이 여기에 딱 맞아 보인다.
아주 유용한 것중에 하나지만 종종 잘못 이해하고 잘못 설정하게되는 NGINX 기능이 속도 제한(rate limiting) 이다. 이것은 주어진 특정한 시간동안 HTTP 요청양을 제한할 수 있도록 한다. 하나의 요청은 웹사이트의 홈페이지를 위한 GET 요청이나 로그인 폼에 POST 요청이다.
속도 제한은 보안 목적을 위해서 사용되어 질 수 있는데, 에를들어 부르트 포스 패스워드 추정 공격의 속도를 낮출 수 있다. 이것은 실제 사용자에 대해 들어오는 요청 비율을 일반적인 값으로 제한하고 (로깅을 통해) 대상 URL을 식별함으로써 DDos 공격으로부터 보호하는데 도움이 될 수 있다. 더 일반적으로, 동시에 아주 많은 사용자 요청으로 인해 압도되어지는 업스트림 애플리케이션 서버를 보호하는데 사용되어진다.
이 블로그에서는 NGINX의 속도 제한의 기본사항과 더블어 고급 설정에 대해서 다룬다. 속도 제한은 NGINX Plus 에 같은 방법으로 동작한다.
NGINX 속도 제한은 어떻게 작동하나
NGINX 속도 제한은 leaky bucket algorithm 을 사용하는데, 이것은 대역폭이 제한된 상황에서 버스트를 다루기 위해 패킷 교환 컴퓨터 네트워크와 통신에 널리 사용된다. 비유를 하자면, 물이 상단에서 부어지고 바닥에서 물이 줄줄 세는 양동이와 같다. 물을 붓는 속도가 양동이에서 새는 속도를 초과하면 물통이 넘치게 된다. 이것을 요청처리로 다시 보면, 물은 클라이언트로부터 요청으로 볼수 있고 양동이는 FIFO 스케줄링 알고리즘에 따라 처리를 기다리는 요청에 대한 큐로 볼 수 있다. 새는 물은 서버에 의해서 처리하기 위한 버퍼에 존재하는 요청으로 볼수 있고 물통이 넘치는 것은 폐기되고 결코 서비스될 수 없는 요청으로 볼 수 있다.
기본적인 속도 제한 설정하기
속도 제한은 두개의 메인 지시문으로 설정되는데, 다음의 예제처럼 limit_req_zone 과 limit_req 이다.
limit_req_zone 은 속도 제한에 대한 파라메터를 정의하고 limit_req 는 나타나는 컨텍스트 내에(예를들어, /login/ 에 대한 모든 요청) 속도 제한을 활성화 한다.
limit_req_zone 지시문은 일반적으로 http 블럭에 정의하는데, 여러 컨텍스트에서 사용할 수 있다. 이것은 다음과 같이 세개의 파라메터를 가진다.
Key – 제한이 적용되는 요청 특징을 정의한다. 위 예에서 NGINX 변수 $binary_remote_addr 은 클라이언트 IP 주소의 이진 표현을 보유한다. 이것은 각각의 유니크한 IP 주소를 세걔의 파라메터로 정의한 요청 속도로 제한 한다. (우리가 이 변수를 사용하는 이유는 일반 문자열로 표현되는 클라이언트 IP 주소 $remote_addr 변수보다 적은 공간을 가지기 때문이다.)
Zone – 각 IP 주소에 상태를 저장하는 사용되는 공유 메모리 존과 어떻게 요청이 제한된 URL 에 접근하는지에 대해 정의한다. 공유 메모리에 정보를 유지하는 다는 것은 NGINX 워크 프로세스들 사이에 공유될 수 있다는 뜻이다. 이 정의는 두 파트를 가진다: 존 이름은 zone= 키워드로 구별되어지고 크기는 콜론(:) 뒤에 온다. 약 16,000 IP 주소에 대한 상태정보는 1 메가 크기를 가지며 위 예제에서는 약 160,000 주소를 저장할 수 있다. 만약 NGINX 가 새로운 엔트리(IP 주소) 를 추가할 필요가 있을때 스토리지가 꽉 찼다면, 가장 오래된 엔트리를 제거 한다. 여유 공간이 새로운 레코드를 수용하기에 충분하지 않는다면, NGINX 는 503 (Service Temporarily Unavailable) 코드 상태를 리턴 한다. 게다가, 메모리 고갈을 방지하기 위해서는 NGINX 가 새로운 엔트리를 만들때마다 이전 60초 동안 사용되지 않은 항목을 최대 2개까지 제거해야 한다.
Rate – 최대 요청 속도 지정. 위 예제에서, 속도는 초당 10 요청을 초과할 수 없다. NGINX 는 실제로 요청을 밀리초(millisecond) 초 단위로 추적하므로 이 제한은 100 밀리초(ms) 마다 1개 요청에 해당 한다. 이 예제에서 버스트를 허용하지 않았기 때문에 이전에 허용 된 요청 이후 100ms 미만에 도착하면 요청이 거부 된다.
limit_req_zone 지시문은 속도 제한과 공유 메모리 존에 대한 파라메터를 정의하지만 실제로 요청 속도를 제한하지 않는다. 요청 속도를 제한하기 위해서는 특정한 location 이나 server 블럭에 limit_req 지시문을 포함하는 제한 적용이 필요하다. 위 예제에서는 /login/ 에 대한 요청 속도를 제한하고 있다.
그래서 이제 각각의 유니크한 IP 주소는 /login/ 에 대해 초당 10 요청으로 제한되고, 좀 더 정확하게, 이전 요청의 100ms 안에 /login/ URL 에 대한 요청을 할 수 없다.
버스트 핸들링
위 예제에서, 서로 100ms 이내에 2개의 요청을 받으면 어떻게 되나? 두번째 요청에 대해 NGINX 는 클라이언트에 503 상태 코드를 리턴 한다. 아마도 이것은 우리가 원하는게 아닐 수도 있는데, 애플리케이션은 실제로는 버스티(bursty, 폭발적인) 경향이 있다. 대신 우리는 초과 요청을 버퍼하길 원하고 적시에 서비스를 원한다. 여기서 업데이트 된 구성에서와 같이 limit_req 에 burst 파라메터를 사용 하다.
burst 파라메터 사용
Apache
1
2
3
4
5
location/login/{
limit_reqzone=mylimitburst=20;
proxy_passhttp://my_upstream;
}
burst 파라메터는 얼마나 많은 요청을 존에서 지정한 속도를 초과해 클라이언트가 만들 수 있는지를 정의한다. (위 예제 mylimit 존에서, 속도 제한은 초당 10 요청 혹은 100ms 당 1개 다) 이전요청 이후에 100ms 보다 조금 빠르게 도착한 요청은 쿠에 넣는데 여기서 우리는 큐 크기를 20으로 지정했다.
만약 21 요청이 주어진 IP 주소로 동시에 도착한다면, NGINX 은 첫번째를 즉각 upstream 서버 그룹에 포워드하고 나머지는 20개는 대기열에 넣는다. 그런 다음 100ms 마다 큐된 요청을 포워드하고 들어오는 요청이 큐된 요청 개수가 20개가 넘어가게 될때에만 클라이언트에 503 을 리턴 한다.
No Delay 를 가지는 큐
burst 를 가지는 설정은 트래픽 흐름을 부드럽게 만들지만, 사이트가 느려져 보일 수 있기 때문에 그렇게 실용적이 않다. 우리의 예제에서, 큐에 20번째 패킷은 포워드되기 위해 2초를 기다리는데 이 시점에서 이에 대한 응답은 클라이언트에게 더 이상 유용하지 않을 수 있다. 이 상황을 해결하기 위해서는 burst 파라메터와 함께 nodelay 파라메터를 추가해야 한다.
nodely 파라메터를 가지는 burst 설정
Apache
1
2
3
4
5
location/login/{
limit_reqzone=mylimitburst=20nodelay;
proxy_passhttp://my_upstream;
}
nodelay 파라메터를 사용하면, NGINX 는 여전히 burst 파라메터에 따라 큐에 슬랏을 할당하고 설정된 속도 제한 부여하지만, 큐된 요청의 포워딩 간격을 두지 않는다. 대신, 요청이 아주 순간에 들어오면, NGINX 는 큐에 슬롯이 활용할 수 있는 한 즉시 포워드 된다. 이것은 “taken” 으로 슬롯을 표시하고(mark) 적절한 시간이 경과 할 때까지 다른 요청에 의해서 사용하도록 해제하지 않는다. (위 예제에서, 100ms 지난후)
이전과 마찬가지로, 20 슬롯 큐가 비어있고 21 요청이 주어진 IP 주소로부터 동시에 들어온다고 가정해 보자. NGINX 는 모든 21번째 요청을 즉각 포워드 하고 큐에 20 번 슬롯을 “taken” 으로 표시하고 나면 100ms 마다 1개 슬롯을 해제하게 된다. (만약 25개의 요청이 있다면, NGINX 는 그들중에 21번째를 즉각 포워드 하고 20번 슬롯을 “taken” 으로 표시하고 나머지 4개의 요청은 503 상태로 거절한다.)
이제 첫번째 요청 세트가 포워드된 이후 101ms 에 또 다른 20개의 요청이 동시에 도착한다고 생각해보자. 큐에서 오직 1 슬롯만이 해제된 상태다. 그래서 NGINX 는 1개 요청을 포워드 하고 다른 19개의 요청은 503 상태로 거절 한다. 대신 20개의 새로운 요청 전에 501ms 가 지났다면 5 개의 슬롯이 해제 된 상태이고 NGINX 는 즉각 5개의 요청을 포워드 하고 15개를 거절 한다.
이런 효과는 초당 10개의 속도 제한과 동일하다. nodelay 옵션은 요청들 사이에 허용되는 시간 간격을 제한하지 않고 속도 제한을 적용할경우에 유용하다.
Note: 대부분, 우리는 limit_req 지시문에 burst 와 nodelay 파라메터를 포함하길 권장한다.
두단계 속도 제한
NGINX Plus R17 이나 NGINX 오픈 소스 1.15.7 에서, 전형적인 웹 브라우저 요청 패턴을 수용하기 위해 요청 버스트를 허용하도록 NGINX 를 설정할 수 있고, 추가적인 과도한 요청을 최대한 지점까지 제한하며 그 이상으로 추가적인 과도한 요청은 거부 된다. 두 단계 속도 제한은 limit_req 지시문에 delay 파라메터로 활성화 된다.
두 단계 속도 제한을 설명하기 위해, 여기서는 초당 5개 요청으로 속도를 제한함으로써 웹 사이트를 보호하도록 NGINX 를 설정한다. 웹사이트는 일반적으로 한 페이지당 4-6 리소스를 가지며 12 리소를 넘지 않는다. 이 설정은 최대 12 요청을 허용 하며 첫 8 요청은 지연(delay) 없이 처리 된다. 지연(delay) 는 5 r/s 한도를 적용하기 위해 8개 과도한 요청 이후에 추가 된다. 12개 과도한 요청 이후에, 모든 추가된 요청은 거부된다.
delay 파라메터는 정의된 속도 제한을 준수하기 위해 버스트 크기 내에서 과도한 요청을 조절(delayed) 하는 지점을 정의한다. 이 구성을 사용하면, 8r/s 에서 지속적인 요청 스트림을 만드는 클라이언트는 다음과 같은 동작을 경험하게 된다.
첫 8 요청은 (delay 값) delay 없이 NGINX Plus 에 의해서 프록시 된다. 그 다음 4개 요청은 (burst – delay) 정의된 5 r/s 속도를 넘지 않도록 지연(delay) 된다. 그 다음 3개 요청은 거부되는데, 전체 버스트 크기를 넘어섰기 때문이다. 후속 요청은 지연된다.
고급 구성 예제
NGINX 의 다른 기능과 함께 기본적인 속도 제한 설정과 조합해, 아주 미묘하게 트래픽을 제한을 구현 할 수 있다.
Allowlisting
이 예제는 “allowlist” 에 없는 모든 요청에 대한 속도 제한을 어떻게 하는 보여준다. (역, allowlist 에 있는 IP 는 속도 제한을 하지 않는다.)
이 예제는 geo 와 map 지시문을 사용해 구성했다. geo 블럭은 allowlist 에 IP 주소에 대해서 $limit 변수에 0의 값을 할당했고 다른 모든 것에는 1 의 값을 할당 했다. 그리고 나서 우리는 그러한 값을 키(key) 로 바꾸기 위해서 map 사용하는데, 그것은:
만약 $limit 가 0 이면, $limit_key 는 빈 문자열(empty string) 이 설정 된다.
만약 $limit 가 1 이면, $limit_key 는 클라이언트의 IP 주소를 바이너리 포맷으로 설정 된다.
이 두가지를 조합해보면, $limit_key 는 허용된 IP 주소에 대해서는 빈 문자열로 설정되고, 그렇지 않으면 클라이언트 IP 주소가 설정 된다. limit_req_zone 지시문에 첫번째 파라메터가 빈 문자열이면, 제한이 적용되지 않는데, 허용된 IP 주소들 (10.0.0.0/8 과 192.168.0.0/24 서브넷) 은 제한이 걸리지 않는다. (역, 10.0.0.0/8 과 192.168.0.0/24 값은 0 이다) 다른 모든 IP 주소들은 초당 5 요청으로 제한이 걸린다.
limit_req 지시문은 제한을 / location 에 적용하고 지연 없는 포워딩으로 설정된 제한을 초과하여 최대 10패킷이 허용된다.
location 에 다중 limit_req 지시문 포함하기
하나의 location 에 다중 limit_req 지시문을 포함할 수 있다. 주어진 요청과 매칭되는 모든 제한은 적용되는데, meaing the most restrictive one is used.(가장 제한적인 것이 사용된다는 뜻이다.). 예를들어, 하나 이상의 지시문이 지연을 부과하는 경우 가장 긴 지연이 사용된다. 비슷하게, 설사 다른 지시분이 그것을 허용한다고 하더라도 어떤 지시문에 효과가 있다면 요청들은 거부 된다.
허용된 목록에 IP 주소들은 첫번째 속도 제한(req_zone) 에 걸리지 않지만 두번째(req_zone_wl) 에 걸리며 초당 15 요청으로 제한된다. 허용목록에 없는 IP 주소드른 양쪽 모두 속도 제한에 걸리는데, 훨씬 제한적인 설정인 초당 5 요청이 적용 된다.
연관 기능 설정하기
Logging
기본적으로, NGINX 는 속도 제한으로 지연되거나 드랍된 요청을 기록한다. 다음과 같다.
Nginx Logging
Apache
1
2015/06/1304:20:00[error]120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com"
로그 엔트리에 포함된 필드는 다음과 같다.
2015/06/1304:20:00 – 로그 엔트리에 기록된 날짜와 시간
[error] – 심각 수준
120315#0 – NGINX 워커의 프로세스 ID 와 쓰레드 ID 인데 # 로 구분 된다.
*32086 – 속도가 제한된 프록시된 연결 ID
limiting requests – 로그 엔트리 기록이 속도 제한(rate limit) 라는 지시자
excess –
zone – 부과 된 속도 제한을 정의한 zone
client – 요청을 생성한 클라이언 IP 주소
server – 서버의 IP 주소 혹은 호스트이름
request – 클라이언트 의해서 생성한 실제 HTTP 요청
host – HTTP 헤더의 Host 값
기본적으로, 위 예제에서 [error] 를 본것처럼 NGINX 는 error 수준에서 거부된 요청들이 기록된다. (지연된 요청들은 한단계 낮은 수준으로, 기본적으로 warn, 기록된다. 로깅 수준을 바꾸기 위해, limit_req_log_level 지시문을 사용해라. 여기서, 우리는 거부된 요청은 warn 수준에서 기록되도록 지정했다.
warn 수준의 로깅 설정
Apache
1
2
3
4
5
6
location/login/{
limit_reqzone=mylimitburst=20nodelay;
limit_req_log_levelwarn;
proxy_passhttp://my_upstream;
}
클라이언트에 Error 코드 전송하기
기본적으로 NGINX 는 클라이언트가 속도 제한을 초과했을때에 503 (Service Temporarily Unavailable) 상태 코드를 응답한다. 다른 상태 코드를 지정하고 싶다면 limit_req_status 지시문을 사용해라.
limit_req_status 를 사용해 다른 상태코드 지정하기
Apache
1
2
3
4
location/login/{
limit_reqzone=mylimitburst=20nodelay;
limit_req_status444;
}
특정 Location 에 모든 요청 거부하기
만약 특정 URL 에 대한 모든 요청들을 거부하기 원한다면, 단지 제한을 하는 말고, deny all 지시문을 포함한 location 블럭을 설정한다.
특정 Location 에 모든 요청 거부
Apache
1
2
3
location/foo.php{
denyall;
}
결론
우리는 HTTP 요청에 대해 서로 다른 location 에 요청 속도를 지정하고 burst와 nodelay 파라메터와 같은 속도 제한에 대한 추가적인 기능 설정등의 NGINX 와 NGINX Plus 가 제공하는 속도 제한에 많은 기능을 알아봤다. 우리는 또한 거부된 요청과 지연된 요청을 어떻게 기록하는지 설명했고, 허용되거나 거부된 클라이언트 IP 주소들에 대해 서로 다른 제한을 적용하는 등의 고급 설정에 대해서도 알아 봤다.
systemd 는 이제 리눅스 시스템의 뼈대가 되는 기본운영 방법이 되었다. 기존에는 System V Init 이였지만 RHEL 7, Ubuntu 16.04부터 기본 시스템운영 프로그램이 되었다.
systemd 는 ‘ctl’ 로 끝나는 명령어들의 집합으로 제어가 가능하다. systemctl, journalctl, timedatectl, hostnamectl, loginctl 이 대표적이다. systemctl 의 경우에는 systemd unit 파일들에 대한 제어와 설정이 가능하다. systemd unit 파일은 기존의 Systemv V init Script 를 대체하는 것으로 일종의 시스템 데몬 프로그램들이라고 보면 된다. 시스템이 시작될때에 자동으로 시작되게 한다거나 종료하게 한다거나 하는것들을 가능하게 한다.
unit 파일은 텍스트 파일이기 때문에 언제든지 파일을 열어서 편한대로 편집이 가능한데, systemctl 명령어는 이런 unit 파일에 대한 편집기능을 제공 한다. unit 파일이 있는 곳으로 가서 텍스트 편집기를 열 필요가 없이 systemctl edit –full 명령어를 이용하면 가능하다.
문제는 systemctl edit — full 명령어를 입력했을 때에 실행되는 에디터가 nano 로 열리는 경우가 많은데, 이것을 바꿀 수 있다.
제일 쉬운 방법은 SYSTEMD_EDITOR 환경변수 설정이다. 대부분 Bash 를 사용하기 때문에 이것을 다음과 같이 쉘 환경변수로 설정 해준다.
SYSTEMD_EDITOR 환경변수 설정
ZSH
1
export SYSTEMD_EDITOR=vim
매번 로그인 할때마다 입력하기 귀찮으면 ~/.bashrc 파일에 추가해주면 로그인할때마다 자동 적용된다.
만일 일반계정으로 로그인을 하고 sudo systemctl edit –full 명령어를 이용한다면 /etc/sudoers 파일에 다음을 추가해 줘야 한다.
/etc/sudoers 파일 추가
ZSH
1
2
sudo visudo
Defaults env_keep+="SYSTEMD_EDITOR"
sudo 를 실행하는 계정에 있는 환경 변수인 SYSTEMD_EDITOR 를 유지하라는 뜻이다.
update-alternatives 로 기본 에디터 변경
update-alternatives 는 alternative 가 가능한 여러 명령어들을 바꿔 주는 기능을 한다. 이것은 매우 유용한데, 예를들어 Python3 관련 버전이 여려개일 경우에 python3 에 기본 버전을 시스템적으로 지정해 줄 수 있다. update-alternatives –list 명령어를 입력하면 현재 등록된 대체가능한 명령어들이 보인다.
리눅스에서 편집기는 editor 라는 명령어로 되어 있고, 정확하게는 심볼릭 링크다, 이것을 update-alternatives 명령어로 바꿔주면 된다.