Tôi sẽ cung cấp cho bạn AuthorizationPolicy tối thiểu cần thiết để gọi nhà cung cấp của bạn, cùng với các biến thể phạm vi tùy chọn và một ghi chú để sửa máy chủ dịch vụ của nhà cung cấp.
Use the custom provider in an AuthorizationPolicy
- Mesh-wide (applies to all workloads):
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: use-ext-authz-mesh
namespace: istio-system
spec:
action: CUSTOM
provider:
name: my-external-authz-provider
rules:
- {}
- Namespace-wide (replace
defaultwith your namespace):
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: use-ext-authz-namespace
namespace: default
spec:
action: CUSTOM
provider:
name: my-external-authz-provider
rules:
- {}
- Single workload (label
app: httpbinas example):
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: use-ext-authz-workload
namespace: default
spec:
selector:
matchLabels:
app: httpbin
action: CUSTOM
provider:
name: my-external-authz-provider
rules:
- {}
- Giải thích: action: CUSTOM với provider.name: my-external-authz-provider báo cho Istio biết để định tuyến các yêu cầu phù hợp đến máy chủ gRPC ext-authz Envoy của bạn. Sử dụng rules: – {} áp dụng cho tất cả các yêu cầu trong phạm vi đã chọn.
Important: fix provider “service” host
- Recommended (use a resolvable host). Nếu đang chạy trong cluster, hãy tham chiếu đến K8s Service FQDN:
extensionProviders:
- name: my-external-authz-provider
envoyExtAuthzGrpc:
service: ext-authz.istio-system.svc.cluster.local
port: "9000"
If the server is external, create a ServiceEntry (and disable TLS if your server is plain gRPC):
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-ext-authz
namespace: istio-system
spec:
hosts:
345678
ports:
- number: 9000
name: grpc
protocol: GRPC
resolution: STATIC
endpoints:
- address: 192.168.101.23
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: external-ext-authz-dr
namespace: istio-system
spec:
host: ext-authz.external.svc.cluster.local
trafficPolicy:
tls:
mode: DISABLE
Then point the provider at that host:
extensionProviders:
- name: my-external-authz-provider
envoyExtAuthzGrpc:
service: ext-authz.external.svc.cluster.local
port: "9000"
Quick verify
- Apply the AuthorizationPolicy in the desired scope.
- Send a request through a sidecar-injected pod; you should see calls hitting your gRPC server (you already log metadata and the full
CheckRequest). - Optionally, check the target pod’s
istio-proxylogs for ext_authz activity. - Changes made earlier enable rich debugging in your
Checkhandler, so you’ll see headers and attributes immediately.
Create Check Rrequest with golang:
// main.go
package main
import (
"context"
"fmt"
"log"
"net"
"strings"
statuspb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
"google.golang.org/protobuf/encoding/protojson"
// Import các định nghĩa proto của Envoy
authv3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
)
// Khai báo một struct để implement interface AuthorizationServer
type server struct{}
// Implement phương thức Check. Đây là nơi logic phân quyền của bạn được đặt.
func (s *server) Check(ctx context.Context, req *authv3.CheckRequest) (*authv3.CheckResponse, error) {
// In ra để debug. Trong thực tế, bạn sẽ dùng logger có cấu trúc.
log.Println("--> New request to Authorizer")
// Log gRPC metadata và thông tin peer (địa chỉ client, TLS... nếu có)
if md, ok := metadata.FromIncomingContext(ctx); ok {
log.Printf("gRPC metadata: %v", md)
}
if p, ok := peer.FromContext(ctx); ok {
log.Printf("peer: addr=%v authInfo=%T", p.Addr, p.AuthInfo)
}
// Pretty-print toàn bộ CheckRequest để debug nhanh mọi thuộc tính
if b, err := (protojson.MarshalOptions{Indent: " "}).Marshal(req); err != nil {
log.Printf("failed to marshal CheckRequest: %v", err)
} else {
log.Printf("CheckRequest JSON:\n%s", b)
}
// Lấy các thuộc tính của request từ payload mà Envoy gửi đến
httpRequest := req.GetAttributes().GetRequest().GetHttp()
method := httpRequest.GetMethod()
requestPath := httpRequest.GetPath()
if i := strings.IndexByte(requestPath, '?'); i >= 0 { // bỏ phần query nếu có
requestPath = requestPath[:i]
}
// ----- LOGIC PHÂN QUYỀN: chỉ cho phép GET /ip -----
if strings.EqualFold(method, "GET") && requestPath == "/ip" {
log.Println("Request is ALLOWED: GET /ip")
return &authv3.CheckResponse{
Status: &statuspb.Status{
Code: int32(codes.OK),
},
}, nil
}
// ----- NẾU KHÔNG THỎA MÃN -----
log.Printf("Request is DENIED: method=%s path=%s", method, requestPath)
// Nếu bị từ chối, trả về Status PermissionDenied.
// Envoy sẽ chuyển đổi nó thành mã lỗi HTTP 403 Forbidden.
return &authv3.CheckResponse{
Status: &statuspb.Status{
Code: int32(codes.PermissionDenied),
Message: fmt.Sprintf("Access Denied: only GET /ip allowed (got %s %s)", method, requestPath),
},
}, nil
}
func main() {
// Khởi tạo một gRPC server mới.
grpcServer := grpc.NewServer()
// Đăng ký implement của bạn với gRPC server.
authv3.RegisterAuthorizationServer(grpcServer, &server{})
// Lắng nghe trên cổng 9000
port := 9000
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
log.Printf("Starting gRPC server on port %d", port)
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %s", err)
}
}