Long-term cloud credentials are oftentimes (intentionally or accidentally) littered in source code, laptops/desktops, servers, cloud resources, etc. It’s easy for credentials to be copied across machines, creating sprawl that is at best, difficult to manage and at worst, unnecessarily increasing leakage risk.
Furthermore, these types of credentials are only necessary when non-cloud infrastructure resources need to communicate with cloud resources; for example, data center servers trying to use AWS S3 bucket. Generally speaking, there is no good reason to have long term credentials anywhere else—employees should instead use temporary credentials by authenticating with the SSO service.
All that said, it is a simple fact that credential leak remains a top culprit in breaches. The OWASP Top 10 Web Application Security Risks puts sensitive data exposure (including credentials) third in the overall list of risks.
Below, we’ll explore how security teams can use osquery to effectively track down and audit the location of long-term credentials across different locations like:
- Source code, binaries
- Configuration files
- Home directories for native cloud command line tools, etc
Using osquery to audit credentials
Osquery can be used to detect and identify credentials in all of these scenarios using Augeas, YARA and other built-in tables. Detecting credentials in users’ home directories can be done instantly using real-time or scheduled queries.
There are various kinds of AWS access keys. Access keys are 20 characters long and follow an uppercase-alpha-numeric format. The first four characters of the access key indicates the type of key. AKIA prefixed keys are long term keys that are of interest.
Prefix |
Resource type |
ABIA |
|
ACCA |
Context-specific credential |
AGPA |
Group |
AIDA |
IAM user |
AIPA |
Amazon EC2 instance profile |
AKIA |
Access key |
ANPA |
Managed policy |
ANVA |
Version in a managed policy |
APKA |
Public key |
AROA |
Role |
ASCA |
Certificate |
ASIA |
Temporary (AWS STS) access key IDs use this prefix, but are unique only in combination with the secret access key and the session token. |
AWS credentials are usually stored in users’ home directory .aws/config and/or .aws/credentials files. Using Osquery, it is trivial to identify AWS credentials across your entire fleet of assets using augeas table. Make sure to avoid gathering secrets using the WHERE clause.
WITH aws_config AS ( SELECT DISTINCT(directory || '/.aws/credentials') AS path FROM users UNION SELECT DISTINCT(directory || '/.aws/config') AS path FROM users )
SELECT * FROM augeas JOIN aws_config USING (path) WHERE lens = 'IniFile.lns_loose' AND label != 'aws_secret_access_key' AND label != 'aws_session_token' AND value != ''; |
When I target this query on my machine and run a real-time query, I get something like the following. It shows that I have config and credentials files.The config file has a region value us-west-2 in default section. The credentials file has two sections (default, production) and two credentials. Access key, Role ARN and expiration date are captured for the STS temporary access key. For a production profile, access keys start with AKIA prefix, and these are the keys we’re looking to identify.
Figure 1. Fleet-wide query results revealing an AWS access key and temporary access key ID. (Click to see larger version.)
Containers and container images
While this is useful for bare metal and virtual machines, what about containers and container images? We can query running containers (docker, containerd, lxd, cri-o) and container images by using system_type in the query clause which supports the following:
- host
- docker_container
- docker_image
- containerd_container
- crio_container
WITH aws_config AS ( SELECT DISTINCT(directory || '/.aws/credentials') AS path, system_type, system_id FROM users WHERE system_type IN ('host', 'docker_container') UNION SELECT DISTINCT(directory || '/.aws/config') AS path, system_type, system_id FROM users WHERE system_type IN ('host', 'docker_container') )
SELECT * FROM augeas JOIN aws_config USING (path, system_type, system_id) WHERE lens = 'IniFile.lns_loose' AND label != 'aws_secret_access_key' AND label != 'aws_session_token' AND value != '' AND system_type IN ('host', 'docker_container'); |
The following output shows that I have AWS credentials in one alpine container in addition to the host:
Figure 2. AWS access key and temporary access key ID discovered in an alpine container and its host. (Click to see larger version.)
Using YARA for extended auditing
What about access and secret keys that are baked into configuration files, source code, etc., and are not necessarily stored in the user's home directory? YARA can be used to monitor files and/or processes which have long term AWS access keys baked into them. Here is a sample YARA rule:
rule AWSAccessKey : AWS { meta: name = "AWS long term access key" author = "Seshu Pasam" strings: $key = /(AKIA)[A-Z0-9]{16}/ fullword condition: $key } |
This can be used to scan memory of existing and new processes launched on a machine. This rule can also be used to scan files and/or directories on an ad-hoc basis to identify matches.
Figure 3. YARA rules can be used to discover AWS credentials baked into configuration files, source code, and more. (Click to see larger version.)
Conclusion
Using osquery to audit and inventory long-term credentials offers a fast way for security teams to reduce the risk of credential leakage. For GCP service credentials and Azure access keys, Augeas, YARA, and ATC (automatic table construction) can be used to identify almost all types of credential patterns in a similar process as shown above.
Learn more about the features and functions of osquery in this comprehensive guide.