Blog Cover Image

Inspire you to have New thinking, Walk out your unique Road.

[研發解決方法] 研究公司的產品功能發布流程、設計並提出自動化解決方案(Fortify on Demand 和 Black Duck 掃描服務)

Posted onDec 3, 2023

System Design of automating release flow

這一個自動化解決方案是我在這個團隊,最後半年的研究。

從 2023 年的 6 月開始,起初只是美國團隊的管理經理開出的一個不切實際的期望,沒有想到最後真的被我們研發並設計一個自動化的解決方案,並且在持著各種不確定性及質疑下,設計架構、實作開發、直到最後開發出一個程式自動化掃描的流程,幫助我們以及美國團隊,甚至推廣到跨組織的團隊。

在它與研發它的過程中,我找到了自己過去尋找很久的自我優勢,見證了我的成長與見證了肯定自我的過程。特別感謝我的團隊隊員們、感謝主管與產品經理的協助與感謝那個常常提出一堆想法卻一一被我打槍,常常被我壓著做事的社會新鮮人合作同事。

感謝公司與團隊的支持,讓我能在我們團隊工作的時光中,讓我能夠發揮很多創新的思想與嘗試、挑戰、研發此項需求的解決方法。

本文大綱

  • 需求介紹與研究流程
  • 找出可自動化的部分及對應的技術解決
  • 初版 local 版本架構設計
  • 黑客松: 延伸版本 - 雲端版本與優化 local 版本
    • 雲端版本 - FoD 和 BD APIs 程式架構
    • Local 版本 - 新增 UI 介面連接初版 Python Script 解釋
  • 功能優化
  • 最後

介紹

在我們完成一次無論是新功能的開發,還是現有功能的優化,當 QA 工程師測試完後,我們將要把新的或優化後的功能發布至 Production 之前,需要通過一連串很冗長複雜的程式資安審核流程。

通過一次此流程平均時間為一個月左右,最快是 2 週,最慢可能一個多月。試想某次我們同時完成了五個新舊功能的開發與優化,所有的釋出(Release)與發布都卡在審核流程。等到所有功能的審核流程通過,大概也就 2-3 個月過去了,才把前幾個月開發的功能順利部署上 Production 給使用者使用。

此為整個流程大致的步驟,我已經移除公司機密的資訊重新畫一次流程圖,不過在公司完成合併後,此流程將會大幅度更改或者取消。

文字版步驟如下:

  • 提出功能發布請求
    • 開啟功能發布請求的 Jira Ticket
    • 填寫所需資訊
    • 送審
  • 審核
    • 審核發布的內容
      • 若幸運一次過,則開啟資安審核的 Jira Ticket
      • 但通常都不太幸運,來來回回好幾天在反覆確定產品與功能的資訊
  • 資安審核
    • Black Duck 掃描
      • 需要針對與功能相關的每個微服務掃描並產出報告
      • 需要證明每個微服務中,程式相關套件沒有致命的資安危機
      • 將以上附件打包至 Jira Ticket
      • 準備審核
    • Fortify On Demand 掃描
      • 對每個功能相關的微服務進行掃描
      • 提供每個掃描結果的網址,並附在 Jira Ticket 上
      • 準備審核
    • ... (最少三個資安掃描服務,最多五個)

在這之中,每個步驟都有一定的可能性會被退回要求修改,來來回回耗費數日的溝通,最耗神的是最一開始產品經理需要向審核人員反覆不斷解釋功能的描述與產品的資訊,而最繁瑣的是工程師們要針對每個微服務手動進行掃描、產生報告、截圖無致命威脅,每次釋出平均 2-4 個微服務,但我們有遇過 5-8 個甚至是 11 個微服務。

此冗長繁瑣的流程,讓我們與美國團隊都頭痛不已,於是美國團隊的主管就提出一個需求,研究看看是否有方法能夠自動化這些流程,剛開始只是開個 Jira Ticket 擺著,畢竟就好像是張很不且實際的需求,沒人想嘗試,在某次 sprint 中被塞到我跟我的新鮮人同事手裡。

研究

從最初一開始詢問產品經理、其他工程師的經驗以及 QA 工程師所需參與的掃描,考古以前的各種文件,終於釐清我在上一塊撰寫的完整的審核流程,然後開始去選出我們能夠對哪些功能達到自動化。

  • 開啟/複製功能發布請求的 Jira Ticket -> Jira API
    • 複製以往過去的 Jira Ticket,確保資訊一致,降低被退回的可能性。
    • 創建新的 Jira Ticket,並複製資訊。
  • 檢查 Ticket 的狀態有無改變 -> Jira API
    • 檢查 Ticket 狀態有任何改變 (代表進到資安審核步驟)
    • 檢查有無最新留言 (代表資訊不完整,被退回)
  • 自動化 Black Duck 掃描 -> Selenium + Jira API 上傳附件
  • 自動化 Fortify On Demand 掃描 -> Selenium + Jira API 新增連結至留言
  • 檢查各個掃描的 Jira Ticket 狀態有無改變或新的留言,寄信給使用者通知已完成流程,可以部署功能於 Production -> Jira API + Python

以上是,我們針對所有的流程,選出認為可能自動化的選項及對應的技術解決方案。

這也是第一次研究的成果,而第二次研究的成果則是設計並實作自動化的程式

初版架構設計 - 第一版 local 版本

由於此研究剛開始的重要度與優先度並不高,並且有時間上的壓力,所以我們沒有付出額外的時間研究其他方式,直接選擇了使用 Python 的 Selenium 套件加上 Jira API 開發 自動化 Black Duck 掃描自動化 Fortify On Demand 掃描 功能。

我們設計了一個在 Local 運行的 Python 程式,並設計了兩種方式可以輸入欲進行掃描的微服務名稱列表: [<服務.1>, <服務.2>, <服務.3>]Jira 的 personal token 好讓完成與收集的掃描資訊自動更新到指定的 Jira Ticket 上。

此為程式流程:

由於我們團隊本身就有一個網站上的格式化的規範文件紀錄每次發佈的微服務與相關資訊,所以第一種啟動程式的方式是附上規範文件的網址,Python 程式會驅動 Selenium 開啟 Chrome 去該網站爬蟲所需資料並開始進行自動化掃描服務。

而考量到美國團隊及其他團隊並沒有類似的規範文件,所以也設計第二種啟動程式的方式,是允許手動輸入微服務的名稱 (以列表形式),如此一來 Python 程式會抓取手動輸入的資訊進行自動化掃描服務。

當取得所需掃描的微服務名稱列表後,便會

  • 自動化 Fortify On Demand 掃描 (驅動 Selenium 開啟 Chrome 進行)
  • 在指定的 Jira Ticket 將掃描後連結更新到留言 (使用 Jira API leave comment)
  • 自動化 Black Duck 掃描 (驅動 Selenium 開啟 Chrome 進行)
  • 在指定的 Jira Ticket 將產出的報告跟證明打包並上傳至附件。 (使用 Jira API update attachment)

若你對怎麼使用 Jira APIs 有興趣,可以參考此篇文章

還有 Selenium 支持 Headless Mode,設定模式後,運行程式不會實際開啟 Chrome 自動化掃描,而是運行在背景,直到完成,讓工程師可以一邊自動化掃描,一邊持續做其他工作。

將這樣,我們第一版的 local 版運行程式完成,也陸陸續續幫我們接下來幾次的新功能部署自動化掃描,也推廣到其他團隊。

黑客松: 延伸版本 - 雲端版本與優化 local 版本

繼第一版程式正式被使用後,剛好公司舉辦的一個兩個月的提倡創新解決方案的內部黑客松競賽,擁有這個研發的自動化方案,就碰巧的讓主管鼓舞我們參賽,並且可以延伸我們在第一版的文件裡寫下的,

未來的工作:若未來有機會,我們將研究雲端運行的版本。

然後過去的自己也就一起順手把現在的自己推入坑裡,開啟了後續雲端版本的研究。

此次黑客松的目標是希望能研發出 AWS 雲端版本的自動化掃描解決方案,然而在剛開始幾天就陷入膠著,我們懷抱著強烈的不確定性與不安,還是定下了幾個方案,至少在最終結果時,若沒達成雲端版本,我們還可以優化原本 Local 版的 Python 程式交件。

遇到的困難問題卡在認證階段。

正如以上的流程圖所示,在打開 Fortify On Demand (FoD) 和 Black Duck (BD) 兩個掃描服務前,我們需要進行一連串的認證,直到依據帳號密碼產出 SAML 認證之後,我們才能透過網站夾帶 SAML 前往兩個服務。

第一版的 Local 版本之所以能運行,是因為我們其實是遠端登入虛擬機,在正式進到虛擬機時已經完成認證,所以打開 Chrome 時,已經可以進入兩個服務,自然 Local python 的 Selenium 執行相同的動作,也可以訪問兩個服務。

可是,在雲端執行意味著所有認證需要從 0 開始執行認證,完成認證步驟後,才能訪問兩個服務。

  • 我們想過使用 AWS ECS 起一個虛擬機,並讓使用者在第一次使用時手動認證,讓虛擬機紀錄所需參數持續通過後續每次掃描的認證,但此想法沒有成功。
  • 也想過要不要開發一個 AWS Amplify 前端頁面,讓使用者透過該頁面輸入帳號密碼一次性密碼完成驗證,但在和其他同事討論之下,會被認為此舉像是釣魚網站作法,有資安疑慮,所以不採用。
  • 最後,我們想到在使用 FoD 和 BD 掃描服務時,有 personal token 的選項,所以思考是否兩個掃描有 APIs 可以使用,這樣我們能事先產生 token,並直接訪問兩個服務,繞過認證。 (這招確實有點偷吃步)
  • 加上我們之前考慮到,如果雲端版本做不出來的話,那我們就只優化 Local 版本的程式碼交件。

所以黑客松的三個方案如下:

  • [雲端版本] 查詢有無其他 AWS 服務或其他方式可以完成認證及產生 SAML 認證。
  • [雲端版本] 研究 FoD 及 BD 的 APIs,並開發 AWS Lambda 透過 Call APIs 方式自動化掃描。
  • [Local 版本] 為原本的 Local 版本設計一個 UI 介面連接原本 Local 版 Python 程式,這樣使用者就不需要再開啟 IDE 手動輸入微服務名稱並透過終端機跑程式了。

最後黑客松的結果,我個人希望是可以展示第二個跟第三個方案。

第一個方案研究是由另一個合作同事研究,所以就不放上來了。

雲端版本 - FoD 和 BD APIs 程式架構

所以針對兩個掃描服務的 APIs,在歷經 2-3 週研究 APIs 後,已經確認可以使用哪些 APIs 達成我們要的目標。

並且規劃雲端版本的程式架構如圖。設計一個 API Endpoint 允許使用者透過 RESTful API 的 POST 請求驅動自動化掃描,驅動兩個 AWS Lambda 分別進行兩個掃描服務,並將產出的報告、連結存到 S3 Bucket 中。

由於 BD 的資安驗證中有一個步驟是需要截圖證明微服務裡使用的套件沒有致命的威脅,研究 APIs 後,證實沒辦法完成截圖的功能,所以我們考慮到可以做一個 Python Script 程式驅動 Selenium 打開 Chrome,透過帶參數的方式 (blackduck/<service>?filter=threaten(化名))到指定的網站進行截圖,以此來彌補雲端上無法截圖的功能。

開發的服務為

  • [AWS Lambda] Fortify On Demand Scanner
  • [AWS Lambda] Black Duck Scanner
  • [AWS Gateway] RESTful POST api endpoint
  • [Local Python Script] automating screenshot by Selenium

POST Request Body

// FoD scan api: /api/v1/fortify-on-demand/
{
  "tenet": "",
  "username": "",
  "token": "",
  "serviceList": []
}
// BD scan api: /api/v1/blackduck/
{
  "token": "",
  "serviceList": []
}

關於 Fortify On Demand 和 Black Duck 的 APIs 研究與使用方式,你可以參考這篇文章

Local 版本 - 新增 UI 介面連接初版 Python Script 解釋

這個版本,我們決定新增一個 UI 介面改善使用者不必再需要使用 IDE 開啟程式,輸入需掃描服務。

由於原先的自動化程式是用 Python 撰寫,所以考量到和 UI 對接,我們使用 Python 的 GUI 套件 Tkinder來以最快速度完成開發,且相對容易和後端的自動化邏輯對接。

介面我簡單用 Figma 畫過。

最初介面呢,就是初版 Local 程式提到的,兩種方式輸入欲掃描的微服務名稱列表

接著設計一個頁面可以動態顯示終端機運行的 Log 資訊,包括成功及錯誤。

最後則是秀出掃描的結果,讓使用者可以手動上傳結果與報告。

在第三方案開發途中有遇到一些小變動,由於第二方案研究 APIs 及開發雲端版本提早完工,所以第三方案有考慮是否能把原本全使用 Selenium 的後端邏輯改成直接透過 APIs 傳送請求至雲端版本,僅保留使用 Selenium 進行 BD 截圖的行為,剛好彌補雲端版本缺失的截圖功能。

且使用 call APIs 的模式也會讓系統穩定性提高,因為在我們正在開發這些延伸的版本時,我們發現由於 BD 掃描服務無聲無息地改了一些前端導致初版 Local script 爬不到 BD 的一些元素報錯,而 APIs 是官方開發,且當有改動時會改在新版的 APIs,不會影響舊版的。

優化

功能上

  • 移除了原先自動化將掃描結果上傳至 Jira Ticket,因為實際運行在真實案例時,我們發現審核部門開的 Jira Ticket,一但上傳檔案或留言就不能編輯或刪除,初版程式有些小 Bugs,導致留言有時候顯示的微服務名稱被截掉一半,或者使用者也不能更改在 Ticket 上 BD 掃名的產出報告,使用者反映過後,決定移除這個自動化 Jira 的功能,改為讓使用者手動檢查後,再上傳。
  • 修正初版上傳過長的 FoD 微服務名稱時會被截掉。
  • 協助收集所有欲掃描的微服務列表的 BD 連結。

最後

除了跟同事合作非常的不順利與不愉快之外,提出的方案、規劃與設計,我個人覺得非常滿意。

最終,我把第二個方案 - [雲端版本] 運用Call AWS Gateway RESTful POST API請求方式驅動兩個架於AWS Lambda 的掃描服務的APIs 開發完成,可順利運行,並交接給美國團隊。

第三個方案在和同事溝(吵)通(架)後,由合作同事點頭進行 UI 開發,我來完善對接的後端邏輯。

而第三個方案並沒有完成,我們也沒有完成黑客松,因為在這之前我已經收到團隊解散且正式資遣的通知,最後日期遠比黑客松的結束日期還早一週,但這是個很有趣的參賽體驗。

也很開心自己最終有完成雲端的版本,並轉交給美國團隊,讓我開發的雲端版本自動化解決方案在後續持續幫助眾生自動化掃描。

為了表示我的風度,我絕對不會說因為合作同事都沒什麼在做,用上班時間做自己的個人專案,或者剛開始沒意見,後來反過來諷刺我訂太多目標跟質疑我設計的架構,但又提不出個所以然,然後又不尊重 Deadline 跟進度,不受控的我行我素去研究其他幫不上忙的技術。

那麼感謝你的觀看啦。