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.
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:
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.
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.
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:
Let’s understand both of them in detail.
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.
A good hash function must adhere to the following criteria:
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.
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
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.
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.
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.