solo-io / gloo

The Feature-rich, Kubernetes-native, Next-Generation API Gateway Built on Envoy
https://docs.solo.io/
Apache License 2.0
4.03k stars 433 forks source link

extauth: userInfo and introspection don't work if you use redis session #5599

Open jmunozro opened 2 years ago

jmunozro commented 2 years ago

Describe the bug extauth: userInfo and introspection don't work if you use redis session

logs from extauth pod in debug mode:

{"level":"debug","ts":1637317060.7194276,"logger":"ext-auth.ext-auth-service","msg":"Received auth request","version":"undefined","request":{"attributes":{"source":{"address":{"Address":{"SocketAddress":{"address":"10.4.0.1","PortSpecifier":{"PortValue":22069}}}}},"destination":{"address":{"Address":{"SocketAddress":{"address":"10.4.0.4","PortSpecifier":{"PortValue":8443}}}},"principal":"CN=*"},"context_extensions":{"config_id":"gloo-system.oauth","source_name":"","source_type":"route"},"request":{"time":1637317060.71823,"http":{"body":"","host":"34.77.238.250","fragment":"","method":"GET","path":"/favicon.ico","scheme":"https","size":0,"query":"","protocol":"HTTP/2","id":"13260799805755250416","headers":{"te":"trailers","referer":"https://34.77.238.250/get","dnt":"1","cookie":"session=KE56Z6DB2SNG6RHRWKAUDXLCXKCSTFKJO3B45BSGNLPGXSDN23ISR2UOKJHG2226VLJG5MXWFH535Z6RS3TQI2B5ORJRGSTVGDNH7KI=",":method":"GET",":path":"/favicon.ico","accept":"image/avif,image/webp,*/*","sec-fetch-dest":"image","sec-fetch-site":"same-origin","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0",":scheme":"https","x-request-id":"39569596-68ae-4d6f-a61b-0ff6c0f2a90b","accept-language":"en-US,en;q=0.5",":authority":"34.77.238.250","accept-encoding":"gzip, deflate, br","x-forwarded-proto":"https","sec-fetch-mode":"no-cors"}}}}}}
{"level":"debug","ts":1637317060.7265162,"logger":"ext-auth.ext-auth-service","msg":"received empty access token","version":"undefined"}
{"level":"debug","ts":1637317060.7265694,"logger":"ext-auth.ext-auth-service","msg":"Access denied by auth authService","version":"undefined","authService":"config_1"}

To Reproduce Steps to reproduce the behavior:

# Create a secret to secure the api
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=*"
kubectl create secret tls upstream-tls --key tls.key --cert tls.crt --namespace gloo-system

# Deploy keycloak (first ext-auth)
kubectl create -f https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/12.0.4/kubernetes-examples/keycloak.yaml
kubectl rollout status deploy/keycloak

export ENDPOINT=$(kubectl -n gloo-system get svc gateway-proxy -o jsonpath='{.status.loadBalancer.ingress[0].*}')
export APP_URL=https://${ENDPOINT}

# Get Keycloak URL and token
KEYCLOAK_URL=http://$(kubectl get service keycloak -o jsonpath='{.status.loadBalancer.ingress[0].ip}'):8080/auth
KEYCLOAK_TOKEN=$(curl -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" "$KEYCLOAK_URL/realms/master/protocol/openid-connect/token" | jq -r .access_token)
# Create initial token to register the client
read -r client token <<<$(curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"expiration": 0, "count": 1}' $KEYCLOAK_URL/admin/realms/master/clients-initial-access | jq -r '[.id, .token] | @tsv')
# Register the client
read -r id secret <<<$(curl -X POST -d "{ \"clientId\": \"${client}\" }" -H "Content-Type:application/json" -H "Authorization: bearer ${token}" ${KEYCLOAK_URL}/realms/master/clients-registrations/default| jq -r '[.id, .secret] | @tsv')
# Add allowed redirect URIs
curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X PUT -H "Content-Type: application/json" -d '{"serviceAccountsEnabled": true, "directAccessGrantsEnabled": true, "authorizationServicesEnabled": true, "redirectUris": ["'${APP_URL}'/callback", "http://portal.example.com/callback"]}' $KEYCLOAK_URL/admin/realms/master/clients/${id}
# Add the group attribute in the JWT token returned by Keycloak
curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"name": "group", "protocol": "openid-connect", "protocolMapper": "oidc-usermodel-attribute-mapper", "config": {"claim.name": "group", "jsonType.label": "String", "user.attribute": "group", "id.token.claim": "true", "access.token.claim": "true"}}' $KEYCLOAK_URL/admin/realms/master/clients/${id}/protocol-mappers/models
# Create first user
curl -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" -X POST -H "Content-Type: application/json" -d '{"username": "user1", "email": "user1@solo.io", "enabled": true, "attributes": {"group": "users"}, "credentials": [{"type": "password", "value": "password", "temporary": false}]}' $KEYCLOAK_URL/admin/realms/master/users
# Create secret with client-secret
glooctl create secret oauth --namespace gloo-system --name oauth --client-secret ${secret}

# Deploy custom server (second ext-auth)
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: extauth-grpcservice
spec:
  selector:
    matchLabels:
      app: grpc-extauth
  replicas: 1
  template:
    metadata:
      labels:
        app: grpc-extauth
    spec:
      containers:
        - name: grpc-extauth
          # Source code: go/src/grpc-service/pkg/auth/v3/auth-with-state.go
          image: gcr.io/solo-test-236622/jesus-passthrough-grpc-service:userinfo2
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 9001
---
apiVersion: v1
kind: Service
metadata:
  name: example-grpc-auth-service
  labels:
      app: grpc-extauth
spec:
  ports:
  - port: 9001
    protocol: TCP
  selector:
      app: grpc-extauth
EOF

# Create authconfig with 2 steps
kubectl apply -f - <<EOF
apiVersion: enterprise.gloo.solo.io/v1
kind: AuthConfig
metadata:
  name: oauth
  namespace: gloo-system
spec:
  configs:
    - oauth2:
        oidcAuthorizationCode:
          appUrl: ${APP_URL}
          callbackPath: /callback
          clientId: ${client}
          clientSecretRef:
            name: oauth
            namespace: gloo-system
          issuerUrl: "${KEYCLOAK_URL}/realms/master/"
          logoutPath: /logout
          scopes:
            - email
          session:
            failOnFetchFailure: true
            redis:
              cookieName: session
              options:
                host: 'redis.gloo-system.svc.cluster.local:6379'
    - oauth2:
        accessTokenValidation:
          introspection:
            clientId: ${client}
            clientSecretRef:
              name: oauth
              namespace: gloo-system
            introspectionUrl: "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token/introspect"
          userinfoUrl: ${KEYCLOAK_URL}/realms/master/protocol/openid-connect/userinfo
    - passThroughAuth:
        grpc:
          address: 'example-grpc-auth-service.default.svc.cluster.local:9001'
          connectionTimeout: 3s
EOF

# Create vs with everything
kubectl apply -f - <<EOF
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: demo
  namespace: gloo-system
spec:
  sslConfig:
    secretRef:
      name: upstream-tls
      namespace: gloo-system
  virtualHost:
    domains:
      - '*'
    routes:
      - matchers:
          - prefix: /
        options:
          extauth:
            configRef:
              name: oauth
              namespace: gloo-system
        routeAction:
          single:
            upstream:
              name: default-httpbin-8000
              namespace: gloo-system
EOF

# Now open a browser
/opt/google/chrome/chrome $APP_URL/get

# Authenticate with user1/password, and check in the logs that the token is captured in custom extauth server
kubectl logs deploy/extauth-grpcservice

Expected behavior Token is extracted from redis

Additional context

jmunozro commented 2 years ago

When this is fixed, it won't work until we fix this other issue: https://github.com/solo-io/gloo/issues/5601

github-actions[bot] commented 1 month ago

This issue has been marked as stale because of no activity in the last 180 days. It will be closed in the next 180 days unless it is tagged "no stalebot" or other activity occurs.