Last week, I presented a talk at fwd:cloudsec titled “It’s Time to Rethink the Shared Security Responsibility Model.” I argued that the balance of responsibility for securing cloud infrastructure environments has shifted too far in the direction of cloud security and development teams who are overwhelmed with configuration options. This imbalance, I posited, is a driving cause of many of the breaches we see in cloud environments today.
One theme that emerged is that cloud providers can do more to reduce the complexity of their environments and make small changes to their default settings across the services they offer. Integration of security callouts, action items, tooltips, etc. can go a long way to reducing developer mistakes. To help illustrate this point further, I’ve dug through the AWS console and put together a list of changes that I believe could have the most impact, while not requiring significant* investment from AWS.
*Please note that I do not have visibility behind the scenes into AWS’s environment, of course, so these are merely meant as suggestions to evoke thought around this topic.
1. Extend the default CloudTrail that is enabled for all new accounts to 365 days of retention. The built-in default of 90 days is not sufficient for proper long-term post-exploitation analysis, should the need arise. Users should always configure their own CloudTrail trails, but many don’t until after a security incident, so the default trail is an important part of the initial account security posture. (Edit: a previous version of this post incorrectly stated the default as being 7 days. This was inaccurate - the default was changed to 90 days.)
2. Make file integrity checks for new CloudTrail logs “always-on” (i.e. remove the option to disable the feature). I’ve never heard any security team, when given the option, say “No, I’d rather not know if my logs have been tampered with.”
3. Make configuring an MFA device for the root user part of the signup process for all new accounts. A phone number is already required for the initial billing setup, so it’s not too big of a leap to enable, at a minimum, SMS-based 2FA if true device-based 2FA is too impactful on signup completion rates. SMS 2FA has its own set of security concerns, but it’s better than the default of “nothing” in place today.
4. Disable the ability to add access keys to the root account. The root account has not been recommended for day-to-day use for nearly a decade; why provide capabilities that allow it to be used as such?
5. Ask users to pick a region at the time of account setup and disable all the others. They can be enabled later when needed. A majority of AWS users will likely never deploy services in more than 1–3 regions; the rest are just added surface area for attackers to remain undetected.
6. Display a warning in the console UI when creating new IAM users or access keys, suggesting users create roles instead.
7. Allow the creation of IAM access keys that expire automatically after a set period time (note: this is not the same as IAM roles which have rotating credentials with a session token). I can’t count the number of times I’ve created an access key simply to test a script from my CLI and never used it again after 5 minutes. Users still use keys because they’re simpler to generate from the UI than IAM role session credentials, but they often wind up sticking around for much longer than anticipated.
8. As an alternative to #7, allow users to generate temporary credentials for an IAM role from the UI to reduce the usage of IAM user access keys. This can already be done via the STS API using the AWS CLI, but a UI option would be a nice addition for those with the right permission.
9. Enforce the usage of MFA for new IAM users with console access by default. Make this an account setting that the root user can disable if necessary. We can already require users to reset their password when signing in, why not also enforce the requirement of an MFA device? Side note: MFA enforcement can be done via an IAM policy condition, but responding to a sign-in attempt with an error message isn’t the same as having a nice UI allowing the user to configure their own device on first sign-in.
10. Set the IAM password policy to something more secure by default. The default configuration simply requires six characters.
11. Highlight IAM users that have only been used from within AWS (and recommend they be converted to IAM roles). The Access Advisor tool is a good start; a new capability could be to locate IAM users who have only accessed the AWS APIs from another AWS service (EC2, Lambda, etc.) based on CloudTrail data and provide callouts/steps to convert the user to a role.
12. Stop setting “Launch Wizard” security groups to “0.0.0.0/0” — use the “My IP” option instead.
13. Add warnings to the security group UI when setting any non-web ports to allow inbound traffic from “0.0.0.0/0”.
14. Remove the “Anywhere” option from the drop-down menu when creating security group rules for non-web ports. Users can still type “0.0.0.0/0” manually, but the “Anywhere” option makes it too easy to over-expose resources.
15. Add a “Public” icon next to all security groups that have rules exposing them publicly.
16. Highlight IAM roles with wildcards or cross-account access in trust policies from the IAM overview page.
17. Highlight IAM roles with wildcards in policy statements from the IAM overview page.
18. Create a new IAM dashboard (or filter) for unused principals allowing for quick bulk disabling of unused users and roles.
19. Allow the root user to define a list of services that aren’t permitted for use. This can be done at the Organization level via a Service Control Policy, but I suspect that many compromised AWS accounts are individual user accounts that don’t belong to an Organization and were created for a single purpose (such as hosting a blog). During the account setup policy the root user should be able to define what services they wish to use and the others should be disabled by default.
20. Enable transfer lock for new domains registered with Route53 by default.
21. For new CloudFront distributions, make “Redirect HTTP to HTTPS” the default.
22. Update the default VPCs provided in every region to use a proper public/private tier architecture. The built-in default VPC is configured so that every subnet is essentially public. Services deployed in the private tier will not have internet access, but a prompt can enable easy creation of a NAT Gateway.
23. Better yet, remove the default VPCs entirely. They’re too often a source of spaghetti infrastructure where everything gets deployed with access to everything else. Require users to define their own VPCs or subnets during the creation of the first set of services. Again, a helpful “wizard” UI can keep this process smooth.
24. Remove the ability to make S3 buckets public for every new account. I’ve written about this before, but I believe the best way to stop having buckets publicly exposed is to completely remove the ability to make them public and create an entirely new service (e.g. “S3 Public Endpoints”) for the purpose of exposing bucket contents if absolutely required.
25. Enable a “Compliance Mode” for PCI, HIPAA, NIST, and other supported compliance programs in which AWS services that are not currently in scope are disabled. Finding which services can and can’t be used today requires extensive reading of documentation and usage of third-party tools.
26. Automatically disable Route53 entries that point to S3 buckets when the bucket is deleted. This protects against the possibility of a sub-domain takeover. If that’s too heavy-handed, add a prompt to the S3 console asking if the user would like to delete the domain during the bucket deletion process.
27. Replace plaintext CloudFormation values for known-sensitive configuration parameters with “***” in the response APIs. Many CloudFormation templates have hard-coded secrets because they support things like RDS “MasterUserPassword”. These values are then forever exposed in the UI and APIs for CloudFormation. Instead, AWS could recognize when plaintext values are passed for a set list of parameters and replace them in the API response with either “***” strings or a link to a dynamically-generated Secrets Manager secret.
These changes are just a start; there are many other places throughout the UI and APIs where security can be more tightly integrated. Some of these changes may require some moderate consideration behind the scenes, but hopefully simple tweaks to default values and more helpful UI warnings can begin to shift developer behavior towards a more secure cloud configuration, while maintaining flexibility and configurability where required.