Understanding and Protecting local authentication for Azure services — Part 1
I recently started a series on protecting access in Azure. In a previous post, I covered anonymous access and protecting them. In this post, I will cover service-level (or local) authentication. Azure services that supports either key-based authentication OR local authentication.
There are about 30 services in Azure that supports some form of local (service-level) authentication and authorization. This can be “long-lived” access keys, temporary access tokens (sas), or local service credentials (usernames and passwords). These include storage and data services like Azure Storage and Cosmos DB, compute services like Batch and Service Fabric Clusters, container services like Container Registry and many more.
Because of the decentralized nature of these types of authentication, organizations experience difficulty in managing them securely at scale. Compromise of a single access key/token/local cred could lead to sensitive data leakage or a supply chain attack (in the case of app runtime services or services involved in the app deployment process like the container registry — ACR). Also, these authentication methods do not support MFA even though there are ways to add additional layers of protection if they need to be used and these will be covered in this series.
Considerations and Risk Assessment for Key-based and local authentication
There are certain aspects that should be considered when planning your protection strategy. Knowing these information will help you to assess the risk and take the right decisions in your approach. They include the following:
- Does the service support local (service-level) credential access?
- Possible impact if the cred is compromised
- Does the service also support identity-based authentication?
- Can local (service-level) credential be disabled?
- Does it support private network isolation/access?
- Can the service be assigned an identity (system or user assigned managed identity)? — The risk here is if the service supports a managed identity that is assigned privileged access to other resources and the local cred allows user-provided code to be executed, it can be leveraged to move laterally across the environment in the case of a compromise.
- Can the service execute user provided code?
- What permissions/roles have access to the cred?
- How do we monitor/detect usage?
In this blog series, I’ll cover these information for key services starting with the Storage service.
Service 1 — Storage Account
Local Authentication on Azure Storage
Access Keys — Every storage account resource has two long-lived 512-bit access keys that are auto-generated at creation time. The keys have full access to both the management and data planes of account services and resources. The permissions are pre-defined and cannot be limited in scope!
The following permissions can be used to gain access to the keys.
Microsoft.Storage/storageAccounts/listkeys/action
There are nine (9) built-in roles that have that permission — Owner, Contributor, Virtual Machine Contributor, Reader and Data Access, Storage Account Key Operator Service Role, Log Analytics Contributor, Logic App Contributor, DevTest Labs User, Disk Snapshot Contributor (not many people are aware that by granting a Logic App contributor or disk snapshot contributor role at a broad scope means granting access to the keys of all the storage account in the scope!)
Account, Service and User Delegation SAS tokens — The main use case for SAS tokens is to limit the scope of access for clients that cannot be trusted with the access keys. The following permissions can be used to generate SAS tokens but they are needed in addition to the permission to read storage accounts — Microsoft.Storage/storageAccounts/read
:
Microsoft.Storage/storageAccounts/listkeys/action
Microsoft.Storage/storageAccounts/listAccountSas/action
Microsoft.Storage/storageAccounts/listServiceSas/action
Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action
Microsoft.Storage/storageAccounts/revokeUserDelegationKeys/action
To ensure that an issued token has not been tampered with, SAS tokens are usually signed with an access key. Account and Service SAS tokens are signed with one of the storage account access keys. User Delegation SAS are signed with a dynamically generated User Delegation Key using an Azure AD credential.
Blob SFTP local users — This option allows cloud operators to create local users (up to 1000) with permissions to specific blob containers using a SFTP client. The authentication method can either be a password or a SSH keypair.
Operators can specify the level of access for the container which can be a combination of any of these — Read, Write, List, Delete, and Create. The supported permission scope is the container-level (Directory-level permissions are not yet supported. Permissions apply to all directories and subdirectories in the container).
Impact of compromise
- Unrestricted data plane access to storage account services — Blob (or Data Lake Gen 2), File, Table and Queue.
- The keys also grant permissions to configure service level properties like CORS settings, retention policy, etc. and to generate container/object level SAS tokens which can leveraged by in an attack chain for persistence (think of an attacker generating long lived SAS tokens to gain access through a backdoor)!
- Some Azure services (like Azure Function) store their “access keys” in a Blob storage container by default. This makes it a popular place to hunt for additional credentials that can be used to move laterally to other services.
- Can the keys be used to create SFTP users (backdoor)
Does it support identity-based authentication?
Yes. All storage account services support identity based authentication with RBAC for authorization (ABAC is in preview for the Blob service). Blob, Queue, File and Table services supports Azure AD auth. The file service supports AD auth.
The SFTP service does not currently support identity-based authentication via a SFTP client at the moment.
Can it be disabled?
Access Keys — Yes this can be disabled via the portal, CLI or using Azure policy.
- Portal: Storage Account → Settings → Configuration → Allow storage account key access
- CLI:
az storage account update -n $acct-name -g $resourcegroup --allow-shared-key-access false
- Policy: There is a built-in policy that can be used to enforce this — Storage accounts should prevent shared key access OR you can create a custom policy that assesses the following setting —
Microsoft.Storage/storageAccounts/allowSharedKeyAccess: true
.
SAS Tokens — Yes this can be disabled. Disabling access key usage also disables Account and Service SAS as the tokens issued are signed by the keys. To disable User Delegation SAS, please refer to this blog post that I did on this.
Blob SFTP local users — Adding users cannot be disabled but the option to use SFTP can be disabled which will remove the option to add local users.
- Portal: Storage Account → Settings → SFTP → Disable SFTP
- Policy: I tested this and the option does not exist yet which is understandable as the feature is in preview. I assume the setting will be
Microsoft.Storage/storageAccounts/isSftpEnabled: true
once it is added. I’ll update if it is not.
Does it support private endpoint?
Yes.
Can it be assigned an identity?
Yes — mainly for the service to access key vault to retrieve the encryption key in a customer managed encryption key scenario. I’ll highly recommend giving it explicit access (and not wide). Also, is this logged?
Can it execute user-provided code?
No. But services can be used to host code that could be executed elsewhere like in the case of the web service (which can host java script code that will be downloaded)
How do I detect usage in my environment?
- Azure Monitor metrics surfaces storage account transactions that use key-based auth (either long-lived access keys or time limited SAS tokens). You can filter the values “AccountKey” and “SAS” of the authentication property as shown below.
2. To get more detailed information about the transaction, you will need to have resource logging enabled for storage account services. You can filter for the identity.Type
property of the transaction record as shown below.
Implementing a protection strategy that scales
The challenge is to protect these credentials from malicious or unintended use in a way that is manageable at scale. An wholistic plan should include the following:
a. Disable usage where functionality is not impacted.
As a general good practice, it is important to enforce centralized “identity and access management” for all cloud service access using identity providers like Azure AD or AD.
Unfortunately, this is not always possible — in some cases due to the option to disable not being available and in some cases due to lack of support for centralized identity access. For example, out of all four Cosmos DB APIs, only two of them support Azure AD authentication with RBAC for authorization. The other APIs currently supports ONLY key-based authentication!
In other cases, the service might support disabling the option but your use case might still require it. For example, if you’re collecting NSG flow logs to a storage account, access key authentication and access is still required. Disabling it or rotating the access keys will actually break flow logging! The only way to fix this is to disable and re-enable NSG Flow Logs!
b. Implement a well-documented usage and distribution strategy that monitors and enforces regular rotation (Where disabling is not an option). The strategy should include the following key areas:
- Implement least privilege access to read the credentials from the resources.
- Implement centralized storage and usage with a secret/key management service like Azure Key Vault and granting access only to the apps or users that use it (if you’re using key vault, RBAC allows for more granularity than access policies). This should include monitoring your services and platforms to detect decentralized or insecure storage/usage of the creds in developer platforms/tools/services (Source control services like Azure Repos and GitHub Repos; Developer tooling like Azure Pipeline variables; Service configuration settings or environment variables for Azure app service, function apps, container instances, etc.)
- Enforce HTTPS only usage for SAS tokens (to protect against man-in-the-middle attacks)
- Implementing an expiration, notification and auto-rotation policy. The creds should be set to expire, near-expiry notification events sent and auto-rotation policy configured. This is possible with the service APIs as most support regeneration operations but you’ll need to work with your developers to test this workflow to prevent availability issues due to credential mismatch!
c. Implement additional layers of protection when disabling is not an option
For example, enforce private endpoint or private access for any resource that uses key-based auth or local service credential in your environment. There is very little valid reason to allow key-based authentication or local service credential over a public endpoint via the Internet!
d. Implement monitoring to detect usage (malicious or unintended usage) of key-based auth or local service credential in your environment
Azure monitor metrics or resource logs are great for this. We’ll cover for the services that we’ll discuss in this series.
e. Have a well-defined process to revoke compromised creds
I deliver beginner to advanced level Azure security training to organizations all over the world. Please reach out at david@chariscloud.com for engagement.