Service Accounts in GCP – Notes from Production Environments
Need Help with your GCP Project?
Contact a certified professional GoogleCloudArchitect today.
Why Google Service Accounts?
Storing credentials in apps is cumbersome (and insecure). A Service account solves this problem - it is an identity that can replace your username / password - or any type of credential (for e.g. in your app.config etc). Think of server to server communication (typically, calling APIs). This requires IAM credentials on the GCP side - which has access to the APIs that need to called / resource that needs to be accessed. This is where service accounts play a crucial role - once defined, the private key can be downloaded and used on the calling server (e.g. a Service Now instance that needs to talk to GCP).
- For a custom SA, regular IAM Is used to control WHICH services an SA can access. No different from IAM that controls human users. This is for custom SAs.
- For built in SAs you can pick which APIs they are allowed to call, during the time of the resource creation.
Can you provide an example of a Service account versus a Human User in a real world scenario?
Say you want to create Folders (or Projects under a folder in GCP).
A service account can be used to create these resources (e.g. projects or folders - see sample terraform code below).
# IAC Service Account Roles for Creating Folders and Projects (using terraform)
iac_service_account_roles = {
owner = "roles/owner"
project_creator = "roles/resourcemanager.projectCreator"
folder_admin = "roles/resourcemanager.folderAdmin"
project_deleter = "roles/resourcemanager.projectDeleter"
} In addition, the service account may also (optionally) add HUMAN users as IAM bindings on the Folder created. These are two separate things. The second piece (the binding) allows a human user access to the resource created (Folder)
Use a combination of baseline roles (defined at the top org level or folder level) AND GCP service accounts at INDIVIDUAL project levels
Service accounts will be used for any project creation and will contain all the IAM bindings that are needed for projects.
Create an SA and create IAM Bindings (roles) for that service account. These roles can extend beyond the project in which the SA lives.
e.g. automation_service_account
Role Bindings — Org Owner, Project Owner, Security Admin
How Many Service Accounts?
If you have separate Deployment pipelines for your base infrastructure and for the apps, think in terms of a FEW Org management Service Accounts and PLENTY of application specific SAs. There is no reason to be stingy with service accounts - they are simply programmatic identities.
A Service Account to impersonate another Service Account?
Resources, applications, users, and even service accounts can all impersonate a service account. Impersonating a service account means that you are able to authenticate as the service account, and now have whatever permissions were granted to it. Logs will show any actions as being performed by the service account. It’s important to understand impersonation, because it could be used in unexpected ways in your environment to escalate privileges.
A Service Account for Short Lived Credentials?
SAs for short term credentials.
An SA to restrict operations (e.g. KMS)
Project Owners automatically get the role to create serviceAccount Keys
iam.serviceAccountKeyAdmin
Each LOB has a shared services. There is also a GLOBAL Shared Services.
One SA for each LOB. There will be one SA
Bindings — IAM Bindings, Resource Level Bindings
Service accounts can be bound to a resource or an identity.
When permissions are assigned to an identity, it’s called an IAM binding.
Bindings can be applied at every point of the hierarchy, and the permissions are inherited down.
When at the lowest level (resource level), the binding is called a resource level binding.
Impersonating Service Accounts - Service Accounts and Impersonation
Yet another technique allows other identities to impersonate service accounts. We don’t need to setup the Key as we would like to impersonate the service account and not perform the action as service account directly.
A service account in GCP is an identity that is provided to allow applications to authenticate and make calls to the GCP APIs.
It does not use passwords, but uses RSA keys to authenticate. If you are familiar with IAM roles in AWS, this is the same concept for GCP. When you assign a service account to a resource, Google automatically rotates the keys for you. This is better than having to store static credentials in your code.
One important concept to keep in mind for GCP is that a service account must be created in a project. However, a service account could be given bindings at a level higher than a project, such as permissions at the Folder or even Organization levels.
I will refer to these types of permissions as “elevated bindings.” These are dangerous, because the permissions at higher levels could give you access to other security controls, and all the projects under that structure will inherit the permissions.
Resources, applications, users, and even service accounts can all impersonate a service account. Impersonating a service account means that you are able to authenticate as the service account, and now have whatever permissions were granted to it.
Logs will show any actions as being performed by the service account. It’s important to understand impersonation, because it could be used in unexpected ways in your environment to escalate privileges.
Creating a project using a service account
You can use a service account to automate project creation. Like user accounts, service accounts can be granted permission to create projects within an organization. Service accounts are not allowed to create projects outside of an organization and must specify the parent resource when creating a project. Service accounts can create a new project using the gcloud
tool or the projects.create()
method.
Impersonating a service account
There are three ways to impersonate a service account to access Google APIs:
- Authentication using RSA private keys
- Authorization using Cloud IAM policies
- Deploying jobs on Google Cloud servicesImpersonating a service account
Access Scopes
The only thing stopping the default service account from being able to utilize all of its permissions are the “access scopes” assigned to the virtual machine. This is a control that dictates which APIs the service account is able to access. So, if the service account is granted access to the Storage API in the IAM policy, the account still cannot access the Storage API if the access scopes do not include the Storage API. Here is an example the access scope options available in the GCP console:
Shared Services Projects and Service Accounts
- Service accounts should be placed in a shared services project.
- KMS Keys also belong in this shared services project.
Compromise
If one of your workloads has been compromised while running the default service account and it also has full scopes enabled, then it could easily enumerate other service accounts in the same project, and even impersonate those service accounts. This is because the default service account has project editor permissions. Those permissions include the ability to impersonate other service accounts in that project.
If the same project contains service accounts with elevated bindings (permissions at the Folder or Organization levels), then that service account can be easily impersonated by the compromised workload. Once the workload is used to impersonate it, that account is now only limited by the permissions granted to the service account with elevated bindings. This could include adding new users, tearing down VPC Service Controls (or other security controls), and launching its own workloads.
An alternative to Service Accounts?
With each SA, you get a JSON key, which can be considered a long-term access key. The more Service Accounts you create, the more of these JSON keys you are left maintaining.
To avoid this multiplicity of JSON keys, you can also use tokens — or short lived access to GCP resources (usually, to built in service accounts).
Recommendations
Due to the dangerous nature of the default service account running with full scopes assigned, we recommend doing the following in your GCP environment:
- No wide scope service accounts (i.e. not spanning across multiple LOBs). Use ONE SA for each LOB.
- Designate a project that will be used for any accounts that require elevated bindings. Keep that project as secure as possible and do not populate it with any public workloads.
- Keep track of who or what can impersonate service accounts. If you lose track of this, privilege escalation becomes a much larger risk.
- Don’t use the default service accounts for your workloads. If your workload does not need to access GCP APIs, then remove the service account all together.
- Don’t create bindings that include primitive roles whenever possible. These are broad, and permissions should be more granular.
Leave a Reply