Skip to content

Instantly share code, notes, and snippets.

@ptesny
Last active April 21, 2024 11:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ptesny/b96206fd8f2d1e6f8ac4f8bfa0c23ff0 to your computer and use it in GitHub Desktop.
Save ptesny/b96206fd8f2d1e6f8ac4f8bfa0c23ff0 to your computer and use it in GitHub Desktop.
Real time access with kyma workloads

Real time access management with kyma/k8s workloads

Table of Contents
  1. Calculate effective sales prices by applying promotional rules
  2. Maintain Promotions App.
  3. Back-End Integration. Integration With SAP Kyma.
  4. Local JWKS OIDC endpoint for JWT token validation.
    1. Istio authentication and authorization based approach.
    2. Ory oathkeeper based API rule and Virtual Service.
  5. Further reading

1. Calculate effective sales prices by applying promotional rules.

image Using kyma functions to handle the promotional events from campaigns defined in the SAP BTP Omnichannel Promotion Pricing integrated with SAP Commerce Cloud may be a rather challenging endeavour.

The main reason being, the promotional events must be handled in a sequence and are subject to draconian time processing constraints (less than 600 milliseconds per event).

2. Maintain Promotions App.

You can use the Maintain Promotions app to create promotions and maintain price derivation rules that offer rewards to customers based on certain eligibility criteria.

3. Back-End Integration. Integration With SAP Kyma.

You can integrate the Maintain Promotions app with your custom back-end system by configuring your own integration flows.
For more information, see Configuring SAP Cloud Integration and Configuring the Destination to a Back-End System for the Maintain Promotions App to create your own package and set up the required destinations.

When using SAP BTP destinations with the Maintain Promotions App, a kyma API rule host or a Vritual service host is the destination definition URL.

Due to the draconian time execution constrainsts, any call to the public internet will trigger the operation timeout.
Thus, the only way to make it work is to eliminate any public internet calls, by privileging the use of the cluster mesh.

4. Local JWKS OIDC endpoint for JWT token validation.

Intensive testing has proven it is impossible to achieve a low latency (< 600msec) while callling into public internet SAP IAS (or any other 3rd party IDP) OIDC endpoints.

The solution is to provide a local JWKS OIDC endpoint for a JWT token validation.

There are two possible implementation options: direclty with istio or with the Ory oathkeeper based API rule, namely:

4.1 Istio authentication and authorization based approach.

Istio RequestAuthentication supports the local jwks arrays out-of-the-box.
However, istio based authentication and authorization are not yet supported by the Kyma API rule editor, leaving the manifest implementation burden to the end users.

4.2 Ory oathkeeper based API rule and Virtual Service.

With ory oathkeeper we need to implement a local jwks endpoint in a customer function/workload itself.

In order to validate a digitally signed JWT token, ory oathkeeper will need to fetch the array of the public keys, from the public internet, as follows:

  • SAP IAS metadata discovery endpoint:
    https://<tenant>.accounts.ondemand.com/.well-known/openid-configuration
  • jwks_uri https://<tenant>.accounts.ondemand.com/oauth2/certs

Alternatively, this jwks array can be fetched upfront and then served from a customer fuction/workload, thus leveraging the internal kyma cluster mesh.
I had already done it in the past, albeit from a different angle, as described in Hardening access to Kyma APIs with a self-made JWT token. | SAP Blogs

  • fetch the jwks array
{
  "keys": [
    {
      "kty": "RSA",
      "x5t#S256": "TucJmTMohZgePAZJ3n0hmfSmi2mq7BCtXLZrlGUtMQk",
      "e": "AQAB",
      "use": "sig",
      "kid": "_kGBVH1j1Smbm3TbkZpoW3jdHwc",
      "x5c": [
        "MIIDEjCCAfqgAwIBAQIGAWFL6WGEMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNVBAYTAkRFMQ8wDQYDVQQKEwZTQVAtU0UxKDAmBgNVBAMTH2ExemdtbXdpei5hY2NvdW50cy5vbmRlbWFuZC5jb20wHhcNMTgwMTMxMTExMDQxWhcNMjgwMTMxMTExMDQxWjBIMQswCQYDVQQGEwJERTEPMA0GA1UEChMGU0FQLVNFMSgwJgYDVQQDEx9hMXpnbW13aXouYWNjb3VudHMub25kZW1hbmQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy+39ppQGyzVJxbIaD7TOFWvxDm1R8TIgOr6jaY3aJaYKzTfvGK4aEV4YBUgtdbgpwHWTrM9hu09Q6ZVsVuWhyij/FAgEpGgssSKu6vCCDim8bElXthcGIhq9IHjE7s9dfaMZepebQkqIMY3VGRnGQIUCL0qQcH478IdDzfUvNZesvmrSDoMouZNwwJLJD4xkpfWnXjlqmT/coh/Jc6MfE2RCaFjMhjyORrHNnRGhLdZ65+T5ReGzJupdqJjB+ODmoGsg3KkMIoL3BQkVycROcn3Q9BNIMm8J0nPTd3vPDuvNA60u7HlVrOtwZu30dpEuRXta3rih85jXe+RPDSEQpwIDAQABggIAADANBgkqhkiG9w0BAQUFAAOCAQEAWFMh0PvK474Sk+ITm7l3fc8RrpT2FCt7ezt815d0IYdCf+M15348da6klmlZyqJOLbpmicDTGl3tKa+XPavlo0bYP/yAuUkSSNWyPv287G9EQW9C7VkIfuUaKOETQGlQjRBMubAuCI31NgzODObErWEvIxU74vcTICnVYClDaiu2SBsSWfpVVnYBYN3Cetem2u3rL617cfI4B08snfFtn37+Qc28T5MJSPDjP96dwzxXnc1uA1Tfi4Y9COqpqcuy4sN5NtS4urzpju8OPsIILRKStAANPxVdmIIaZLxTdEUz4frz/JecEb8XxzOJFdmCXzhszulnlrJ3e9ITUQ9usg=="
      ],
      "alg": "RS256",
      "n": "y-39ppQGyzVJxbIaD7TOFWvxDm1R8TIgOr6jaY3aJaYKzTfvGK4aEV4YBUgtdbgpwHWTrM9hu09Q6ZVsVuWhyij_FAgEpGgssSKu6vCCDim8bElXthcGIhq9IHjE7s9dfaMZepebQkqIMY3VGRnGQIUCL0qQcH478IdDzfUvNZesvmrSDoMouZNwwJLJD4xkpfWnXjlqmT_coh_Jc6MfE2RCaFjMhjyORrHNnRGhLdZ65-T5ReGzJupdqJjB-ODmoGsg3KkMIoL3BQkVycROcn3Q9BNIMm8J0nPTd3vPDuvNA60u7HlVrOtwZu30dpEuRXta3rih85jXe-RPDSEQpw"
    }
  ]
}
  • flatten the jwks using, for instance, a json formatter: https://jsonformatter.org/
{"keys":[{"kty":"RSA","x5t#S256":"TucJmTMohZgePAZJ3n0hmfSmi2mq7BCtXLZrlGUtMQk","e":"AQAB","use":"sig","kid":"_kGBVH1j1Smbm3TbkZpoW3jdHwc","x5c":["MIIDEjCCAfqgAwIBAQIGAWFL6WGEMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNVBAYTAkRFMQ8wDQYDVQQKEwZTQVAtU0UxKDAmBgNVBAMTH2ExemdtbXdpei5hY2NvdW50cy5vbmRlbWFuZC5jb20wHhcNMTgwMTMxMTExMDQxWhcNMjgwMTMxMTExMDQxWjBIMQswCQYDVQQGEwJERTEPMA0GA1UEChMGU0FQLVNFMSgwJgYDVQQDEx9hMXpnbW13aXouYWNjb3VudHMub25kZW1hbmQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy+39ppQGyzVJxbIaD7TOFWvxDm1R8TIgOr6jaY3aJaYKzTfvGK4aEV4YBUgtdbgpwHWTrM9hu09Q6ZVsVuWhyij/FAgEpGgssSKu6vCCDim8bElXthcGIhq9IHjE7s9dfaMZepebQkqIMY3VGRnGQIUCL0qQcH478IdDzfUvNZesvmrSDoMouZNwwJLJD4xkpfWnXjlqmT/coh/Jc6MfE2RCaFjMhjyORrHNnRGhLdZ65+T5ReGzJupdqJjB+ODmoGsg3KkMIoL3BQkVycROcn3Q9BNIMm8J0nPTd3vPDuvNA60u7HlVrOtwZu30dpEuRXta3rih85jXe+RPDSEQpwIDAQABggIAADANBgkqhkiG9w0BAQUFAAOCAQEAWFMh0PvK474Sk+ITm7l3fc8RrpT2FCt7ezt815d0IYdCf+M15348da6klmlZyqJOLbpmicDTGl3tKa+XPavlo0bYP/yAuUkSSNWyPv287G9EQW9C7VkIfuUaKOETQGlQjRBMubAuCI31NgzODObErWEvIxU74vcTICnVYClDaiu2SBsSWfpVVnYBYN3Cetem2u3rL617cfI4B08snfFtn37+Qc28T5MJSPDjP96dwzxXnc1uA1Tfi4Y9COqpqcuy4sN5NtS4urzpju8OPsIILRKStAANPxVdmIIaZLxTdEUz4frz/JecEb8XxzOJFdmCXzhszulnlrJ3e9ITUQ9usg=="],"alg":"RS256","n":"y-39ppQGyzVJxbIaD7TOFWvxDm1R8TIgOr6jaY3aJaYKzTfvGK4aEV4YBUgtdbgpwHWTrM9hu09Q6ZVsVuWhyij_FAgEpGgssSKu6vCCDim8bElXthcGIhq9IHjE7s9dfaMZepebQkqIMY3VGRnGQIUCL0qQcH478IdDzfUvNZesvmrSDoMouZNwwJLJD4xkpfWnXjlqmT_coh_Jc6MfE2RCaFjMhjyORrHNnRGhLdZ65-T5ReGzJupdqJjB-ODmoGsg3KkMIoL3BQkVycROcn3Q9BNIMm8J0nPTd3vPDuvNA60u7HlVrOtwZu30dpEuRXta3rih85jXe-RPDSEQpw"}]}
  • create a dedicated internal cluster mesh endpoint
module.exports = { 
  main: async function (event, context) {

    const req = event.extensions.request;
    
    switch (req.path) {

      case '/jwks_uri': 
      {
        //return event.extensions.response.redirect('https://<tenant>.accounts.ondemand.com/oauth2/certs');
        return '{"keys":[{"kty":"RSA","x5t#S256":"TucJmTMohZgePAZJ3n0hmfSmi2mq7BCtXLZrlGUtMQk","e":"AQAB","use":"sig","kid":"_kGBVH1j1Smbm3TbkZpoW3jdHwc","x5c":["MIIDEjCCAfqgAwIBAQIGAWFL6WGEMA0GCSqGSIb3DQEBBQUAMEgxCzAJBgNVBAYTAkRFMQ8wDQYDVQQKEwZTQVAtU0UxKDAmBgNVBAMTH2ExemdtbXdpei5hY2NvdW50cy5vbmRlbWFuZC5jb20wHhcNMTgwMTMxMTExMDQxWhcNMjgwMTMxMTExMDQxWjBIMQswCQYDVQQGEwJERTEPMA0GA1UEChMGU0FQLVNFMSgwJgYDVQQDEx9hMXpnbW13aXouYWNjb3VudHMub25kZW1hbmQuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy+39ppQGyzVJxbIaD7TOFWvxDm1R8TIgOr6jaY3aJaYKzTfvGK4aEV4YBUgtdbgpwHWTrM9hu09Q6ZVsVuWhyij/FAgEpGgssSKu6vCCDim8bElXthcGIhq9IHjE7s9dfaMZepebQkqIMY3VGRnGQIUCL0qQcH478IdDzfUvNZesvmrSDoMouZNwwJLJD4xkpfWnXjlqmT/coh/Jc6MfE2RCaFjMhjyORrHNnRGhLdZ65+T5ReGzJupdqJjB+ODmoGsg3KkMIoL3BQkVycROcn3Q9BNIMm8J0nPTd3vPDuvNA60u7HlVrOtwZu30dpEuRXta3rih85jXe+RPDSEQpwIDAQABggIAADANBgkqhkiG9w0BAQUFAAOCAQEAWFMh0PvK474Sk+ITm7l3fc8RrpT2FCt7ezt815d0IYdCf+M15348da6klmlZyqJOLbpmicDTGl3tKa+XPavlo0bYP/yAuUkSSNWyPv287G9EQW9C7VkIfuUaKOETQGlQjRBMubAuCI31NgzODObErWEvIxU74vcTICnVYClDaiu2SBsSWfpVVnYBYN3Cetem2u3rL617cfI4B08snfFtn37+Qc28T5MJSPDjP96dwzxXnc1uA1Tfi4Y9COqpqcuy4sN5NtS4urzpju8OPsIILRKStAANPxVdmIIaZLxTdEUz4frz/JecEb8XxzOJFdmCXzhszulnlrJ3e9ITUQ9usg=="],"alg":"RS256","n":"y-39ppQGyzVJxbIaD7TOFWvxDm1R8TIgOr6jaY3aJaYKzTfvGK4aEV4YBUgtdbgpwHWTrM9hu09Q6ZVsVuWhyij_FAgEpGgssSKu6vCCDim8bElXthcGIhq9IHjE7s9dfaMZepebQkqIMY3VGRnGQIUCL0qQcH478IdDzfUvNZesvmrSDoMouZNwwJLJD4xkpfWnXjlqmT_coh_Jc6MfE2RCaFjMhjyORrHNnRGhLdZ65-T5ReGzJupdqJjB-ODmoGsg3KkMIoL3BQkVycROcn3Q9BNIMm8J0nPTd3vPDuvNA60u7HlVrOtwZu30dpEuRXta3rih85jXe-RPDSEQpw"}]}';
      }
  • use the cluster local jwks endpoint with an API rule
apiVersion: gateway.kyma-project.io/v1beta1
kind: APIRule
metadata:

  name: foo
  namespace: <namespace>

spec:
  gateway: kyma-gateway.kyma-system.svc.cluster.local
  host: bar.<shoot>.kyma.ondemand.com
  rules:
    - accessStrategies:
        - config:
            jwks_urls:
              - >-
                http://foo.<namespace>.svc.cluster.local/jwks_uri          
          handler: jwt
  service:
    name: foo
    port: 80
  timeout: 1

5. Further reading.

drawing

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment