As more and more systems are migrated to the cloud, the old ways of remaining secure no longer hold up. Previously, securing the network perimeter, and the assumption that anything within that perimeter is trustworthy are outmoded and should no longer be used.
We therefore need a new solution to replace these out-of-date practices, and this is where Zero Trust comes in. Zero Trust is simply a set of principals used to secure modern cloud-based systems. The three core principals are:
- Verify Explicitly
- Use least privileged access
- Assume Breach
These three principals can be used as guides on how to secure cloud resources that can, in theory, be accessed from anywhere in the world by any person or device.
As an example, previously company servers could only be managed from the office where they were stored but with AWS and Azure, those servers live in the cloud and can be managed from any computer in the world. This means that securing access to those servers is paramount, as they contain the most valuable asset a company has, it’s data.
Initially when we started using AWS, we implemented named Identity and Access Management (IAM) accounts with AWS Managed polices, then, over time, we added Groups, progressing to custom IAM policies based on role, and for a long time this worked. But we don’t like to stand still, and we are committed to practising what we preach and that means Zero Trust. In a nutshell the rules of zero trust are – Always authenticate, limit access using Just-in-Time and Just-Enough-Access, and minimise the blast radius of breaches.
We have a policy of no public Remote Desktop Protocol (RDP) access to any of our servers (as this a very, very bad idea, just google “RDP Brute Force Ransomware” for some horror stories). So, to allow our developers and ops people to access virtual machines we decided to start using AWS Systems Manager to tunnel RDP traffic without exposing any ports to the internet (incidentally, in the Linux world we could do the same thing with SSH traffic). This also has the nice side benefit of logging the connection history so we can audit who was doing what, and when.
We also are very conscious of the bad practice of using admin accounts as their daily drivers, this is bad for a couple of reasons. One, if your credentials get compromised, your admin credentials and all the access that entails will be exposed, and two, accidents happen and clicking round in the console or mistyping a command can have some serious consequences. So, stopping admins from using their admin accounts for their daily driver account was another goal.
The benefits of moving to a Single Sign-On (SSO) based system:
- Enforced Multi Factor Authentication (MFA) as well as the advanced authentication features available in Azure AD.
- Quicker onboarding of new staff.
- Logging when and where people access the system from
- A more seamless login experience for our developers.
In our environment we have three main types of users:
- Administrators: Manage all the servers in AWS.
- General Developers: Create applications using IaaS resources.
- LightSail Developers: Create applications hosted only on LightSail infrastructure.
The plan was to create groups (and populate them with users) for the previously listed roles within Azure Active Directory (Azure AD), sync these into AWS, then assign polices to these users/groups so they can do their jobs.
The basic idea of how this all fits together is shown in the diagram below.
To start, we looked at how we could use our current Identity provider (Azure AD) to create users/groups in AWS. It turns out this is supported natively by AWS SSO. So, we setup our Azure AD tenancy to be the source of truth in AWS SSO and setup syncing.
The following three Azure AD groups, Admins, Developers, and Developers-LightSail were setup in Azure AD and populated with the appropriate users. These were then synced over to AWS SSO. Once these users and groups were synced over to AWS SSO, we had to create some permission sets to allow our users access to do their work.
Permissions were set up using AWS SSO policy sets. These contain a mixture of AWS managed policies such as “CloudWatchReadOnlyAccess” and custom policies defined in json.
For Developers we setup the following policy sets:
- Devs_SSM, to allow access, via AWS Systems Manager, to EC2 instances.
- Devs_Console to allow access to IaaS services in the console such as EC2, CloudWatch logs, and CloudFront, etc, etc.
- Devs_LightSail to allow access specifically to LightSail resources.
For administrators we created a policy set called Admins_RO, that had the AWS managed policy “SecurityAudit” attached, and a custom policy that allows for the assuming of different IAM roles with higher levels of access. This allows us to fulfil our second goal of least privilege in our daily driver accounts while still allowing administrators to assume a role with higher privileges when needed.
So, the theory all stacks up but how does this look in practice?
A user would navigate to the AWS SSO portal (https://company.awsapp.com/start) and sign in with their Azure AD credentials. They’re then presented with a list of the Accounts available to them.
They can either click Command line or programmatic access and are presented with a set of access keys that can be used with the AWS CLI or PowerShell tooling.
Or if they choose Management console, they’ll be taken to the main AWS console and from there they can access resources or go on to assume different roles.
? Bonus, the AWS CLI tool natively supports SSO using the “aws configure sso” command, so you can skip the AWS SSO portal login altogether and only use SSO in the CLI if you so desired.