APISIX Ingress 認證使用
身份認證在日常生活當中是非常常見的一項功能,大家平時基本都會接觸到,Apache APISIX 作爲一個 API 網關,目前已開啓與各種插件功能的適配合作,插件庫也比較豐富,目前已經可與大量身份認證相關的插件進行搭配處理,如下圖所示。
基礎認證插件比如 Key-Auth
、Basic-Auth
,他們是通過賬號密碼的方式進行認證。複雜一些的認證插件如 Hmac-Auth
、JWT-Auth
,如 Hmac-Auth
通過對請求信息做一些加密,生成一個簽名,當 API 調用方將這個簽名攜帶到 APISIX,APISIX 會以相同的算法計算簽名,只有當簽名方和應用調用方認證相同時才予以通過。其他則是一些通用認證協議和聯合第三方組件進行合作的認證協議,例如 OpenID-Connect
身份認證機制,以及 LDAP
認證等。
APISIX 還可以針對每一個 Consumer (即調用方應用)去做不同級別的插件配置。如下圖所示,我們創建了兩個消費者 Consumer A、Consumer B,我們將 Consumer A 應用到應用 1,則後續應用 1 的訪問將會開啓 Consumer A 的這部分插件,例如 IP 黑白名單,限制併發數量等。將 Consumer B 應用到應用 2 ,由於開啓了 http-log 插件,則應用 2 的訪問日誌將會通過 HTTP 的方式發送到日誌系統進行收集。
basic-auth
首先我們來了解下最簡單的基本認證在 APISIX 中是如何使用的。basic-auth
是一個認證插件,它需要與 Consumer 一起配合才能工作。添加 Basic Auth 到一個 Service 或 Route,然後 Consumer 將其用戶名和密碼添加到請求頭中以驗證其請求。
首先我們需要在 APISIX Consumer 消費者中增加 basic auth 認證配置,爲其指定用戶名和密碼,我們這裏在 APISIX Ingress 中,可以通過 ApisixConsumer
資源對象進行配置,比如這裏我們爲前面的 nexus 實例應用添加一個基本認證,如下所示:
# nexus-basic-auth.yaml
apiVersion: apisix.apache.org/v2alpha1
kind: ApisixConsumer
metadata:
name: nexusBauth
spec:
authParameter:
basicAuth:
value:
username: admin
password: admin321
ApisixConsumer
資源對象中只需要配置 authParameter
認證參數即可,目前只支持 BasicAuth
與 KeyAuth
兩種認證類型,在 basicAuth 下面可以通過 value 可直接去配置相關的 username 和 password,也可以直接使用 Secret 資源對象進行配置,比起明文配置會更安全一些。
然後在 ApisixRoute
中添加 authentication,將其開啓並指定認證類型即可,就可以實現使用 Consumer 去完成相關配置認證,如下所示:
apiVersion: apisix.apache.org/v2beta2
kind: ApisixRoute
metadata:
name: nexus
namespace: default
spec:
http:
- name: root
match:
hosts:
- ops.qikqiak.com
paths:
- "/nexus*"
- "/static/*"
- "/service/*"
plugins:
- name: proxy-rewrite
enable: true
config:
regex_uri: ["^/nexus(/|$)(.*)", "/$2"]
- name: redirect
enable: true
config:
regex_uri: ["^(/nexus)$", "$1/"]
- name: redirect
enable: true
config:
http_to_https: true
backends:
- serviceName: nexus
servicePort: 8081
authentication: # 開啓 basic auth 認證
enable: true
type: basicAuth
直接更新上面的資源即可開啓 basic auth 認證了,在 Dashboard 上也可以看到創建了一個 Consumer:
然後我們可以進行如下的測試來進行驗證:
# 缺少 Authorization header
➜ curl -i http://ops.qikqiak.com/nexus/
HTTP/1.1 401 Unauthorized
Date: Tue, 11 Jan 2022 07:44:49 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
WWW-Authenticate: Basic realm='.'
Server: APISIX/2.10.0
{"message":"Missing authorization in request"}
# 用戶名不存在
➜ curl -i -ubar:bar http://ops.qikqiak.com/nexus/
HTTP/1.1 401 Unauthorized
Date: Tue, 11 Jan 2022 07:45:07 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.10.0
{"message":"Invalid user key in authorization"}
# 成功請求
➜ curl -uadmin:admin321 http://ops.qikqiak.com/nexus/
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>openresty</center>
</body>
</html>
consumer-restriction
**不過這裏大家可能會有一個疑問,在 Route 上面我們並沒有去指定具體的一個 Consumer,然後就可以進行 Basic Auth 認證了,那如果我們有多個 Consumer 都定義了 Basic Auth 豈不是都會生效的?**確實是這樣的,這就是 APISIX 的實現方式,所有的 Consumer 對啓用對應插件的 Route 都會生效的,如果我們只想 Consumer A 應用在 Route A、Consumer B 應用在 Route B 上面的話呢?要實現這個功能就需要用到另外一個插件:consumer-restriction。
consumer-restriction
插件可以根據選擇的不同對象做相應的訪問限制,該插件可配置的屬性如下表所示:
其中的 type 字段是個枚舉類型,它可以是 consumer_name
或 service_id
,分別代表以下含義:
-
consumer_name
:把 consumer 的 username 列入白名單或黑名單(支持單個或多個 consumer)來限制對服務或路由的訪問。 -
service_id
:把 service 的 id 列入白名單或黑名單(支持一個或多個 service)來限制 service 的訪問,需要結合授權插件一起使用。
比如現在我們有兩個 Consumer:jack1 和 jack2,這兩個 Consumer 都配置了 Basic Auth 認證,配置如下所示:
Conumer jack1
的認證配置:
➜ curl http://192.168.31.46/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"username": "jack1",
"plugins": {
"basic-auth": {
"username":"jack2019",
"password": "123456"
}
}
}'
Conumer jack2
的認證配置:
➜ curl http://192.168.31.46/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -i -d '
{
"username": "jack2",
"plugins": {
"basic-auth": {
"username":"jack2020",
"password": "123456"
}
}
}'
現在我們只想給一個 Route 路由對象啓用 jack1 這個 Consumer 的認證配置,則除了啓用 basic-auth
插件之外,還需要在 consumer-restriction
插件中配置一個 whitelist
白名單(當然配置黑名單也是可以的),如下所示:
➜ curl http://192.168.31.46/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"basic-auth": {},
"consumer-restriction": {
"whitelist": [
"jack1"
]
}
}
}'
然後我們使用 jack1 去訪問我們的路由進行驗證:
➜ curl -u jack2019:123456 http://127.0.0.1:9080/index.html -i
HTTP/1.1 200 OK
...
正常使用 jack2 訪問就會認證失敗了:
➜ curl -u jack2020:123456 http://127.0.0.1:9080/index.html -i
HTTP/1.1 403 Forbidden
...
{"message":"The consumer_name is forbidden."}
所以當你只想讓一個 Route 對象關聯指定的 Consumer 的時候,記得使用 consumer-restriction
插件。
jwt-auth
在平時的應用中可能使用 jwt 認證的場景是最多的,同樣在 APISIX 中也有提供 jwt-auth
的插件,它同樣需要與 Consumer 一起配合才能工作,我們只需要添加 JWT Auth 到一個 Service 或 Route,然後 Consumer 將其密鑰添加到查詢字符串參數、請求頭或 cookie 中以驗證其請求即可。
由於目前 ApisixConsumer
還不支持 jwt-auth
配置,所以需要我們去 APISIX 手動創建一個 Consumer,可以通過 APISIX 的 API 進行創建,當然也可以直接通過 Dashboard 頁面操作。在 Dashboard 消費者頁面點擊創建消費者:
點擊下一步進入插件配置頁面,這裏我們需要啓用 jwt-auth
這個插件:
在插件配置頁面配置 jwt-auth
相關屬性,可參考插件文檔 https://apisix.apache.org/zh/docs/apisix/plugins/jwt-auth/:
可配置的屬性如下表所示:
然後提交即可創建完成 Consumer,然後我們只需要在需要的 Service 或者 Route 上開啓 jwt-auth
即可,比如同樣還是針對上面的 nexus 應用,我們只需要在 ApisixRoute
對象中啓用一個 jwt-auth
插件即可:
apiVersion: apisix.apache.org/v2beta2
kind: ApisixRoute
metadata:
name: nexus
namespace: default
spec:
http:
- name: root
match:
hosts:
- ops.qikqiak.com
paths:
- "/nexus*"
- "/static/*"
- "/service/*"
plugins:
- name: jwt-auth
enable: true
- name: redirect
enable: true
config:
http_to_https: true
- name: redirect
enable: true
config:
regex_uri: ["^(/nexus)$", "$1/"]
- name: proxy-rewrite
enable: true
config:
regex_uri: ["^/nexus(/|$)(.*)", "/$2"]
backends:
- serviceName: nexus
servicePort: 8081
需要注意的是 authentication
屬性也不支持 jwt-auth
,所以這裏我們通過 plugins
進行啓用,重新更新上面的對象後我們同樣來測試驗證下:
➜ curl -i http://ops.qikqiak.com/nexus/
HTTP/1.1 401 Unauthorized
Date: Tue, 11 Jan 2022 08:54:30 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.10.0
{"message":"Missing JWT token in request"}
要正常訪問我們的服務就需要先進行登錄獲取 jwt-auth
的 token,通過 APISIX 的 apisix/plugin/jwt/sign
可以獲取:
➜ curl -i http://192.168.31.46/apisix/plugin/jwt/sign\?key\=user-key
HTTP/1.1 200 OK
Date: Tue, 11 Jan 2022 09:01:29 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.10.0
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY0MTk3ODA4OX0.rdzMxM4QAKI444c3SC3u3ZqfW9rKnsqrdorLHCGqrQg
要注意上面我們在獲取 token 的時候需要傳遞創建消費者的標識 key,因爲可能有多個不同的 Consumer 消費者,然後我們將上面獲得的 token 放入到 Header 頭中進行訪問:
➜ curl -i http://ops.qikqiak.com/nexus/ -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY0MTk3ODA4OX0.rdzMxM4QAKI444c3SC3u3ZqfW9rKnsqrdorLHCGqrQg'
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 8802
Connection: keep-alive
......
Expires: 0
Server: APISIX/2.10.0
<!DOCTYPE html>
<html lang="en">
......
可以看到可以正常訪問。同樣也可以放到請求參數中驗證:
➜ curl -i http://ops.qikqiak.com/nexus/?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY0MTk3ODA4OX0.rdzMxM4QAKI444c3SC3u3ZqfW9rKnsqrdorLHCGqrQg
HTTP/1.1 200 OK
......
此外還可以放到 cookie 中進行驗證:
➜ curl -i http://ops.qikqiak.com/nexus/ --cookie jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTY0MTk3ODA4OX0.rdzMxM4QAKI444c3SC3u3ZqfW9rKnsqrdorLHCGqrQg
HTTP/1.1 200 OK
......
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Ynr6Pe1YhLboq9pJiF-nhA