Service Accounts reside at the core of API-first businesses. Using Service Accounts & API Keys, one can save hours of manual work required by engineers to set up and maintain Pipelines, Deployments, Audits, Secrets, Resources, User Provisioning, and much more.

In this blog, we’ll be discussing the internal architecture of Service Accounts, API Keys, and how DevOps engineers can use them to build scalable and maintainable CI/CD infrastructure.

What Are Service Accounts?

A service account is a specific kind of account used by an application instead of a person. Applications generally use service accounts to make authorized API calls.

For example, in Harness, you can create a Service Account, assign it permissions, and use it to perform operations across modules (CI, CD, CCM, and Feature Flags) that you might be performing manually as of now.

Service accounts are different from user accounts in the following ways:

  1. Service accounts cannot log in via browsers or cookies.
  2. Service accounts are authenticated using API Key Tokens and not passwords.
  3. Service accounts cannot be added to UserGroups and cannot inherit permissions as Users do from the UserGroups they are part of.

Why Do We Need Service Accounts?

You might wonder, “Why should a CI/CD platform like Harness support Service Accounts when the same thing can be done via a User Account?” 

The one-word answer is: “Automation.”

Using Service Accounts, enterprises can automate almost everything related to CI/CD and remove hours of manual engineering work. For example: if a DevOps engineer spends around an hour every day on triggering and monitoring the same set of workflows manually via UI, he/she can automate all of it using Service Accounts and save considerable time.

Another important aspect is Automated User Provisioning for large enterprises. Large enterprises have different sets of access management policies for allowing a user to access a third party tool. Provisioning these policies manually can be error-prone: manual provisioning may lead to wrong permissions, resulting in compliance issues at later stages.

Service Accounts can solve this issue by automating User Provisioning via workflows for different departments of large enterprises – and also by making it process-oriented.

How to Configure Service Accounts

Now that we have established the importance of Service Accounts, let’s understand the internal architecture and how It can be used in Harness. 

A Service Account is a PrincipalType same as User in Harness that can be assigned roles. 

Service Accounts: Creating a new account
Service Accounts: API Keys

After creating a Service Account, you can create multiple API Keys within the Service Account. Within each API Key, you can create multiple Tokens. 

Each API Key Token inherits roles of the parent Service Account. You can create, rotate, or delete N number of tokens within an API Key, and the same permission set will be applied to it.

An API Key Token has two important properties:

  1. Token Value (e.g. sat.6187b7b3454a8772c2fa00f8.7QHqFTzJUaUnDVJ76UYv)
  2. Token Expiration Time (e.g. 2021/12/31)

Let’s understand both of them in detail.

Token Value

Tokens should be treated equivalent to a password, because they can grant the same level of access to processes/scripts as logged-in Users. Due to high security risk, it is not recommended to store Tokens in plain text, hence Hashing is a must.

Hashing is the process of generating a string, or hash, from a given string using a mathematical function known as a cryptographic hash function.

Choosing a Strong Hash Algorithm

A good hash function must adhere to the following criteria:

  1. Deterministic: The same api_key_token processed by the same hash function should always produce the same hash.
  2. Irreversible: Generating an api_key_token from its hash should be impossible.
  3. High Entropy: Any small change to an api_key_token should produce a vastly different hash.
  4. Resist Collisions: Two different api_key_token should not produce the same hash.

There are various Hashing options available, e.g.: MD5, SHA256, SHA512, PBKDF2, scrypt, bcrypt, etc. However, MD5 is broken because it’s simply too fast and there are better options available than the SHA family.

Some great hash functions that meet all the above criteria are PBKDF2, bcrypt, and scrypt. They all are good and widely-accepted hash functions. We chose bcrypt. 

Why bcrypt? 

Increasing the speed and power of computers can be used by attackers to exploit weak hash algorithms. Not all cryptographic algorithms are designed to scale with computing power. The security of the password depends on how fast the selected cryptographic hashing function can calculate the password hash. A fast function would execute faster when running on more powerful hardware.

To mitigate this risk, we can design a hash function that could be tuned to run slower on new powerful hardware as well.

bcrypt was designed by Niels Provos and David Mazières. It is based on the Blowfish cipher for Blowfish and crypt for the name of the hashing function used by the UNIX password system.

bcrypt mitigates dictionary attacks by combining the expensive key setup phase of Blowfish with a variable number of iterations to increase the workload and duration of hash calculations. 

Another advantage of bcrypt is that it requires salt by default, which enforces security Best Practices. Hashing, in combination with salt, protects passwords from rainbow table attacks. 

Below is an example of a hash generated by bcrypt:

$2a$10$ZLhnHxdpHETcxmtEStgpI./Ri1mksgJ9iDP36FmfMdYyVg9g0b2dq

  • The “2a” represents the bcrypt algorithm version.
  • The “10” represents the strength of the algorithm.
  • The “ZLhnHxdpHETcxmtEStgpI.” part is the randomly-generated salt. These 22 characters are salt.
  • The remaining part of the last field is the actual hashed version of the plain text.

Token Expiration Time

Each Token has an expiration date attached to it, after which it cannot be used to authenticate/authorize. It needs to be rotated periodically. 

Rotating a Token immediately can mark it invalid and break automation processes, so in Harness, we provide functionality where you can rotate an expiring Token and set the deadline for marking it invalid in the future. Meanwhile, your automation processes can incorporate new rotated Tokens and keep running without any failures. 

For this set time window (deadline), both old and rotated Tokens remain valid to enable smooth transitions by various processes.

How to Use the Service Account Token

To use this Token while invoking any Harness API from the automation scripts, you need to pass it in the X-API-KEY header. 

X-API-KEY: sat.6187b7b3454a8772c2fa00f8.7QHqFTzJUaUnDVJ76UYv

This format of API Key Token is a result of deep discussions and thoughts to integrate it with pattern-based fraud detection, request tracing, and rate-limiting poorly written automation scripts. We’ll discuss these in detail in another blog.

Conclusion

In this blog, we have learned about Service Accounts and their importance for CI/CD platforms to support large-scale automation. We have also learned about various tradeoffs in choosing the correct hashing algorithm to secure API Key Token-based access. You can read about how Cloud platforms such as GCP use Service Accounts.

It seems you like deep dive pieces! Why not read another? Learn more about Event-Driven Architecture at Harness, or A Data-Driven Approach To Quality Debt At Harness.