Principle of Least Privilege
- 19 min read - Text OnlyIn the InfoSec space, professionals have to draw a line of what they can trust and where they cannot, they then address and secure what they cannot trust.
Within this post, I will reference AWS for examples, AWS permits an ABAC model. However, it is possible to emulate an RBAC model within AWS's ABAC model.
As for Principle of Least Privilege, the idea is that instead of trusting a resource, client, or user with everything, only trust it with exactly what it needs to function.
For example, instead of trusting a user and password with full access to all resources in the cloud account, a security engineer would
- By default deny all access to all resources
- Specify policies which:
- Enumerate resources or resources with wildcards which access is granted
- Specify actions or scopes which may apply to resources afforded
- Optionally constrain actions or resources with conditions
- Link these policies to network, compute, storage, and identities
At the end with the principle of least privilege applied, the application would have no privileges for resources it has no requirement for.
Example Application
As an example throughout this post, let's consider an application that users upload images to for forum avatars. The application would then upload the processed images to an object store with public access, and track the resources and who they belong to in a database. At the users request, these images may also be deleted or replaced. It may also automatically use Gravatar to find a default image to use for a forum user.
It would look something like this in the AWS space.
┌──────────┐
│ │
│ Database │
│ │
└──────────┘
▲
│
│
┌────────────────┐ ┌─────┴───────┐ ┌──────────────────┐
│ │ │ │ │ │
│ Load Balancer ├─────►│ Application ├────────►│ Images S3 Bucket │
│ │ │ │ │ │
└────────────────┘ └─────────────┤ └──────────────────┘
│
│ ┌──────────────────┐
│ │ │
└────────►│ DB Credentials │
│ │
└──────────────────┘
We have a public load balancer, an application, a database, an AWS resource for saving images, and some credentials.
Let's also assume that the application and database are in a Virtual Private Cloud (VPC) together, which can be thought of like as an internal network for resources, appliances, and services. While the load balancer is also on the VPC, it has a public facing IP address and therefore can be contacted from outside the VPC.
To access the database, the application must present credentials, which are stored separately from the application. So, before the application can connect, it would get the credentials from Secrets Manager, or Simple Systems Manager Parameter Store. In this case, Secrets Manager is used. Thus the application first retrieves the secret from Secrets Manager using its Principal to authenticate with the service, and then presents those credentials to the database.
When users use this example service, the application will store the original and modified contents in the object store S3. It may also need to delete objects. So it will need permissions for that too. Finally, it may also ask Gravatar, an external service, for a default avatar to use once it has some identifying data from the user.
Principal
Now, I mentioned a keyword a few times: Principal. Like Capitol and Capital, the word principal has no relation to principle.
Key Security Concepts | Microsoft DocsA principal represents the identity and role of a user and acts on the user's behalf.What is really a Principal in .NET - Stack Overflow
When authorizing access to a resource or the ability to run some code, it is not sufficient merely to know which user is authorizing the action, but under what role they are authorizing it. Think of this as being roughly equivalent to when you elevate a shell: the shell is now running under a different principal (with more privileges), even though the identity of the principal is still the same (your user account). The IIdentity
type is focused around issues of authentication, i.e. establishing that an identity known to the system actually belongs to an agent that wants to act under that identity. This is a necessary prerequisite for authorizing anything, but is not the whole story.
In AWS: a role may have multiple policies. A policy has multiple statements. A statement Allows or Denies actions upon resources and may be subject to additional conditions that constrain the effect of the statement and or policy.
Applications deployed in AWS typically use the machine's identity which is tied to a single role at the management layer. Whereas applications outside of AWS typically rely on an AWS user. An AWS User can be assigned to groups, and have roles attached to the user. An AWS User Group can have multiple roles associated. There may be delegating ways to not use users, but I have not personally done this exercise.
Now, you may be thinking, I access stuff all the time, as a user, without specifying what roles or permissions I have. AWS's Identity and Access Management (IAM) style does not require the application to select the role it uses. Instead AWS IAM creates a Principal just in time with the identity which contains all roles tied to the identity. But to actually authorize the request, all applicable roles in the principal are explored, and evaluated, and a determination is made to allow or deny the action upon the resource.
The behavior of how Principals are formed differs wildly across public clouds. For example, Google Cloud requires declaring scopes up front when requesting an OAuth bearer token. The JWT bearer token that comes back becomes the principal, identifying who or what is executing a call to a resource, and for what permissions and constraints it has when accessing resources.
Service Privileges
Back to AWS, what would the policy look like for this application? Remember, this application's needs are
- Save or Delete image assets in an S3 bucket, this maps to
s3:PubObject
ands3:DeleteObject
- Image assets uploaded should be made public, this maps to
s3:PutObjectAcl
- Retrieve the credentials and connection details for the database which is
secretsmanager:GetSecretValue
Therefore:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::example-images-bucket/*"
},
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:us-east-1:555555555555:secret:database-secret"
}
]
}
Once this policy exists, a role can be created with this single policy. Then the application instance can be provisioned with this role attached.
The above example doesn't truly demonstrate the "Attribute based access control", but it does show how least privilege can be enforced. Conditions like: Allow buckets * with tag team=developers
and environment=production
would make this more attribute-like.
Network Privileges
While the application is now restrained as far as AWS's resources go, this isn't the end of the story. The network is wide open between all networked resources!
The application and database appliance may accept connections from any networked resource in the virtual private cloud (VPC). Unless security is configured to be deny by default.
To make these resources fit the principle of least privilege, we should constrain their network access! Specifically the application and database network access.
This is performed with Security Groups in AWS. And in fact, there's a really neat feature in Security Groups, they can reference one another!
In this example, suppose the following security groups are created
sg-🍐
- The Load Balancer, with rules such that- Allow
TCP
port80
from * - Allow
TCP
port443
from *
Which in summary means anything can access this resource over TCP with ports 80 and 443.
- Allow
sg-🍋
- Access to the application, as a reference, no rules are set.Which on its own does nothing, but when applied to a resource is a tag that other rules can reference.
sg-🍊
- The Application, a rule is set such that- Allow
TCP
port80
fromsg-🍋
- Allow
TCP
port443
to *
Which in summary means that anything with the
sg-🍋
security group is permitted to contact this resource over port 80. No other resources, IPs, etc. have been permitted to contact it. The application must contact S3 over HTTPS, as well as Gravatar. So HTTPS (port 443) access is granted to all addresses.- Allow
sg-🍏
- Access to the database, as a reference, no rules are set.Which on its own does nothing, but when applied to a resource is a tag that other rules can reference.
sg-🍎
- The Database, a rule is set such that- Allow
TCP
port3306
fromsg-🍏
- Deny * to *
Which in summary means anything with the
sg-🍏
security group is permitted to contact this resource over port 3306 (mysql). No other resources, IPs, etc. have been permitted to contact it. It cannot contact any resources.- Allow
Visually, the security groups are applied as follows
- The load balancer has sg-🍐 and sg-🍋
- The application has sg-🍏 and sg-🍊
- The database has sg-🍎
┌───────────────┐
│ │ * sg-🍐
│ Load Balancer │ * sg-🍋
│ │
└───────┬───────┘
│
▼
┌─────────────┐
│ │ * sg-🍏
│ Application │ * sg-🍊
│ │
└──────┬──────┘
│
▼
┌──────────┐
│ │
│ Database │ * sg-🍎
│ │
└──────────┘
While you could assign a load balancer a specific IP address and in the application's security group sg-🍊
include that IP address as allowed to contact the application over port 80, this method can be fragile over time and can make migrations difficult. What if the load balancer appliance was at end of life and all services needed to be migrated to the next generation of load balancers without downtime? It would be tedious and error prone to repeat this process with manual IP copying and pasting on each security group. While it would be easy to just add sg-🍋
to the new load balancer and swap the DNS pointer.
Here we see an example of attribute based access control (ABAC). The security group sg-🍋
is an attribute of the load balancer. Given sg-🍊
permits connections from resources with this attribute, the access control model is in this instance attribute based.
Conclusion
The principle of least privilege is used in the infosec industry to rigidly define trust for applications, networks, and identities. There are many models to define trust, here we see that attribute based models afford a powerful and flexible approach to defining trust. While Amazon has many resources on the matter, their Principal method works for them but may not work for you. If you plan to implement your own system for authorizing applications (don’t in production), I recommend looking at Google’s documentation on mimicking theirs. That is, a step to acquire an attestation of authorization, which includes authenticating, and using the attestation with a service or relying party.