關於AWS-EC2-設定HTTPS

Justin Lee
17 min readMay 31, 2017

在架好AWS-EC2後,我們可以透過80 port來連接到HTTP。但若是要設成HTTPS又該怎麼設定呢?這部份讓筆者娓娓道來。

筆者在AWS-EC2的環境為:

  • 作業系統:linux
  • 後端程式語言:node js
  • 後端框架:express

在進行設定HTTPS之前,首先我們要先了解什麼是SSL憑證?以及憑證的申請過程大概是什麼情況?

什麼是SSL憑證(Secure Socket Layer certificate)?

SSL 會將Client端與Server端之間所傳輸的資料進行加密,而這些加密後的資料會受到安全機制的保護,防止在資料傳輸時,遭到第三方攔截或修改資料。當web擁有SSL憑證時,網址會由HTTP轉為HTTPS,意謂著這個web是有經過CA(Certificate Authorities)認證的,可以放心瀏覽web內容。

SSL的好處:

  • 用於識別web身份。
  • 將client端及server端之間的資料進行加密,保護敏感資料。

憑證申請過程

以client-server端的角度來說明的話,sever端為了向client端表示自己的身份,這時會請第三方的CA來申請個類似「身份證」的憑證。而這個憑證是公開的,每當client端連到帶有HTTPS的網站時,都可以看到這個憑證是哪個CA發的,甚至是server端是哪個單位、來自哪裡…等資訊。其申請過程為:

  1. server端產生private key及public key。
  2. server端會將public key及自己web的基本上資訊一起傳過去給CA進行簽署認證。
  3. CA簽署完畢後的public key稱之為「certificate」。由CA取回後,放入server中作為SSL的public key使用。
  4. 當client端來到server端的web時,就會取得sever的certificate(也就是SSL的public key),而client端的瀏覽器(如:chrome, firefox..)所預存其各個CA的public key就會認證server端的certificate。
  5. 若認證通過就會告知client端這個網站的HTTPS是沒有問題的。之後,瀏覽器就可以用public key來加密,由此建立HTTPS。

而這部份更詳細的過程可以參考:

在稍微了解HTTPS的原理後,就可以開始進行設定HTTPS啦!

但…

在設定HTTPS前,首先要先申請一個Domain name。

這是因為如果我們直接使用AWS給予我們的domain去申請,其domain所有權是amazon的,CA若要簽發憑證會先確認其domain的所有權人是不是你。所以還是得要先去申請一個domain name,才能取得CA所給憑證。

那該怎麼申請一個domain呢?

基本上,現在有許多domain的註冊商,每個註冊商所給的domain價格及服務也會有些許的不同,而這部份就請讀者去自行比較了。

在申請好自己的domain後,就可以開始處理AWS-EC2部份的設定。

AWS-EC2(該服務有一年免費)

先假設筆者都有設定好基本的EC-2的instance,在登入AWS-EC2的主控台後,先去「NETWORK & SECURITY」的「Security Groups」去看自己的Security Group其Inbound內的inbound rules有沒有HTTPS。

  • 若有,請無視這段。
  • 若沒有,就自行「Add Rule」一個Type為HTTPS的rule,接著Source就設為Custom就可以。

Route-53(該服務需付費)

在申請新的domain後,我們必須將我們申請到的domain連結到我們AWS-EC2的IP,這時需要透過Route-53的DNS來幫我們進行轉址的動作。(當然也可以透過其他免費的DNS,由於筆者這部份是使用Route-53,所以其他的DNS就不詳述,但操作流程也是差不多的。)

其設定的步驟為:

  1. 至Route-53後,去「Hosted zones」建立一個新的Hosted Zone,按下「Create Hosted Zone」就可以開始設定。
  2. 在「Domain Name」處輸入自己所申請的domain name,並在「Type」選擇”Public Hosted Zone” ,並按下「Create」。
  3. 之後按下「Create Record Set」來設定將自己AWS-EC2 instance的IP對應到domain name上,在「Name」的地方數入”www”,並在底下的「Value」的地方輸入自己instance的IP,之後按下「Create」。
  4. 在設定完第3步驟後,我們要將「Type」為NS的四個Value值。如:
ns-11.awsdns-01.com
ns-111.awsdns-02.net
ns-1111.awsdns-22.org
ns-2222.awsdns-22.co.uk

帶到起初自己買domain的註冊商那邊,去設定namesserver。

5. 由於註冊商的不同,其各自的設定介面也會有所不同,所以筆者就不詳述如何設定namesserver。簡單來說,就是將Route-53所給予的四個DNS,設定到自己domain註冊商的namesserver中,這樣只要向任何一個DNS做查詢,就能知道自己domain的IP位置是什麼。

當設定好EC2後,終於可以開始進行申請SSL認證這部份啦!

申請SSL認證

筆者這部份是使用Let’s Encrypt來申請。它是一個免付費的SSL認證,但憑證只有三個月。這部份也好解決,可以自行寫個排程去解決或是手動更新。

下述操作都在AWS-EC2上面執行。

  1. 首先,先去Let’s Encrypt的github將整個certbot給git clone下來,並切換到該目錄底下,輸入./certbot-auto指令後它就會自己開始安裝certbot。
$ git clone https://github.com/certbot/certbot.git
$ cd certbot
$ ./certbot-auto

2. 但在ec2的環境中會發現到它會跳出下列警示:

FATAL: Amazon Linux support is very experimental at present...
if you would like to work on improving it, please ensure you have backups
and then run this script again with the --debug flag!
Alternatively, you can install OS dependencies yourself and run this script
again with --no-bootstrap.

3. 所以我們在輸入指令./certbot-auto --debug就會開始安裝certbot。

$ ./certbot-auto --debug

4. 待certbot安裝完成後,就能開始申請SSL憑證,這時我們輸入自己的email及自己的domain(這邊我們先以test@gmail.com及test.com來做範例):

$ ./certbot-auto certonly --manual --email test@gmail.com -d test.com

這時就會跳出一些問題問你,而這邊就不詳述說明這些問題:

Saving debug log to /var/log/letsencrypt/letsencrypt.log-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: a
-------------------------------------------------------------------------------
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about EFF and
our work to encrypt the web, protect its users and defend digital rights.
-------------------------------------------------------------------------------
(Y)es/(N)o: y
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for test.com
-------------------------------------------------------------------------------
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.
Are you OK with your IP being logged?
-------------------------------------------------------------------------------
(Y)es/(N)o: y

比較需要注意的是這邊,當回答上述問題後會出現:

-------------------------------------------------------------------------------
Make sure your web server displays the following content at
http://test.com/.well-known/acme-challenge/8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8 before continuing:
8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8.SEzRU_ltn9T0PJuB3sYqRg0HguKQbmGgRhEcxoRihbkIf you don't have HTTP server configured, you can run the following
command on the target server (as root):
mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge
cd /tmp/certbot/public_html
printf "%s" 8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8.SEzRU_ltn9T0PJuB3sYqRg0HguKQbmGgRhEcxoRihbk > .well-known/acme-challenge/8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8
# run only once per server:
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"
--------------------------------------------------------------------Press Enter to Continue

我們就可以在AWS-EC2上開啟另外個terminal來輸入下列指令:

//建立資料夾
$ mkdir -p /tmp/certbot/public_html/.well-known/acme-challenge
//轉到public_html資料夾底下
$ cd /tmp/certbot/public_html
//輸入下列字串
$ printf "%s" 8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8.SEzRU_ltn9T0PJuB3sYqRg0HguKQbmGgRhEcxoRihbk > .well-known/acme-challenge/8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8
//開啟它所指定其python的HTTP server
$(command -v python2 || command -v python2.7 || command -v python2.6) -c \
"import BaseHTTPServer, SimpleHTTPServer; \
s = BaseHTTPServer.HTTPServer(('', 80), SimpleHTTPServer.SimpleHTTPRequestHandler); \
s.serve_forever()"

========================================

補充說明:

這邊的意思是要我們在test.com的domain上,設置一個HTTP method為GET的API(port:80),而Let’s Encrypt就會連接到我們這支API來確認這個認證動作的請求。也就是說,今天就算我們沒使用它所提供的python API的自動生成,自己生成一個API來進行認證的確認也是可行的。

API URL: 
http://test.com/.well-known/acme-challenge/8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8
response內容:
8DbYzrgVXmtimLHcK9GcWGyk858_Wvw7VcdXt-yEnQ8.SEzRU_ltn9T0PJuB3sYqRg0HguKQbmGgRhEcxoRihbk

========================================

待輸入完成後按下「enter」。若設定成功就會出現,並告知這個憑證可以持續到2017–08–24,且若是想要重新認證該憑證,就只要輸入”certbot-auto renew”就可以,十分方便。(若是想要自動更新,就額外寫個排程檔來執行該指令就可以)

Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/test.com/fullchain.pem. Your cert will
expire on 2017-08-24. To obtain a new or tweaked version of this
certificate in the future, simply run certbot-auto again. To
non-interactively renew *all* of your certificates, run
"certbot-auto renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le

之後,我們就可以在路徑”/etc/letsencrypt/live/test.com/”(這邊test.com請自動轉換成自己的domain name)底下發現到四個.pem的檔案:

  • cert.pem: 所申請domain name的SSL憑證。
  • chain.pem: Let’s Encrypt所給的chain證書。
  • fullchain.pem: cert.pem與chain.pem的合併檔。
  • privkey.pem: SSL憑證的private key。

然後,我們可以開始設定最後一個步驟了。

node js 部份

這時候我們就要開始設定HTTPS的port,但這邊先提到到上面AWS-EC2那部份的「inbound rules」。由於EC2的HTTPS rules所給予的port是443,所以當我們的專案是放在由express生成的專案資料夾底下的話,就能直接到/bin/www底下去設定。

var app = require('../app');
var https = require('https');
var fs = require('fs');
app.set('httpsport', 443);
var options = {
key: fs.readFileSync('/etc/letsencrypt/live/test.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/test.com/cert.pem'),
ca: fs.readFileSync('/etc/letsencrypt/live/test.com/chain.pem')
};
var httpsServer = https.createServer(options, app);httpsServer.listen(app.get('httpsport'))
httpsServer.on('error', onError);

若是使用者開發環境是使用Apache或NGINX,則可以參考:

Let’s Encrypt setup for Apache, NGINX & Node.js

小結

經過上面很長的設定後,使用者就可以在自己的網站上看到小綠鎖圖案啦!

這時,我們可以透過SSL Server Test來觀察下自己web的安全等級。通常設定好HTTPS的web其安全等級都會是A。

最後,還是要再提一下將web用到HTTPS的好處:

  • 用於識別web身份。
  • 將client端及server端之間的資料進行加密,保護敏感資料。

除了這些,還有google會讓有設定HTTPS的web,使其更容易被搜尋的到。

還在等什麼!趕快去讓自己的web有HTTPS吧 !

參考資料:

--

--