Skip to content
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

THREESCALE-11015 - Support client_secret_jwt and private_key_jwt as authentication type for token introspection policy #1464

Merged
merged 4 commits into from
Jul 8, 2024

Conversation

tkan145
Copy link
Contributor

@tkan145 tkan145 commented May 30, 2024

Known issue

Some time failed with the following error

/opt/app-root/src/gateway/src/apicast/policy_loader.lua:98: Invalid config for policy: failed to validate dependent schema for "auth_type": value should match only one schema, but matches none

This is due to the use of oneOf and seems like a bug. I will need to investigate this further.

The original intention was to add support for a single algorithm and then upgrade lua-retsy-jwt afterwards and have a minimal schema structure change. However, the jsonschema validation fails when the emum field only contains a single value so I decided to remove it for now.

@eguzki if you know a better way to build apicast-config.json or how to solve this problem, please let me know


What

This PR mainly adding 2 new authentication method for token introspection policy, client_secret_jwt and private_key_jwt.

JIRA: https://issues.redhat.com/browse/THREESCALE-11015
Reference: https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication

Why only HS256 and RS256 are supported?

This is due to the version of lua-resty-jwt (0.20) that we use

Support sign algorithm

RHKB 24 lua-resty-jwt 0.20 lua-resty-0.2.2 lua-resty-0.2.3
client_secret_jwt HS256
HS384
HS512
HS256
HS512
HS256
HS512
HS256
HS512
private_key_jwt RS256
RS382
RS512
ES256
ES384
ES512
PS256
PS384
PS512
RS256 RS256
ES256
RS256
RS512
ES256
ES512

Highest we can go is 0.2.2 but this only add support for ES256
0.2.3 introduce a new dependency lua-resty-openssl. See #1375 (comment)

Eventually we will need an update but given the amount of work involved, I'd like to keep version 0.20 for now

Verification steps:

Validate client_secret_jwt authentication method

  • Checkout this PR
  • Build a new runtime image
$ make runtime-image IMAGE_NAME=apicast-test
  • Navigate to keycloak dev-environment
$ cd dev-environments/keycloak-env
  • Update apicast-config.json with the following
diff --git a/dev-environments/keycloak-env/apicast-config.json b/dev-environments/keycloak-env/apicast-config.json
index 071296cd..2ee79be1 100644
--- a/dev-environments/keycloak-env/apicast-config.json
+++ b/dev-environments/keycloak-env/apicast-config.json
@@ -90,6 +90,17 @@
               "auth_type": "use_3scale_oidc_issuer_endpoint"
             }
           },
+          {
+            "name": "token_introspection",
+            "version": "builtin",
+            "configuration": {
+              "auth_type": "client_secret_jwt",
+              "client_id": "oidc-issuer-for-3scale",
+              "client_secret": "oidc-issuer-for-3scale-secret",
+              "client_jwt_assertion_audience": "https://keycloak:8080/realms/basic/protocol/openid-connect/token",
+              "introspection_url": "https://keycloak:8080/realms/basic/protocol/openid-connect/token/introspect"
+            }
+          },
           {
             "name": "apicast",
             "version": "builtin",
  • Start dev-environment
$ make gateway IMAGE_NAME=apicast-test
$ make keycloak-data
  • Configure keycloak client to use client-secret-jwt
    • Open keycloak dashboard in the browser at `https://127.0.0.1:9090
    • Login with admin/adminpass
    • Navigate to basic realm
    • Navigate to Client -> oidc-issuer-for-3scale -> Credentials
    • Change Client Authenticator to Signed JWT with Client Secret and use HS256 algorithm
    • Click Save
  • Get the access token
$ export ACCESS_TOKEN=$(make token)
  • Run request
$ curl -v --resolve stg.example.com:8080:127.0.0.1 -H "Authorization: Bearer ${ACCESS_TOKEN}" "https://stg.example.com:8080"
  • The response should be 200

Validate private_key_jwt authentication method

  • Configure keycloak client to use signed_jwt
    • Navigate to the keycloak dashboard Client -> oidc-issuer-for-3scale -> Credentials
    • Change Client Authenticator to Signed JWT with RS256 signature algorithm
    • Navigate to Key tab and click generate a new key
    • Select archive format PCKS12 and fill in required fill and save keystore file to local disk
    • From the downloaded keystore.p12 file, run the following command to extract private key
openssl pkcs12 -in keystore.p12 -nodes -nocerts | openssl rsa -out privatekey.rsa
  • Encode certificate as base64
$ openssl base64 -A -in privatekey.rsa
  • Stop dev-environment
CTRL-C
  • Update apicast-config.json
diff --git a/dev-environments/keycloak-env/apicast-config.json b/dev-environments/keycloak-env/apicast-config.json
index 071296cd..a5ff3ffb 100644
--- a/dev-environments/keycloak-env/apicast-config.json
+++ b/dev-environments/keycloak-env/apicast-config.json
@@ -90,6 +90,19 @@
               "auth_type": "use_3scale_oidc_issuer_endpoint"
             }
           },
+          {
+            "name": "token_introspection",
+            "version": "builtin",
+            "configuration": {
+              "auth_type": "private_key_jwt",
+              "client_id": "oidc-issuer-for-3scale",
+              "client_secret": "oidc-issuer-for-3scale-secret",
+              "client_jwt_assertion_audience": "https://keycloak:8080/realms/basic/protocol/openid-connect/token",
+              "introspection_url": "https://keycloak:8080/realms/basic/protocol/openid-connect/token/introspect",
+              "certificate_type": "embedded",
+              "certificate": "data:application/octet-stream;name=privatekey.rsa;base64,LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2d0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktrd2dnU2xBZ0VBQW9JQkFRRDQwNWl2OG5GNlNpTmIKUFVIOTdqVjVxNXliOVlDd3hXVGdQZVF1Y0l0c1RJWDNMcDF1aSs5TXZueDUzYStERGhmUjJ2SE5hcS90aXE1aQpsalNGL3V1TEZZdjhPOGc0eFVZUTVFTjFjR1VDSld1NkRTNmtDRFI2VjM0MVgxb0xpWUp4M05zbHdLdUcwcm5qCmpyZURpK2tXaHdrMWZYVE5LczJRSlI1U
npsbW9YMFN5Wnh5YzUyN2ZZYmdjRGlQUFI3RTZrT2wvdXdEMlI4bk0KY28xcE5EKzJvL2svMWtQV2dLNXlZeEswYmRRd2JpcENoKzBUaUlnSXBxS3h0WVlZVHZyalVoRjNUNHpCYXErNQpNZ1ljRjdFSlRJM3ZFaklodmFSN1ZjUjNsYW9QUU9KcCtQMmErUkZCN3IwMEVOTHduUmdyWXhHa1JtK3dUeDA5CjZnTnozTFh6QWdNQkFBRUNnZ0VBTmxjN29yMC9WQllwMTR5dXcwNkpCaXZZMVdTTnVNMDdKUS9QSytjdlE3VUkKa3IxdTYwd0xORWJyZDAvWE96ZFNNMlh0NWM4VllicW1MK2lleXQ2cndTR3hBeUpwTFNERUZ2OUt6alNBRXJKcQpidVRmR1RxamYwNXBS
UzJ3UkJIQlY2MkVmSit4dGcyQ1JEU1FWbDJ4UjFheFI2bkEzdWVvb2dEQk9OdG9VREVqCjJhMDNQd2M0ano1Qlo4RmZsQ3JPcmE5M2dlTlRpLzRRTUwrZDdlbWIrQjN3a2R4aFF4ZnUwdWtxeUl6c1VXTy8KV2plMzFQbWZRL0hKRUhtM3BUMklySTIva21lQjN4NzBkUmRLYnJEK2taMXFDK2JpOWhoZjUvZThVbzBWM0d5RgoxeDd5RXQ2VHY5aWk2UjZESVlUMDV1T1V1MUU2aXVOQmN3SzFBSWYwRlFLQmdRRDlrV3pOMzNUZVpKSFBFdjdMCmlQNmFEbjdDS1liWVRwcDVOT0dkL3Vab2Q4dTV1ZkZJRW1NV00yc0RMZEp3cGRIWVRpZENxSktlQlRkbC85ODUKcU9
WNHRLbmxNV2NZam96bysrT0JPc2U0cnd0NDNCMVRLNzRDdHRCYlZWVElPbnVqdlk4d2EvU0hiaDlESlNFLwpEcjdOeUxiWDloY3BLeHVIaHF0NWJqV1hiUUtCZ1FEN05vZWU5eVFSYklQbUxHRjI3QnFmenBXdjhERDNuUkdBCnFBWnY2VHdTblpUOTM5UVlzRi9ZLzIxdjVPamdGcGJERmt4S3lNMkJHV09sZ1RMaXZHUnIzZ2o3TGxMRUh6OTYKejRVSEUzVlpJbDVIY2hQemZHakpVVVJscXVxbk1MRHJ5ME1uZ1RIREhuME5KdXhJTm9xUXdPaHJpQ1FRSzVOMwoxelJoSVI1RzN3S0JnUURqd3VPYmpMTWFLL1c0cmRSR0dIaXhBb0lqZjArTExoZWM5YjRPdis1UU
9nSzVnZWJUCm1RaDk0Wk9tMkZybEtsenlVVWo4bkJTT2Noc1B1S1RXMHZuRDBXdWwzaGsvdXBPaGx0Z0V0VHEramlUYzI4SlAKZWNRRUJoZmpZaU4wY3V1cDZWUWI1MnhPMWNDby9Fbi9yUXdBSmVEdTNUSnluVER1TEM0TU5jMVhoUUtCZ1FDcwphVUZ0UGFzNGRpU1ViYk02dmxLTGlXbzhoUG5taDV0Q2xJOU9jV0cwV1FpdnNOWE5XQWVBVTlZVkxLTVRZUTE1CnVTMEZTb21ZYUFkMnlKUlcvdnRnK05OcktPRFBENjh1cDR4aVRkMkZIa3hjZHBQdzBWck5pSVFMenVFYmZCU0EKMEZFM3BMaTFkSkJZM1hUZkh1ZTg3MWpVckd3cjJPeHVISG9yaTJKUE93S0JnU
UNoTUxUUXFBNlE2Qk9CUFAxYQpsQlNSMG05RUJld0k2Y0s0QmhUNVl0U21JUjN3Kzk3OWN5eEJJQ0JVcHRMelEyVzMwM0syc1l2RXhkYzRTU2hVCkFuV01jZE5WWDhvQmc4bEFpZTFuaUFuTmFqb213SGxCV25OUUVUZjdTYmR6NHFFUFVFbFJRaXRId0VhUjdIbmQKMG1tQzRXcllqQUJVRDFUMlVUWXdQYWJmbWc9PQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg=="
+            }
+          },
           {
             "name": "apicast",
             "version": "builtin",

Replace the content after base64 with the based64 string of your certificate from previous step.

  • Start gateway
$ make gateway IMAGE_NAME=apicast-test
  • Run request
$ curl -v --resolve stg.example.com:8080:127.0.0.1 -H "Authorization: Bearer ${ACCESS_TOKEN}" "https://stg.example.com:8080"
  • The response should be 200

@tkan145 tkan145 changed the title THREESCALE-11015 - Support client_secret_jwt as authentication type for token introspection policy THREESCALE-11015 - Support client_secret_jwt and private_key_jwt as authentication type for token introspection policy Jun 4, 2024
@tkan145 tkan145 marked this pull request as ready for review June 4, 2024 07:59
@tkan145 tkan145 requested a review from a team as a code owner June 4, 2024 07:59
jsonschema validation fails randomly when enum contains only a single
value. For now, remove the algorithm and use the hardcoded value until
we can upgrade lua-resty-jwt and support additional signing algorithms.
Copy link
Member

@eguzki eguzki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Verification tests passed

@tkan145 tkan145 merged commit bbc60a8 into 3scale:master Jul 8, 2024
14 checks passed
@tkan145 tkan145 deleted the token_introspection_auth branch July 8, 2024 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants