Try   HackMD

rsyslog server (tls) 架設與使用

配置環境介紹

  • LogServer
    跑 ubuntu server , 預計佈署 rsyslog server 收計 AP 送來的Log資料。

  • AppServer
    透過 Docker 佈署的 Net Core 網站或跑其他應用程式,預計將 Docker 相關的 Log 轉送到上面的 LogServer。

前置準備

  • ubuntu server 預設就有安裝 rsyslog 套件了,不過如果要支援 tls 傳輸的話需要在多裝一個套件。
    apt install rsyslog-gnutls
    這個動作 LogServer 跟 AppServer 都要安裝。

  • 產生相關憑證

    • 建立一個憑證中心的 ca 證 , 這邊假定是 EriCaRoot.crt
      這檔案需要佈署到 LogServer 跟 AppServer
    • 用上面憑證中心發行兩張憑證出來
      • For LogServer
        • LogCert.crt (憑證), LogPrivkey.key (私鑰)
      • For AppServer
        • AppCert.crt (憑證), AppPrivkey.key (私鑰)
  • 佈署憑證檔案
    這邊把憑證相關檔案都放到 /etc/rsyslog.d/tls 下面,後續設定檔會需要指定憑證的完整路徑,所以這路徑只是我喜歡放這邊,不是一定要放這邊,佈署完成後兩個主機上的狀況太概會是。(檔案權限都設定為 644)

    • LogServer 的 /etc/rsyslog.d/tls 有三個檔案
      EriCaRoot.crtLogCert.crtLogPrivkey.key
    • AppServer 的 /etc/rsyslog.d/tls 有三個檔案
      EriCaRoot.crtAppCert.crtAppPrivkey.key

rsyslog 設定調整

  • LogServer 部分

    • 新增設定檔 /etc/rsyslog.d/01-tls.conf
      ​​​​module(load="imtcp" # TCP listener
      ​​​​    StreamDriver.Name="gtls"
      ​​​​    StreamDriver.Mode="1" # TLS-only 模式
      ​​​​    StreamDriver.Authmode="x509/certvalid" # 驗證客戶端證書是否有效
      ​​​​    )
      ​​​​
      ​​​​# make gtls driver the default and set certificate files
      ​​​​global(
      ​​​​    DefaultNetstreamDriver="gtls"
      ​​​​    DefaultNetstreamDriverCAFile="/etc/rsyslog.d/tls/EriCaRoot.crt"
      ​​​​    DefaultNetstreamDriverCertFile="/etc/rsyslog.d/tls/LogCert.crt"
      ​​​​    DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/tls/LogPrivkey.key"
      ​​​​    )
      ​​​​
      ​​​​    # start up listener at port 6514
      ​​​​    input(
      ​​​​    type="imtcp"
      ​​​​    port="6514"
      ​​​​    )
      ​​​​
      ​​​​# 定義模板:按主機名貯存日誌
      ​​​​template(name="DynFileByHostname" type="string" string="/var/log/clients/%HOSTNAME%.log")
      ​​​​
      ​​​​# 定義模板:按 IP 地址貯存日誌
      ​​​​template(name="DynFileByIP" type="string" string="/var/log/clients/%FROMHOST-IP%.log")
      ​​​​
      ​​​​# 或者按 IP 地址存储
      ​​​​*.* ?DynFileByIP
      ​​​​& stop
      
  • AppServer 部分

    • 新增設定檔 /etc/rsyslog.d/01-tls.conf
      ​​​​global(
      ​​​​    DefaultNetstreamDriver="gtls"
      ​​​​    DefaultNetstreamDriverCAFile="/etc/rsyslog.d/tls/EriCaRoot.crt"
      ​​​​    DefaultNetstreamDriverCertFile="/etc/rsyslog.d/tls/AppCert.crt"
      ​​​​    DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/tls/AppPrivkey.key"
      ​​​​    )
      
    • 新增設定檔 /etc/rsyslog.d/01-tls.conf
      ​​​​template(name="DockerLog" type="string" string="/var/log/docker.log")
      ​​​​
      ​​​​if $programname startswith 'docker-' then {
      ​​​​    
      ​​​​    action(type="omfile" dynaFile="DockerLog") # 本地寫入一份
      
      ​​​​    action(type="omfwd"                        # 設定送往遠端 LogServer
      ​​​​       queue.type="linkedlist"                 # 設定用記憶體當駐列,黨 LogServer 暫時離線時候 資料會緩存在記憶體中後續再重送
      ​​​​       queue.size="10240"                      # 最大駐列的紀錄筆數
      ​​​​       action.resumeRetryCount="-1"            # 重新傳送失敗上限限制(-1為無限次)
      ​​​​       queue.saveOnShutdown="on"               # rsyslog 服務停止時,駐列如果有東西沒送先存到檔案.
      ​​​​       queue.filename="docker_fwd"             # 拿來暫存的檔案名稱
      ​​​​       protocol="tcp"                          # 走 tcp 傳輸
      ​​​​       target="LogServer.eri.com.tw"           # 對應 LogServer 的 IP 或 域名
      ​​​​       port="6514"                             # 對應 LogServer 的 Port
      ​​​​       StreamDriver="gtls"                     # 設定 tls 傳輸
      ​​​​       StreamDriverMode="1"                    # tls 模式
      ​​​​       StreamDriverAuthMode="x509/certvalid")  # 驗證伺服器端證書是否有效
      
      ​​​​    # 上面的 action 可以寫很多個,以這邊的案例就是本地寫一份,異機在送一份 , 
      ​​​​    # 如果有多台 LogServer , 要同時送到多台就是 action 繼續給他家下去就對啦
      ​​​​    # 要設定成 App => LogServer1 => LogServer2 .... => LogServerN 這種多層傳輸也是可以的
      ​​​​    # 端看實際場景有沒有需要搞到這麼複雜。
      ​​​​    & stop                                     # 結束相關紀錄的處理
      
      ​​​​}
      
  • 重啟 rsyslog 服務

    ​​systemctl restart rsyslog.service
    

調整 docker 的 Log 設定

docker 沒特別設定預設啟動 container 時,Log是會送到本地的 json,每個 container 各自立的資料,位置在 /var/lib/docker/containers/... 下面,可以透過設定 /etc/docker/daemon.json 把所有的 log 都送往本地的 rsyslog 處理。設定範例如下:

​​{
​​  "log-driver": "syslog",
​​  "log-opts": {
​​    "tag": "{{.DaemonName}}-{{.Name}}"
​​  } ,
​​  //..........略
​​}

調整後透過 systemctl restart docker.service 讓設定生效。
這邊注意調整過 daemon.json 影響的只有調整後啟動的容器,之前啟動的 Log 還是維持在 json 模式,需要把容器銷毀重啟才會改用新的設定。如果是用 docker-compose.yaml 啟動的容器,處理上就很簡單,先 down 在 up 就搞定了。
docker compose down && docker compose up -d

設定日誌輪替(logrotate)

完成上面設定後 AppServer , 所有的 Docker Container 的 Log 應該就都會往本機 rsyslog 發送然後寫入 /var/log/docker.log 裡面了。然後再轉送到 LogServer 的 /var/log/clients/下面,但預設 log檔會一直長大,這時候就需要另外一個機制日誌輪替(logrotate),這大部分的 Linux 發行版預設都有安裝了,我們只要調整設定讓他多去處理我們新增的日誌檔案目標就好。

調整範例

  • LogServer
    編輯 /etc/logrotate.d/rsyslog 加入 /var/log/clients/*.log
    ​​​​​...略
    ​​​​​/var/log/clients/*.log
    ​​​​​{
    ​​​​​   rotate 4
    ​​​​​   weekly
    ​​​​​...略
    
  • AppServer
    編輯 /etc/logrotate.d/rsyslog 加入 /var/log/docker.log
    ​​​​​...略
    ​​​​​/var/log/clients/*.log
    ​​​​​{
    ​​​​​   rotate 4
    ​​​​​   weekly
    ​​​​​...略
    

後續處理

/etc/logrotate.d/rsyslog 預設是一週切一個檔案(weekly)保留4份(rotate 4),大約就保留一個月左右的紀錄量。如果要改變保留份數或
改變切割方式例如要一天切一個,用日期當檔名,設定的內容可能就會變成。

​​​ ....略
​​​ daily
​​​ missingok
​​​ rotate 180
​​​ dateext
​​​ dateformat -%Y-%m-%d
​​​ ....略

使用心得

  • 容器化佈署是現在的趨勢,一整個系統可能被分割為多個容器,甚至於會分散部署在多台的伺服器上。
    1. 透過上面的配置過程,可以有效的將日誌做集中的管理。
    2. 透過 TLS 憑證的授權確保 rsyslog server不會被濫用。
    3. rsyslog server 提供的操作只有單向的寫入,以資安層面來說就算 AppServer 被攻陷,駭客也最多也只能清除 AppServer 上那份 Log,LogServer 上的不會被破壞。
    4. 透過 日誌輪替(logrotate) ,可以針對 AppServer、LogLogServer 做不同的保留策略。例如 AppServer 保留7天 (做短期緩衝), LogLogServer 保留半年(或更長)。
      後續日誌存放空間是否充足的問題,就只要把關注點放在 LogLogServer 處理就可以。
  • 上面簡化略過了一些憑證產生與logrotate的細部說明,這些部分有需要可以另外在研究。