1. 程式人生 > >etcd許可權系統認證過程加cache

etcd許可權系統認證過程加cache

最近在研究etcd的許可權機制,etcd用的認證方式比較簡單basic auth。原理也比較簡單易懂,但輕率上線後,發現一個大坑,就是認證時候用來比較密碼的雜湊是bcript,而且是每個請求都會調。這個耗時很大,導致叢集效能下降的厲害,基本不能用了。

查遍官方文件,說3.1+ 用https common name的方式可以解決這個問題,但是我就不想上https,涉及改造的工作量有點大,就想通過auth簡單的把誤操作的行為隔離一下。

於是乎只能開始動手改了,簡單的加一個cache先用。

首先我們用的etcd版本為2.1.1

git clone https://github.com/coreos/etcd.git

git checkout v2.1.1

下載程式碼後,切換到 v2.1.1 tag下

開啟目錄 etcdserver

在目錄下新增新檔案,姑且叫做 password_map.go

新增如下程式碼

?
// author:ZeaLoVe // password map of etcd v2 api package auth import ( "fmt" "sync" ) // key  : string  meke by hashed password + plaintext password // value: error   the result of CompareHashAndPassword
type PasswordMap struct { sync.RWMutex M map[string]error } var DefaultPasswdMap = PasswordMap{ M: make(map[string]error), } func (this *PasswordMap) Hit(hashed, pt string) bool { this.RLock() defer this.RUnlock() if _, ok := this.M[hashed+pt]; ok { return ok } return false } // Get must called after Hit
func (this *PasswordMap) Get(hashed, pt string) error { this.RLock() defer this.RUnlock() if val, ok := this.M[hashed+pt]; ok { return val } return fmt.Errorf("no hit") } func (this *PasswordMap) Set(hashed string, pt string, err error) { if hashed == "" { return } this.Lock() defer this.Unlock() this.M[hashed+pt] = err }

開啟該資料夾下的auth.go 找到 CheckPassword函式

修改為

?
func (u User) CheckPassword(password string) bool { if DefaultPasswdMap.Hit(u.Password, password) { return DefaultPasswdMap.Get(u.Password, password) == nil } err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) DefaultPasswdMap.Set(u.Password, password, err) return err == nil }

對於其他版本,雖然實現上可能有些區別,但整個原理是一樣的(我看過3.1的基本沒怎麼改變)。此改造不會影響第一次請求的耗時,但後面不會對相同的密碼再次呼叫bcript,會直接返回快取的結果,極大提高了效能

但該實現沒有回收快取的空間,所以如果有人對同一個賬號用各種不同的密碼輪番攻擊,可能會導致記憶體持續上升。但經過壓測,發現即使試十萬次記憶體也只上漲不到30M。可以暫時忽略這個問題。

即使記憶體大到一定程度,重啟也可以恢復。