-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: add authorizationGroups property to K8s SAR authorization, fixes #506 #507
Conversation
cf7f823
to
8a90020
Compare
@guicassolato I was thinking back to an authorization requirement we had in managed openshift connectors, where we were authorizing against an org field in JWT, and a groups claim.
|
@dhirajsb, I think it should be straightforward and match the SAR API, i.e., For cases like the one you described, one can always use CEL. E.g., the following resolves to a list containing a single string equal to the org name used as group. authorizationGroups:
expression: [auth.identity.org_name] Because it's CEL, we can do fancy stuff. E.g.: |
I was thinking about CEL after I wrote that comment, but wasn't sure how capable it was. Good to know we can cover fairly complex use cases with it. 👍 |
67af11c
to
3982ccc
Compare
…uadrant#506 Signed-off-by: Dhiraj Bokde <[email protected]>
Co-authored-by: Guilherme Cassolato <[email protected]> Signed-off-by: Dhiraj Bokde <[email protected]>
…in SAR API call Signed-off-by: Dhiraj Bokde <[email protected]>
Signed-off-by: Dhiraj Bokde <[email protected]>
2408994
to
8048628
Compare
Signed-off-by: Dhiraj Bokde <[email protected]>
8048628
to
1353e29
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job, @dhirajsb! Thank you so much for this!
Leaving here a few verification steps for the record. We should probably add some docs too at some point.
Verification steps
Setup the environment:
make local-setup DEPLOY_KEYCLOAK=1 FF=1
kubectl port-forward deployment/envoy 8000:8000 2>&1 >/dev/null &
kubectl port-forward deployment/keycloak 8080:8080 2>&1 >/dev/null &
In the Keycloak Admin UI (http://keycloak.127.0.0.1.nip.io:8080 | admin:p):
- Define a
talker-api-members
role in thedemo
client of thekuadrant
realm - Create a Token Mapper of 'User Client Role' type to set the
groups
token claim - Map the realm user
john
to thedemo:talker-api-members
role
Create permissions in the Kubernetes RBAC:
kubectl apply -f -<<EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: reader
rules:
- apiGroups: ["talker-api.127.0.0.1.nip.io"]
resources: ["messages"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: readers
subjects:
- kind: Group
name: talker-api-members
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: reader
apiGroup: rbac.authorization.k8s.io
EOF
Try the deprecated API
Create the AuthConfig:
kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta3
kind: AuthConfig
metadata:
name: talker-api-protection
spec:
hosts:
- talker-api.127.0.0.1.nip.io
authentication:
keycloak:
jwt:
issuerUrl: http://keycloak.default.svc.cluster.local:8080/realms/kuadrant
authorization:
"k8s-rbac":
kubernetesSubjectAccessReview:
groups: # <== this will grant access to all requests given the rolebinding created before; not specifying this would require users to be bound directly to the role (not the group)
- talker-api-members
user:
expression: auth.identity.preferred_username
resourceAttributes:
group:
value: talker-api.127.0.0.1.nip.io
resource:
value: messages
namespace:
value: default
verb:
expression: request.method.lowerAscii()
EOF
Consumer the API as a user who is a member of talker-api-members
:
ACCESS_TOKEN=$(kubectl run token --attach --rm --restart=Never -q --image=curlimages/curl -- http://keycloak.default.svc.cluster.local:8080/realms/kuadrant/protocol/openid-connect/token -s -d 'grant_type=password' -d 'client_id=demo' -d 'username=john' -d 'password=p' -d 'scope=openid' | jq -r .access_token)
curl -H "Authorization: Bearer $ACCESS_TOKEN" http://talker-api.127.0.0.1.nip.io:8000 -i
# HTTP/1.1 200 OK (due to the SAR request with static groups)
Consume the API as a user who is not a member of talker-api-members
:
ACCESS_TOKEN=$(kubectl run token --attach --rm --restart=Never -q --image=curlimages/curl -- http://keycloak.default.svc.cluster.local:8080/realms/kuadrant/protocol/openid-connect/token -s -d 'grant_type=password' -d 'client_id=demo' -d 'username=jane' -d 'password=p' -d 'scope=openid' | jq -r .access_token)
curl -H "Authorization: Bearer $ACCESS_TOKEN" http://talker-api.127.0.0.1.nip.io:8000 -i
# HTTP/1.1 200 OK (due to the SAR request with static groups)
Try the new API
Create the AuthConfig:
kubectl apply -f -<<EOF
apiVersion: authorino.kuadrant.io/v1beta3
kind: AuthConfig
metadata:
name: talker-api-protection
spec:
hosts:
- talker-api.127.0.0.1.nip.io
authentication:
keycloak:
jwt:
issuerUrl: http://keycloak.default.svc.cluster.local:8080/realms/kuadrant
authorization:
"k8s-rbac":
kubernetesSubjectAccessReview:
authorizationGroups: # <== checks whether any of the actual groups the user is a member of has permission
expression: auth.identity.groups
user:
expression: auth.identity.preferred_username
resourceAttributes:
group:
value: talker-api.127.0.0.1.nip.io
resource:
value: messages
namespace:
value: default
verb:
expression: request.method.lowerAscii()
EOF
Consume the API as a user who is a member of talker-api-members
:
ACCESS_TOKEN=$(kubectl run token --attach --rm --restart=Never -q --image=curlimages/curl -- http://keycloak.default.svc.cluster.local:8080/realms/kuadrant/protocol/openid-connect/token -s -d 'grant_type=password' -d 'client_id=demo' -d 'username=john' -d 'password=p' -d 'scope=openid' | jq -r .access_token)
curl -H "Authorization: Bearer $ACCESS_TOKEN" http://talker-api.127.0.0.1.nip.io:8000 -i
# HTTP/1.1 200 OK
Consumer the API as a user who is not a member of talker-api-members
:
ACCESS_TOKEN=$(kubectl run token --attach --rm --restart=Never -q --image=curlimages/curl -- http://keycloak.default.svc.cluster.local:8080/realms/kuadrant/protocol/openid-connect/token -s -d 'grant_type=password' -d 'client_id=demo' -d 'username=jane' -d 'password=p' -d 'scope=openid' | jq -r .access_token)
curl -H "Authorization: Bearer $ACCESS_TOKEN" http://talker-api.127.0.0.1.nip.io:8000 -i
# HTTP/1.1 403 Forbidden
Thanks for testing a built version @guicassolato . I'm also working on testing this locally with a modified model registry. I'll let you know if I run into any issues. |
No description provided.