Goal: Use keycloak to authenticate and (somehow)authorize for ingressgateway exposed services.
So I am using oauth2-proxy as ext_authz provider. In terms of authentication this is fine, but for authorization it doesnt have access control like for these hosts+paths allow users with these roles, etc.
So I still want to use istio’s claim based access control.
So I have got the pipeline setup this way.
- First an authpolicy with custom action “oauth2-proxy” that uses keycloak for token and login, and forwards all relaent headers to upstream.
- Another Deny(/allow) action authpolicy that dictates whether or not to allow based on the jwt token claim, that oauth2-proxy is putting.
I thought technically this should work because Custom action comes before deny/allow.
But it not working. Need HELP!!
The request(httpbin) gets denied by the second auth policy, even though i verify that, the token part of “Authorization: Bearer $JWT_TOKEN” this header contains the value in claim request.auth.claims[realm_access_roles]
, see below for jwt token and authpolicies.
For this I removed the second authpolicy and the setup works. The request is properly redirected to keycloak & authenticated and I can see the header also in httpbin
.
questions:
- Do i need a RequestAuthentication in this case? because a valid JWT token is coming as an Authorization: Bearer header anyway
- Did I get something wrong in my setup?
- Is there any other way I can have better access control with oauth2-proxy’s builtin settings which use the keycloak roles and match url, something like that (I know this is more an oauth2-proxy question)
- Is there any other way with istio to achieve the feature like this in oauth2-proxy where; if there is no(valid) auth header redirect to keycloak login and get token put in header, and redirect back to previous url, then authorize based on claims/roles??.
- Is there any other way of achieving what i want?
Thank a lot.
Any input is much appreciated.
(click) Here are my two authpolices:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: sample-httpbin-authn-policy
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway-internal
action: CUSTOM
provider:
name: oauth2-proxy
rules:
- to:
- operation:
hosts: ["api-internal.v3box1.mosip.net","temp-gate.v3box1"]
paths: ["/httpbin","/httpbin/*"]
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: sample-httpbin-authz-policy
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway-internal
action: DENY
rules:
- to:
- operation:
hosts: ["api-internal.v3box1.mosip.net","temp-gate.v3box1"]
paths: ["/httpbin","/httpbin/*"]
when:
- key: request.auth.claims[realm_access_roles]
notValues: ["kibana_access"]
(click) And when i remove the second AuthPolicy, here is the output that i get on httpbin (redacted):
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-GB,en;q=0.9",
"Authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI2VS05d2w5NmZpLXpIRFNuUDNTVTUzd0lhVVRVVnljUTl2WnZVMmlmNDlVIn0.eyJleHAiOjE2Mzc3NzYzNTksImlhdCI6MTYzNzc3NjA1OSwiYXV0aF90aW1lIjoxNjM3Nzc2MDU5LCJqdGkiOiI4Njk4YzFkMS1iNjc5LTRmMDctYmIxOS1kOTY3MTllMDlmNWMiLCJpc3MiOiJodHRwczovL2lhbS52M2JveDEubW9zaXAubmV0L2F1dGgvcmVhbG1zL2lzdGlvIiwiYXVkIjoiaXN0aW8tYXV0aC1jbGllbnQiLCJzdWIiOiI1OTQ4ZGQyOS1hZjFiLTQxM2MtODQyYS03N2U4YWNhNGJjMDIiLCJ0eXAiOiJJRCIsImF6cCI6ImlzdGlvLWF1dGgtY2xpZW50Iiwibm9uY2UiOiJmakMwRUo4TkdjRUxGdk1LaTFkbWRjdXFpRll1YXlNSTc5OXdwQ1k4NzNJIiwic2Vzc2lvbl9zdGF0ZSI6IjVlMjMyZDdiLWNiOGMtNDQxYi1iNTA4LWE5ZjRjZjhjYzEwOSIsImF0X2hhc2giOiI3a3RZQmlsR1pHbDVfQjRDcG54LTR3IiwiYWNyIjoiMSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicmVhbG1fYWNjZXNzX3JvbGVzIjpbImtpYmFuYV9hY2Nlc3MiLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiZGVmYXVsdC1yb2xlcy1pc3RpbyJdLCJuYW1lIjoiTGFsaXRoIEtvdGEiLCJncm91cHMiOltdLCJpc19raWJhbmFfYWNjZXNzIjoidHJ1ZSIsInByZWZlcnJlZF91c2VybmFtZSI6ImxhbGl0aCIsImdpdmVuX25hbWUiOiJMYWxpdGgiLCJmYW1pbHlfbmFtZSI6IktvdGEiLCJlbWFpbCI6ImxhbGl0aEBtb3NpcC5pbyJ9.dKyMO_ubVRh_Dcv1T0dJEG0WtxMSgjt3nfM67OCzgTTT0jILYZDKCXh-x7TyGWV6QJ0ibK-JOsUAsHEemLvlhDt_HvtXAIm4kC1DhAFwj8O6f2jfm9bpocmOdC4lKUFV3YDdUxcX8QMzyJTfHLYkPtVjwvomDB6DVDL5PhIqhJI5sVXPNo14bkKVLb-SBQoEI9QtfRQmuFqoOk3UZBOdfX-ROVyTn2mMKRUa4SVMhGbPvcPViScscVpDYTl6tjxwnto7VwHRa1-oOmGJhrmpZ9jzqZnMWKG9D68ikcn1oA1qd_pqOeIBZRTe6-NjhBaRr2kY-6brN9k7SYeYuZNarg",
"Cookie": <big cookie>
<lots of headers>
"X-Auth-Request-Access-Token": <bearer token>
<lots of other headers>
}
<others>
}
(click) here is the decoded jwt token(redacted). Note the string "kibana_access" is present in the list in claim "realm_access_roles".
{
<some_fields>
"iss": "https://<domain>/auth/realms/istio",
"aud": "istio-auth-client",
"sub": "<key>",
"typ": "ID",
"realm_access_roles": [
"kibana_access",
"offline_access",
"uma_authorization",
"default-roles-istio"
],
"name": "Lalith Kota",
"groups": [],
<some_other_metadata>
}
And for the oauth2-proxy setup;
(click) Here is my istio configmap (redacted)
data:
mesh: |-
defaultConfig:
proxyMetadata:
ISTIO_META_IDLE_TIMEOUT: 0s
holdApplicationUntilProxyStarts: true
discoveryAddress: istiod.istio-system.svc:15012
gatewayTopology:
numTrustedProxies: 2
proxyMetadata: {}
tracing:
zipkin:
address: zipkin.istio-system:9411
enablePrometheusMerge: true
pathNormalization:
normalization: MERGE_SLASHES
rootNamespace: istio-system
trustDomain: cluster.local
extensionProviders:
- name: oauth2-proxy
envoyExtAuthzHttp:
service: oauth2-proxy.oauth2-proxy.svc.cluster.local
port: 80
includeRequestHeadersInCheck: ["authorization", "cookie"]
includeAdditionalHeadersInCheck:
X-Auth-Request-Redirect: "https://%REQ(:authority)%%REQ(:path)%"
headersToUpstreamOnAllow: ["x-forwarded-access-token", "authorization", "path", "x-auth-request-user", "x-auth-request-email", "x-auth-request-access-token"]
headersToDownstreamOnDeny: ["content-type", "set-cookie"]
(click) and here is my oauth2-proxy configuration (redacted):
provider = "keycloak-oidc"
oidc_issuer_url = "https://<domain>/auth/realms/istio"
email_domains = ["*"]
upstreams = ["static://200"]
redirect_url = "https://<domaint>/oauth2/callback"
insecure_oidc_allow_unverified_email = true
reverse_proxy = true
pass_access_token = true
pass_authorization_header = true
silence_ping_logging = true
set_authorization_header = true
set_xauthrequest = true
skip_provider_button = true
skip_auth_strip_headers = true
ssl_insecure_skip_verify = true
whitelist_domains = ["<base domain>"]
cookie_domains = ["<base domain>"]