Service to service authentication/authorization within same space - sap-cloud-platform

We've deployed 2 java services on SAP CF and both are deployed in the same space and bound to the same Xsuaa instance.
Now Service A needs to call service B with the access token of the user. Service A already has the current access token available in the current user context. I'd like to use the destination service for this, instead of calling the service B exposed URL directly. But I'm having trouble setting this up.
What do I need to put in the destination? An OAuth2JwtBearer?
If using an OAuth2JwtBearer, then what are the proper clientId/clientSecret, the ones from XSUAA?
When using a JWT Bearer destination, I get the following error: "Unable to map issuer, http://gvrn-development.localhost:8080/uaa/oauth/token , to a single registered provider"
Any help on this would be great.

Related

Keycloak authentication: how can a external user get an token without exposing client secret

I have a query about how keycloak is supposed to be working with client without GUI access.
Basically I have:
A keycloak server configured with a realm, clients(Access type confidential) and Users
A server application with a GUI that also provide API, secure with keycloak (client, user, blablabla)
This is kind of working already as I am able to log on the GUI, have the redirect, etc..
Even accessing the APIs works well, when I have access to a GUI: I log on my UI, follow the redirect and get my UI to display the token. The the human (to differentiate the user from an application), can use the token in any API client.
In this context the user never sees the client secret, which is instinctively the right way. (note that I am very opened to people telling me my instinct is wrong!)
What I am NOT able to do so far is to find the way a server application (without GUI) can get a valid token?
The authorization_endpoint, as far as I understand it, requires both the client id and the client secret) to get a token, which I would rather avoid: I don't think giving my client secret to all my "customers" is the proper way to do it.
Alternatively I could create an API on my client that woudl ask for user credential and ask for the token in its behalf, but that would expose the clients credentials to my application, which is against the whole concept!
I tried setting my client Access type as public, but when I use the API call below I also get a error:
POST /auth/realms/realmname/protocol/openid-connect/tokenAPI
'grant_type=client_credentials'
'client_id=client_id'
'username=username'
'password=password'
{
"error": "unauthorized_client",
"error_description": "Public client not allowed to retrieve service account"
}
Would anyone know how this is supposed to be done ?
Thanks in advance.
Max
(...) A server application (without GUI) can get a valid token... typically using the Client Credentials flow.
But we would define in this case a dedicated Client for your server (client?) application to authenticate against. The returned token (not bound to a specific user) will serve for authorizations on allowed applications (i.e. your classic GUI or API clients).
So, basically you should (in very short):
define a specific confidential Client in your Keycloak
add the desired applications (or other Clients) to the Client Scope(s). Those you want to authorize transitively from this Client.
authenticate against this Client with Client Credentials flow (given the token endpoint, client id, credentials, scope)
ensure that you are authenticating through TLS and that parameters are included in request body (and not in headers - for enhanced privacy)
further harden security of your Client(s)
When you do not want anymore this particular server (client?) application to access your applications, you can change the corresponding "authentication" Client's secret/credentials or simply delete it.
"I don't think giving my client secret to all my "customers" is the proper way to do it."
You are right and the proposed method above strictly avoids that. Each customer would have its own credentials.
EDIT
(adding more details)
By performing as above, you would end up with the following scheme:
Flow Keycloak Server
C/S app. or Customer X <--- Client Creds ---> Auth. Client X
--- Access Token ---> Appl. Client <--> Appl. Server
C/S app. or Customer Y <--- Client Creds ---> Auth. Client Y
--- Access Token ---> Appl. Client <--> Appl. Server
Browser users <--- Standard ------> Appl. Client <--> Appl. Server
Note: this is not a detailed flow chart. Arrows mostly show relationships here.
Finally, please note that the terminology may differ a little here, but the proposed method is basically the same that Google uses. So you may aswell take some inpiration from there:
https://developers.google.com/identity/protocols/oauth2
I just had the same problem some weeks ago
In my case, I have a backend API and a frontend application that the users can use.
Eventually, I can't share the client_secret to the frontend application.
So here is my solution:
On keycloak, create a client (ex front_end_client) with grant type public
This client is going to be used by the frontend application to authenticate users using implicit flow (with PKCE will be more secure)
On keycloak, create a second client (On the same REALM as the first client) with grant type confidential, this client is going to be used by the backend API
Now, this is how it works:
Frontend app authenticate users and get the access token (Using the font_end_client)
The frontend app sends this token for every request to the backend
Backend app verify this token, and can retrieve permissions from it

Metaflow: "Missing authentication token" when accessing the metadata/metaflow service URL in the browser

I’m currently experimenting on Metaflow. I followed the documentation and was able to deploy an aws setup with the given cloud formation template.
My question is why is that I’m always getting a:
message: "Missing Authentication Token"
when I access METAFLOW_SERVICE_URL in the browser, even if I made sure that the APIBasicAuth was set to false during the creation of cloudformation?
Shouldn’t this setting make the metadata/metaflow service accessible without the authentication/api key?
How can I resolve this? Or is this expected? That is, I cannot really view the metadata/metaflow service url via browser?
Thanks in advance
This was resolved under this github issue.
You still need to set the x-api-key header if you are trying to access the service url via the browser. To get the api-key you can go to the aws console
Api Gateway -> Api Keys -> show api key
Alternatively you can use the metaflow client in the sagemaker notebook which should be automatically setup for you via the template.
Also worth mentioning that there are two sets of endpoints: The one provided by the api gateway (which you seem to be hitting) and the one provided by the service itself. The api gateway forwards the requests the the service endpoints but needs the x-api-key to be set in the header. You can probably try hitting the service endpoints directly since you disabled auth.

How to create base authentication in kubernetes?

I want to create base authentication in kubernetes. every document say that I should create CSV or file then enter the username and password in it. but I do not want to use file I want to some database or kubernetes handle it.
what can I do for base authentication?
You can based your authentication on tokens if you don't want to use static pasword file.
First option:
Service Account Tokens
A service account is an automatically enabled authenticator that uses signed bearer tokens to verify requests.
The plugin uses two flags(which are optional):
Service accounts are usually created automatically by the API server and associated with pods running in the cluster through the ServiceAccount Admission Controller. Bearer tokens are mounted into pods at well-known locations, and allow in-cluster processes to talk to the API server. Accounts may be explicitly associated with pods using the serviceAccountName field of a PodSpec.
Service account bearer tokens are perfectly valid to use outside the cluster and can be used to create identities for long standing jobs that wish to talk to the Kubernetes API. To manually create a service account, simply use the kubectl create serviceaccount (NAME) command. This creates a service account in the current namespace and an associated secret.
The created secret holds the public CA of the API server and a signed JSON Web Token (JWT).
The signed JWT can be used as a bearer token to authenticate as the given service account. See above for how the token is included in a request. Normally these secrets are mounted into pods for in-cluster access to the API server, but can be used from outside the cluster as well.
There is some drawbacks because service account tokens are stored in secrets, any user with read access to those secrets can authenticate as the service account. Be careful when granting permissions to service accounts and read capabilities for secrets.
Second:
Install OpenID Connect (full documentation you can find here: oidc).
OpenID Connect (OIDC) is a superset of OAuth2 supported by some service providers, notably Azure Active Directory, Salesforce, and Google. The protocol’s main addition on top of OAuth2 is a field returned with the access token called an ID Token. This token is a JSON Web Token (JWT) with well known fields, such as a user’s email, signed by the server.
To identify the user, the authenticator uses the id_token (not the access_token) from the OAuth2 token response as a bearer token.
Since all of the data needed to validate who you are is in the id_token, Kubernetes doesn’t need to “phone home” to the identity provider. In a model where every request is stateless this provides a very scalable solution for authentication.
Kubernetes has no “web interface” to trigger the authentication process. There is no browser or interface to collect credentials which is why you need to authenticate to your identity provider first.
There’s no easy way to authenticate to the Kubernetes dashboard without using the kubectl proxy command or a reverse proxy that injects the id_token.
More information you can find here: kubernetes-authentication.

What's the hostname of openshift master server for internal access?

If I want to access the REST API of the openshift master server from anywhere in my company I use https://master.test04.otc-test.company.com:8443 which works just fine.
Now I'm writing an admin application that is accessing the REST API and is deployed in this openshift cluster. Is there a generic name or environment variable in openshift to get the hostname of the master server?
Background: My admin application will be deployed on multiple openshift clusters which do not have the same URL. It would be very handy to have them autodiscover the hostname of the current master server instead of configuring this value for every deployment.
Use environment variables:
https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT
In the container, unless service account details are not being mounted, you can also access the directory:
/var/run/secrets/kubernetes.io/serviceaccount
In this you can then find a token file which contains the access token for the service account the container runs as. This means you can create a separate service account for the application in that project, and use RBAC to control what it can do via the REST API.
That same directory also has a namespace file so you know what project the container is running in, and files with certificates to use when accessing the REST API over a secure connection.
This is the recommended approach, rather than trying to pass an access token to your application through its configuration.
Note that in OpenShift 4, if you need to access the OAuth server endpoint, it is on a separate URL to what the REST API is. In 3.X, they were on the same URL.
In 4.0, you can access the path /.well-known/oauth-authorization-server on the REST API URL, to get information about the separate OAuth server endpoint.
For additional information on giving REST API access to an application via a service account, see:
https://cookbook.openshift.org/users-and-role-based-access-control/how-do-i-enable-rest-api-access-for-an-application.html
Note that that page currently says you can use https://openshift.default.svc.cluster.local as URL, but this doesn't work in OpenShift 4.

Service broker error when adding Single Sign On service

In Bluemix, when I try to add the Single Sign On service to a Java app, I get this error:
Service broker error: {"description"=>"CTJSO0015E The service instance with ID \"XXXXXXXXXX\" must be configured before the operation can be performed."}
The key parts of the error message are:
Service broker error ...
CTJSO0015E The service instance ...
must be configured before the operation can be performed.
My app is a new, empty Java runtime. The service instance gets created but doesn't get bound to the app. When I try to bind the service myself, I get the same error.
How do I get around this problem and bind the SSO service to the app?
Unlike other Bluemix services, the Single Sign On service must be configured before it can be bound to an app. That process is explained in Single Sign On/Configuring the service.
As the docs explain, you must create the service unbound (not bound to an app), configure it, then you can bind the configured service instance to the application.
This is also explained here: Service Broken error While adding Single Sign On service.