本文使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或從新修改使用,但須要註明來源。 署名 4.0 國際 (CC BY 4.0)html
本文做者: 蘇洋前端
建立時間: 2019年08月05日 統計字數: 7023字 閱讀時間: 15分鐘閱讀 本文連接: soulteary.com/2019/08/05/…nginx
在公網搭建的 GitLab 頻頻遇到安全挑戰,然而其實只須要作一兩個簡單的動做,維護成本就可以大大下降,而且還能避免未被許可的內容,被搜索引擎爬蟲暴露的處處都是。git
本篇文章,咱們就來聊聊公網搭建的 GitLab 代碼倉庫的安全小細節。docker
公網搭建 GitLab ,常見的攻擊面主要有:編程
前兩點能夠經過 SLB
+ VPC
進行網絡隔離,來下降被攻擊風險。後兩點除了保證最快跟進系統安全補丁,升級應用版本外,其實還有更好的解決方案,畢竟存放着數據的程序,每次升級都有未知的風險:瀏覽器
Basic Auth
來解決。可是加一層 Basic Auth
其實會對 GitLab 使用形成一些麻煩。安全
GitLab 程序自己並不支持 Basic Auth
,這裏須要使用一個 Web 前端軟件來完成這部分的工做,好比:Nginx、Traefik。bash
我這裏選擇使用 Traefik,由於配置更簡單,具體配置能夠參考以前文章的「 添加網絡請求驗證 」小節。網絡
在配置聲明裏添加一句話就夠了,好比這樣:
- "traefik.gitlab.frontend.auth.basic=soulteary:$apr1$E86fARwM$tXmggGAtCEDKqsBCSvDA3/ 複製代碼
這樣處理以後,全部的 HTTP 請求就都會被驗證是不是合法訪問啦。而其餘的端口和協議則不受影響,好比開在22端口的 SSH 服務等。
當訪問頁面的時候,會展現相似下面的對話框,要求用戶登錄,不然會提示 401 Unauthorized
。
當爬蟲/安全檢測工具請求頁面的時候,若是沒有提交用戶名和密碼,得到的結果也是同樣。
curl -I https://gitlab.domain/
HTTP/2 401
content-type: text/plain
vary: Accept-Encoding
www-authenticate: Basic realm="traefik"
content-length: 17
date: Sat, 03 Aug 2019 18:22:17 GMT
複製代碼
若是你輸入了正確的用戶名以及用戶密碼,你會發如今你的請求參數中會出現一個額外的請求參數 authorization
。
參數數值通常由兩部分構成,第一部分表示加密方式(加密協議名稱),第二部分則是你的身份信息(更多信息詳見 RFC 7617)。
現代瀏覽器通常會很智能的在你第一次正確輸入以後,將身份信息記錄下來,攜帶在後續的每一次請求中,若是是使用程序或者工具的話,則須要手動將 authorization
信息加入到每個 HTTP 的請求頭中。
然而 Basic Auth 擋住了外來者隨意訪問的同時,還擋住了 GitLab CI Runner。
這是怎麼回事呢,咱們繼續往下看。
在解釋爲何 CI Runner 會被 Basic Auth
攔住時,咱們須要先了解另一個協議規範 RFC1738 中對於 HTTP 協議的定義:
//<user>:<password>@<host>:<port>/<url-path>
複製代碼
當咱們使用客戶端(瀏覽器、curl等工具)請求這類格式的地址時,部分客戶端會將 user:password
部分轉換爲標準的 HTTP Authorization
請求頭。
在不作任何修改時,CI 直接執行會報錯,日誌輸出相似下面:
Running with gitlab-runner 12.0.2 (d0b76032)
on ci-runner sGNUJnq6
Using Shell executor...
Running on ci-runner...
Fetching changes with git depth set to 50...
Initialized empty Git repository in /data/runner/builds/sGNUJnq6/0/config/project/.git/
Created fresh repository.
remote: 401 Unauthorized
fatal: Authentication failed for 'https://gitlab-ci-token:[MASKED]@gitlab.domain/repo.git/'
ERROR: Job failed: exit status 1
複製代碼
結合文章前面的內容,咱們知道這裏是缺乏了 Authorization
請求頭,那麼咱們嘗試給請求補上這個請求頭,在 CI 和 GitLab 中間搭建一臺 Proxy ,讓 CI 請求 GitLab 數據的時候,自動完成「認證」。
若是使用 Nginx 搭建一個支持 GET/POST 請求的代理,核心配置以下:
location / {
forward-http-post-requests-via-rewrite
proxy_pass https://192.168.0.123;
proxy_redirect https://192.168.0.123/ /;
proxy_read_timeout 10s;
proxy_set_header Host 'gitlab.domain';
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Authorization 'Basic YmFhaABCD';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto 'https';
proxy_http_version 1.1;
}
複製代碼
再次使用 curl 對 GitLab 進行請求,發現沒有出現以前的 401
非驗證提示:
curl -I https://gitlab.domain/
HTTP/2 302
cache-control: no-cache
content-type: text/html; charset=utf-8
date: Sat, 03 Aug 2019 18:45:39 GMT
location: https://gitlab.domain/users/sign_in
referrer-policy: strict-origin-when-cross-origin
referrer-policy: strict-origin-when-cross-origin
server: nginx
strict-transport-security: max-age=315360000
vary: Accept-Encoding
x-content-type-options: nosniff
x-download-options: noopen
x-frame-options: DENY
x-permitted-cross-domain-policies: none
x-request-id: Z8uahE5gN39
x-runtime: 0.012164
x-ua-compatible: IE=edge
x-xss-protection: 1; mode=block
複製代碼
打開項目配置,會發現 Runner 已經上線。
繼續在 GitLab Runner 運行 CI 流水線,會看到仍是報錯沒法經過構建。
Running with gitlab-runner 12.2.0~beta.1803.g41d5c6ad (41d5c6ad)
on ci-runner S8sY8o6A
Using Shell executor...
Running on ci-runner...
Fetching changes with git depth set to 50...
Reinitialized existing Git repository in /data/runner/builds/S8sY8o6A/0/project/.git/
> GitLab: The project you were looking for could not be found.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
ERROR: Job failed: exit status 1
複製代碼
還記得前面提到過的 Authorization
請求頭和 HTTP RFC規範嗎?GitLab Runner 在處理 CI 任務的時候,使用的是https://gitlab-ci-token:[MASKED]@gitlab.domain/repo.git/
這樣的 HTTP 協議,請求中的用戶名和密碼和 Nginx ProxyPass 中的字段「八字不合」。
那麼不使用 HTTP 協議,使用 SSH 協議或許能解決問題。
惋惜的是,官方並不支持 GitLab Runner 使用 SSH 協議進行倉庫下載,有相似需求的用戶還真很多,若是你願意找,相似下面的 issue 還有很多:
雖然官方沒有直接提供這個功能,可是從官方文檔中看到有一個 clone_url
,查找代碼發現實現很簡單,只須要稍微改造就可以知足咱們的需求:
// GetRemoteURL checks if the default clone URL is overwritten by the runner
// configuration option: 'CloneURL'. If it is, we use that to create the clone
// URL.
func (b *Build) GetRemoteURL() string {
cloneURL := strings.TrimRight(b.Runner.CloneURL, "/")
if !strings.HasPrefix(cloneURL, "http") {
return b.GitInfo.RepoURL
}
variables := b.GetAllVariables()
ciJobToken := variables.Get("CI_JOB_TOKEN")
ciProjectPath := variables.Get("CI_PROJECT_PATH")
splits := strings.SplitAfterN(cloneURL, "://", 2)
return fmt.Sprintf("%sgitlab-ci-token:%s@%s/%s.git", splits[0], ciJobToken, splits[1], ciProjectPath)
}
複製代碼
改動後的代碼以下:
// GetRemoteURL checks if the default clone URL is overwritten by the runner
// configuration option: 'CloneURL'. If it is, we use that to create the clone
// URL.
func (b *Build) GetRemoteURL() string {
cloneURL := strings.TrimRight(b.Runner.CloneURL, "/")
if !strings.HasPrefix(cloneURL, "http") && !strings.HasPrefix(cloneURL, "ssh") {
return b.GitInfo.RepoURL
}
variables := b.GetAllVariables()
ciJobToken := variables.Get("CI_JOB_TOKEN")
ciProjectPath := variables.Get("CI_PROJECT_PATH")
splits := strings.SplitAfterN(cloneURL, "://", 2)
if strings.HasPrefix(cloneURL, "ssh") {
ciProjectPath = strings.TrimLeft(ciProjectPath, "/")
return fmt.Sprintf("git@%s:/%s.git", splits[1], ciProjectPath)
}
return fmt.Sprintf("%sgitlab-ci-token:%s@%s/%s.git", splits[0], ciJobToken, splits[1], ciProjectPath)
}
複製代碼
若是你不想在浪費時間在折騰構建環境上,能夠參考我以前寫的一篇文章: 源碼編譯 GitLab Runner 。
再次執行 CI 任務,會發現已經可以順利的進行啦。
Running on ci-runner...
Fetching changes with git depth set to 50...
Reinitialized existing Git repository in /data/runner/builds/S8sY8o6A/0/project.git/
Checking out 860587f6 as master...
Skipping Git submodules setup
Warning: Permanently added '192.168.x.x' (ECDSA) to the list of known hosts.
From gitlab.domain:project
3957006..860587f master -> origin/master
Updating 3957006..860587f
Fast-forward
.gitlab-ci.yml | 6 +++---
README.md | 1 +
2 files changed, 4 insertions(+), 3 deletions(-)
Stopping service ...
Stopping service ... done
Removing service ...
Removing service ... done
Network service is external, skipping
Creating service ...
Creating service ... done
Job succeeded
複製代碼
GitLab 先折騰到這裏,或許後面有時間的會寫一篇更加全面的折騰攻略。若是你對 GitLab 感興趣,能夠瀏覽我以前寫的相關文章。
—EOF
我如今有一個小小的折騰羣,裏面彙集了一些喜歡折騰的小夥伴。
在不發廣告的狀況下,咱們在裏面會一塊兒聊聊軟件、HomeLab、編程上的一些問題,也會在羣裏不按期的分享一些技術沙龍的資料。
喜歡折騰的小夥伴歡迎掃碼添加好友。(請註明來源和目的,不然不會經過審覈)