Skip to Content
Technical Articles
Author's profile photo Gopal Anand

Adding Authentication and Authorisation to Approuter with XSUAA binding in Kyma runtime

Pre-read:

This blog requires basic knowledge of kyma runtime, if you are not aware of it you can refer to the following sources:

 SAP Help Documentation on Kyma

Kyma Project

XSUAA

Contents

This blog contains the following information:

  • How to create XSUAA instance in kyma runtime.
  • How to bind create secrets for XSUAA instance.
  • How to bind secret to Approuter using volume mounts.
  • Exposing the router to the public internet

 

Let’s get started:

The first step is to create an xsuaa service instance, we will be doing it through yaml.

apiVersion: services.cloud.sap.com/v1alpha1
kind: ServiceInstance
metadata:
  name: garouter-uaa
  namespace: <your namespace>
spec:
  serviceOfferingName: xsuaa
  servicePlanName: application
  externalName: garouter-uaa
  parameters:
    xsappname: <id>-garouter
    tenant-mode: dedicated
    oauth2-configuration:
      redirect-uris:
        - "https://<cluster domain>/login/callback"
    scopes:
      - name: "$XSAPPNAME.admin"
        description: Admin
    role-templates:
      - name: admin
        description: Admin
        scope-references:
          - "$XSAPPNAME.admin"
    role-collections:
      - name: Approuterkyma
        description: kyma approuter role
        role-template-references:
          - "$XSAPPNAME.admin"

It can also be created by passing the above configuration using JSON format, for details you can refer to this blog

Well now that we have the xsuaa configuration, let’s also add the configuration for service binding:

apiVersion: services.cloud.sap.com/v1alpha1
kind: ServiceBinding
metadata:
  name: routerauth-binding
spec:
  serviceInstanceName: garouter-uaa
  secretName: routerauth-binding
  externalName: garouter-uaa

My app-router is very basic at this moment and it’s having xs-app.json where I have defined routes and one plain HTML page.

xs-app.json

{
    "welcomeFile": "index.html",
    "authenticationMethod": "route",
    "routes": [
        {
            "source": "^/user-api(.*)",
            "target": "$1",
            "service": "sap-approuter-userapi",
            "authenticationType": "xsuaa",
            "scope": "$XSAPPNAME.Admin"
        },
        {
            "source": "^/(.*)",
            "authenticationType": "xsuaa",
            "localDir": "resources"
        }
  
    ]
}

Now to deploy the router We need to containerize the app. I’m using docker for this purpose. Here’s the docker file:

FROM node:lts-alpine
ENV NODE_ENV=production
WORKDIR /usr/src/app
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]
RUN npm install
COPY . .
EXPOSE 5000
RUN chown -R node /usr/src/app
USER node
CMD ["npm", "start"]

Once you have built the image and pushed it to the docker hub. Let’s create a deployment file.

Build the images using the following command:

docker build  --rm -f "Dockerfile" -t <your docker repo>/approuterinkyma:latest "."   --no-cache

One thing to note is that SAP’s approuter Use’s @sap/xsenv package internally to parse and load service keys and secrets bound to the application, this makes the process to load secrets easy.

@sap/xsenv loads the secret in the following manner

/etc/
    /secrets/
            /sapcp/
                 /hana/
                 |    /hanaInst1/
                 |    |          /user1
                 |    |          /pass1
                 |    /hanaInst2/
                 |               /user2
                 |               /pass2
                 /xsuaa/
                       /xsuaaInst/
                                  /user
                                  /pass

You can read more about it at  @sap/xsenv

Now let’s look at the deployment configuration:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: garouter
  labels:
    app: garouter
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: garouter
      version: v1
  template:
    metadata:
      labels:
        app: garouter
        version: v1
    spec:
      containers:
        - name: garouter
          image: gopalanand/approuterinkyma:latest
          imagePullPolicy: Always
          resources:
              limits:
                cpu: "250m"
                memory: "128Mi"
              requests:
                cpu: "250m"
                memory: "128Mi"
          ports:
            - containerPort: 5000
          volumeMounts:
            - name: garouter-uaa
              mountPath: "/etc/secrets/sapcp/xsuaa/garouter-uaa"
              readOnly: true
      volumes:
        - name: garouter-uaa
          secret:
            secretName: routerauth-binding

Now let’s create a service and API to make it accessible to the internet:

---
apiVersion: v1
kind: Service
metadata:
  name: garouter
  labels:
    app: garouter
    service: garouter
spec:
  ports:
    - port: 5000
      name: http
  selector:
    app: garouter

---
apiVersion: gateway.kyma-project.io/v1beta1
kind: APIRule
metadata:
  name: garouter
spec:
  gateway: kyma-gateway.kyma-system.svc.cluster.local
  host: garouter.<your cluster host>
  service:
    name: garouter
    port: 5000
  rules:
    - accessStrategies:
        - config: {}
          handler: allow
      methods:
        - GET
        - POST
        - PUT
        - PATCH
        - DELETE
        - HEAD
      path: /.*
  

Well, now let’s put all these configurations together, and use the command

kubectl apply -f deployment.yaml

Once everything is created, let’s go to the API rules section on kyma consume and launch our application.

Login page(looks like this because I have multiple Identity providers):

 

The application:

 

When you click on the hyperlink, it will throw a forbidden message.

Authorisation

We have secured the application with the XSUAA service and the currentUser API has been secured with an authorization check.  To access this endpoint go to BTP cockpit and assign “Approuterkyma” role to your user.

🎆 fireworks. It’s working.

If you want to see the router code or deployment.yaml you can find here.

Further reading:

Deploy CAP Application on kyma

SAP S/4HANA Extended Business Process Scenario

ECC Extend Business Process Scenario

Assigned Tags

      9 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Vinay Kumar Kumawat
      Vinay Kumar Kumawat

      great blog, I was looking for exactly this for XSUAA on Kyma, thanks for the information.

       

      I tried this and got the error :

      Invalid%20redirect

      Invalid redirect

      Author's profile photo Gopal Anand
      Gopal Anand
      Blog Post Author

      Hi Vinay,

      You can try with the following configuration for XSUAA in redirect url:

       oauth2-configuration:
            redirect-uris:
              - https://*/**

      Best regards,
      Gopal

      Author's profile photo Bram Purnot
      Bram Purnot

      Hi Gopal,

       

      great blog! Have you also tried and succeeded to get the "role-collection" working? Whenever I add this, the XSUAA instance creation seems to get stuck and is not created.

      Thanks,
      Bram

      Author's profile photo Gopal Anand
      Gopal Anand
      Blog Post Author

      Hi Bram Purnot ,

      I have tried and succeeded to get the "role-collection" working, You need to ensure that the name of role-collection you are providing during the instance creation is unique in that sub account. If there's a role collection that is already there and you are creating it again in different XSUAA service. You will get the error.

      here's an example of role collection:

      {
      	"xsappname": "uniquename_xsuaa",
      	"tenant-mode": "dedicated",
      	"authorities": ["$ACCEPT_GRANTED_AUTHORITIES"],
      	"scopes": [{
      			"name": "$XSAPPNAME.Display",
      			"description": "display"
      		},
      		{
      			"name": "$XSAPPNAME.Update",
      			"description": "Update "
      		},
      		{
      			"name": "$XSAPPNAME.Create",
      			"description": "create"
      		},
      		{
      			"name": "$XSAPPNAME.Delete",
      			"description": "delete"
      		}
      	],
      	"role-templates": [{
      		"name": "Retailer",
      		"description": "Retailer role for the app",
      		"scope-references": [
      			"$XSAPPNAME.Update"
      		]
      	}],
      	"role-collections": [{
      		"name": "Unique-Retailer-RoleCollection",
      		"description": "retailer roles for espm cloud native",
      		"role-template-references": [
      			"$XSAPPNAME.Retailer"
      		]
      	}], 
        "oauth2-configuration": { 
                          "redirect-uris": [	
                                            "https://*/**"] } 
      }
      Author's profile photo Bram Purnot
      Bram Purnot

      Thanks for the quick reply. I added it directly to the deployment yaml file but it still doesn't seem to like it. I made sure the role collection name is unique but without any luck.

      Author's profile photo Gopal Anand
      Gopal Anand
      Blog Post Author

      Can you try creating the instance in Kyma cockpit by passing the json as parameter.

      Author's profile photo Bram Purnot
      Bram Purnot

      Thanks! I figured it out. Apparently I had a "." in the role template name (e.g. EC.User). Apparently it doesn't like that. Removing the dot solved the issue.

       

      Thanks,

      Bram

      Author's profile photo Jay Adnure
      Jay Adnure

      Hi Gopal,

       

      thank you for this awesome blog. I followed every step you mentioned and also added role collection to my user still it gives 403 when clicked on hyperlink. Do we have any extra steps to be followed?

       

      kr,

      Jay

      Author's profile photo Luiz Gomes
      Luiz Gomes

      And how is the service call within nodejs?

      const xsenv = require('@sap/xsenv');
      xsenv.loadEnv()
      const services = xsenv.getServices({ xsuaa: { label: 'xsuaa' } });
      console.log(services);