Kubernetes with OpenShift World Tour: Get hands-on experience and build applications fast! Find a workshop!

Manage service credentials for serverless applications

Serverless applications are often called “serviceful” applications because developers use lots of external APIs and platform services when creating applications. Combining third-party application services with serverless functions makes it much faster to build applications, but it means that serverless applications need to manage individual access tokens for external services. Developers have to manually provision and maintain individual API keys as default actions parameters.

In this tutorial, I’ll show a simpler way of managing service credentials using IBM Cloud Functions and IBM Cloud Identity and Access Management (IAM) enabled namespaces. IAM-enabled namespaces are mapped to new IAM service IDs upon creation. Service IDs and API keys for the namespace are automatically provisioned and managed by Cloud Functions. The API key is provided in the Cloud Functions runtime environment using an environment variable.

You can then use this API key as the single access token for any IAM-enabled service, including the Cloud Functions platform. This approach is much simpler and securer than having to create (and manage) dozens of individual service keys. Access policies for platforms services can be dynamically added, removed, or modified for the service ID without having to change the serverless function code.

Learn how to add additional service access policies to the Cloud Functions service ID and use the API key to access those platform services. This tutorial uses IBM Cloud Object Storage as the example IAM-enabled service to access from Cloud Functions.

Specifically, you’ll learn how to do the following:

  • Provision an IBM Cloud Functions namespace with IAM support.
  • Access the IAM API key from within the Cloud Functions runtime.
  • Add additional service access policies to the Cloud Functions service ID.
  • Access an IAM-enabled platform service using the Cloud Functions IAM API key.

Prerequisites

Before you begin, you’ll need the following:

Estimated time

Completing this tutorial should take a developer between 10 to 15 minutes.

Step 1. Create new Cloud Functions namespace with IAM support.

  1. Open IBM Cloud Functions.
  2. Open the namespace menu on the home page. namespace-menu
  3. Click Create Namespace.
  4. Fill in the form to create a new namespace called test-iam-namespace. Both the resource group and location form fields can have any allowed value. create-namespace
  5. Click Create to enable the new namespace. After the namespace is created, the namespace menu should auto-select the new namespace. No resources (actions, triggers, rules) will be present in this new empty namespace.

Step 2. Create a Cloud Functions action to list Cloud Object Storage bucket files.

  1. Open the Cloud Functions Actions page in the web UI.
  2. Create a new action by clicking Create.
  3. Fill in the Create Action form with the following values:

    Action Name: list-bucket-files
    Enclosing Package: (Default Package)
    Runtime: Node.js 10

  4. Click Create at the bottom of the form. create-action The Cloud Functions UI will now open the action overview page with a source code editor. The action will be created from example boilerplate function code. This will be shown in the editor panel.
  5. Replace the action source code in the editor panel with the following code:

    Replace <COS_ENDPOINT> to be the Cloud Object Storage endpoint for the bucket.
    Replace <COS_BUCKET> with the Cloud Object Storage service bucket name.

     javascript
     const COS = require('ibm-cos-sdk').S3;
    
     function main(params) {
       const IAM_API_KEY = process.env['__OW_IAM_NAMESPACE_API_KEY']
       const ENDPOINT = '<COS_ENDPOINT>'
       const BUCKET = '<COS_BUCKET>'
    
       const config = {
         endpoint: ENDPOINT,
         apiKeyId: IAM_API_KEY
       };
    
       const cos = new COS(config);
    
       const options = {
         Bucket: BUCKET
       };
    
       return cos.listObjects(options).promise().then(files => ({files: files}))
     }
    
  6. Click Save to update the action source code.

    The IAM API key for the Cloud Functions namespace is automatically injected into the action runtime using a custom environment parameter (__OW_IAM_NAMESPACE_API_KEY). This API key is provisioned using the service ID mapped to the Cloud Functions namespace. By default, the only access policies assigned to the service ID are those allowing it to interact with the Cloud Functions platform.

    Cloud Functions Node.js runtime comes with the IBM Cloud Object Storage SDK pre-installed in the runtime environment. This means it can be used without having to include it in the deployment package.

Step 3. Check that the Cloud Functions action fails with authorization errors.

Click Invoke on the action source code panel. failed-invocations This will cause the action to be invoked and an error to be thrown. This will show as a failed activation in the activation list. The action result should have the AccessDenied code. This correctly indicates default access policies for the Cloud Functions service ID do not provide access to the Cloud Object Storage service.

Adding the Cloud Object Storage access policy to the Cloud Functions service ID will allow this function to work without any changes to the action source code.

Step 4. Add a Cloud Object Storage access policy to the Cloud Functions service ID.

  1. Open the IAM management console on IBM Cloud.
  2. Select the Service IDs menu option from the left-hand panel. This will display a list of all the service IDs available for the current account. service-ids-list
  3. Select the service ID with the same name as the Cloud Functions namespace (test-iam-namespace). Service IDs created by Cloud Functions are locked by default to prevent accidental changes. This is because Cloud Functions needs the API key added to that service ID to interact with the platform on behalf on the user. The service ID must be unlocked before making changes.
  4. Unlock the service ID to allow changes by clicking the right-hand menu icon and selecting Unlock. default-policies
  5. Click the Access policies tab on the management page for this service ID.
  6. Click the Assign access button on the Access policies tab.
  7. Select the Assign access to resources menu option within the Choose Access Type window. select-assign-access
  8. Open the Services menu and select Cloud Object Storage.
  9. Open the Service instance menu and select the instance of Cloud Object Storage the action is going to access.
  10. Leave the Resource type and Resource ID fields empty. select-cos-service The Select roles form fields allow you to choose the access level this service ID will have for the service. It is a good policy to only provide the minimal level of access possible to complete the operations by the client. In this example, the action is only trying to access a list of files within the bucket. This means only the Reader role is necessary.

    Read more about the different roles and how this applies to Cloud Object Storage.

  11. Select the Reader option from the Assign service access roles form. Leave all other options unchecked. select-access-role
  12. Click Assign.
  13. Use the menu on the right-hand side to Lock the service ID to prevent further changes.

    Now that you added the Cloud Object Storage access policy to the correct service ID, the Cloud Functions action should now work without modification. new-access-policy

Step 5. Check that the Cloud Functions action no longer has issues accessing bucket files.

Click Invoke on the action source code panel again. The new activation should now be successful! The result of the invocation should be a list of files contained within the bucket (with associated metadata). successful-invocation

Summary

Now that IBM Cloud Functions takes advantage of IAM integration, it’s much easier to manage service credentials for serverless applications on IBM Cloud. Previously, developers had to manually provision and manage service keys for all the different platform services used in the application. Having individual API keys stored as default action parameters became challenging after you used more than a few services!

This is much simpler with the new IAM-enabled namespaces in Cloud Functions. Each namespace has an associated service ID automatically provisioned, which can be used to create API keys to access authorized platform services. Cloud Functions automatically injects a default API key for the service ID into the runtime. This API key can be utilized with client libraries for any platform services for IAM-enabled services.

Access policies for external service access can be added to the namespace’s service ID. Access policies can be changed dynamically, allowing you to add, remove, or modify access policies without changing the serverless application code. This is a much simpler and securer approach for managing service credentials for applications on Cloud Functions.

James Thomas