參考連結

前言

可以參考我的論文方向,是如何在資料庫中滿足零信任要求,零信任機制其實核心說白了就是存取控制機制,在Authentication驗證這個人是誰之時,取得所有相關的上下文,甚至是風險,經過多方考量後,最後做Authorization授權。那既然我們的目的在於,如何在資料庫中滿足零信任要求…

就要去探討到,做驗證和授權的地方在資料庫的哪裡?非Connection莫屬了。
但是到底有哪些方式可以介入Connection呢?

  1. 透過第三方介入connection Pool

    • 講到驗證和授權,就會想到建立連線時,我們通常會提供driver, username, password, url來建立連線,而建立連線時最常提到的是Connection Pool,其實說白了就是一個application和datasource建立連線時的中間層,這個中間層可以做很多事情,像是連線池、讀寫分離、快取查詢結果等等。而我們就是要在這個中間層做驗證和授權。
    • 簡單介入Connection Pool的方式,像可以改寫一些應用程式的第三方套件,像是Spring Boot使用的HikariDataSource
  2. 使用Database Proxy

    • 我第一次看到這個詞是在看Hikari的Source Code時,發現有Proxy的連線設定。後來上網一查,立馬跳出來的就是AWS RDS Proxy。AWS RDS Proxy全名稱Relation Database。
    • 透過Database Proxy也可以做到驗證和授權,簡單來說他就是介於多個應用程式跟資料庫的中間層。
    • 與Connection Pool類似都是作為應用程式中間層的存在,但是應用面比較廣,因為他不是只有針對單一應用程式,而是作為所有應用程式的連線資料庫的入口。

使用Database Proxy

AWS RDS Proxy

AWS RDS Proxy是一個中間層的服務,可以讓應用程式與資料庫之間的連線更加穩定,並且提供了一些功能,像是連線池、讀寫分離、快取查詢結果等等。AWS有許多應用程式,像是AWS Lambda、Fargate、Amazon ECS或EKS,等多個應用程式中會有大量且快速地開啟或關閉,與資料庫伺服器間的連結的需求,而這樣的操作容易耗盡資料庫的記憶體和運算資源。

連接池:減輕建立新連接時,對資料庫記憶體和運算資源造成的影響

因此才有了RDS Proxy,Amazon RDS Proxy的執行個體會維護與RDS資料庫執行個體間建立的連接池,減輕建立新連接時,對資料庫記憶體和運算資源造成的影響,並且在應用程式間共用這些連結,進而提高資料庫的效率以及應用程式的可擴展性。

連線中斷:避免因為資料庫服務中斷,造成應用程式可用性問題

而且RDS Proxy能夠在維持現有連接的狀態下,連接新的資料庫執行個體,因此可以最大程度減少因為資料庫服務中斷,所造成的應用程式可用性問題,當資料庫故障時,RDS Proxy會直接將請求路由到新的資料庫執行個體,這樣可以使得故障轉移時間減少66%。

身份驗證:避免把權限寫死在程式碼中

RDS Proxy讓使用者可強制資料庫存取使用IAM身份驗證,因此將能避免資料庫憑證被寫死在程式碼中的安全性風險,多增加了一道的安全性控制,而且藉由RDS Proxy,使用者還能以AWS Secrets Manager集中管理資料庫憑證。

操作說明

其實做Database Proxy的好處就是,可以在不同應用程式中共享那個Connection來加快速度,在微服務的世界,不同應用存取一個database的需求很大,但是如果每個應用都要自己建立一個Connection,那麼就會造成資源的浪費,而且也不好管理。因此我們可以透過RDS Proxy來管理這些Connection,讓不同的應用程式共享同一個Connection。

可以參考以下影片了解Proxy怎麼建立和設定:

kingshard

kingshard是一個由Go開發高性能MySQL Proxy項目,可以做到以下幾點,也是可以作為零信任架構的可用功能:

  1. SQL的讀寫分離:讀寫分離最簡單的就是所有寫入的都寫入到一台服務,讀取時讀取一台服務。通常是主從式master-slave架構,由master負責寫的服務,會與 slave 進行資料同步。slave主要用來讀的服務。
  2. 透明的Connection Pool,不需要每次做連線: 透明的連線池,就是在應用程式中不需要額外的程式碼,就可以使用連線池的功能。
  3. SQL的日誌輸出:幾本上可以收集這些日誌,近一步做分析利用。
  4. SQL的黑白名單機制:支持客戶端IP訪問白名單機制,只有白名單中的IP才能訪問kingshard(支持IP 段)。甚至可以偵測SQL的內容,當偵測到有危險的SQL時,可以直接將該SQL拒絕執行。

架構說明


kingshard的整體工作流程如下所述:

  1. 讀取配置文件並啟動
  2. 在配置文件中設置的監聽端口監聽客戶端請求
  3. 收到客戶端連接請求後,啟動一個goroutine單獨處理該請求
  4. 首選進行登錄驗證,驗證過程完全兼容MySQL認證協議,由於用戶名和密碼在配置文件中已經設置好,所以可以利用該信息驗證連接請求是否合法。
  5. 用戶名和密碼都正確時,轉入下面的步驟,否則返回出錯信息給客戶端。
  6. 認證通過後,客戶端發送SQL語句
    1. kingshard對客戶端發送過來的SQL語句,進行詞法和語義分析。識別出SQL的類型和生成SQL的路由計劃。如果有必要還會改寫SQL。然後轉發到相應的DB
    2. 也有可能不做詞法和語義分析直接轉發到相應的後端DB。如果轉發SQL是分錶且跨多個DB,則每個DB對應啟動一個goroutine發送SQL和接收該DB返回的結果。
  7. 接收並合併結果,然後轉發給客戶端。

改寫 Hikari Datasource

除了Proxy之外,如果是針對特定應用程式,希望連線可以共享,而非每次建立新的Connection則可以考慮改寫Hikari Datasource。但是這個就不像Proxy那樣方便並且使用廣泛。就像前一篇Day09 - 淺入淺出 JDBC, Connection Pool所提到的,有很多第三方套件實作,其中spring boot預設採用Hikari,因為他是效能之冠。但是如果我們希望在getConnection()的時候可以先驗證一下Application的身份,或是在prepareStatement()的時候可以先驗證一下Application的權限,免不了要自己重新定義裡面的實作方法。

具體來說,可以怎麼重新撰寫自己的實作呢?

繼承HikariDataSource

1
2
3
4
5
6
7
public class MyHikariDataSource extends HikariDataSource {
@Override
public Connection getConnection() throws SQLException {
// 這裡可以做一些設定
return super.getConnection();
}
}

在config中設定自己的class

1
2
3
4
5
spring.datasource.type=com.test.dao.MyHikariDataSource    #指定自己的class
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/db
spring.datasource.username=USERNAME
spring.datasource.password=PASSWORD

我的下一步

目前比較能知道的是,透過Proxy能夠介入Connection Pool的應用面向更廣,所以接下來幾天要先能夠深入了解:

  • [ ] 目前保護資料庫的方式與實施ZTA於Database的必要與
  • [ ] 雲端不同proxy的功能比較,安全性的比較功能。
    • [ ] 比較市面上目前有的solution,裡面缺了什麼樣的功能
    • [ ] cloudfare zta tunnel 目的是建立安全的database connection, cloudfare 是讓遠端工作者可以安全連線
  • [ ] 清楚你做出內容的貢獻可以是什麼?

在了解可以介入Connection Pool的方式後,決定要採用Proxy的方式進行研析,但是這就意味著要深入了解Mysql的連線協議,以及Proxy的實作方式。這個部分我會在下一篇文章中進行介紹。目前規劃如下:

  • [ ] 深入了解Mysql協議
  • [ ] 學習 Go 語言
  • [ ] 深入了解Proxy的實作方式