Reduce Your Attack Surface by Using Custom Roles

4 min read

Learn how advanced IBM Cloud security features are applied to limit the risk of leaked API keys. 

We are used to reading about leaked API keys — misconfigurations, bugs and insider attacks are common causes for opening up cloud resources for unauthorized access. But how can we reduce the attack surface limit risks? In this blog post, I discuss how to utilize custom roles with IBM Cloud. They are an Identity and Access Management (IAM) feature to define your own set of privileges for resources. Then, you can grant those roles to users and service IDs, either directly or through access groups and trusted profiles.

Overview: Custom roles for scoped security

To access resources in an IBM Cloud account, a user, service ID or trusted profile needs the proper authorization. For that, you must check the assigned, existing privileges against the required ones. With IBM Cloud IAM, the privileges refer to the type of action that is performed. Hence, you often read about actions that are mapped to roles.

In the screenshot below from the dialog to assign access, you see roles with their included actions available for IBM Cloud Code Engine. The Code Engine service access role Manager has 7 associated actions, and the platform access Administrator includes 43 actions. When clicking on the 7 behind Manager, the related actions and a description are shown. It includes actions like "codeengine.tenant.entities.update." That privilege is required to update existing items — such as an app, job, secrets and more — in a Code Engine project.

In the screenshot, you also see a section called Custom access with a role called CEoperate. I defined this custom role to include only three actions. That role could be assigned instead of (or together with) the built-in roles, granting the three included privileges (actions):

Roles have a set of actions (privileges).

Roles have a set of actions (privileges).

You may be wondering how I defined the custom role above. There are the typical options available, including the IBM Cloud console (browser UI), API and Terraform. You can start by going to the IAM roles section in the IBM Cloud console. When you create a role, you first provide the display name, ID and description. From there, you can select from the existing IAM-enabled services and account management categories. Then, it shows all available actions and you can limit to those of an already existing role.

For the custom role CEoperate, I selected Code Engine as the service, then displayed the seven assigned actions for the role Writer. For my use case, I only added privileges to read and update existing items in a project and the ability to view project (tenant) details. With that, I'm ready to create the custom role:

Define a custom role based on system roles.

Define a custom role based on system roles.

Use case: Scoped access for shared DevOps API keys

Knowing how custom roles can be defined and used, the next step is to apply them for enhanced security. To automate processes, I often have to provide API keys. Even when using a service ID with limited privileges to run automations, it is still a valid API key for my account. For many services, the existing Writer role includes operations for the whole lifecycle: create, update, delete and read. To limit the associated risk (i.e., the possible damage caused by a leaked API key), my strategy is to strip the service ID from the ability to create and delete resources. 

For the Code Engine example, it means that someone with the role CEoperate can only obtain and then update apps and jobs with associated configurations. It would still be possible to run the automation to scale an app to zero overnight or deploy a new code revision, but they can't create new apps or jobs and delete existing ones. It is a security improvement over the existing and, so far, required Writer role.

You can also define a similar DevOps-oriented role for other IBM Cloud services and compute options. Another use case is to define scoped custom roles to allow (limited) resource monitoring or to perform certain administrative tasks.

In the previous section, I described how to use the IBM Cloud console to define a custom role. It is how I start learning a new feature — but, then I quickly move on to automating steps. The following shows the definition of the same custom role CEoperate using IBM Cloud provider for Terraform:

resource "ibm_iam_custom_role" "CodeEngine_operate" {
  name = "CEoperate"
  description = "Role to only perform limited operations for DevOps."
  display_name = "CEoperate"
  service = "codeengine"
  actions = ["", "codeengine.tenant.entities.update", "" ]

To be fully operational, few additional privileges are needed — the predefined Reader/Viewer roles to see existing resource groups and service instances, optionally restricted to specific resource groups and cloud regions. I could have included the required actions into the custom role. But I prefer to have the roles as simple and specific as possible and grant other privileges separately.


Custom roles are an IBM Cloud security feature to map a set of privileges to a name. As shown above, they are great to easily configure scoped service access outside the existing system roles. They can be used to reduce the attack surface by limiting allowed actions of a service ID and associated API key to the bare minimum. In the example, I introduced a specialised DevOps role that is capable of updating existing Code Engine apps and jobs (e.g., to roll out a new code revision) but cannot create or delete any new resources.

If you have feedback, suggestions, or questions about this post, please reach out to me on Twitter (@data_henrik) or LinkedIn

Be the first to hear about news, product updates, and innovation from IBM Cloud