Deploy Private Github Python Packages on Heroku without Exposing Credentials in Code

最近我們公司在heroku python的環境上deploy遇到了一些問題.

在heroku的python環境下, 會執行pip install requirements.txt 去安裝所需要的套件. 我們遇到的問題是我們自己有一個private package想要安裝在heroku上. 而當你有了private package之後, 事情就變得很複雜了XD

Goal

其實我們想在Heroku上面想做的事情很簡單, 就是安裝一個github上我們自己private repo裡的package. pip本身支援了蠻多種方式給使用者安裝, 我們只需要能夠讓下面的方法中其中一種方式成功就好:

  • pip install git+https://github.com/my_account/myrepo.git
  • pip install git+ssh://github.com/my_account/myrepo.git
  • pip install git+https://{username}:{password}@github.com/my_account/myrepo.git

在這邊麻煩的事情其實是我們並不想去commit任何像是credential的東西在git裡面, 因為這會造成一些security的issue. 所以這個時候怎麼讓heroku可以在build的時候知道crendential的資訊就會變得很重要

Third-Party Buildpack Solutions

在一開始往這些方向survey的時候其實有發現一些第三方buildpacks可以支援在build的時候設定關於github的token或者是ssh-key, 這兩個是我覺得可以直接解決問題的:

但經過一番討論之後, 我們還是決定不要依靠第三方的buildpacks, 原因有二:

  • maintenance: 這樣當每個在這個project的開發者都必須要了解第三方的buildpack大概做了什麼事情, 然後沒有被maintain之後必須maintain這些stack
  • security: 如果沒有看code的話, 我們實際上不知道他做了什麼

(不過其實有把這兩個repo都看過一次, 其實做的事情都蠻簡單的而且很符合我們想要的功能, 主要還是因為security的考量所以我們放棄他)

Solution without Using Third-Party Buildpacks

後來強者我同事跑進去看了heroku python buildpack的source code, 發現了在python的環境下, 其實執行script的順序是這樣

  1. bin/detect
  2. bin/pre_compile
  3. bin/compile←就是在這一步的時候執行 pip install -r requirments.txt
  4. bin/post_compile
  5. bin/release

根據這個資訊我們嘗試了一下

  1. 設定heroku上面的環境變數 GITHUB_USERGITHUB_PASSWORD
  2. 在Repo裡面放上這個檔案 bin/pre_compile, 檔案裡面的內容是生成private repo的link之後塞到 requirement.txt 裡. 在執行 bin/compile 之前會執行這個檔案, 然後就可以解決這個問題了.
# !/bin/bash
echo "Generate myrepo to requirements.txt"
MY_REPO_GIT="git+https://${GITHUB_USER}:${GITHUB_PASSWORD}@github.com/my_account/myrepo.git"
echo MY_REPO_GIT >> requirements.txt

Failed Try

在嘗試的過程中, 我們有試過用 setup.py 去做一些客製化的事情(像是在 setup.py 裡面拿credential去生成private repo link. 但這個方式是不行的, 後來有跟heroku team聊一下, 他們的理由是一般的 setup.py 實際上可以做很多事情. 而在heroku裡面實際上是生成 -e .requirements.txt 裡然後執行 pip install -r requirements.txt , 所以他是把要deploy的project當一般第三方套件安裝. 這樣子如果第三方套件的 setup.py 裡面寫了不安全的東西的話, 對整個build環境都是危險的.

Thoughts

其實在追這個東西的時候還蠻有趣的, 雖然有時候覺得很@#$@#%. 但在了解之後實在是蠻爽的. 其中跟heroku support team有來回了一下發現 pre_compile 這個檔案好像是一個deprecated feature, 不確定什麼時候會不能用, 但在官方有比較的support之前, 這個也許是比較好的方法了QQ

References

Note: 最近在嘗試也用英文寫作, 所以這篇文章會同步放在我的codementor account下面: https://www.codementor.io/bruce3557/deploy-private-github-python-packages-on-heroku-without-exposing-credentials-in-code-p294vhr24