External Authorization這功能主要拿來做request的驗證,可以在request裡面加了一個header進行判斷,
如果有符合的header與value時才會讓request導流到後端服務。
有些行為不能直接從request ban掉時,可以透過External Authorization進行加工處理,做到ban ban的動作,這些要怎麼操作就看人啦~~
kubectl edit configmap istio -n istio-system
data:
mesh: |-
# Add the following content to define the external authorizers.
extensionProviders: #可以分成http/gRPC二種,這邊的還是以gRPC為主
- name: "sample-ext-authz-grpc" #名稱後續會用到,要設定一致
envoyExtAuthzGrpc:
service: "ext-authz.foo.svc.cluster.local" #external service路徑
port: "9000"
- name: "sample-ext-authz-http"
envoyExtAuthzHttp:
service: "ext-authz.foo.svc.cluster.local"
port: "8000"
includeHeadersInCheck: ["x-ext-authz"]
重啟istiod,重新載入configMap
kubectl rollout restart deployment/istiod -n istio-system
可以參考這個作法 grpc_server
主要是透過這幾個lib處理,分成v2跟v3版本
corev2 "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
authv2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
typev2 "github.com/envoyproxy/go-control-plane/envoy/type"
typev3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
啟動gRPC server時要做這件事情,不然不會做authzore
authv2.RegisterAuthorizationServer(grpc, &extAuthzServerV2{})
authv3.RegisterAuthorizationServer(grpc, &extAuthzServerV3{})
重點就是這個部份啦,這邊定義了什麼條件才能http 200,什麼條件 403,再依自己的需求進行調整
func (a *AuthorizationServer) Check(ctx context.Context, req *auth.CheckRequest) (*auth.CheckResponse, error) {
log.Println(">>> Authorization called check()")
authHeader, ok := req.Attributes.Request.Http.Headers["authorization"]
if !ok {
return returnUnAuthenticated("Unable to find Authorization Header"), nil
}
var splitToken []string
log.Printf("Authorization Header %s", authHeader)
if ok {
splitToken = strings.Split(authHeader, "Bearer ")
} else {
log.Println("Unable to parse Header")
return returnUnAuthenticated("Unable to parse Authorization Header"), nil
}
if len(splitToken) == 2 {
token := splitToken[1]
if stringInSlice(token, strings.Split(AUTHZ_ALLOWED_USERS, ",")) {
var aud []string
if token == "alice" {
aud = []string{"http://svc1.default.svc.cluster.local:8080/", "http://be.default.svc.cluster.local:8080/"}
} else if token == "bob" {
aud = []string{"http://svc2.default.svc.cluster.local:8080/"}
} else if token == "carol" {
aud = []string{"http://svc1.default.svc.cluster.local:8080/"}
} else {
aud = []string{}
}
claims := MyCustomClaims{
token,
aud,
jwt.StandardClaims{
Issuer: AUTHZ_ISSUER,
Subject: AUTHZ_ISSUER,
//Audience: aud,
IssuedAt: time.Now().Unix(),
ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
},
}
log.Println("Using Claim %v", claims)
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
token.Header["kid"] = AUTHZ_SERVER_KEY_ID
ss, err := token.SignedString(privateKey)
if err != nil {
return returnUnAuthenticated("Unable to generate JWT"), nil
}
log.Printf("Issuing outbound Header %s", ss)
return &auth.CheckResponse{
Status: &rpcstatus.Status{
Code: int32(rpc.OK),
},
HttpResponse: &auth.CheckResponse_OkResponse{
OkResponse: &auth.OkHttpResponse{
Headers: []*core.HeaderValueOption{
{
Header: &core.HeaderValue{
Key: "Authorization",
Value: "Bearer " + ss,
},
},
},
},
},
}, nil
} else {
log.Printf("Authorization Header missing")
return returnPermissionDenied("Permission Denied"), nil
}
}
return returnUnAuthenticated("Authorization header not provided"), nil
}
前面的動作都完成了,剩下最一步部署EnvoyFilter
,這邊其實跟Rate Limits很雷同,一樣是定義名稱,指定grpc服務路徑,done
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: my-ext-authz
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
subFilter:
name: "envoy.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.ext_authz
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz"
failure_mode_allow: true
grpc_service:
envoy_grpc:
cluster_name: ext_cluster_grpc
timeout: 0.5s
- applyTo: CLUSTER
match:
cluster:
service: test-ext.dev-xbb.svc.cluster.local
patch:
operation: ADD
value:
name: ext_cluster_grpc
type: STRICT_DNS
connect_timeout: 1s
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: ext_cluster_grpc
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: test-ext.dev-xbb.svc.cluster.local
port_value: 9000
以上步驟完成之後就可以實作出External Authorization囉