[實作筆記] GCP 使用 IAP 連線 VM

簡介 IAP(Identity-Aware Proxy

GCP 的 IAP(Identity-Aware Proxy)是一個身份驗證和授權服務,
用於保護和管理對 Google Cloud 資源的訪問。
它提供了對虛擬機器(VM)實例的安全連接和控制,並可用於 SSH、RDP 等流量的安全轉發(Forwarding)。

通過 IAP,我們可以實現零信任訪問模型,僅允許經過身份驗證和授權的用戶訪問資源,
並且可以根據用戶的身份和上下文進行細粒度的訪問控制。
這提高了資源的安全性並減少了潛在的安全風險。

零信任訪問模型

零信任訪問模型(Zero Trust Access Model)是一種安全設計方法,該方法不假設內部網絡是可信的,
並對每個訪問請求進行驗證和授權,無論該請求來自內部還是外部網絡。
在零信任模型中,所有訪問都需要通過驗證和授權,並且需要進一步的身份驗證和授權步驟,
以確定用戶是否具有訪問資源的權限,更多可以查看參考資料。

比較 VPN 與 RDP

其他常見的連線方式包括傳統的虛擬專用網絡(VPN)和遠程桌面協議(RDP),
它們通常用於在企業內部建立安全連接,但對於雲環境和遠程用戶來說,這些方法可能不夠靈活和安全。

IAP 提供了一個更強大和安全的連接方式。
它在零信任訪問模型下工作,通過驗證和授權機制確保只有經過驗證的用戶可以訪問資源。
以下是 IAP 的優勢:

  • 精確的身份驗證和授權:IAP 可以根據用戶的身份和上下文進行細粒度的訪問控制,僅允許授權的用戶訪問資源。
  • 無需公開 IP 地址:IAP 通過提供 IAP 隧道和代理服務,不需要公開資源的實際 IP 地址,增強了安全性。
  • 雲原生和易於使用:IAP 是 GCP 的原生服務,與其他 GCP 服務整合,易於設置和管理。

前情提要

客戶在 GCP 上部署了多台 VM,每個 VM 都有公開的外部 IP 地址,並允許開發者使用 SSH 進行連線。
這樣的設置存在著安全風險,也需要為這些公開的 IP 付出額外的成本。

為了提高安全性並解決這個問題,我們使用 GCP 的 IAP(Identity-Aware Proxy)。
透過 IAP,我可以實現更安全的連線方式,不需要使用 Public IP 。
IAP 提供了精確的身份驗證和授權,只有經過驗證的使用者才能訪問 VM。
這種設置符合零信任訪問模型,提高了資源的安全性,同時減少了潛在的安全風險。

實務操作

我有一台測試用的 VM beta 已經拔除了 public IP,

  1. 首先啟用(enable) Cloud Identity-Aware Proxy API,「Security」->「Identity-Aware Proxy」

  2. 在 IAM > Permissions 找到需要登入 VM 主機的帳戶加上「IAP-secured Tunnel User」這個角色

  3. 防火牆規則,IP Range: 35.235.240.0/20, 開通指定的 Protocols and ports,比如我們要 SSH 連線,就開通 tcp:22,Targets 設為 Specified targets tags Target tags 為 ingress-from-iap,

  4. 需要登入 VM 加上 tag ingress-from-iap

  5. 可以用以下語法測試連線

    1
    gcloud compute ssh beta --project=my-project --zone=asia-east1-c --troubleshoot --tunnel-through-iap
  6. 排除所有問題後嚐試連線

    1
    gcloud compute ssh beta --project=my-project --zone=asia-east1-c --tunnel-through-iap

補充說明

  • 開發環境在連線時已經透過 gcloud auth login 取得權限了。
  • 連線的目標主機仍然需要設定 SSH 金鑰
  • 35.235.240.0/20 是 GCP 中 IAP 使用的特定 IP 範圍,不可修改

20230711 補充

透過 IAP 連線會出現 “Increasing the IAP TCP upload bandwidth” 的警告
可以參考官方文件

下載 Numpy

1
$(gcloud info --format="value(basic.python_location)") -m pip install numpy

設定環境變數

1
export CLOUDSDK_PYTHON_SITEPACKAGES=1

參考

(fin)

[實作筆記] MongoDB 解決方案評估-- Mongo Atlas

前情提要

最近在 VM 部署了 MongoDB, 不知道為什麼同事在 QA 與正式環境採取了兩個不同的作法,
因此產生了一些版本不一致的問題。
為此需要更換 MongoDB 版本,進而有一些討論,  
決策的考量主要有兩個面向,一、維運的成本。二、實際應付的帳務成本。
可行的方案比較如下,

  • VM 部署 MongoDB
    • GCP
    • Azure
    • Other Cloud …
  • Mongo Atlas(Start from GCP Marketing)
    • GCP VM with MongoDB(Pay as You Go)
    • Azure VM with MongoDB
  • Azure CosmosDB

實作隨筆:Mongo Atlas(Start from GCP Marketing)

測試規劃

mongo atlas 連線的測試架構

如圖,為了不影響原有的環境,我打算建一組新的 VPC Network 進行實驗,
並在這個網路中建立一台實體的 VM 機器,待 Mongo Atlas 設定完成後,
進行連線的測試。

測試的方法,由於 MongoDB Atlas 採用一種安全性較高的連線政策,
必需使用以下連線集群的三種方式才可以連到資料庫:
第一種,IP Access List,使用 GUI 建立 Cluster 的當下會自動加入一組你所在網路對外的 IP,
如果不是固定 IP 可能會有問題
第二種,Peering ,要付錢的版本 M10 以上才可用,也是我們這次實作的重點目標
最後一種,Create a Private Endpoint,也是
M10 以上才可用,但是不是我們這次的主要實作項目,所以不過多的展開。

從 GCP Marketing 建立 Mongo Atlas

在 GCP 的 Marketing 搜尋並訂閱 Mongo Atlas 後點擊 MANAGE ON PROVIDER
在 Mongo Atlas 建立 Cluster,也可以建立 Project 與 User 作更細緻的管控。
這時候可以到 Network Access 查看 IP Access List 的清單,應該會有你網路上設定的對外 IP,
這個流程是自動化的,但是我個人認為不是固定 IP 的話可能會有問題,如果有人可以給我一些提點會十分感激。

IP Access List

建立 VM

GCP 建立 VM 是十分簡單的,就不多作說明。
同時記得安裝我們的測試工具 - mongosh

Mongo DB 相關

切換 db

1
use mydb

查詢目前 DB 狀態

1
db.status()

Create User

1
db.createUser({ user: "username", pwd: "password", roles: [{ role: "roleName", db: "databaseName" }] });

Drop User

1
db.dropUser("username");

查詢 User

1
db.getUsers()

User 加入角色

1
db.grantRolesToUser("username", [{ role: "readWriteAnyDatabase", db: "mydb" }])

User 移除角色

1
db.revokeRolesFromUser("usernmae", [{ role: "readWrite", db: "admin" }])

前置作業: GCP VPC 與 Firewall Rules 設定

為了避免影響原有的系統,
建立 GCP 一組新的 VPC Network : vpc-lab,一般來說 GCP 的專案會有自動建立一組 default VPC Network,
default VPC Network 會預設建立以下的防火牆規則

  • default-allow-icmp – 允許來自任何來源對所有網路 IP 進行存取。ICMP 協議主要用於對目標進行 ping 測試。
  • default-allow-internal – 允許在任何埠口上的實例之間建立連接。
  • default-allow-rdp – 允許從任何來源連接到 Windows 伺服器的 RDP 會話。
  • default-allow-ssh – 允許從任何來源連接到 UNIX 伺服器的 SSH 會話。

與此對應,我也建立相同的規則給vpc-lab,如下:

  • vpc-lab-allow-icmp
  • vpc-lab-allow-internal
  • vpc-lab-allow-rdp
  • vpc-lab-allow-ssh

可以用以下的語法測試一下網路是否能連,如果可以連線再進行 mongodb connection 的測試

1
ping {ip address}
1
telnet {ip address} {port}
1
nc -zv {ip address}

測試連線用的語法

如果網路測試沒有問題,再進行 mongodb 的連線,由於目前沒有設定 Peering 連線,
所以在開發機上可以(網路環境需要在 IP Access List 內),而使用 GCP VM 會無法連線,
開發機連線 GCP MongoDB 語法

1
mongosh mongodb://{user:pwd}@{mongodb_ip}:27017/my_db

開發機連線 MongoDB Atlas 語法

1
mongosh mongodb+srv://{user:pwd}@{atlas_cluster_name}.mongodb.net/my_db

Peering 實作

首先需要在 Mongo Atlas 進行設定,
Network Access > Peering > Add Peering Connection
在 Cloud Provider 中選擇 GCP,

Mongo Atlas Setting

設定 Project ID、VPC Name 與 Atlas CIDR,
比較特殊的是 Atlas CIDR 在 GUI 的說明是

An Atlas GCP CIDR block must be a /18 or larger.
You cannot modify the CIDR block if you have an existing cluster.

但我遇到的狀況是,無法修改預設值為 192.168.0.0/16
建立後會產生一組 Peering 的資料,請記住 Atlas GCP Project ID 與 Atlas VPC Name

Mongo Atlas Peering

接下來到 GCP > VPC Network > GCP Network Peering 選擇 Create peering connection
在 Peered VPC network 中選擇 Other Project,並填入上面的 Atlas GCP Project ID 與 Atlas VPC Name

大概等待一下子就會生效了(網路上寫 10 分鐘,實測不到 3 分鐘)

參考

(fin)

[實作筆記] RWD 設計與 100vh 在行動裝置瀏覽器上的誤區

前情提要

參考圖片

RWD 設計與 100vh 在行動裝置瀏覽器上的誤區

我的網頁有作 RWD 的設計,需求大概是這樣,
綠色是在網頁底部懸浮的選單功能,
紅色區塊是一個控制面版,許多的功能、按鈕、連結都設定在上面。

我最一開始的設定方法如下,

1
height: 100vh;

在瀏覽器上使用模擬器顯示正常,但是在手機上就會出現異常
主要是手機上的 Chrome 和 Firefox 瀏覽器通常在頂部有一個 UI(例如導覽列及網址列等)  
而 Safari 更不同網址列在底部,這使得情況變得更加棘手。
不同的瀏覽器擁有不同大小的視窗,手機會計算瀏覽器視窗為(頂部工具列 + 文件 + 底部工具列)= 100vh。
使用 100vh 將整個文件填充到頁面上時可能導致顯示問題,因為內容可能超出視窗範圍或被遮擋。
因此,在移動設備上進行響應式設計時,應該避免使用 100vh 單位。

解決方法

解決的方法有好幾種,

JS 計算

使用 JavaScript 監聽事件,動態計算高度,缺點是效能較差,在主流的框架(EX:React)要小心觸發重新渲染的行為

1
2
3
4
5
6
const documentHeight = () => {
const doc = document.documentElement
doc.style.setProperty('--doc-height', `${window.innerHeight}px`)
}
window.addEventListener(‘resize’, documentHeight)
documentHeight()

CSS 變數

使用 CSS 變數

1
2
3
4
5
6
7
8
9
10
11
:root {
--doc-height: 100%;
}

html,
body {
padding: 0;
margin: 0;
height: 100vh; /* fallback for Js load */
height: var(--doc-height);
}

min-height 與 overflow-y

留言有人提到使用min-heightoverflow-y
但我的情境不適合,而且這個作法會產生捲軸

1
min-height: 100vh;
1
2
height: 100vh;
overflow-y: scroll;

進一步依照不同的使用情境也許我們需要 @supports

1
2
3
4
@supports (-moz-appearance: meterbar) {
/* We're on Mozilla! */
min-height: calc(100vh - 20px);
}

或是 Browser Hacks 的手法

1
2
3
4
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
/* We are on Internet Explorer! */
min-height: calc(100vh - 10px);
}

position:fixed 的作法

下面的方法可以將元素固定在畫面底部

1
2
3
4
position: fixed;
left: 0;
right: 0;
bottom: 0;

這是我最後選擇的方法,原文的討論相當精彩有趣,
但是我需要的其實是置底,而不是捲軸。
順帶一提我的專是基於 vue 與 tailwindcss,所以下面是 vue 與 tailwindcss 的寫法

1
2
3
<div class="fixed bottom-0 top-0">
<!--HERE THE FEATURES-->
</div>

參考

(fin)

[實作筆記] 管理 Linux 主機與 GCP VM 的磁碟

前情提要

在 GCP VM 上建立的 GitLab Runner 空間不足,導致執行失敗。
我們需要確保 GitLab Runner 有足夠的存儲空間來運行 CI 的 Jobs 。
有兩個解決方案可供選擇:
一、是清理磁碟空間
透過清理磁碟空間,可以移除不需要的文件和暫存資料,釋放寶貴的儲存空間。
二、是擴展磁碟空間
而擴展磁碟空間則是增加磁碟的容量,讓 GitLab Runner 可以持續運行而不受空間限制。
根據具體情況,可以選擇其中一種或兩種方案來解決空間不足的問題

第一部分:查詢與清理磁碟空間

要查詢 Linux 主機的磁碟空間,可以使用 df 命令。下面是使用 df 命令查詢磁碟空間的語法:

1
df -h

這將顯示磁碟空間的使用情況,包括每個檔案系統的大小、已使用的空間、可用的空間以及使用百分比。
要查詢特定目錄或資料夾的磁碟使用情況,可以使用 du 命令。以下是使用 du 命令查詢磁碟使用情況的語法:

1
du -h --max-depth=1 /path/to/directory

這將顯示指定目錄或資料夾的磁碟使用情況,並以人類可讀的格式顯示結果。
可以查詢到一些 cache 或是 log 如果沒有必要的話,可以將之刪除。

要清除 Docker 的磁碟空間,可以使用以下語法:

1
docker system prune -f

第二部分:擴展 GCP VM 的磁碟空間

要在 GCP VM 上垂直擴展 boot 磁碟空間,可以按照以下步驟進行操作:

在 GCP 控制台上,找到並選擇要擴展的 VM 實例。

  • 停止 VM:前往 VM instances 找到要停止的 VM,勾選後 STOP
  • 調整:前往 Disks,找到要 VM instances 所用的 Disk,點擊 Edit 後增加磁碟的大小。
  • 啟動 VM 實例。

小結

無論是清理磁碟空間還是擴展磁碟空間,都是為了讓我能確保足夠的空間供 GitLab Runner 使用,
確保順利運行 CI Jobs!

(fin)

[踩雷筆記] Hexo 網站跑版

前情提要

我的部落格是基於 Hexo 建立的靜態網站,
前幾天,我發佈了一篇新文章,但樣式出現了錯亂。
為了了解發生的問題與解決方案,必須先知道我們的架構,
相關的有三個儲存庫:

Gitlab Group

Github Page

這是部落格的主要內容,使用 Github Page 部署。
通常情況下,我們不會直接對它進行修改,因為大部分的更動都是透過串接的 Github Action 自動完成的。
這個儲存庫代表了整個流程的最終成果。

hexo action

這是我們的自動化工具,結合 Github Action 可以實現持續集成與部署(CI/CD)。
雖然平時不太需要特別注意,但它是相當重要的一環。

Source

這是我們撰寫文章的主要地方,也是整個部落格的功能和版面設計的編排處。

問題追蹤記錄

首先檢查了網頁載入的樣式,發現找不到 style.css 檔案,但有 style.styl
為了緊急處理,我先提供一個正確的 style.css

幸好我在本地端能夠生成正確的 style.css 檔案,所以我先緊急上傳了一個版本到 Github Page
重新執行本地端的測試,一切正常。再次進行部署,結果樣式又跑掉了。
於是我再次手動修正了 Github Page 的問題。

追查了一下 Github Action,發現在這個 commit 之後,異常情況開始發生:

1
2
-"hexo-renderer-stylus": "^2.1.0",
+"hexo-renderer-stylus": "^3.0.0",

從這個記錄中可以得知,問題出在 hexo-renderer-stylus 的更新,而且是一個較大的版本變動。
接下來我嘗試在本地端測試,但卻沒有發現問題。
我開始思考是不是我的部署環境(CI/CD)與本機環境的差異,
第一個是 Node 版本太舊了(12.x.x),所以我先更新了本機的 Node 版本到 20.x.x。
所以我修改了 hexo action,使用最新的 Node 20.x 版本的映像檔。
然而,重新執行部落格的持續部署作業仍然失敗,無法產生 style.css

盲點與解決方式

在這裡我卡住了很久,始終找不到原因。
再次梳理持續部署的流程,結果發現我使用的 hexo-action 版本為 v1.0.5。
原來我忽略了一個步驟,需要為 hexo action 添加新的標籤。
此外,在我們的 Source 的流程中(.github/workflows),
也需要修改為新的 action 標籤 uses: marsen/[email protected]

1
2
3
4
5
    # Deploy hexo blog website.
- name: Deploy
id: deploy
- uses: marsen/[email protected]
+ uses: marsen/[email protected]

(fin)

[實作筆記] 基於 Docker 的 CI Docker 映像檔加速構建流程

前情提要

在現代軟體開發的流程中,持續整合(Continuous Integration,簡稱 CI)是一個重要的概念,
它可以幫助開發團隊在頻繁的程式碼變更中保持項目的穩定性和品質。
而 Docker 作為一個輕量級的容器技術,在 CI 中也扮演著重要的角色。
本篇文章將介紹一個基於 Docker 的 CI Docker 映像檔(Dockerfile_project)的實作記錄(手動,未來將調整為自動化)。

實作

首先,這個 CI Docker 映像檔是基於 php:8.x 映像檔建立的,並且預先安裝了 composer 和 ext-mongodb 擴展。
這樣開發團隊在進行 PHP 項目的 CI 時,就可以直接使用這個映像檔,而不需要額外安裝這些依賴。

在開始使用之前,我們需要訪問 GitLab 的 Docker Registry,所以我們首先需要創建一個 Token。
在 GitLab 的項目設置中,可以找到「Settings > Repository > Deploy tokens」,
在這裡我們需要勾選「read_registry」和「write_registry」權限,以便於讀取和寫入映像檔。

接下來,我們需要使用以下指令來登錄到 GitLab 的 Docker Registry:

1
docker login $GITLAB_REGISTRY_URL -u $GITLAB_REGISTRY_USERNAME -p $GITLAB_REGISTRY_TOKEN

登錄成功後,我們就可以開始建立映像檔了。使用以下指令可以建立映像檔:

1
docker build -t registry.gitlab.com/my_group/subgroup/project .

如果你的電腦跟我一樣是 Mac M2 晶片,可以使用以下指令進行建立:

1
docker buildx build --platform linux/amd64 -t registry.gitlab.com/my_group/subgroup/project --load .

最後,我們需要將建立的映像檔推送到 GitLab 的 Docker Registry 中:

1
docker push registry.gitlab.com/my_group/subgroup/project

至此,我們已經完成了 CI Docker 映像檔的建立和推送的過程。
現在開發團隊可以在持續整合的過程中使用這個映像檔,從而確保項目的穩定性和品質。

小結

在本文中,我們介紹了一個基於 Docker 的 CI Docker 映像檔(Dockerfile_project)的實作步驟。
透過這個映像檔的建立和使用,開發團隊在持續整合(CI)過程中取得了顯著的效率提升。

使用這個新的 Docker 映像檔後,我們見證了從原本的 4 分鐘大幅改進至僅需 30 秒的驚人效果。
這意味著開發團隊現在能夠更快速地完成整個 CI 流程,並且在更短的時間內獲得即時的反饋。

這種效率的提升主要歸功於 Docker 的輕量級容器技術,以及映像檔中預先安裝的依賴(如 composer 和 ext-mongodb)。
透過這些優勢,開發團隊可以在相同的硬體資源下更有效地執行構建和測試操作,從而節省了寶貴的時間。

因此,使用這個新的 Docker 映像檔對於任何需要進行持續整合的專案來說都是一個明智的選擇。
它不僅能提升開發團隊的效率,同時也能確保項目的穩定性和品質。

(fin)

[實作筆記] Mac M2 建立 Docker Image

前情提要

在我的 Gitlab-CI 當中有個步驟 — 建立 Php Image — 十分的冗贅,
需要花3分鐘左右安裝 ext-mongo 與 composer,
如果可以找到已經安裝好的 Image 版本就可以省下這3分鐘。
但是找不到,所以我決定自已建一個 Image 吧

遇到的問題

在構建 GitLab CI 流程時,我遇到了一個問題。
我在開發機上建立了 PHP 的 Docker Image,但在 Gitlab-CI Runner 運行 Image 時,
出現了 “standard_init_linux.go:219: exec user process caused: exec format error” 的錯誤。
這個錯誤表示容器內部執行的可執行文件格式不正確或無效。

進一步分析後,我意識到問題可能是由於容器映像與主機操作系統的處理器架構不兼容引起的。
由於我的筆電是基於 Apple M2 晶片的 Mac,它使用的是 ARM 架構,而我的 CI 使用的容器映像可能是針對 x86 架構設計的。

解決方法

Docker for Mac 提供了一個功能稱為「多架構建置(Buildx)」,它允許我們在具有不同處理器架構的環境中建立 Docker Image。
以下是在 Mac 上建立 x86 架構的 Docker Image 的步驟:
確保您已安裝 Docker for Mac,並確保 Docker 客戶端已啟用 Buildx 功能。
可以使用以下命令來檢查是否啟用了 Buildx:

1
docker buildx version

如果 Buildx 功能已啟用,您應該能夠看到有關 Buildx 的相關訊息。

創建一個新的 Buildx builder,指定 x86 架構。使用以下命令:

1
2
docker buildx create --name mybuilder --use
docker buildx inspect --bootstrap

這將創建一個名為 “mybuilder” 的 Buildx builder,並將其設置為當前使用的 builder。

使用新建立的 builder 建立 Docker Image。
在 Dockerfile 所在的目錄中執行以下命令:

1
docker buildx build --platform linux/amd64 -t Image-name:tag .

在這個命令中,–platform linux/amd64 指定要建立的架構為 x86 架構。

為了將結果映像推送到容器倉庫,您可以加上 –push 選項,例如:

1
docker buildx build --platform linux/amd64 -t Image-name:tag --push .

這將在建置完成後將映像推送到指定的容器倉庫。

如果您只是想將映像載入到本地的 Docker 中,您可以使用 –load 選項,例如:

1
docker buildx build --platform linux/amd64 -t Image-name:tag --load .

實際上使用 --load 在本地端建立的 Image 因為架構不同也無法在本地端執行。

小結

使用了 Docker for Mac 的「多架構建置(Buildx)」功能,
讓我在 M2 Mac 上也可以成功建立 x86 架構的 Docker Image。
使用這個 Image 讓我可以省下 89% 的時間(3 分鐘 →20 秒)

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - 機敏資料的處理

前言

請參考前篇 架構,
我們已經可以部署程式了.
更進一步討論一些實務上的狀況,這篇我們來討論如何處理一些特別的環境設定。

功能、組態與祕密

我們的程式有時會有一些設定,依照不同情境我的分類如下:
功能,是指提供給使用者的設定,簡單的有訂閱通知的開關,或是回呼的 callback url 等.
組態,不牽扯商業邏輯,純屬系統的設定,例如:站台第三方交互的網址,Stage 的名稱等.
祕密,相當於組態,但是不可以外留,否則有資安風險,例如:ClientId、Token、Secret 等.

今天討論的會是組態與祕密,然後我想參考一些資料,
一個是分散系統的建議作法 12 Factors - Config

The twelve-factor app stores config in environment variables (often shortened to env vars or env).
Env vars are easy to change between deploys without changing any code; unlike config files,
there is little chance of them being checked into the code repo accidentally; and unlike custom config files,
or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.

另一個是 Php Laravel 的官方作法

Laravel utilizes the DotEnv PHP library. In a fresh Laravel installation,
the root directory of your application will contain a .env.example file that defines many common environment variables.
During the Laravel installation process, this file will automatically be copied to .env.

想法

理想上、長遠上來我想要走到符合 12 Factory 的建議,
實務上考慮到現實情況和時間限制,加上我對 PHP 和 Laravel 不太熟悉:
現有系統的架構又不是分散式,我決定優先處理減少人為部署的工,而選擇以下的解決方案,

  1. 使用 Gitlab CI/CD 變數來保護敏感資料:
    Gitlab 提供了 CI/CD Variables 功能,可以將敏感資料儲存在 Group Variables 變數中
  2. 在 CI 過程中置換這些變數。
    這樣可以避免將敏感資料直接寫入到 .env 檔案中,提高了安全性(至少機敏資料不會在 Teams 或 Slack 中丟來丟去,或是寫入版控)。
    使用讀取 .env.example 檔案的方式,然後根據需要替換其中的參數值。
    這樣一來,我們可以根據不同的環境需求,動態生成 .env 檔案,而不需要手動修改原始 .env 檔案。

這樣的解決方案結合了 Gitlab CI/CD 的變數功能和動態生成 .env 檔案的方式,使得我們能夠更安全和靈活地管理參數。
雖然這不是 Laravel 官方的最佳實踐,但在缺乏 Laravel 經驗的情況下,這是一個可行且有效的解決方案。

重要的是,這個解決方案能夠讓我們在開發過程中保護敏感資料,同時又不需要深入理解 Laravel 的配置機制。
希望這個解決方案能對其他面臨相同問題的開發者有所幫助。
如果你對於 Laravel 的配置機制比較熟悉,當然也可以探索更適合的方法來保護參數。

實作

Gitlab Group
如圖,GitLab Group 是 GitLab 平台上的一個功能,它允許用戶在同一組織或專案的上下文中管理多個項目,方便協作、權限管理和組織層次的控制。

在 GitLab 中,Group 除了提供組織和專案的管理功能外,還可以使用 CI/CD Variables(持續整合/持續部署變數)來保護敏感資料。
CI/CD Variables 是在 GitLab CI/CD 過程中使用的環境變數,可以在項目層級或 Group 層級定義。

通過 Group 層級的 CI/CD Variables,你可以在整個 Group 內的多個專案中共享和管理變數。
這樣可以方便地保護和管理敏感資訊,例如 API 金鑰、密碼、配置設定等。
透過使用 Group 層級的 CI/CD Variables,你可以在所有專案中統一管理這些敏感資料。

而下面是一段 gitlab-ci 的範例,CI 過程中讀取 Gitlab 的 Group Variables 的並生成 .env 檔

1
2
3
4
- sed -e "s|#{APP_KEY}|$APP_KEY|"
-e "s|#{GOOGLE_CLIENT_ID}|$GOOGLE_CLIENT_ID|"
-e "s|#{GOOGLE_CLIENT_SECRET}|$GOOGLE_CLIENT_SECRET|"
.env.qa > .env

然後在 GCP 的 VM 加上 IAM 設定,Gitlab 對每個帳號設定適合的角色,
初步達成自動化與安全限制。

可能的(?)更好的作法

  • 環境變數與分散式系統 ???
  • 使用雲服務的 Secret Management ???
  • 實作 Laravel Best Practice ???

如果你更好的作法請推薦給我

20230607 補充

使用 CI 建置不同環境的 .env 檔是一件痛苦的事,再更好的方法出現前,我只能儘量減少重複,
下面是一個例子,我需要建立 QA 與 Production 的 .env 檔,
而我目前的作法會在 Gitlab 的 CI/CD Variables 建立不同的 Key,
像是 MY_QA_APP_KEYMY_PROD_APP_KEY
而基礎的設定值又來自不同的檔案 .env.qa 與 .env.production apl
這真是一個糟糕的實作,不過為了動態組出不同的 key,
可以參考以下的寫法,注意單雙引號有不同行為

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.config_temp: &config_script
script:
# Create Env
- echo "KEY:$(eval echo '${'${PREFIX}'APP_KEY}')"
- sed -e "s|#{APP_KEY}|$(eval echo '${'${PREFIX}'APP_KEY}')|"
-e "s|#{GOOGLE_CLIENT_ID}|$(eval echo '${'${PREFIX}'GOOGLE_CLIENT_ID}')|"
-e "s|#{GOOGLE_CLIENT_SECRET}|$(eval echo '${'${PREFIX}'GOOGLE_CLIENT_SECRET}')|"
.env.${suffix} > .env
# 中略
config-qa:
stage: build
variables:
PREFIX: "MY_QA_"
suffix: "qa"
needs: [build]
<<: *config_script

config-production:
stage: build
variables:
PREFIX: "MY_PROD_"
suffix: "production"
needs: [build]
<<: *config_script

參考

(fin)

[實作筆記] Gitlab CI/CD 與 GCP - User Account

前言

請參考前篇,我們將建立兩台 VM,
一台作為 CI/CD 用的 Gitlab Runner,另一台作為 Web Server,
本篇將介紹 Gitlab Runner 的相關設定,
架構如下
GCP 與 Gitlab

參考我們的架構圖,

Linux 系統的使用者管理

使用 Linux 作業系統管理使用者帳號如新增、刪除或修改使用者帳號資訊等等。
以下是幾個常用的命令。

useradd

使用者帳號可以讓你進入系統,執行操作和管理文件等。
這是一個基本的命令,通常需要以系統管理員的權限執行。
範例如下:

1
useradd john

這個命令將會新增一個名為 john 的使用者帳號。

userdel

刪除一個使用者帳號,你可以使用 userdel。
刪除使用者帳號會刪除該使用者的所有文件,因此請確保你已經備份了重要的文件。
範例如下:

1
userdel john

這個命令將會刪除名為 john 的使用者帳號。

usermod

修改使用者帳號的資訊,例如姓名或者家目錄,你可以使用 usermod 命令。
範例如下:

1
usermod -c "John Smith" john

這個命令將會修改名為 john 的使用者帳號的姓名為 John Smith。

2023/05/23 補充使用情境

  • 查詢 www 的 group 有包含哪些 user?
  • 用 usermod 將 user gitlab-runner 加入 group www
  • 再次查詢 www 的 group 有包含哪些 user?
1
2
3
4
5
$ grep '^www:' /etc/group
www:x:1008:
$ sudo usermod -aG www gitlab-runner
$ grep '^www:' /etc/group
www:x:1008:gitlab-runner

補充:g+w 和 755 的差別

g+w 和 755 是針對文件或目錄的權限設置。

g+w 表示給與用戶組寫入權限(write permission)。
這意味著屬於該文件或目錄所屬組的成員可以對其進行寫操作,例如創建、修改或刪除文件。
其他用戶和組仍可能具有其他權限,如讀取或執行權限。

755 是八進製表示法,用於設置文件或目錄的權限。具體而言,它代表以下權限:

所有者(Owner)具有讀、寫和執行權限(rwx = 4 + 2 + 1 = 7)。
屬組(Group)具有讀和執行權限(r-x = 4 + 0 + 1 = 5)。
其他人(Others)具有讀和執行權限(r-x = 4 + 0 + 1 = 5)。
因此,g+w 僅給予了用戶組寫入權限,而 755 給予了所有者讀寫執行權限,用戶組和其他人的讀執行權限。

要注意的是,g+w 是一種相對於當前權限的增量設置,而 755 是一種直接指定權限的絕對設置。
具體取決於文件或目錄的初始權限,兩者可能會有不同的效果。

資料夾權限

可以用以下語法列出資料夾內的檔案與資料夾權限

1
ls -al

在 Linux 系統中,檔案的類型和權限使用特殊的符號來表示。
第一個字元表示檔案的類型,例如目錄、檔案或連結檔等等。
d 是目錄,-是檔案,l 是 link file;
b 是可儲存的周邊設備、c 是鍵盤、滑鼠等設備。

接下來的三個字元代表三種權限,分別是讀取(r)、寫入(w)和執行(x)。
每三個一組,分別對應檔案的擁有者、群組帳號和其他帳號。如果沒有權限,則會用減號來表示。
這些權限可以用來控制不同使用者對於檔案的存取權限。

在 macOS 中最後一個字元,有可能是 @+. 或沒有字元
@:代表此檔案有擴展屬性(Extended Attributes)。
+:代表此檔案有 ACL(Access Control List)權限限制。
.:代表此檔案有 SELinux 安全屬性(SELinux Security Attributes)。
沒有字元:代表此檔案沒有以上特性

舉例來說

1
drwx------ 87 mark.lin  rd      2784  4 12 13:21 Library

這是一個名為 Library 的資料夾,擁有者是使用者 mark.lin,群組是 rd。
權限設定為只有擁有者有讀、寫、執行權限,而群組和其他使用者都沒有任何權限。

調整資料夾權限

1
chown -R mark:mark /www/api

chown:用於更改文件或目錄的擁有者和群組的命令。
-R:對目錄及其子目錄進行遞歸操作。
mark:mark:擁有者和群組名之間使用冒號分隔,這裡將 /www/api 目錄及其所有子目錄和文件的擁有者和群組都設置為 mark。
如果您的系統中不存在名為 mark 的使用者和群組,這條命令會失敗

20230707 補充說明

sudo chown -R www:www : 此命令用於更改指定目錄下的所有文件和子目錄的所有者(owner)和所屬群組(group)。chown 是 “change owner” 的縮寫。-R 選項表示要遞歸地更改所有子目錄和文件的所有者和所屬群組。www:www 是欲更改的目標所有者和所屬群組的用戶名和群組名,這裡是 www。

sudo chmod 775 -R : 此命令用於更改指定目錄下的所有文件和子目錄的權限設定。chmod 是 “change mode” 的縮寫。-R 選項表示要遞歸地更改所有子目錄和文件的權限。775 是許可權的數值表示法,其中第一個數字 7 表示所有者的權限設定,第二個數字 7 表示所屬群組的權限設定,最後一個數字 5 表示其他用戶的權限設定。每個數字由三個位元組組成,分別表示讀取(4)、寫入(2)和執行(1)權限。

建立 VM 的 Account

在 GCP 的實作上我們不需要直接建立帳戶與群組,記得架構圖中的 SSH Key 嗎?
當我們在 Compute Engine Metadata 建立 SSH KEYS 時,就會依照這把 KEY 的 Comments 建立一個 Linux VM 帳號
因此我們的 VM 就會有對應的帳號資料

參考

(fin)

[聲明] 關於支語警察

如果它看起來像支語警察、貼文像支語警察、留言像支語警察,那麼它可能就是支語警察。

聲明

  • 理解並尊重
  • 是否修改內容由我判斷
  • 文化交流本來就會相互影響
  • 只在增進理解上作文章的修改

緣由小記事

5566 與注音文的戰爭

記得 21世紀初有一段時間,在 PPT 當時的大學生/高中生分為兩派,
一派是喜歡 5566 寫注音文,較為年輕; 一派是不喜歡 5566 討厭注音文,較為年長,
長時間在網路論戰,PPT 大多是年長者的勝場,常見有禁注音文入版規,甚之 56 開版被閙到關版。

然後他們都老了,之所以說這段往事,是給自已的反省,
我還是不寫注音文,但是沒那麼討厭 56 了,
當時在版上的種種行為,被我認定為世代的集體霸凌,而我認為這種事不該再發生。

文化交流本來就會互相影響

不論是支語、晶晶體、古早的注音文,
我認為都有其歷史脈絡與背景故事,
注音文表示電腦打字的盛行、晶晶體是與國際交流、支語則代表的兩岸交流的頻繁程度。
而台灣科技發達、地理政治位置都處於世界各個文化的交匯地帶,本來就會有各式各樣的文化衝擊。

我理解你討厭中國

因為在國際上的各種打壓、飛彈、擾台,中國真的很雞掰。

我更討厭思想審查、蓋世太保

透過控制對方的言論的輸出、輸入來控制思想,
這很納粹、也很現在的中國。

正體中文的價值

理解各種母語面臨的危機,
但正體中文在中文語系也變少數了,
我覺得這很珍貴,也是台灣文化的一環,
不然看看滿族、內蒙、新彊、西藏被中國共產黨搞成什麼鬼。
不需特眨低正體中文,來強調自已母語多優秀。

專業從業人員應有標準

可以的話中文語系應該用同一套標準來說明相關的專業知識是最好的,
實務上應該有政治問題造成的困難。
不然就說原文吧,科技應該快要能解開巴別塔的詛咒了。

順帶一提,看過支語警察的對照表是互相衝突的,支語警察們請建立自已的標準吧。

AI 潤飾版

如果一個人的語言、貼文和留言都充滿著批評和指責他人使用支語,那麼這個人很可能就是所謂的支語警察。

聲明:本人尊重並理解不同的文化背景和價值觀,修改文章僅在於增進彼此理解,且修改內容應由原作者自行判斷。

文化交流是相互影響的,因此我們不應該排斥使用不同的語言和文字,例如注音文、晶晶體和支語。
這些語言和文字都有其歷史脈絡和背景故事,例如注音文表示電腦打字的盛行,晶晶體則表示了對英文的追崇,
而支語則反映了台灣與中國交流的頻繁程度。台灣處於世界各種文化的交匯地帶,因此各種的文化衝擊是不可避免的。

雖然我理解一些人對中國政府的態度很反感,但我更反對思想審查和控制言論的行為。
這種行為與納粹主義和現代中國的行為很相似。

正體中文是台灣文化的一環,也是中文語系的寶貴資源。
儘管我理解各種台灣本土多數母語面臨的危機,但我認為正體中文應該被尊重和保護。
與此同時,我們也不應該輕視其他語言和文字,以表達我們的優越性。

對於專業從業人員,使用同一套標準來說明相關的專業知識是最好的。
然而,由於政治問題的影響,實踐上可能會存在困難。
不過,我相信科技很快就可以幫助我們克服語言障礙,實現真正的文化交流。

最後,提醒一下支語警察們,他們的對照表往往互相矛盾,因此建立一套公正的標準將是有益的。

我猜有人反對使用 AI 寫的文章

我的建議啦: 不爽不要看

(fin)

Please enable JavaScript to view the LikeCoin. :P