Asahi Linux for M1 Mac

這個Asahi Linux專案主要是想要讓M1 版本的MACs可以執行Linux,所以之後如果有相關的需求時,感覺可以來這看看是否可以用。

目前的進度來看,離正常使用應該還有段距離,希望這些類似的專案都能成功;可以想象如果可以有一台執行Linux的筆電,並且同時有M1的高效與不秏電,這個應該是許多開發者都希望有的一台電腦呀XDDD

Reference

Apple最近的隱私變動

最近Apple 發表了新的功能,主要是為了避免一些兒童性犯罪(Child Sexual Abuse Material (CSAM))的問題,該功能預計會在iOS 15, iPadOS 15, watchOS 8, and macOS Monterey.* 中更新。

這功能最近引起了大量的社群反彈,雖說是立意良善的功能,但由於該功能是直接透過裝置中的AI/ML相關的演算法去推測出目前裝置上的照片是否有違反規則的照片,這其實也大幅的侵犯了使用者的隱私,而主要社群的反彈點如下:

  • 若Apple與一些極權國家合作,則代表Apple極有可能透過使用者的手機/電腦來監視使用者的照片,這其實蠻讓人擔憂的。
  • 另個社群考量點在於演算法本身的準確度,像是這篇文章指出,目前已知的perceptual hash algorithms都存在不同的缺失,所以如果Apple CSAM detection判斷錯了,那就會對使用者造成一些困擾。

後續再來看看Apple會如何回應…

UPDATED: Aug 11th, 2021

目前Apple 的回應是,他們只會使用CSAM detection 在使用者上傳到iCloud上 照片/影片;跟預期的差不多,Apple先說明他們只會針對特定情境才會做CSAM detection, 以試著降低一些負面聲量…

感覺事件是還沒完全結束,應該還會有後續…

UPDATED: Aug 14th, 2021

連Apple 的軟體技術主管都出來澄清了,這項新的功能的概念是,當使用者將照片上傳到icloud時,相較於像Google, Facebook在server上做照片的辨識,Apple則是選擇先在裝置上辨識(感覺像preprocess的概念);而整個機制被觸發的情況只有在使用者將照片上傳到icloud時才會觸發…

不過這也意味著,觸發機制如果被更改了,那就代表使用者的手機是被監控的;另一個點也是說,如果iphone有這種機制了,這樣只要這間公司與 政府合作,就代表一般人的生活其實都會被監控著…

reference:

Socks5 proxy server的設定

今天跟DK開會時,他利用些片段時間分享了他的工作環境設定,主要是關於他怎麼透過設定他的環境來同時可以連接dev, stage, production的環境。
會有這個分享主要也是因為我們在切換環境時,相對較笨拙點,都是透過連接不同的vpn server來切換到不同的環境下,但同時也只能在同時間點,只能連接到某個環境。

那就來進入主題了,他分享的方式,主要是透過在本機端建立socks5 proxy server, 將對於特定目標位址的流量,proxy到遠端預先設定好的jump server,再到對應的最終目標位址。

Step 1. 建立遠端的jump server

只要遠端的server有開啟ssh server的,就已經可以當成jump server了,而我們的stag jump server 就是這樣設定的。

Step 2. 設定 ~/.ssh/config (optional)

為了更容易的連接jump server,而不用每次都打一大串的ssh 指令,我們可以把連接jump server的相關設定寫到 ~/.ssh/config下,範例如下:

Host staging_jumper
   HostName our-jump-server.com
   IdentityFile ~/.ssh/jump-server.key
   User my-username

Step 3. 在本機端啟動socks5 server

由於剛剛在上一步有設定好連接jump server時,需要的ssh user 與 key,所以這邊可以很簡單的用下面的ssh指令啟動socks5 server

ssh -D 1081 -C -N -f staging_jumper

-D 1080 代表要將連往本機端 port 1081的流量轉送到staging_jumper上。
-f 代表要在背景執行
-C 代表要壓縮資料
-N 代表不執行任何遠端指令,通常做port forwarding 都會代入這flag

如果要關閉在背景的socks5 server,則可以用ps -aux 找出剛啟用的socks5 server pid,接著再使用kill指令去停掉正在運行的sock5 server process。

Step 4. 檢查是否有socks5 server是否有運作正常

curl --socks5 localhost:1081 http://your-staging-service.com

可以簡單透過curl 指令,來發起一個http的request到我們剛啟用的socks5 server port上。 如果成功的話,理論上會看到我們預期的html 網頁了。

Step 5. 設定SwitchyOmega

這是一個browser extension,主要是可以讓我們連接不同的網頁時,可以使用預先設定好的條件或方式來連接。
舉例來說,我們可以設定當接http://192.168.10.2:8080這個位址時,就自動透過我們預先設定好的socks5 server 與jump server 連接,此外,它還可以透過wildcard的方式來導流特定網段或特定domain 的網頁。

如以下範例

當我們啟用本機端的socks5 server以後,就可以到下面的SwitchyOmega頁面去設定代理伺服器。

之後,只需要再設定auto switch來決定哪些目標網頁要使用哪些代理伺服器就完成了

reference:

Kubernetes 的安全強化指南

Hacker Daily News上看到的新資訊,美國的National Security AgencyCybersecurity and Infrastructure Security Agency 出版的一個Kubernetes安全強化指南;雖然很久沒用kubernetes了,但對於這相關的資訊還是些記錄一下,以後說不定有機會用到。

CTR_KUBERNETES HARDENING GUIDANCE.PDF (defense.gov)

放在dropbox的備用連結

實作 API Rate limiter

最近剛好公司某個專案需要將資料傳輸到遠端的某個服務上,而那個服務可能會有頻寬上的限制,所以我們的資料傳送端必須加入Rate limit這功能,以免瞬間的資料流造成資料被丟棄的問題;也趁這個機會多整理一點 Rate limit相關的知識…

rate limiting vs throttling

這兩個名詞常分別或一起出現在討論rate limiting 的相關文章中,而我也常搞混這兩個詞的意義,所以稍微再整理一下它們所代表的意思:

Rate limiting 指的是,限制requests在某個時間區間內,其可允許執行requests的數量。

Throttling 指的是,控制requests在特定的時間區間內出現時,允許可執行requests的 一種流程。

一個簡單的例子是,當我們限制某個API 每秒只能執行 100次,這是一個Rate limiting的流程;而當我們再把時間看得更細時,平均我們每100 ms 可以服務10個requests。
在這 100 reqs/s的情境下,控制requests 可以被服務的頻率的一個程序就是throttling。
* 這邊我們可以控制當requests 超過 10 reqs/100ms,就被丟棄 或是可以允許requests 最多到burst 20 reqs/100ms)
* 另一種Throttling的情境是,在某一秒的requests數量為105,那超過的這5個requests 我們可以允許它們被服務(soft throttling)或直接丟棄那5個requests(hard throttling)

簡而言之,Rate limiting比較偏向資源服務在大方向的一個規範,而Throttling責聚焦在實作上一些情境下的處理流程。

Rate limiting 相關演算法

Token bucket

Token bucket 主要的概念是,想像我們有一個水桶,裡面最多可以放到n 個token;每使用者需要使用某個資源時,他就必須到水桶中取走一個token,而如果水桶中沒有任何的token時,則使用者無法使用他想要用的資源。

而水桶中的token 會依照 1/n second的速率補充到水桶中,當水桶補滿n個token時,就不再補充任何的token了。

特色:

  • 如果水桶中的token是滿的,其會允許使用者瞬間可以同時索取n個token,也就是允許requests 最多同時burst到n個。
  • 可能會導致某個時間區間下,各個時間點request量不平均。
  • Golang 有內建的lib 原生支援這個演算法。
  • 主要的應用在於,如果我們必須限制我們的requests在固定區間下是有限的,但區間下的每個時間點是允許突然暴增的requests。

Leaky bucket

Leaky bucket 是常用來與Token bucket比較的一個演算法;其概念上是,我們會有一個水桶,並且我們有定義好這個水桶可以往下流出的速率,當我們的requests的量大於可允許流出的速率時,則會被queue起來;而同時間我們也會定義水桶中最多可允許queue起來的量,如果超過時,則這些新的requests 則會被丟棄。

https://en.wikipedia.org/wiki/Leaky_bucket

特色:

  • 概念上對於burst requests的限制較嚴,主要是用來維持每個時間點下的requests流量是固定的。
  • Golang 中可以參考uber-go/ratelimit 這套 open source solution。
  • 比較適合像是,網路頻寬或流量控制的相關應用。

相關文章:

Fixed window counter

這個演算法的概念是,我們定義每個時間區間下可以允許的requests 量是n,而這個區間間是固定的。(例如 [12:00:01-12:00:02), [12:00:02, 12:00:03) )
每個區間會有個counter,每當有新的request時,我們就會有個計算目前這個區間下已count的量,如果加入這個request會導致count > n,則我們會丟棄這個新的request。

特色:

  • 實作上相對簡單,且對burst的限制較不嚴。
  • 如果requests 量剛好發生的時間在,前一個區間的下半段與下一個區間的上半段時,則可能發生這段跨區間的requests量是我們原本定義的n的2倍。
    (e.g. 假設我們每個區間的允許的量是n ,而有n個requests發生在[12:01:30, 12:02:00),另外n個requests發生在[12:02:00, 12:02:30),則如果我們單看區間[12:01:30, 12:02:30)時,會發現requests量可能暴增到2n。)

Sliding window logs

這個演算法類似於Fixed window counter,會針對每一個request記錄其發生的時間,所以當一個新的request出現時,演算法會去比較目前時間點回推到過去的某個時間點下,這段時間區間中的request數量,再來衛量這個新的request是否允許,如果不允許的話,則這個新的request則會被丟棄。

隨著時間的流動,已經過期的request 記錄也會被清除…

特色:

  • 解決了Fixed window counter演算法可能會遇到的request burst問題。
  • 實作上,可能計算會相對較秏資源;因為每次要確認一個新的request是否允許時,需要從目前時間點往回計算,而且過期的記錄要刪除也會是額外要做的事。

Sliding window counter

這個演算法是整合了Fixed window counter + Sliding window log的演算法的作法;概念上也是使用Fixed window counter的概念,只是每個時間區間又再切成多個子區間,所以每次在比對某個request是否可以服務時,就是比對目前時間點下的子區間再加上過去發生過的多個子區間之count 總合,如果低於某個值rate limit最初設定的值的話,那就代表這個新的request 是可以被服務的,反之則丟棄這個request。

舉例來說,我們定義某個API 的 rate limit 為每秒n個,則在實作上,我們可以多切10個子區間, 所以每個子區間的間隔會是100ms,以12:00:01這個區間為例,實際上記錄的子區間有12:00:01.1, 12:00:01.212:00:01.9 等等。
所以當一個新的request發生時,演算法會去計算目前這個子區間所有的count數量以及過去9個子區間count 數量的總合,再來比對加入這個新的request是否還是小於 n,如果是的話則允許服務這個api request。

特色:

  • 整合了Fixed window counter 與Sliding window log的優點,且實作上也不難實現。

在分散式系統上的一些實務上作法

使用Central Storage – Redis/memcached

這是一個蠻常見的作法,透過一個高效的儲存db來存放一些狀態資料,每當一個新的request發生時,就先去儲存db獲取先前儲存的狀態(token/count… etc)來判定目前的request是否可以被服務。

特色:

  • 效能瓶頸會是在redis/memcached本身,不過對大多數的應用來說應該是夠用了。
  • 網路上可以找到蠻多資源的,相關的教學文或已經寫好的open source library。
  • 若單存使用Redis/Memcached所提供的一般API時,可能在大量request發生時要小心處理race condition的問題。(或許要額外引入distributed lock之類的機制)
  • 如果使用Redis + Lua時,則可以實現atomic operation,解決race condition的問題。

相關文章:

使用client based rate limiting

概念上是rate limit 的管理是放在client service 那邊管理的,而所有的client service 會透過一個central storage 來獲取某個API/Resource的total rate limiting與client rate limiting 。

舉例來說,我們可以在etcd上設定某個API的rate limiting為n,並且也記錄了目前註冊過的client service數量m,所以每個client service 相對於這個API的rate limit就會是n/m, 這樣每次client service在服務request時就只需要直接參考目前本機上的rate limit (n/m)就可以了。
而在這個例子下,我們還可以透過ectd的watch 機制來讓所有的client service即時的獲取更新後的nm值。

特色:

  • 效能可以到非常好,因為rate limit是實作在client 端,所以特別適合超大流量的應用。
  • 有個先決條件為,流量必須很平均的分散在所有的client端,這樣才會更有效的使用到所有分配到rate。
  • 作為取捨,對於rate limit的控制會相對沒那麼精準,畢境如果有client端的service 掛掉了,會有段時間差,之後所有的client才會獲取得最新的資訊。

相關文章:

自行設計的rate limit cluster

mailgun這間公司有open source了一套Go的distributed rate limit service – guberator,其概念上是把micro services的概念應用到rate limit service上,每個client端的機器,都會另外在佈署這個gubernator peer,而gubernator之間是靠grpc來溝通的。

每個gubernator都會管理不同resource的rate limit,所以每當某個client service要服務某個request時,它會需要與本機端的gubernator詢問request 相關的limit,而本機端的gubernator 則會知道相對應的資訊是存在本機或是其它的gubernator上。

由於資訊還是由某個gubernator管理,所以理論上也會受限於單機可以處理的上限,但在這邊gubernator有透過一個自行實作的batch機制來提高機器處理的上限值。

這個機制也蠻容易理解的,主要就是再處理rate limit request之前,先把收到的requests 打包起來再送出去成一個單一的batch request。從文章上有提到,batch機制的預設是每當收到對於某個resource的第一個request時,會再等500 micro seconds來收集更多對同一個resource的請求,當時間到了以後,再處理這一包batch過的rate limit request;
假設在這段時間內,收到3000 個對於某個resource的rate limit requests,則只需要某個gubernator送出一個rate limit request,其request quota量為3000,接下來就只需要看收到request的gubernator它那邊會允許多少quote是可以被執行的。

相關文章:

Reference:

Mac shell上的快捷鍵

最近看到別人分享的一篇bash shell 快捷鍵對照縮圖以後,感覺可以稍微練一下,對平常工作應該會有不少幫助XD

後來找了一下網路上的資訊,看來Apple 的官方就有放快捷鍵對照表了,決定也順便整理一下我自己的版本:

動作快速鍵Notes
重新放置插入點將游標移至新插入點的同時按住 Option 鍵
將插入點移至該行起始處Control + A
將插入點移至該行結尾處Control + E
將插入點向前移動一個字元向右鍵
將插入點向後移動一個字元向左鍵
將插入點向前移動一個單字Option + 向右鍵我的iterm2這邊要用Control + 向右鍵
將插入點向後移動一個單字Option + 向左鍵我的iterm2這邊要用Control + 向左鍵
刪除行Control + U被刪除的整列會被複製
刪除至文字行結尾處Control + K
向前刪除至文字結尾處Option + D(已選取「使用 Option 鍵作為 Meta 鍵」時可使用)無法使用
刪除前面的一個文字Control + W這個文字會被複製起來
貼上Control+W 所複製的文字Control + Y
刪除一個字元Delete 鍵
調換兩個字元的位置Control + T目前選的字元會與前面的字元對調
https://support.apple.com/zh-tw/guide/terminal/trmlshtcts/mac

References:

AWS egress 的費用

某天剛好看到了這篇文章AWS’s Egregious Egress (cloudflare.com),才知道原來AWS在頻寬這邊的計價(outgoing)真的蠻貴的,尤其是當你所用的AWS region是在一些已開發國家。

https://blog.cloudflare.com/aws-egregious-egress/
https://blog.cloudflare.com/aws-egregious-egress/

這邊算下來的數字來看,同樣的頻寬,如果是使用一般跟ISP租用每個月XX Mbps來相比,在北美這邊可以貴到約ISP 價錢的那邊的80陪。

hmmm…. 真的是蠻貴的…

雖然說AWS 的ingress是不計算費用的,但蠻多資料相關服務,其本身的egress 費用看來是無法避免的,所以這篇文章可以拿來參考一下一些AWS在營運上,頻寬費用上應該要注意的事項…

PostgreSQL 上資料插入時產生的duplicate key conflict

事發經過

起因於最近工作上遇到的一個小插曲,剛好寫完某一個服務以後,發現某一個整合測試會在特定的情況下發生錯誤。

在經過一系列的測試以後,發現整合測試的錯誤只會發生在測試資料庫剛被初始化完成時;在進一步追下去發現,每次噴出來的錯誤訊息為 ERROR: duplicate key value violates unique constraint "files_pkey",這個錯誤其實蠻奇妙的,因為這張表的id 我是讓其內部自動產生的(auto increment),但在資料庫執行一段時間以後,發現同樣的測試又可以pass了。

最後追下去發現stckoverflow上,其它人也有遇到類似的問題,照著答案中的方向去試了以後就順利解決了。

解決方案

在PostgreSQL中,如果我們設定primary key 為serial or bigserial時,PostgreSQL內部會產生一組relation用來管理對應的primary key 其下一組資料寫入時,auto increment 後的值為何。

由於我在產生測試資料時是有包含id的值,所以造成對應的那張表的id sequence誤判了當新的一筆資料要再被寫入時對應的id值,但再過了一段時間以後,PostgreSQL內部又會重新sync id sequence,所以才會有資料庫運行一段時間後,測試又可以通過了的情況。

最後的解決方案就是重新整理測試資料,讓其不包含id,所以那張表的id的管理就完全由其資料庫內部來作,自然就解決了id sequence out of sync的問題了。
(stackoverflow 文章中有另外提到其它手動的方式,來讓 primary key sequence重新對應上表的資料)

References

無所不在的SQL injection

一樣是在Hacker Daily News看到的一篇文章,作者說明了他在google上找到了30個關於php + email 註冊 的相關教學文章,發現其中的16筆是有SQL injection 的風險。

趁這個機會再來複習一下SQL Injection, 畢境這是非常常見的攻擊之 一;主要的攻擊手段是將一段有害的字串,透過網頁輸入的方式傳送至伺服器上,而伺服器的程式在沒有做任何檢查的情況下,就帶入網頁送上來的那些參數並執行了特定的SQL而造成問題。

從oswap上看到的一個典型的範例是,讓使用者在網頁端填入firstname與 lastname,然後伺服器這邊就透過使用者給的資訊來去資料庫找對應的使用者資訊,若此時使用者給的是像這樣的資訊

Firstname: evil'ex and Lastname: Newman

且執行的SQL可能會是長這樣, 其造成的問題就是會讓資料庫試著去執行evil 指令而失敗

select id, firstname, lastname from authors where firstname = 'evil'ex' and lastname ='newman'

事實上,還有更多網路上可以找到的攻擊範例,而解決方式就是在伺服器這邊需要針對使用者傳上來的資訊做更多的驗證,之後才可以使用。
另外,一些常見的web framework通常都會將這些驗證自動套用到程式中,所以如果我們有使用web framework的話,也可以看一下所使用的framework是否有對應的處理方式。

reference