云原生應(yīng)用安全的方法
?保護(hù)云原生應(yīng)用程序需要正確理解微服務(wù)向各種消費(fèi)者公開的接口(邊界)。需要在每個邊界上應(yīng)用適當(dāng)?shù)墓ぞ吆蜋C(jī)制,以實現(xiàn)適當(dāng)?shù)陌踩墑e。正確保護(hù)運(yùn)行應(yīng)用程序的基礎(chǔ)架構(gòu)也非常重要。這包括保護(hù)容器映像、安全運(yùn)行容器運(yùn)行時以及正確配置和使用容器編排系統(tǒng) (Kubernetes)。
微服務(wù)安全格局
在前微服務(wù)時代,大多數(shù)應(yīng)用程序都遵循 MVC 架構(gòu)。今天,我們將這些稱為單體應(yīng)用程序。與此類應(yīng)用程序相比,云原生應(yīng)用程序是高度分布式的,如圖 1 所示。
圖 1:單體應(yīng)用與云原生應(yīng)用
單體應(yīng)用程序通常有一個入口點。除此之外,除了數(shù)據(jù)庫調(diào)用或類似的交互之外,一切都發(fā)生在一個進(jìn)程中。相比之下,云原生應(yīng)用程序的曝光表面要高得多。如圖 1 所示,云原生應(yīng)用程序通常具有多個通過網(wǎng)絡(luò)進(jìn)行通信的組件(服務(wù))。任何給定組件的每個入口點都需要適當(dāng)保護(hù)。
保護(hù)應(yīng)用程序邊界
讓我們進(jìn)一步詳細(xì)說明應(yīng)用程序邊界并了解我們需要擔(dān)心的實際邊界。
識別云原生應(yīng)用程序中的通信邊界
典型的云原生應(yīng)用程序的后端架構(gòu)將包含多個業(yè)務(wù)域。每個業(yè)務(wù)領(lǐng)域都封裝了一組微服務(wù)。以零售系統(tǒng)為例;訂單處理和庫存管理可以是兩個擁有自己的微服務(wù)集合的業(yè)務(wù)領(lǐng)域。
業(yè)務(wù)領(lǐng)域內(nèi)的微服務(wù)將能夠無邊界地安全地相互通信。這在圖 2 中顯示為“域內(nèi)東西向流量”。可以使用雙向 TLS 實現(xiàn)該域內(nèi)的安全通信??梢允褂梅?wù)網(wǎng)格實現(xiàn)雙向 TLS 。一種更輕量級的方法可能是傳遞由其中一個網(wǎng)關(guān)頒發(fā)的授權(quán)令牌。我們將在本文后面討論這種方法。
圖 2:云原生應(yīng)用架構(gòu)
跨業(yè)務(wù)域的微服務(wù)不應(yīng)該能夠自由地相互通信,除非它們被公開為 API 并明確允許通信。
這在圖 2 中顯示為“域間東西向流量”。該業(yè)務(wù)域邊界的概念在論文“基于單元的架構(gòu)”中進(jìn)一步解釋。
有一個清晰的邊界將所有微服務(wù)與客戶端應(yīng)用程序(Web/移動應(yīng)用程序)分開。這在圖 2 中顯示為“南北交通”。
API 和 API 網(wǎng)關(guān)的使用來保護(hù)云原生應(yīng)用程序
接下來,讓我們確定我們定義為 API 和微服務(wù)的內(nèi)容。任何需要暴露在給定邊界之外的微服務(wù)(或集合)都需要定義為 API。API 通常具有 OpenAPI、GraphQL、AsyncAPI 等規(guī)范。API 網(wǎng)關(guān)用于跨邊界公開 API。API網(wǎng)關(guān)的主要任務(wù)如下:
- 接受來自呼叫客戶端的消息。
- 確??蛻舳藫碛姓_級別的身份驗證/授權(quán)。
- 將消息轉(zhuǎn)發(fā)到正確的目標(biāo)(微服務(wù))。
如圖 2 所示,API 網(wǎng)關(guān)保護(hù)南北通道以及域間東西通道的云原生應(yīng)用程序。
OAuth2.0 在保護(hù)云原生應(yīng)用程序中的作用
調(diào)用 API 的客戶端需要先從令牌服務(wù)獲取 OAuth2.0 訪問令牌,然后才能與 API 對話。API 網(wǎng)關(guān)在允許訪問目標(biāo)之前驗證令牌并確保它是由受信任的機(jī)構(gòu)頒發(fā)的。這如圖 3 所示。盡管獲得對 API 的訪問權(quán)很常見,但令牌的類型以及獲取它們的方式會根據(jù)這些令牌的用例而有所不同。
圖 3:獲取和使用 OAuth2.0 訪問令牌的工作流程
OAuth2.0 規(guī)范有一個稱為授予類型的概念,它定義了獲取訪問令牌的步驟。Prabath Siriwardena 所著的 Advanced API Security是一本了解 OAuth2.0 概念及其用例的好書。
云原生應(yīng)用授權(quán)
擁有有效的訪問令牌是客戶端訪問 API 的主要要求。訪問令牌的主要好處之一是它不僅允許您調(diào)用 API,而且還可以指定您可以使用它執(zhí)行的操作類型。
使用 OAuth2.0 范圍進(jìn)行授權(quán)
想象一個產(chǎn)品目錄 API 有兩個操作:一個用于檢索產(chǎn)品列表(GET /product-list),另一個用于修改產(chǎn)品列表(PUT /product-list)。在零售商店應(yīng)用程序中,所有用戶都應(yīng)該能夠檢索產(chǎn)品列表,而只有選定的用戶應(yīng)該能夠修改產(chǎn)品列表。
在 API 上對此進(jìn)行建模的標(biāo)準(zhǔn)方法是說產(chǎn)品列表更新操作需要一個特殊的“范圍”。除非用于訪問此 API 的令牌具有此范圍,否則將不允許該請求。OpenAPI規(guī)范允許將范圍綁定到操作。
一旦客戶端知道它需要一個特殊的范圍來訪問一個操作,它就會請求令牌服務(wù)發(fā)出一個帶有所需范圍的令牌。當(dāng)驗證請求用戶/客戶端被授權(quán)獲取請求的范圍時,令牌服務(wù)將相關(guān)范圍綁定到令牌。此工作流程如圖 4 所示。
圖 4:使用范圍訪問 API
我們可以看到身份驗證和授權(quán)在 API 網(wǎng)關(guān)處終止。但是在某些情況下,實際的微服務(wù)需要了解用戶/客戶端訪問服務(wù)以執(zhí)行業(yè)務(wù)邏輯的詳細(xì)信息。此要求是通過 API 網(wǎng)關(guān)發(fā)出輔助 JWT 格式令牌(不是訪問令牌)并將其轉(zhuǎn)發(fā)到目標(biāo)服務(wù)來完成的。這個輔助令牌可以在該域內(nèi)的微服務(wù)中傳遞,并用于在該域內(nèi)建立相互信任。
OPA 授權(quán)
除了權(quán)限之外,我們可能還需要在云原生應(yīng)用程序中實現(xiàn)其他授權(quán)規(guī)則。考慮限制對工作日上午 8 點到下午 6 點之間可用的某些應(yīng)用程序功能的訪問。雖然這些可以在微服務(wù)的源代碼中實現(xiàn),但這不是一個好的做法。
這些是可以改變的組織策略。最佳實踐是將此類策略從代碼外部化。
Open Policy Agent (OPA) 是一個輕量級的通用策略引擎,不依賴于微服務(wù)。授權(quán)規(guī)則可以在Rego中實現(xiàn)并掛載到 OPA。
圖 5 說明了 OPA 可用于授權(quán)規(guī)則的模式。
圖 5:使用 OPA 進(jìn)行授權(quán)
使用 Docker 保護(hù)容器
Docker 是最流行的打包和分發(fā)微服務(wù)的工具。Docker 容器封裝了微服務(wù)及其依賴項,并存儲在容器注冊表(私有或公共)中。
圖 6:Docker 構(gòu)建和推送
外部化應(yīng)用程序秘密
微服務(wù)通常依賴于數(shù)據(jù)庫、第三方 API、其他微服務(wù)等。要連接到這些類型的系統(tǒng),微服務(wù)可能依賴于敏感信息(秘密),例如證書和密碼。在單體應(yīng)用程序中,這些類型的信息存儲在服務(wù)器配置文件中。
只有特權(quán)用戶才能訪問服務(wù)器配置文件。但在微服務(wù)世界中,開發(fā)人員通常將此信息與微服務(wù)代碼一起存儲在屬性文件中。當(dāng)開發(fā)人員構(gòu)建這樣的容器并將其推送到容器注冊表時,任何可以訪問容器映像的人都可以使用此信息!
為了防止這種情況發(fā)生,我們需要將應(yīng)用程序機(jī)密從代碼中外部化。讓我們看一下執(zhí)行此操作的 Java 程序中的示例 Dockerfile:
FROM openjdk:17-jdk-alpine
ADD builds/sample-java-program.jar \
sample-java-program.jar
ENV CONFIG_FILE=/opt/configs/service.properties
ENTRYPOINT ["java", "-jar", "sample-java-program.jar"]
此 Dockerfile 中的第三行指示 Docker 創(chuàng)建一個名為的環(huán)境變量并將CONFIG_FILE其指向該/opt/configs/service.properties位置。與其在源代碼中硬編碼秘密或從固定文件位置讀取代碼,不如編寫微服務(wù)的代碼,以便它查找此環(huán)境變量的值以確定配置文件位置并將其內(nèi)容加載到內(nèi)存中。有了這個,我們成功地避免了代碼中的秘密。如果我們用這個文件構(gòu)建一個 Docker 容器,它不會包含任何敏感信息。接下來,讓我們看看如何將我們需要的值外化。
在運(yùn)行從上述 Dockerfile 構(gòu)建的 Docker 映像之前,我們需要將其掛載到具有正確值的實際配置文件的位置。這可以通過以下 Dockerrun命令完成:
:\> docker run -p 8090:8090 --mount type=bind, \ source="/hostmachine/configs/service.properties" \
target="/opt/configs/service.properties"
該source部分包含容器主機(jī)上文件系統(tǒng)的路徑。該target部分包含容器文件系統(tǒng)上的路徑。該--mount命令指示 Docker 運(yùn)行時將源掛載到目標(biāo)上,這意味著service.properties文件現(xiàn)在可以安全地維護(hù)在主機(jī)的文件系統(tǒng)上,并在啟動容器之前掛載到容器運(yùn)行時。這樣,我們將敏感信息從 Docker 上的微服務(wù)本身外部化。
Docker 內(nèi)容信任
現(xiàn)代軟件由許多依賴項組成。軟件供應(yīng)鏈?zhǔn)菑膽?yīng)用程序代碼到 CI/CD 一直到生產(chǎn)的軟件依賴項的集合。由于惡意軟件通過其依賴鏈進(jìn)入應(yīng)用程序運(yùn)行時,軟件供應(yīng)鏈攻擊非常頻繁。
在 Docker 上運(yùn)行的云原生應(yīng)用程序依賴于從一個或多個存儲庫中提取的 Docker 映像。毫無戒心的開發(fā)人員可能會依賴惡意 Docker 映像,該映像隨后會危及他們的應(yīng)用程序。為了防止這種情況,Docker 引入了一種稱為 Docker Content Trust (DCT) 的機(jī)制,該機(jī)制允許鏡像發(fā)布者使用加密密鑰對鏡像進(jìn)行簽名,并且 Docker 鏡像的用戶可以在使用前驗證鏡像。在您的開發(fā)和 CI/CD 流程中使用DCT將確保您僅依賴于云原生應(yīng)用程序中受信任且經(jīng)過驗證的 Docker 映像。
開發(fā)人員需要設(shè)置一個名為的環(huán)境變量DOCKER_CONTENT_TRUST并將其值設(shè)置為 1,以在使用 Docker 的所有環(huán)境中強(qiáng)制執(zhí)行 DCT。例如::\> export DOCKER_CONTENT_TRUST=1。設(shè)置此環(huán)境變量后,它將影響以下 Docker 命令:push、build、create、pull和run。這意味著如果您嘗試對docker run未經(jīng)驗證的圖像發(fā)出命令,您的命令將失敗。
docker特權(quán)
任何操作系統(tǒng)都有一個稱為 root 的超級用戶。默認(rèn)情況下,所有 Docker 容器都以 root 用戶身份運(yùn)行。這不一定是壞事,這要歸功于 Linux 內(nèi)核上的命名空間分區(qū)。但是,如果您在容器中使用文件掛載,則獲得容器運(yùn)行時訪問權(quán)限的攻擊者可能非常有害。以 root 訪問權(quán)限運(yùn)行容器的另一個問題是,它授予攻擊者訪問容器運(yùn)行時的權(quán)限,以便將其他工具安裝到容器中。這些工具可能會以各種方式損害應(yīng)用程序,例如掃描開放端口等。
Docker 提供了一種以非特權(quán)用戶身份運(yùn)行容器的方法。Linux 中的 root 用戶 ID 為 0。Docker 允許我們通過傳入用戶 ID 和組 ID 來運(yùn)行 Docker 容器。以下命令將在用戶 ID 900 和組 ID 300 下啟動 Docker 容器。由于這是一個非 root 用戶,因此它可以對容器執(zhí)行的操作是有限的。
Docker run --name sample-program --user 900:300 nuwan/sample-program:v1
結(jié)論
正確保護(hù)云原生應(yīng)用程序并非易事。API 網(wǎng)關(guān)和相互信任是確保我們的通信渠道安全且我們擁有零信任架構(gòu)的關(guān)鍵。OAuth2.0、范圍和 OPA(或類似)是確保 API 得到正確身份驗證和授權(quán)的基礎(chǔ)。
超出這個范圍,我們還需要關(guān)注在 Kubernetes 上使用正確的安全最佳實踐、正確處理機(jī)密(密碼)、保護(hù)事件驅(qū)動的 API 等等。API、微服務(wù)和容器是云原生應(yīng)用程序的基礎(chǔ)。每個開發(fā)人員都需要及時了解最新的安全進(jìn)步和最佳實踐。?