HTTPS 를 위한 Private SSL

Web server certificates 과정

Securing a web site with a server certificate 단계

  1. 비밀키를 생성한다.
  2. 비밀키로 CSR certificate siging requests 을 생성한다.
  3. CSR 을 CA 로 사인한다.
  4. 사인한 CERT 를 받고 설치한다.

1. 비밀키를 생성한다.

rsa 를 사용해 4096크기 비밀키를 생성한다.

1
2
3
4
5
# cd /etc/ssl/private 
# openssl genrsa -out my_rsa.key 4096
Generating RSA private key, 4096 bit long modulus (2 primes)

# chmod 0600 private/my_rsa.key
1
# chmod 0600 private/my_rsa.key

Public Key 생성

1
명령: openssl rsa -in [private key 파일명] -pubout -out [파일명]
1
# openssl rsa -in my_rsa.key -pubout -out my_rsa.pub 

2. Create a CSR(certificate signing request) from this key,

인증서 발급을 위한 필요한 정보를 담고 있는 인증서 신청서를 작성한다.

1
명령어 : openssl req -new -key [private key 파일명] -out [파일명]

비밀키에서 CSR 파일 작성을 요청하면 아래 내용을 묻는다.

1
# openssl req -new -sha256 -key ./my_rsa.key -out ./my_rsa.csr 
1
# openssl req -new -key private.key -out private.csr

인증서 발급을 위한 필요한 정보를 담고 있는 인증서 신청 형식 데이터 이다.

  • Country Name (국가코드) KR
  • State or Province Name (시/도의 전체이름) Seoul
  • Locality Name (시/군/구 등의 이름) Songpa-gu
  • Organization (회사이름) XXXX
  • Organization Unit (부서명) Server
  • Common Name (SSL 인증서를 설치할 서버의 Full Domain) www.xxxx.com
      • Common Name 에는 인증서를 설치할 사이트의 도메인의 이름을 넣어야 한다. (ip, port, http, https 포함불가능)

4. CA 인증한 CRT 인증서 만들기

CSR 을 CA에서 인증해 CRT 파일을 생성한다. 여기서는 비밀키와 CSR 요청서를 바탕으로 CRT 인증서를 생성한다.

1
명령어 : openssl req -x509 -days [기간] -key [private key 파일명] -in [csr 파일명] -out [파일명] -days [기간]

x509 를 이용하고 365일 사용 가능한 crt 인증서를 생성한다.

1
openssl req -x509 -days 365 -key my_rsa.key -in my_rsa.csr -out my_rsa.crt -days 365

생성한 혹은 CA에서 받은 CRT 파일은 아래 같이 확인해 볼 수 있다.

1
openssl x509 -text -in yourdomain.crt -noout

5. CRT 파일을 PEM 파일로 변환한다.

1
openssl x509 -in mycommoncrt.crt -out mycommonpem.pem -outform PEM 

[Tip] 인증서 Config 파일 (test.conf)

위에서 만들다 보면 계속 같은 내용을 써야 한다. 그래서 그 부분을 파일로 만들어 놓고 csr, crt 생성할때 사용하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[req]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn

[dn]
C=KR
ST=Seoul
L=Seoul
O=COMPANY
OU=DEV
emailAddress=test@test.com
CN = testmachine

[req_ext]
subjectAltName = @alt_names

[alt_names]
IP.1 = 111.111.111.111
DNS.1 = test.com

csr 을 생성한다.

1
openssl req -new -key private.key -out private.csr -config test.conf

csr, crt 파일을 생성한다.

1
openssl req -x509 -days 365 -key private.key -in private.csr -out mycommoncrt.crt -days 365 -config test.conf

그리고 이렇게 해서 인증서를 만들었을때 subjectAltName 이 안들어간다 . 그 부분이 필요할 경우에는 이렇게 명령어를 사용하면 된다.

1
openssl req -x509 -days 365 -key private.key -in private.csr -out mycommoncrt.crt -days 365 -config test.conf -extensions req_ext

openssl 팁 몇가지

CRT 파일 확인

openssl x509 -text -noout -in <인증서파일> : 인증서 내용을 볼수 있다.

Verifying Your Keys Match

1
2
3
openssl pkey -pubout -in .\private.key | openssl sha256
openssl req -pubkey -in .\request.csr -noout | openssl sha256
openssl x509 -pubkey -in .\certificate.crt -noout | openssl sha256

NGINX 웹 서버 TLS 암호화 추가

개인키와 TLS 인증서 crt 파일을 사용한다.

1
2
$ sudo mkdir /etc/nginx/tls/private
$ mv my_rsa.key my_rsa.crt /etc/nginx/tls/private
  1. 개인 키는 /etc/nginx/tls/private/my_rsa.key 파일에 저장됩니다.
  2. 개인 키 및 CSR(인증서 서명 요청) 생성 및 CA(인증 기관)에서 인증서 TLS 인증서는
    • /etc/nginx/tls/private/example.com.crt 파일에 저장됩니다.
1
2
3
4
5
6
7
server {
listen 443 ssl;
server_name www.thinkbee.kr;
root /home/qkboo/Home/www/thinkbee.kr/;
ssl_certificate /etc/nginx/tls/private/my_rsa.crt;
ssl_certificate_key /etc/nginx/tls/private/my_rsa.key;
}

참고

  1. Howto – Install a self signed web server certificate
  2. openssl quick reference guide
  3. Openssl로 SSL 을 위한 인증서 발급하기 (HTTPS),blog
  4. Nginx - HTTPS and Certificate SSL,blog
  5. NodeJS와 Nginx 웹 서버,blog

HTTPS를 위한 공인인증서 - Let's Encrypt 발급

2020-06-02: 매뉴얼 방식 수정

2020-02-02: 최초 작성
{:.right-history}

Nginx 서버에서 HTTPS 사용할 수 있는 공인인증서를 발급해 설치하려고 한다.

  • 여기서는 Lets Encrypt 무료 공인인증서 발급을 다룬다.
  • letsecrypt 공인인증서는 3개월 정도 기간만 사용 가능하고 갱신해야 한다.
  • **단독 도메인을 호스팅하는 개인 서버에서 Nginx**에 적용해 본다.

인증서는 개별 도메인 혹은 와일드카드 인증서 로 도메인 안의 모든 호스트를 포함하는 두 종류로 발급이 가능하다.

자세히 보기

Nginx - HTTPS and Certificate SSL

Nginx를 HTTPS를 사용할 수 있도록 사설 인증서와 그리고 공인 인증서를 이용해 SSL을 활성화 하는 과정을 정리했다.

Nginx 설치와 서버, 프락시 등의 사용 방법에 대해서는 Nginx on Ubuntu/Debian 문서를 참조한다.

자세히 보기

Nginx - Install, WebDAV, Proxy on Ubuntu/Debian

nginx를 사용해서 일반 웹 서비스, SSL, WebDav 서비스와 다른 외부 웹 서비스와 연동하는 설정을 해보자.

  • 여기서 node.js 애플리케이션을 연동한다.

## Nginx 설치와 구성

우분투/데비안 계열에서 apt-get install 명령으로 설치한다.

자세히 보기

NodeJS와 Nginx 웹 서버

Nginx with nodejs

nginx를 사용해서 일반 웹 서비스와 node.js 애플리케이션을 연동하는 방법을 살펴보자.

Nginx 구성

Nginx 설치가 되었다고 가정한다.

nginx 구성 파일

/etc/nginx 밑에 가상 호스트 환경에 맞게 파일을 구성한다.

/etc/nginx/site-available/myhome.conf

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
server {

listen 80 default_server;
server_name _;

index index.html index.htm index.nginx-debian.html;

location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://127.0.0.1:50000/;
proxy_redirect off;

try_files $uri $uri/ =404;
}

log_not_found off;

gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
}

http 에 대한 구성

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
 http {
upstream my_node_app {
server 127.0.0.1:8000;

server {
listen 80;
server_name localhost domain.com;
access_log /var/log/nginx/my_node_app.log;
location ~ /static/ {
root /home/node/my_node_app;
if (!-f $request_filename) {
return 404;
}
}
location / {
proxy_pass http://my_node_app;
proxy_redirect off;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
}
}
}

nginx 구성을 재시작한다

1
2
3
$ cd /etc/nginx/sites-enabled
$ sudo ln -s /etc/nginx/sites-available/test.conf test.conf
$ sudo service nginx reload

Nginx with Node.js

nodejs 를 연동하기 위한 Proxy 구성을 추가한다.

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
server {

listen 80;
server_name test.example.com;

location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://127.0.0.1:52222/;
proxy_redirect off;
}

log_not_found off;

gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript text/x-js;
}

SSL

Nginx를 이용해 SSL 제공을 해주자.

Private SSL 설정

1
2
3
4
5
6
7
$ sudo mkdir /etc/nginx/ssl
$ cd /etc/nginx/ssl
$ sudo openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
$ sudo openssl rsa -passin pass:x -in server.pass.key -out server.key
$ sudo rm server.pass.key
$ sudo openssl req -new -key server.key -out server.csr
$ sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Nginx 설정

/etc/nginx/site-available/yoursite.com

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
server {
listen 443 default;
server_name erp.yclean.co.kr;

access_log /var/log/nginx/oddo.access.log;
error_log /var/log/nginx/oddo.error.log;

ssl on;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
keepalive_timeout 60;

ssl_ciphers HIGH:!ADH:!MD5;
ssl_protocols SSLv3 TLSv1;
ssl_prefer_server_ciphers on;

proxy_buffers 16 64k;
proxy_buffer_size 128k;

location / {
proxy_pass http://127.0.0.1:8069;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}

location ~* /web/static/ {
proxy_cache_valid 200 60m;
proxy_buffering on;
expires 864000;
proxy_pass http://127.0.0.1:8069;
}
}

server {
listen 80;
server_name erp.yclean.co.kr;

add_header Strict-Transport-Security max-age=2592000;
rewrite ^/.*$ https://$host$request_uri? permanent;
}

http 리다이렉트

http://serverfault.com/questions/250476/how-to-force-or-redirect-to-ssl-in-nginx

1
2
3
4
5
server {
listen 80;
server_name signup.mysite.com;
rewrite ^ https://$server_name$request_uri? permanent;
}

The best way as it described in the official how-to is by using the return directive:

1
2
3
4
5
server {
listen 80;
server_name signup.mysite.com;
return 301 https://$server_name$request_uri;
}

site file 활셩화

1
2
3
$ sudo ln -s /etc/nginx/sites-available/yourOdooSite.com /etc/nginx/sites-enabled/yourOdooSite.com

$ sudo /etc/init.d/nginx restart

CORS

CORS(Cross-Origin resource sharing)은 웹 페이지 도메인 밖의 다른 도메인에서 제한된 웹 페이지를 자원을 허용하도록 하는 메커니즘이다.[^2]

You need to enable CORS on the server (localhost:8080). Check out this site: http://enable-cors.org/

All you need to do is add an HTTP header to the server:

1
Access-Control-Allow-Origin: http://localhost:3000

전체적으로 열어 주려

1
Access-Control-Allow-Origin: *

다음 같이 nginx 설정을 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
et $cors '';
if ($http_origin ~ '^https?://(localhost|www\.yourdomain\.com|www\.yourotherdomain\.com)') {
set $cors 'true';
}

if ($cors = 'true') {
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
# required to be able to read Authorization header in frontend
#add_header 'Access-Control-Expose-Headers' 'Authorization' always;
}

if ($request_method = 'OPTIONS') {
# Tell client that this pre-flight info is valid for 20 days
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}

Nginx와 Proxy 서비스

Nginx를 앞단에 두고 Proxy를 이용해 nodeJS, Djang, Angular 등의 서비스를 이용할 때, nginx나 backend 둘 중 한 곳에서 CORS를 활성화 해주면 된다.

Nginx에서 CORS

Nginx에서 CORS를 허용하려면 아래 설정을 사용할 수 있다. [^1]

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
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
}
}

이와 비슷한 방법으로

https://gist.github.com/m4ttbrock/7337183

CORS node.js

https://enable-cors.org/server_expressjs.html

if your app is created with simple node.js set it in your response headers like

1
2
3
4
5
6
7
8
9
10
var http = require('http');

http.createServer(function (request, response) {
response.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE'
});
response.end('Hello World\n');
}).listen(3000);

if your app is created with express framework
use a CORS middleware like

1
2
3
4
5
6
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
}

cors module

cors 모듈을 이용할 수 있다.

https://github.com/expressjs/cors

Enable All CORS requets
1
2
3
var cors = require("cors");

app.use(cors());
Enable CORS for a Single Route
1
2
3
app.get("/products/:id", cors(), function (req, res, next) {
res.json({ msg: "This is CORS-enabled for a Single Route" });
});
Configuring CORS
1
2
3
4
5
6
7
8
var corsOptions = {
origin: "http://example.com",
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
};

app.get("/products/:id", cors(corsOptions), function (req, res, next) {
res.json({ msg: "This is CORS-enabled for only example.com." });
});

참조

[^1]: CORS on Nginx
[^2]: Cross-origin resource sharing