Closed ajoysinha closed 4 years ago
Can you share some more information about the environment? Kubernetes version, type of deployment, network config, istio version. Enough info that someone can reproduce the issue.
It would also be useful if you can share the logs from the various containers involved.
Istio version: 1.5.4
Envoy version:
$ kubectl exec -it prometheus-567f84f4d8-zrnwt -c istio-proxy -n istio-system pilot-agent request GET server_info
{
"version": "9b4239dee83dd8894bfc579d412ccd894cff2597/1.13.1-dev/Clean/RELEASE/BoringSSL"
}
Kubernetes version: v1.14.0
OPA-Istio version: opa:0.20.5-istio
With the above setup, the policy is enforced as expected:
$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/productpage
200
$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/api/v1/products
403
Also the ext_authz
filter seems to be properly set in the Envoy config:
$ istioctl proxy-config listeners productpage-v1-88646568d-wlqfq --port 15006 -o json
>>>>
{
"name": "envoy.ext_authz",
"config": {
"grpc_service": {
"google_grpc": {
"stat_prefix": "ext_authz",
"target_uri": "127.0.0.1:9191"
}
},
"with_request_body": {
"allow_partial_message": true,
"max_request_bytes": 8192
}
}
},
>>>>
Istio version: 1.6.0
Envoy version:
$ kubectl exec -it prometheus-57b7b99577-wmztl -c istio-proxy -n istio-system pilot-agent request GET server_info
{
"version": "12cfbda324320f99e0e39d7c393109fcd824591f/1.14.1/Clean/RELEASE/BoringSSL"
}
Kubernetes version: v1.14.0
OPA-Istio version: opa:0.20.5-istio
With the above setup, the policy is NOT enforced as expected:
$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/productpage
200
$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/api/v1/products
200
The issue seems to be that Envoy is not calling out to OPA since the ext_authz
filter is not set in the Envoy config for the productpage
app.
We may have to update the EnvoyFilter
CRD to remove any deprecated fields to make this work.
Here are the version list i am currently using in my local environment, [ using minikube ]
istio Version : 1.6.0 Minikube Version : 1.9.2 OPA-Istio version: opa:0.20.5-istio
I have tested it with istio Version : 1.5.4 [ changed from 1.6.0 ] Minikube Version : 1.9.2 OPA-Istio version: opa:latest-istio
and application is working as expected with OPA policy
curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/productpage
200
curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/api/v1/products
403
It seems that there is some issue with istio version 1.6.0
Thanks for verifying @ajoysinha . If we update the EnvoyFilter CRD to use the newer fields it should probably work. 1.6.0
may not be supporting the older format anymore. I'll try that out as well.
I am upgraded my istio version to 1.6.3 ..but still facing the issue. ### we are planning to use istio plugin with this plugin version in production .. can you please tell me ..if this is possible or we should revert back to some old version. what version should be appropriate ..
ajoy@workspace:~$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/productpage
200
ajoy@workspace:~$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/api/v1/products
200
my versions are
istio Version : 1.6.3 minikube version: v1.11.0
istioctl version client version: 1.6.3 control plane version: 1.6.3 data plane version: 1.6.3 (9 proxies)
@ajoysinha anything before 1.6.0
should work. I can spend some time on this next week to update the Envoy filter crd with the new format. I believe if we do that, 1.6.x
should work as well.
Hey we are running into the same issue. I'm unsure what from the filter needs to be removed to get this to work. Any way you could point me in the right direction?
Hello @blastdan, the Envoy Filter needs to be updated to follow this format.
I tried to modify the filter to crd to the value below. It's still not picking anything up at this point.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: ext-authz
namespace: istio-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.ext_authz"
patch:
operation: INSERT_FIRST
value:
name: "envoy.ext_authz_config"
config:
with_request_body:
max_request_bytes: 8192
allow_partial_message: true
grpc_service:
# NOTE(tsandall): when this was tested with the envoy_grpc client the gRPC
# server was receiving check requests over HTTP 1.1. The gRPC server in
# OPA-Istio would immediately close the connection and log that a bogus
# preamble was sent by the client (it expected HTTP 2). Switching to the
# google_grpc client resolved this issue.
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: "ext_authz"
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.ext_authz"
patch:
operation: INSERT_FIRST
value:
name: "ext_authz_config"
config:
stat_prefix: "ext_authz"
grpc_service:
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: "ext_authz"
is there anything obvious I'm doing wrong? The only thing I can't seem to specify with the new format is the Listener Protocol. I'm going to keep working on it to see how it goes.
Ok, I've done a lot more work on this.
I have the HTTP_FILTER being applied properly and it's successfully blocking the requests
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: ext-authz
namespace: istio-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: "envoy.ext_authz"
typed_config:
"@type": type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz
with_request_body:
max_request_bytes: 8192
allow_partial_message: true
grpc_service:
# NOTE(tsandall): when this was tested with the envoy_grpc client the gRPC
# server was receiving check requests over HTTP 1.1. The gRPC server in
# OPA-Istio would immediately close the connection and log that a bogus
# preamble was sent by the client (it expected HTTP 2). Switching to the
# google_grpc client resolved this issue.
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: "ext_authz"
I used INSERT_BEFORE so that it will be applied to sub httpFilters collection instead of INSERT_FIRST that tries to apply it to the top filters. The documentation shows that if you don't apply a subfilter query it will apply the results to the top of the list
Insert operation on an array of named objects. This operation is typically useful only in the context of filters, where the order of filters matter. For clusters and virtual hosts, order of the element in the array does not matter. Insert before the selected filter or sub filter. If no filter is selected, the specified filter will be inserted at the front of the list.
this produces the expected results.
$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/productpage
200
$ curl -s -o /dev/null -w "%{http_code}" --user alice:password http://$GATEWAY_URL/api/v1/products
403
However when I add the NETWORK_FILTER to try and replicate the TCP filter defined in the original quickstart.yaml
############################################################
# Envoy External Authorization filter that will query OPA.
############################################################
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: ext-authz
namespace: istio-system
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: "envoy.ext_authz"
typed_config:
"@type": type.googleapis.com/envoy.config.filter.http.ext_authz.v2.ExtAuthz
with_request_body:
max_request_bytes: 8192
allow_partial_message: true
grpc_service:
# NOTE(tsandall): when this was tested with the envoy_grpc client the gRPC
# server was receiving check requests over HTTP 1.1. The gRPC server in
# OPA-Istio would immediately close the connection and log that a bogus
# preamble was sent by the client (it expected HTTP 2). Switching to the
# google_grpc client resolved this issue.
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: "ext_authz"
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.tcp_proxy"
patch:
operation: INSERT_FIRST
value:
name: "ext_authz"
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.ext_authz.v2.ExtAuthz
stat_prefix: "ext_authz"
grpc_service:
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: "ext_authz"
The opa-istio sidecars fail to start because the healthchecks are being blocked by the filter. The go into a crashloop.
Is the NETWORK_FILTER needed, or is the HTTP filter sufficient?
@blastdan this is great progress ! We will need the network filter as well. I'm curious why aren't you applying the ext_authz filter before the tcp_proxy filter ?
Basically the match looks for all instances for "envoy.tcp_proxy" and places the ext_auth filter first in that filters list. I was trying to replicate the
- insertPosition:
index: FIRST
that was in the original quickstart.
The way I have the network filter written it places the filter above "istio.metadata_exchange", "istio.stats". I'll try the filter with INSERT_BEFORE to see if that works,
I tried with INSERT_BEFORE
pod details returns
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 51s default-scheduler Successfully assigned default/productpage-v1-6987489c74-gnbs5 to docker-desktop
Normal Pulling 50s kubelet, docker-desktop Pulling image "docker.io/istio/proxyv2:1.6.4"
Normal Pulled 46s kubelet, docker-desktop Successfully pulled image "docker.io/istio/proxyv2:1.6.4"
Normal Created 46s kubelet, docker-desktop Created container istio-init
Normal Started 46s kubelet, docker-desktop Started container istio-init
Normal Pulled 45s kubelet, docker-desktop Container image "docker.io/istio/examples-bookinfo-productpage-v1:1.16.2" already present on machine
Normal Created 45s kubelet, docker-desktop Created container productpage
Normal Started 44s kubelet, docker-desktop Started container productpage
Normal Pulling 44s kubelet, docker-desktop Pulling image "docker.io/istio/proxyv2:1.6.4"
Normal Pulled 43s kubelet, docker-desktop Successfully pulled image "docker.io/istio/proxyv2:1.6.4"
Normal Created 42s kubelet, docker-desktop Created container istio-proxy
Normal Started 42s kubelet, docker-desktop Started container istio-proxy
Normal Pulled 17s (x2 over 42s) kubelet, docker-desktop Container image "openpolicyagent/opa:0.21.0-istio" already present on machine
Normal Created 17s (x2 over 42s) kubelet, docker-desktop Created container opa-istio
Normal Started 17s (x2 over 42s) kubelet, docker-desktop Started container opa-istio
Warning Unhealthy 17s (x3 over 37s) kubelet, docker-desktop Liveness probe failed: Get "http://10.1.0.251:8282/health?plugins": EOF
Normal Killing 17s kubelet, docker-desktop Container opa-istio failed liveness probe, will be restarted
Warning Unhealthy 7s (x4 over 37s) kubelet, docker-desktop Readiness probe failed: Get "http://10.1.0.251:8282/health?plugins": EOF
All filter chains end up with the ext_authz filter applied at the network level as seen below. I'm wondering if we need to only have it applied to some filter chains?
"filters": [
{
"name": "istio.metadata_exchange",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange",
"value": {
"protocol": "istio-peer-exchange"
}
}
},
{
"name": "istio.stats",
"typedConfig": {
"@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
"typeUrl": "type.googleapis.com/envoy.extensions.filters.network.wasm.v3.Wasm",
"value": {
"config": {
"configuration": "{\n \"debug\": \"false\",\n \"stat_prefix\": \"istio\"\n}\n",
"root_id": "stats_inbound",
"vm_config": {
"code": {
"local": {
"inline_string": "envoy.wasm.stats"
}
},
"runtime": "envoy.wasm.runtime.null",
"vm_id": "tcp_stats_inbound"
}
}
}
}
},
{
"name": "ext_authz",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.network.ext_authz.v2.ExtAuthz",
"statPrefix": "ext_authz",
"grpcService": {
"googleGrpc": {
"targetUri": "127.0.0.1:9191",
"statPrefix": "ext_authz"
}
}
}
},
{
"name": "envoy.tcp_proxy",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy",
"statPrefix": "InboundPassthroughClusterIpv4",
"cluster": "InboundPassthroughClusterIpv4",
"accessLog": [
{
"name": "envoy.file_access_log",
"typedConfig": {
"@type": "type.googleapis.com/envoy.config.accesslog.v2.FileAccessLog",
"path": "/dev/stdout",
"format": "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% \"%DYNAMIC_METADATA(istio.mixer:status)%\" \"%UPSTREAM_TRANSPORT_FAILURE_REASON%\" %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" %UPSTREAM_CLUSTER% %UPSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_REMOTE_ADDRESS% %REQUESTED_SERVER_NAME% %ROUTE_NAME%\n"
}
}
]
}
}
]
So the opa-istio
container comes up but fails liveness and readiness checks as those calls are expected to be authorized ? Is this accurate @blastdan or am I missing something here ?
That seems to be the issue for me @ashutosh-narkar. I'm not 100% sure how to move forward, as I don't fully understand what level of blocking is required in each filter section to satisfy the security requirements.
I'll take your example and experiment with the network filter. Thanks !
I've created this PR with the updated Envoy Filter configuration using @blastdan's provided example. I've tested this with Istio v1.5.x and v1.6.x and it seems to work fine. @ajoysinha feel free it try it out. Thanks @blastdan for your contribution !
@ashutosh-narkar the latest PR does not contain the NETWORK_FILTER. Was that intentional? I've managed to get it to work with the following configuration (verified in Istio 1.5 and 1.6):
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: authx
namespace: istio-system
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
name: envoy.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.ext_authz.v3.ExtAuthz
failure_mode_allow: false
stat_prefix: ext_authz
grpc_service:
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: ext_authz
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
subFilter:
name: "envoy.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
failure_mode_allow: false
grpc_service:
google_grpc:
target_uri: 127.0.0.1:9191
stat_prefix: ext_authz
@bbdimitriu , When i am trying to implement NETWORK_FILTER it is throwing error. but only HTTP_FILTER is working fine. is NETWORK_FILTER is must for EnvoyFiltter .. I am running on 1.6.11 istio version on EKS 1.16
@ajoysinha the exact above configuration works fine on my setup (Istio 1.6.8 + Kubernetes 1.15). Can you provide details of the thrown error?
@bbdimitriu , i am trying to execute this on following setup ..
Istio : 1.6.11 k8s : 1.16 [ EKS ] OAP : 0.24
And I am getting following error during deployment.
Liveness probe failed: Get http://172.31.43.142:8282/health?plugins: EOF Readiness probe failed: Get http://172.31.43.142:8282/health?plugins: EOFut
But, if I remove NETWORK_FILTER patching, [ keeping HTTP_FILTER only ] it is working fine.
@ashutosh-narkar do we need NETWORK_FILTER for sidecar communication.
@ajoysinha have you named your service as described here: https://istio.io/v1.6/docs/ops/configuration/traffic-management/protocol-selection/#manual-protocol-selection?
@bbdimitriu ..yes , my service port is prefixed with http- . and it is working for HTTP_FILTER, Do I need to change it for NETWORK_FILTER .. please suggest.
@ajoysinha you should only need the http filter.
I am trying to implement sample provided by https://github.com/open-policy-agent/opa-istio-plugin
Implement step by step from https://github.com/open-policy-agent/opa-istio-plugin#quick-start
It deployed successfully and service also exposed
Also I can see that opa-istio is injected as sidecar with all the deployed applications
but opa policy is not working
As documentation says "Check that alice can access /productpage BUT NOT /api/v1/products"
product page is displaying with invocation of curl --user alice:password -i http://$GATEWAY_URL/productpage
when i am accessing curl --user alice:password -i http://$GATEWAY_URL/api/v1/products
It is displaying following result
But this is not expected.. It seems that sample is not working properly