Autorización Externa
Esta tarea muestra cómo configurar una política de autorización de Istio utilizando un nuevo valor para el campo de acción, CUSTOM
,
para delegar el control de acceso a un sistema de autorización externo. Esto se puede utilizar para integrar con autorización OPA,
oauth2-proxy
, su propio servidor de autorización externo personalizado y más.
Antes de empezar
Antes de comenzar esta tarea, haga lo siguiente:
Lea los conceptos de autorización de Istio.
Siga la guía de instalación de Istio para instalar Istio.
Despliegue workloads de prueba:
Esta tarea utiliza dos workloads,
httpbin
ycurl
, ambos desplegados en el namespacefoo
. Ambos workloads se ejecutan con un proxy Envoy sidecar. Despliegue el namespacefoo
y los workloads con el siguiente comando:$ kubectl create ns foo $ kubectl label ns foo istio-injection=enabled $ kubectl apply -f @samples/httpbin/httpbin.yaml@ -n foo $ kubectl apply -f @samples/curl/curl.yaml@ -n foo
Verifique que
curl
puede acceder ahttpbin
con el siguiente comando:$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{\http_code}\n" 200
Desplegar el autorizador externo
Primero, debe desplegar el autorizador externo. Para ello, simplemente desplegará el autorizador externo de ejemplo en un pod independiente en la malla.
Ejecute el siguiente comando para desplegar el autorizador externo de ejemplo:
$ kubectl apply -n foo -f https://raw.githubusercontent.com/istio/istio/release-1.26/samples/extauthz/ext-authz.yaml service/ext-authz created deployment.apps/ext-authz created
Verifique que el autorizador externo de ejemplo está en funcionamiento:
$ kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz 2021/01/07 22:55:47 Starting HTTP server at [::]:8000 2021/01/07 22:55:47 Starting gRPC server at [::]:9000
Alternativamente, también puede desplegar el autorizador externo como un contenedor separado en el mismo pod de la aplicación que necesita la autorización externa o incluso desplegarlo fuera de la malla. En cualquier caso, también deberá crear un recurso de entrada de service para registrar el service en la malla y asegurarse de que sea accesible para el proxy.
El siguiente es un ejemplo de entrada de service para un autorizador externo desplegado en un contenedor separado en el mismo pod de la aplicación que necesita la autorización externa.
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: external-authz-grpc-local
spec:
hosts:
- "external-authz-grpc.local" # El nombre del service a usar en el proveedor de extensión en la configuración de la malla.
endpoints:
- address: "127.0.0.1"
ports:
- name: grpc
number: 9191 # El número de puerto a usar en el proveedor de extensión en la configuración de la malla.
protocol: GRPC
resolution: STATIC
Definir el autorizador externo
Para utilizar la acción CUSTOM
en la política de autorización, debe definir el autorizador externo que está permitido
utilizar en la malla. Esto se define actualmente en el proveedor de extensión
en la configuración de la malla.
Actualmente, el único tipo de proveedor de extensión compatible es el proveedor Envoy ext_authz
.
El autorizador externo debe implementar la API de verificación ext_authz
de Envoy correspondiente.
En esta tarea, utilizará un autorizador externo de ejemplo que
permite solicitudes con la cabecera x-ext-authz: allow
.
Edite la configuración de la malla con el siguiente comando:
$ kubectl edit configmap istio -n istio-system
En el editor, agregue las definiciones de proveedor de extensión que se muestran a continuación:
El siguiente contenido define dos proveedores externos
sample-ext-authz-grpc
ysample-ext-authz-http
utilizando el mismo serviceext-authz.foo.svc.cluster.local
. El service implementa tanto la API de verificación HTTP como gRPC según lo definido por el filtroext_authz
de Envoy. Desplegará el service en el siguiente paso.data: mesh: |- # Agregue el siguiente contenido para definir los autorizadores externos. extensionProviders: - name: "sample-ext-authz-grpc" envoyExtAuthzGrpc: service: "ext-authz.foo.svc.cluster.local" port: "9000" - name: "sample-ext-authz-http" envoyExtAuthzHttp: service: "ext-authz.foo.svc.cluster.local" port: "8000" includeRequestHeadersInCheck: ["x-ext-authz"]
Alternativamente, puede modificar el proveedor de extensión para controlar el comportamiento del filtro
ext_authz
para cosas como qué cabeceras enviar al autorizador externo, qué cabeceras enviar al backend de la aplicación, el estado a devolver en caso de error y más. Por ejemplo, lo siguiente define un proveedor de extensión que se puede utilizar conoauth2-proxy
:data: mesh: |- extensionProviders: - name: "oauth2-proxy" envoyExtAuthzHttp: service: "oauth2-proxy.foo.svc.cluster.local" port: "4180" # El puerto predeterminado utilizado por oauth2-proxy. includeRequestHeadersInCheck: ["authorization", "cookie"] # cabeceras enviadas a oauth2-proxy en la solicitud de verificación. headersToUpstreamOnAllow: ["authorization", "path", "x-auth-request-user", "x-auth-request-email", "x-auth-request-access-token"] # cabeceras enviadas al backend de la aplicación cuando se permite la solicitud. headersToDownstreamOnAllow: ["set-cookie"] # cabeceras enviadas de vuelta al cliente cuando se permite la solicitud. headersToDownstreamOnDeny: ["content-type", "set-cookie"] # cabeceras enviadas de vuelta al cliente cuando se deniega la solicitud.
Habilitar con autorización externa
El autorizador externo ya está listo para ser utilizado por la política de autorización.
Habilite la autorización externa con el siguiente comando:
El siguiente comando aplica una política de autorización con el valor de acción
CUSTOM
para el workloadhttpbin
. La política habilita la autorización externa para las solicitudes a la ruta/headers
utilizando el autorizador externo definido porsample-ext-authz-grpc
.$ kubectl apply -n foo -f - <<EOF apiVersion: security.istio.io/v1 kind: AuthorizationPolicy metadata: name: ext-authz spec: selector: matchLabels: app: httpbin action: CUSTOM provider: # El nombre del proveedor debe coincidir con el proveedor de extensión definido en la configuración de la malla. # También puede reemplazar esto con sample-ext-authz-http para probar la otra definición de autorizador externo. name: sample-ext-authz-grpc rules: # Las reglas especifican cuándo activar el autorizador externo. - to: - operation: paths: ["/headers"] EOF
En tiempo de ejecución, las solicitudes a la ruta
/headers
del workloadhttpbin
serán pausadas por el filtroext_authz
, y una solicitud de verificación será enviada al autorizador externo para decidir si la solicitud debe ser permitida o denegada.Verifique que una solicitud a la ruta
/headers
con la cabecerax-ext-authz: deny
es denegada por el servidorext_authz
de ejemplo:$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl "http://httpbin.foo:8000/headers" -H "x-ext-authz: deny" -s denied by ext_authz for not found header `x-ext-authz: allow` in the request
Verifique que una solicitud a la ruta
/headers
con la cabecerax-ext-authz: allow
es permitida por el servidorext_authz
de ejemplo:$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl "http://httpbin.foo:8000/headers" -H "x-ext-authz: allow" -s | jq '.headers' ... "X-Ext-Authz-Check-Result": [ "allowed" ], ...
Verifique que una solicitud a la ruta
/ip
es permitida y no activa la autorización externa:$ kubectl exec "$(kubectl get pod -l app=curl -n foo -o jsonpath={.items..metadata.name})" -c curl -n foo -- curl "http://httpbin.foo:8000/ip" -s -o /dev/null -w "%{\http_code}\n" 200
Verifique el registro del servidor
ext_authz
de ejemplo para confirmar que fue llamado dos veces (para las dos solicitudes). La primera fue permitida y la segunda fue denegada:$ kubectl logs "$(kubectl get pod -l app=ext-authz -n foo -o jsonpath={.items..metadata.name})" -n foo -c ext-authz 2021/01/07 22:55:47 Starting HTTP server at [::]:8000 2021/01/07 22:55:47 Starting gRPC server at [::]:9000 2021/01/08 03:25:00 [gRPCv3][denied]: httpbin.foo:8000/headers, attributes: source:{address:{socket_address:{address:"10.44.0.22" port_value:52088}} principal:"spiffe://cluster.local/ns/foo/sa/curl"} destination:{address:{socket_address:{address:"10.44.3.30" port_value:80}} principal:"spiffe://cluster.local/ns/foo/sa/httpbin"} request:{time:{seconds:1610076306 nanos:473835000} http:{id:"13869142855783664817" method:"GET" headers:{key:":authority" value:"httpbin.foo:8000"} headers:{key:":method" value:"GET"} headers:{key:":path" value:"/headers"} headers:{key:"accept" value:"*/*"} headers:{key:"content-length" value:"0"} headers:{key:"user-agent" value:"curl/7.74.0-DEV"} headers:{key:"x-b3-sampled" value:"1"} headers:{key:"x-b3-spanid" value:"377ba0cdc2334270"} headers:{key:"x-b3-traceid" value:"635187cb20d92f62377ba0cdc2334270"} headers:{key:"x-envoy-attempt-count" value:"1"} headers:{key:"x-ext-authz" value:"deny"} headers:{key:"x-forwarded-client-cert" value:"By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=dd14782fa2f439724d271dbed846ef843ff40d3932b615da650d028db655fc8d;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/curl"} headers:{key:"x-forwarded-proto" value:"http"} headers:{key:"x-request-id" value:"9609691a-4e9b-9545-ac71-3889bc2dffb0"} path:"/headers" host:"httpbin.foo:8000" protocol:"HTTP/1.1"}} metadata_context:{} 2021/01/08 03:25:06 [gRPCv3][allowed]: httpbin.foo:8000/headers, attributes: source:{address:{socket_address:{address:"10.44.0.22" port_value:52184}} principal:"spiffe://cluster.local/ns/foo/sa/curl"} destination:{address:{socket_address:{address:"10.44.3.30" port_value:80}} principal:"spiffe://cluster.local/ns/foo/sa/httpbin"} request:{time:{seconds:1610076300 nanos:925912000} http:{id:"17995949296433813435" method:"GET" headers:{key:":authority" value:"httpbin.foo:8000"} headers:{key:":method" value:"GET"} headers:{key:":path" value:"/headers"} headers:{key:"accept" value:"*/*"} headers:{key:"content-length" value:"0"} headers:{key:"user-agent" value:"curl/7.74.0-DEV"} headers:{key:"x-b3-sampled" value:"1"} headers:{key:"x-b3-spanid" value:"a66b5470e922fa80"} headers:{key:"x-b3-traceid" value:"300c2f2b90a618c8a66b5470e922fa80"} headers:{key:"x-envoy-attempt-count" value:"1"} headers:{key:"x-ext-authz" value:"allow"} headers:{key:"x-forwarded-client-cert" value:"By=spiffe://cluster.local/ns/foo/sa/httpbin;Hash=dd14782fa2f439724d271dbed846ef843ff40d3932b615da650d028db655fc8d;Subject=\"\";URI=spiffe://cluster.local/ns/foo/sa/curl"} headers:{key:"x-forwarded-proto" value:"http"} headers:{key:"x-request-id" value:"2b62daf1-00b9-97d9-91b8-ba6194ef58a4"} path:"/headers" host:"httpbin.foo:8000" protocol:"HTTP/1.1"}} metadata_context:{}
También puede ver en el registro que mTLS está habilitado para la conexión entre el filtro
ext-authz
y el servidorext-authz
de ejemplo porque el principal de origen se rellena con el valorspiffe://cluster.local/ns/foo/sa/curl
.Ahora puede aplicar otra política de autorización para el servidor
ext-authz
de ejemplo para controlar quién puede acceder a él.
Limpieza
Elimine el namespace
foo
de su configuración:$ kubectl delete namespace foo
Elimine la definición del proveedor de extensión de la configuración de la malla.
Expectativas de rendimiento
Consulte benchmarking de rendimiento.