Brokering OCI IAM Short-Lived Session Tokens for Multi-Cloud Applications

September 18, 2023 | 9 minute read
Ty Stahl
Cloud Security Architect
Text Size 100%:

Since the recent announcement of the release of OCI IAM Short-Lived session tokens - I have been eager to author a post to highlight one of its many uses. This widely requested feature opens up a number of interesting use cases that customers will be able solve with this capability. Lastly as the title suggests, it also serves as another useful security tool in OCI’s multi-cloud strategy which we will see in the forthcoming use case.

Before we dive into the architecture, let’s briefly summarize what the short-lived session token capability is; and perhaps more importantly – why it can be the right tool for some of your applications.  When we look at enterprises that are running various heterogeneous workloads - whether it is a single OCI tenancy, multiple tenancies – or even an application spread across other cloud service providers – we are faced with the challenge of managing credentials and access controls. 

Prior to this service - API Keys were primarily the secure and portable credential that enables programmatic interactions with OCI’s APIs. However, they do pose some challenges when you look at governance of those credentials.  Given that an API Key is persistent and long-lived in nature - if it were to somehow become unexpectedly lost or stolen, then it could take time to discern which transactions are truly legitimate.  At this point, your only fail-safe choice is to rotate the key and redistribute it to the appropriate individuals and/or services in order to immediately close the door on any potential bad actor.

To help alleviate some of that risk, OCI IAM has introduced short-lived tokens – which you may also see them referred to going forward as the User Principal Session Token (UPST).  The characteristics of these tokens are very attractive when you apply them to multi-cloud application ecosystems and asynchronous application architectures.

Use Case

With all of that said - I will frame this into a real-world scenario.  It is a common security practice for DevOps/CICD processes to require a token specifically granted for the job which has guardrails built around its longevity.  This, of course, is to prevent any user from intercepting the token from the pipeline and using it for other purposes outside of DevOps.  For this demo, the user principal will be a Service Account - so it will be generically used by the application with no direct association to any end-users of the application.

The goal of this service is simple. I want to create a UPST issuer which essentially acts as an Secure Token Service (STS) that does the following:

1. Input – accept an OAuth2 bearer token with a specific scope, and provide a request payload that includes 2 simple parameters​​​​​​

  • User OCID for the Service Account will need to be requested
  • Public Key to be embedded into the JWK for request signature protocol
  • (Optionally) Token Expiration - by default the function code will request the full 60 minutes but you are able to pass in a duration between 5-60 minutes which is referenced in the Generate User Security Token API definition

2. Process - the function securely retrieves the API Key from an OCI Secret and invokes the IAM Services with that API Key to request a short-lived token

3. Output – returns the JWT token with a 60 minute lifetime

For this cloud-native demo - we will leverage several of the OCI services which I will briefly summarize their purpose:

  • OCI Functions - a serverless implementation that leverages the OCI Java SDK to facilitate the OCI UPST token exchange
  • API Gateway - provides a public endpoint and OAuth2-compliant authorization capability
  • OCI IAM Domain - the foundational IAM service where the user principal, credentials are managed, and the tokens are generated
  • OCI Vault Secrets - the service where we can place sensitive materials such as an API Key which the function is able to access
     

Architecture

Setup

OCI IAM User setup

As a prerequisite, we need to create a user within the OCI IAM default domain that will have the API Key associated to the user.  Make sure you save the private key in a familiar location, because you will add it as a secret in the OCI vault, next. 

If your user is a Service Account, you may also want to reduce the User Capabilities of the user to only have API Key credentials.  This will reduce the ability for the user to have login access to the OCI console or other credential types.

User Capabilities

Create a Secret

Now, that we have the service account user setup along with the API key in our possession, we will need to add it as a secret in the vault.  Once completed, make sure to capture the OCID of that secret - as you will need to reference that from within your function in order to retrieve and exchange for a UPST token.

If you do not have already have an OCI Vault setup - you can use this blog to get started.. 

Vault Secret

Next, we need to create an IAM policy to authorize the functions service to be able to have access to the OCI secrets from this doc.

Allow service faas to use secrets-family in compartment Dev
Allow service faas to read vaults in compartment Dev
Allow service faas to use keys in compartment Dev

Note: This policy is fairly permissive for demonstration purposes, however you can create a more granular policy for authorizing functions to specific secrets.  In addition, if the token broker was an application running on an OKE cluster or OCI compute instance - you would use Dynamic Group Policies to authorize the Instance/Resource Principal access to the secrets.  Examples here.

Create the Token Exchange Function

First, we need to create the function itself using the code examples found here.  I chose to use the Java SDK, and need to be sure to include the required dependencies and latest versions in your project manifest.

<groupId>com.oracle.oci.sdk</groupId> <artifactId>oci-java-sdk-common</artifactId> <version>3.21.0</version> <groupId>com.oracle.oci.sdk</groupId> <artifactId>oci-java-sdk-identity</artifactId> <version>3.21.0</version> <groupId>com.oracle.oci.sdk</groupId> <artifactId>oci-java-sdk-identitydataplane</artifactId> <version>3.21.0</version>

Once your function is built and deployed, you should be able to test it locally simply by using the Fn Project command line tools or OCI CLI to verify that the code is behaving properly.

OAuth2 Client Configuration for API Gateway

Since we will be using the OCI IAM OAuth2 services to enforce authorization on our function API - we need to setup some Resource Servers and Clients.  Here is a useful blog that I followed as a reference which walks us through the configuration.

First, I created the Resource Server which defines the Scopes that can be requested and honored.

idcs oauth

 

Next, I need to create the Client Configuration.  I chose to use the client credentials OAuth2 flow since the use case is for a secure application that we trust to keep the secrets safe. This will produce a ClientID and Secret that I will use to get the bearer access_token.  Lastly, I want to assign the ability to request the necessary scopes in order to authorize the application to invoke the token exchange exposed by the API Gateway.

Scope

Note: Alternatively, if our application was a user-facing client where we need to preserve the identity of the actor - we would want use the Authorization Code flow that would allow us to extract the Subject of the access_token and generate the UPST token based of those claims.

API Gateway 

Now that all of the core functionality is completed for the user token exchange, we can now expose the function as a public web service that can be consumed by applications.  For that, we will use the API gateway service. I followed this fantastic blog by my colleague to achieve this setup.

As we start the basic configuration of the API Gateway, we will have to configure the Authentication Policy for the deployment.  Since we are using OCI IAM as our Authorization Server and Resource Server in the previous section, the configuration will be straight forward.  In addtion, I wanted to call out that the API Gateway can support other OAuth2 compliant authorization services - not just OCI IAM.  That means -  if you already have an existing enterprise IAM service that you prefer to use - it can be substituted with a few minor configurations changes.  

apigateway1

Continuing on - we will need to explicitly define which scopes that are authorized to invoke the service.

scopes

Now the easy part, we will simply specify our function as the target backend of this API in the routes portion.

routes

Lastly - as all things OCI - security is always going to be a default deny.  We must allow the API gateway instance to invoke our function.  To do that - we need to create another dynamic group and IAM policy that allows specific access to the resource.  Again, you will likely want to be more prescriptive with the IAM policies; however - for the purpose of this demonstration, we will just allow the API Gateway instance to use all functions in the tenancy.

Policy

At this point, it is safe to say that we should be ready to test out the token exchange service. To do this, I will use a simple tool like curl within the OCI Cloud Shell to invoke the IAM services to get that initial access_token using the client credentials flow.

Test1

Now that we have our access_token - we need to include it as part of the Authorization header as a Bearer token - which the API gateway will validate against the OCI IAM service that we configured in the Authentication section of the deployment. Additionally in the body of the function - I specify the two required parameters to forward to the function - the ocid of the user and a RSA public key.

JWT Token

If the test is successful, you will receive a JWT token that can be inspected as shown below.  As you can see, the difference of the iat and exp epoch times is 1800 seconds.  Therefore, this token will only be valid for 30 minutes.

{
  "sub": "ocid1.user.oc1..aaaaaaaaieac2dhv4xugkv7d5capfqz6d4o2v4l",
  "aud": "oci",
  "pstype": "natv",
  "ttype": "te",
  "iss": "authService.oracle.com",
  "ptype": "user",
  "sess_exp": "Tue, 12 Sep 2023 17:01:00 UTC",
  "exp": 1694538060,
  "iat": 1694536260,

  "jti": "427670e7-e876-4103-91c3-a4b390888464",
  "tenant": "ocid1.tenancy.oc1..aaaaaaaasqkfsrzfn2eehnjdzoo7p3jixlycp",
  "jwk":
   "{\"kid\":\"ocid1.tenancy.oc1..aaaaaaaasqkfsrzfn2eehnjdzoo7p3jixlycp\",\"n\"
     :\"rh1dTq2GdgxQEMziN_tlO1FNX3ohLg3oYcja8-bDqjAAC7PRCBgEUc7-RYzM5wO6rbIS_hl
     lczhkkLJ_9zn_ril-_-ayl4piWtmRXENq4-GBTteusqHHYI1G3a67m5w8AqX_oa9Jwj99SUPyi
     bLwxMZS0zS5pbtWHHBhexvJfzl_unb0Y-5ZY-mEDbEs7FxyFJGm9VDIK0eMaAf22moXx1hRa0L
     3yYxXEr7ek2XBOfAafWS-7AHUxGMeZsXvS5YkTsApfgKKDHwp
     \",\"e\":\"AQAB\",\"kty\":\"RSA\",\"alg\":\"RS256\",\"use\":\"sig\"}"
}

 

Conclusion

The introduction of OCI IAM short-lived session tokens adds another tool to meet the needs of their multi-cloud and hybrid workload objectives. This blog serves just as one simple example of the challenges short-lived tokens can help solve. Further, I am looking forward to the genesis of more multi-cloud use cases and token exchange patterns that customers can use to secure their workloads.

References

OCI GenerateUserSecurityToken API Docs
 

Ty Stahl

Cloud Security Architect


Previous Post

Extending SaaS by AI/ML - Part 4: Using SaaS data with LangChain Prompt Templates for Few-Shot learning

Rekha Mathew | 7 min read

Next Post


Extending SaaS by AI/ML features - Part 5: Modelling using a SaaS Data Pool on-premise

Ulrich Janke | 23 min read