Technical Articles
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
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
great blog, I was looking for exactly this for XSUAA on Kyma, thanks for the information.
I tried this and got the error :
Invalid redirect
Hi Vinay,
You can try with the following configuration for XSUAA in redirect url:
Best regards,
Gopal
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
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:
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.
Can you try creating the instance in Kyma cockpit by passing the json as parameter.
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
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
And how is the service call within nodejs?