
作者/ Nuwan Dias
來源/翻譯外網
保護雲原生應用程式需要正确了解微服務向各種消費者公開的接口(邊界)。需要在每個邊界上應用适當的工具和機制,以實作适當的安全級别。正確定護運作應用程式的基礎架構也非常重要。這包括保護容器映像、安全運作容器運作時以及正确配置和使用容器編排系統 (Kubernetes)。
01
微服務安全格局
在前微服務時代,大多數應用程式都遵循 MVC 架構。今天,我們将這些稱為單體應用程式。與此類應用程式相比,雲原生應用程式是高度分布式的,如圖 1 所示。
圖 1:單體應用與雲原生應用
單體應用程式通常有一個入口點。除此之外,除了資料庫調用或類似的互動之外,一切都發生在一個程序中。相比之下,雲原生應用程式的曝光表面要高得多。如圖 1 所示,雲原生應用程式通常具有多個通過網絡進行通信的元件(服務)。任何給定元件的每個入口點都需要适當保護。
保護應用程式邊界,讓我們進一步詳細說明應用程式邊界并了解我們需要擔心的實際邊界。
02
識别雲原生應用程式中的通信邊界
典型的雲原生應用程式的後端架構将包含多個業務域。每個業務領域都封裝了一組微服務。以零售系統為例;訂單處理和庫存管理可以是兩個擁有自己的微服務集合的業務領域。
業務領域内的微服務将能夠無邊界地安全地互相通信。這在圖 2 中顯示為“域内東西向流量”。可以使用雙向 TLS 實作該域内的安全通信。可以使用服務網格實作雙向 TLS 。一種更輕量級的方法可能是傳遞由其中一個網關頒發的授權令牌。我們将在本文後面讨論這種方法。
圖 2:雲原生應用架構
跨業務域的微服務不應該能夠自由地互相通信,除非它們被公開為 API 并明确允許通信。
這在圖 2 中顯示為“域間東西向流量”。該業務域邊界的概念在論文“基于單元的架構”中進一步解釋。
有一個清晰的邊界将所有微服務與用戶端應用程式(Web/移動應用程式)分開。這在圖 2 中顯示為“南北交通”。
03
API 和 API 網關的使用來保護雲原生應用程式
接下來,讓我們确定我們定義為 API 和微服務的内容。任何需要暴露在給定邊界之外的微服務(或集合)都需要定義為 API。API 通常具有 OpenAPI、GraphQL、AsyncAPI 等規範。API 網關用于跨邊界公開 API。API網關的主要任務如下:
- 接受來自呼叫用戶端的消息。
- 確定用戶端擁有正确級别的身份驗證/授權。
- 将消息轉發到正确的目标(微服務)。
如圖 2 所示,API 網關保護南北通道以及域間東西通道的雲原生應用程式。
04
OAuth2.0 在保護雲原生應用程式中的作用
調用 API 的用戶端需要先從令牌服務擷取 OAuth2.0 通路令牌,然後才能與 API 對話。API 網關在允許通路目标之前驗證令牌并確定它是由受信任的機構頒發的。這如圖 3 所示。盡管獲得對 API 的通路權很常見,但令牌的類型以及擷取它們的方式會根據這些令牌的用例而有所不同。
圖 3:擷取和使用 OAuth2.0 通路令牌的工作流程
OAuth2.0 規範有一個稱為授予類型的概念,它定義了擷取通路令牌的步驟。
05
雲原生應用授權
擁有有效的通路令牌是用戶端通路 API 的主要要求。通路令牌的主要好處之一是它不僅允許您調用 API,而且還可以指定您可以使用它執行的操作類型。
06
使用 OAuth2.0 範圍進行授權
想象一個産品目錄 API 有兩個操作:一個用于檢索産品清單(GET /product-list),另一個用于修改産品清單(PUT /product-list)。在零售商店應用程式中,所有使用者都應該能夠檢索産品清單,而隻有標明的使用者應該能夠修改産品清單。
在 API 上對此進行模組化的标準方法是說産品清單更新操作需要一個特殊的“範圍”。除非用于通路此 API 的令牌具有此範圍,否則将不允許該請求。OpenAPI規範允許将範圍綁定到操作。
一旦用戶端知道它需要一個特殊的範圍來通路一個操作,它就會請求令牌服務發出一個帶有所需範圍的令牌。當驗證請求使用者/用戶端被授權擷取請求的範圍時,令牌服務将相關範圍綁定到令牌。此工作流程如圖 4 所示。
圖 4:使用範圍通路 API
我們可以看到身份驗證和授權在 API 網關處終止。但是在某些情況下,實際的微服務需要了解使用者/用戶端通路服務以執行業務邏輯的詳細資訊。此要求是通過 API 網關發出輔助 JWT 格式令牌(不是通路令牌)并将其轉發到目标服務來完成的。這個輔助令牌可以在該域内的微服務中傳遞,并用于在該域内建立互相信任。
07
OPA 授權
除了權限之外,我們可能還需要在雲原生應用程式中實作其他授權規則。考慮限制對工作日上午 8 點到下午 6 點之間可用的某些應用程式功能的通路。雖然這些可以在微服務的源代碼中實作,但這不是一個好的做法。
這些是可以改變的組織政策。最佳實踐是将此類政策從代碼外部化。
Open Policy Agent (OPA) 是一個輕量級的通用政策引擎,不依賴于微服務。授權規則可以在Rego中實作并挂載到 OPA。
圖 5 說明了 OPA 可用于授權規則的模式。
圖 5:使用 OPA 進行授權
08
使用 Docker 保護容器
Docker 是最流行的打包和分發微服務的工具。Docker 容器封裝了微服務及其依賴項,并存儲在容器系統資料庫(私有或公共)中。
圖 6:Docker 建構和推送
09
外部化應用程式秘密
微服務通常依賴于資料庫、第三方 API、其他微服務等。要連接配接到這些類型的系統,微服務可能依賴于敏感資訊(秘密),例如證書和密碼。在單體應用程式中,這些類型的資訊存儲在伺服器配置檔案中。
隻有特權使用者才能通路伺服器配置檔案。但在微服務世界中,開發人員通常将此資訊與微服務代碼一起存儲在屬性檔案中。當開發人員建構這樣的容器并将其推送到容器系統資料庫時,任何可以通路容器映像的人都可以使用此資訊!
為了防止這種情況發生,我們需要将應用程式機密從代碼中外部化。讓我們看一下執行此操作的 Java 程式中的示例 Dockerfile:
此 Dockerfile 中的第三行訓示 Docker 建立一個名為的環境變量并将CONFIG_FILE其指向該
/opt/configs/service.properties位置。與其在源代碼中寫死秘密或從固定檔案位置讀取代碼,不如編寫微服務的代碼,以便查找此環境變量的值以确定配置檔案位置并将其内容加載到記憶體中。有了這個,我們成功地避免了代碼中的秘密。如果我們用這個檔案建構一個 Docker 容器,它不會包含任何敏感資訊。接下來,讓我們看看如何将我們需要的值外化。
在運作從上述 Dockerfile 建構的 Docker 映像之前,我們需要将其挂載到具有正确值的實際配置檔案的位置。這可以通過以下 Dockerrun指令完成:
該source部分包含容器主機上檔案系統的路徑。該target部分包含容器檔案系統上的路徑。該--mount指令訓示 Docker 運作時将源挂載到目标上,這意味着service.properties檔案現在可以安全地維護在主機的檔案系統上,并在啟動容器之前挂載到容器運作時。這樣,我們将敏感資訊從 Docker 上的微服務本身外部化。
10
Docker 内容信任
現代軟體由許多依賴項組成。軟體供應鍊是從應用程式代碼到 CI/CD 一直到生産的軟體依賴項的集合。由于惡意軟體通過其依賴鍊進入應用程式運作時,軟體供應鍊攻擊非常頻繁。
在 Docker 上運作的雲原生應用程式依賴于從一個或多個存儲庫中提取的 Docker 映像。毫無戒心的開發人員可能會依賴惡意 Docker 映像,該映像随後會危及他們的應用程式。為了防止這種情況,Docker 引入了一種稱為 Docker Content Trust (DCT) 的機制,該機制允許鏡像釋出者使用加密密鑰對鏡像進行簽名,并且 Docker 鏡像的使用者可以在使用前驗證鏡像。在您的開發和 CI/CD 流程中使用DCT将確定您僅依賴于雲原生應用程式中受信任且經過驗證的 Docker 映像。
開發人員需要設定一個名為的環境變量DOCKER_CONTENT_TRUST并将其值設定為 1,以在使用 Docker 的所有環境中強制執行 DCT。例如::\> export DOCKER_CONTENT_TRUST=1。設定此環境變量後,它将影響以下 Docker 指令:push、build、create、pull和run。這意味着如果您嘗試對docker run未經驗證的圖像發出指令,您的指令将失敗。
11
碼頭勞工特權
任何作業系統都有一個稱為 root 的超級使用者。預設情況下,所有 Docker 容器都以 root 使用者身份運作。這不一定是壞事,這要歸功于 Linux 核心上的命名空間分區。但是,如果您在容器中使用檔案挂載,則獲得容器運作時通路權限的攻擊者可能非常有害。以 root 通路權限運作容器的另一個問題是,它授予攻擊者通路容器運作時的權限,以便将其他工具安裝到容器中。這些工具可能會以各種方式損害應用程式,例如掃描開放端口等。
Docker 提供了一種以非特權使用者身份運作容器的方法。Linux 中的 root 使用者 ID 為 0。Docker 允許我們通過傳入使用者 ID 群組 ID 來運作 Docker 容器。以下指令将在使用者 ID 900 群組 ID 300 下啟動 Docker 容器。由于這是一個非 root 使用者,是以它可以對容器執行的操作是有限的。
12