$ cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
운영체제의 패키지들을 최신 버전으로 업데이트 합니다. (선택사항)
$ sudo yum update
docker와 docker-registry 패키지를 설치합니다
$ sudo yum -y install docker docker-registry
설치된 docker를 재부팅시에도 자동 실행하도록 합니다 (선택사항)
$ sudo systemctl enable docker.service
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
docker 서비스를 실행하고 상태를 확인해 봅니다
$ sudo systemctl start docker.service
$ systemctl status docker.service
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2021-07-08 15:55:35 JST; 24s ago
Docs: http://docs.docker.com
...
기초적인 것들이 늘 가장 어려운 법입니다. 여러 환경에 구축된 쿠버네티스 클러스터를 다루는 상황이 되니 이게 뭥미~ 하는 생각이 들면서 머릿속이 하얗게 변했습니다. 가령 로컬 환경에 시험용 클러스터가 구축되어 있고 (이하 docker-desktop) 구글 클라우드 플랫폼에 클러스터를 하나 구성한 상황에서 (이하 k8snopd) kubectl 로 양쪽 클러스터를 제어하는 방법의 정리입니다.
kubectl 설정 파일 확인하기
kubectl 을 사용하고 있다면 .kube/config 파일에 (맥 기준) 액세스 할 수 있는 클러스터 정보가 기록되어 있습니다. 언급 드린 것처럼 로컬 환경과 GCP 환경에 클러스터가 구성되어 있습니다. 로컬 환경은 맥 용 Docker Desktop 에서 클러스터를 만들었고, GCP 는 gcloud CLI 를 이용해서 원격지 환경에 클러스터를 만들고 접근할 수 있게 가이드를 따랐습니다.
이 상태라면 .kube/config 에는 두 클러스터 접근을 위한 설정이 들어가 있게 됩니다. 설정된 내용은 cat 등으로 조회할 수도 있지만 kubectl 을 이용해서 조회하는 것이 더 깔끔합니다.
먼저 clusters 노드로 두개의 cluster 가 지정돤 것이 보입니다. name 키에 지정된 이름이 각각 다른게 보이시죠? GCP 에 만든 클러스터 이름은 다소 복잡합니다. GCP 의 리전명 등이 포함되어 있네요. 이어서 각 클러스터에 접근할 때 사용되는 사용자 토큰 등의 정보가 이어집니다.
kubectl 에서 클러스터 바꾸는 방법
위의 설정에서 주목할 값 중 하나는 current-context 입니다. 제 경우는 GCP 를 나중에 설정해서 그런지 GCP 가 현재 컨텍스트라고 지정되어 있습니다. 즉, kubectl 명령을 사용하면 특별히 컨텍스트를 지정하지 않으면 GCP 의 클러스터로 명령을 날리게 됩니다. 한번 해볼까요?
% kubectl get nodes
NAME STATUS ROLES AGE VERSION
gke-k8snopd-default-pool-8130c84d-371t Ready <none> 63m v1.18.16-gke.502
gke-k8snopd-default-pool-8130c84d-l26t Ready <none> 63m v1.18.16-gke.502
gke-k8snopd-default-pool-8130c84d-xrkt Ready <none> 63m v1.18.16-gke.502
그렇다면 로컬 클러스터 (docker-desktop) 로 컨텍스트를 바꾸어 노드 목록을 받아오고 싶다면 어떻게 해야 할까요? kubectl 이 제공하는 --context 매개변수를 이용해서 클러스터의 컨텍스트명을 입력해 주면 쉽게 대상 클러스터를 바꿀 수 있습니다. 함 해보죠!
% kubectl get nodes --context docker-desktop
NAME STATUS ROLES AGE VERSION
docker-desktop Ready master 5d23h v1.19.3
인증서를 다루다보면 가장 많이 사용하는 것이 OpenSSL 입니다. OpenSSL 의 명령들중 자주 사용하는 것들을 기억해두면 생활이 편리해지고 퇴근시간이 빨라지는 장점이 있습니다. 서버나 로컬 터미널 환경에 미리 alias 로 몇 가지 등록해 두면 두고두고 편리하게 사용할 수 있는 명령들을 몇 가지 정리해 보았습니다.
근래에 제공되는 대부분의 서비스는 SSL 혹은 TLS 를 이용하여 보안된 채널로 통신이 수행되도록 하는 것이 일반적입니다. 하물며 개인이 만드는 토이 프로젝트부터 대학교에서 과제로 제출하는 웹 사이트도 HTTPS 를 사용하지 않는 경우를 찾아보기 힘듭니다. 네, 물론 이 와중에서 Non-secure 로 버티는 곳들도 <당연히> 있긴 합니다.
예전에는 HTTPS 를 이용하기 위해 인증서를 구매해야 했고, 보통 년단위의 갱신을 하다보니 비용 부담이 있었습니다. 하지만, 3개월마다 주기적으로 인증서를 업데이트 받는 조건으로 도메인 단위 인증서 (Domain Validation) 를 무료로 발급해주는 렛츠인크립트 Let's Encrypt 의 대중화 이후, 인증서 구매 비용도 단지 핑계가 된지 오래입니다.
하지만, 이런 인증서 구매와 별개로 서버측에 SSL 설정을 구성하고 적용하는 것은 생각보다 까다롭게 생각하는 경우가 많습니다. 보통 한번 설정해 두면 수정하지 않아서 보안 사고의 원인이 되기도 하고, 설정을 잘못하는 바람에 특정한 단말기들이 서비스에 접근하지 못하는 장애를 겪기도 합니다. 원체 그 파급력이 크다보니 <그리 어려운 일이 아님에도 불구하고> 인증서 교체에 대해서 전문가를 찾는 경우가 종종 생깁니다.
이러한 엔지니어들의 고충을 잘 알고 있는 곳이 모질라 재단이기 때문일까요? 모질라에서 제공하는 SSL 설정 생성기는 이 모든 두려움으로부터...는 아니겠지만, 기본적인 설정 실수로 장애가 발생하는 것을 막아줄 수 있는 여러분의 친구, 좋은 도구가 될 수 있을 것 같습니다.
다양하다!
일단 이 도구가 커버해주는 서버측 소프트웨어의 범주가 무척 넓습니다. 널리 사용되는 아파치나 nginx 에서부터 AWS 의 ALB, ELB 도 포함이 되어 있습니다. HAProxy 와 Go 기반으로 서버측 엔드포인트를 만들때 쓸 수 있는 옵션들도 제공하고 있어 왠만한 서버측 도구의 SSL 설정에 활용도가 높아 보입니다.
가운데 위치한 Mozilla Configuration 은 SSL/TLS 의 어떤 버전을 지원할 것인가에 따라 선택 가능한 항목입니다. 이 항목의 변경은 설정 생성시에 추가되는 Cipher Suite 의 종류에 영향을 주는 부분입니다. SSL/TLS 버전이 상위로 갈 수록 취약한 암호화 알고리즘을 사용할 수 없게 됩니다. 하지만, 오래된 사용자들은 SSL/TLS 의 상위 버전 자체를 사용할 수 없는 경우도 있기 때문에, 사용자 분포에 따라 취약한 알고리즘을 써야 하는 경우도 있을 겁니다.
가장 오른쪽에는 각 서버 어플리케이션의 버전에 따라 달라진 부분을 반영하기 위해 버전 정보를 기입할 수 있는 입력창이 위치해 있습니다. HSTS 와 OCSP Stapling 을 사용할 것인지에 따라 옵션을 선택할 수 있게 되어 있는 것도 눈에 띕니다.
# generated 2021-02-08, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1d, modern configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=modern&openssl=1.1.1d&guideline=5.6
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /path/to/signed_cert_plus_intermediates;
ssl_certificate_key /path/to/private_key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# modern configuration
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
# replace with the IP address of your resolver
resolver 127.0.0.1;
}
TLS 1.3 을 기준으로 NGINX 를 위한 설정을 생성해 보았습니다. HTTP 로 인입된 경우 HTTPS 로 스킴을 바꾸도록 301 리디렉션 하는 서버 컨텍스트가 앞에 위치해 있고, 443 포트로 HTTP/2.0 을 지원하는 엔드포인트를 열고 있습니다. 센스있게 IPv6 를 위한 포트 바인딩도 함께 추가되어 있네요!
그 외의 지시자들은 일름에서 유추할 수 있는 것처럼 프로토콜 버전의 지정, 인증서 파일의 위치, 세션 티켓 사용을 위한 옵션들이 지정되어 있습니다. 서버측의 prefer_server_ciphers 가 off 로 생성된 부분은 그 의도가 있을텐데 (아마도 NGINX 에서 TLS 1.3 사용시 기본 Cipher Suite 의 영향?) 자세한 건 문서를 좀 살펴봐야 할 것 같네요.
우리가 코드를 수정하거나 서버의 설정을 변경할 때 늘 하는 말이 있습니다. <지금 니가 무슨짓을 하는지 모른다면, 아무것도 하지 말아라> 라는 말이 바로 그것입니다. 각 설정이나 코드가 존재하는 것은 다 이유가 있어서 입니다. (예, 정말 가끔 이유 없이 존재하는게 없진 않습니다만...) 자동 생성된 설정을 참고하고 사용하는 것은 좋지만, 추가된 설정 항목들이 "왜" 들어갔는지에 대해서는 한번쯤 문서를 찾아보고 고개를 끄덕인 다음 Ctrl-C, V 하는 아름다운 자세를 견지하시기 바랍니다!