How to avoid privilege escalation in AWS? - amazon-web-services

I'm trying to figure out how to implement three contradicting requirements in AWS
Have a few admins with privileged access to IAM, Lambda, VPC, RDS and EC2.
Keep secret data in SSM Parameter Store that no one except my app can read.
Let admins create and deploy my app.
Things to keep in mind - since my app should be able to read the secret there is an IAM role and policies that grant access to it.
I can deny admins access to the Parameter Store. But that would not stop them from assuming my app role and reading the secret data. What makes it worse is many ways to assume role:
AssumeRole API.
Create EC2 Instance, assign role, login and read secrets under EC2 instance role.
Same with AWS Lambda.
If I deny access to the role they can Create a new role with right set of policies.
If I deny access to policies then they can replicate them.
If I deny access to IAM admins cannot do their job.
Given that many privilege escalation paths how do I protect secret data in AWS?

Related

Can AWS IAM roles be used for app running outside AWS?

So I think that the simplest solution is my problem is to use AWS for everything but I wanted to understand what is possible:
I understand that IAM roles can be associated with an AWS service such as EC2 or Lambda so that an application/function running within that service can retrieve credentials to sign API requests to other AWS services.
I have a previous application running on Heroku and using Amazon S3. Currently I have an IAM user set up for this application which signs requests to the AWS API using the access keys associated with the IAM user account. I think that best practice is to use an IAM role rather than a user for application source code AWS API calls, however is it possible to set this up for the application hosted outside of AWS or would I need to migrate the application to AWS EC2 in order to use IAM roles?
It doesn't matter where the application is hosted but to assume an IAM role you will need IAM credentials (chicken and egg). Typically you would design a secure way for your app to retrieve these base credentials. This is one disadvantage of running your compute outside of AWS (because it can't automatically assume an IAM role).
One option would be to create an IAM user whose only permissions were to be able to assume a given IAM role. Supply those IAM user credentials to your application, outside of AWS, securely and have the application assume the IAM role, ideally with an ExternalId that itself is also securely stored and securely retrieved by your application. Additionally, you can manage access to the IAM role, for example defining which principals can assume the role, and under which conditions.
AWS announced a new feature AWS IAM Anywhere that should help if you need to avoid using access/secret keys. It's more complicated but follows security best practices.
AWS Identity and Access Management (IAM) now enables workloads that
run outside of AWS to access AWS resources using IAM Roles Anywhere.
IAM Roles Anywhere allows your workloads such as servers, containers,
and applications to use X.509 digital certificates to obtain temporary
AWS credentials and use the same IAM roles and policies that you have
configured for your AWS workloads to access AWS resources.
and more here:
create a trust anchor where you either reference your AWS
Certificate Manager Private Certificate Authority (ACM Private CA) or
register your own certificate authorities (CAs) with IAM Roles
Anywhere. By adding one or more roles to a profile and enabling IAM
Roles Anywhere to assume these roles, your applications can now use
the client certificate issued by your CAs to make secure requests to
AWS and get temporary credentials to access the AWS environment.
AWS Announcement: https://aws.amazon.com/about-aws/whats-new/2022/07/aws-identity-access-management-iam-roles-anywhere-workloads-outside-aws/
User Guide:
https://docs.aws.amazon.com/rolesanywhere/latest/userguide/introduction.html
From Heroku docs:
Because of the sensitive nature of your S3 credentials, you should never commit them to version control. Instead, set them as the values of config vars for the Heroku apps that will use them.
Use the heroku config:set to set both keys
heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy
Adding config vars and restarting app... done, v21
AWS_ACCESS_KEY_ID => xxx
AWS_SECRET_ACCESS_KEY => yyy
The above is in line with AWS's own best practices for managing AWS access keys, specifically not embedding access keys directly in code.
You can't use IAM roles in the sense that it is picked up automatically by AWS, outside of AWS, without specifying credentials specifically.
Your next best option is environment variables (as detailed above), specifying the access key ID and secret access key for a user with a role granting the least privilege required for the files they need to read from S3 e.g. specific bucket name, specific files, even specific IP addresses if possible, etc.

Is it possible to access Redshift with an IAM role from another account? how?

We’re trying to implement Redshift with authentication via SAML.
In our case, we have many AWS accounts and the Redshift cluster is in one of them. We need to viabilize the access via roles from these accounts to the one that hosts the cluster. Discarding the necessity of having to manage user/password.
The way we implemented it’s already possible to login using IAM roles, but we still need the cross-account.
Does anyone knows if it's possible ?
Since you already have signin working with IAM roles, the process would be:
Amazon Redshift in Account-A
IAM Role (Role-A) in Account-A that has:
Permission to access Redshift via IAM (I think it's just permission to call GetClusterCredentials?)
A Trust Policy allowing the Role to be assumed by specified other accounts (or specific roles in those accounts)
Other accounts wanting to access Redshift will:
Call AssumeRole() to assume Role-A
Use the returned temporary credentials to access Redshift using Role-A
Thus, Redshift only ever sees a login being requested from Account-A.

Why is Role switching not allowed when logged in as AWS root user?

As per AWS documentation here - You cannot switch roles when you sign in as the AWS account root user.
If we go by AWS best practices i.e. not to use root user to perform actions, this restriction makes sense & supports why AWS does not allow role switch as root user. However, when using a Bucket policy, a root user in one account can access a Bucket in another account & AWS does not seem restricting that unlike roles (Technically, both are cross account actions using resource policies).
Why does this 'root user restriction' apply only for roles and not buckets - Any security reasons?
Access to services is normally granted via IAM permissions on IAM Users, IAM Groups and IAM Roles.
Some AWS services also permit the creation of policies that can grant access to aspects of that specific service. Examples are:
Amazon S3 bucket policies
Amazon SQS queue access policies
Amazon SNS access policies
These policies can be used to grant cross-account access, and also unauthenticated access such as public access to objects in Amazon S3 buckets and the ability to send unauthenticated messages to an Amazon SQS queue.
These policies are used to grant additional access. They do not involve "assuming" any additional roles.
I think there is some misunderstanding on the use of roles and a bucket policy with external account's root as principle.
The roles are meant to be temporary assumed, for someone or something that normally does not have permissions for some action. This could be a user or service from same or different account.
However, when you use other account's root in a bucket policy principle, you are giving that account permanent (until manually revoked by you) trust to the bucket for all or some actions on it. You use root as the principle so that the owner of the other account can delegate access to its own users or roles. You fully trust the other account to manage the access to the bucket without your involvement.
Off course if you are not comfortable giving such trust to the other account, you can limit access to you bucket to a given IAM user or a role only. This will obviously limit the ability of the owner of the other account to delegate access to your bucket.

What are the benefits of sharing an IAM role instead of a IAM key?

I'm told sharing IAM roles with third parties is more secure than sharing IAM keys. Currently we limit IAM keys with IP filters, many conditions on access control.
Why would sharing IAM roles be better. My understanding is they can use their role to assume privilege for a time limited period from something like the boto3 api. But if they can assume the role without limit, how is there a security benefit over a key?
First, as you mentioned, the short-lived session credentials used by a role limits the time that compromised credentials can be used.
Second, with an IAM user, any time the third party needs to access resources in your account, they must posses the access key and secret key of your IAM user. If they want to access resources from your account from an EC2 instance, they need to have a way to securely push the keys to the EC2 instance. If they want to access resources from a Lambda, they need to make the keys available to the Lambda. If they want to access resources from a mobile device, they need to push the credentials to the mobile device (where they are more difficult to secure, let alone rotate).
Managing these credentials is not only additional work for the third party, but also additional risk for you. The long-lived credentials for your IAM user are now being passed around by a third party.
Using an IAM role instead, you can allow the third party to access resources without passing your credentials around. An EC2 instance can avoid handling your credentials using EC2 instance roles. Lambda, similarly, can avoid handling your credentials by using execution roles. On a mobile device, there is Cognito.
To grant an external party access to the AWS resources owned by you, you have following options:
[WORST APPROACH] You create an IAM user (say, Foo) and grant it the required permissions and then share the same with the external parties. This is obviously the worst approach as now you have no segregation between who is making calls to your resources because in effect, it is always Foo who is calling you.
You let your clients create IAM users in their own accounts and then whitelist them in your resource's policy. This works, given that your resource supports resource-level policies (S3 and API Gatewaydo). Now, even if they do support resource-level policies, now it is an overhead for you to whitelist all such users created by all your clients, which can access the resource.
You create an IAM role, grant it capabilities (in terms of IAM policies) to access your resource and then whitelist your clients' IAM users to assume that role. This will be your way of saying that "this role is capable of accessing my resource and if you can assume this role, so do you". Moreover, this also prevents you from sharing the credentials as AWS STS does all that work in generating the temporary credentials for you.

Restrict access to S3 based on EC2 Instance and User

I have seen in earlier posts that I can restrict access to S3 bucket using the EC2 instance IAM Role. But the catch here is, if I have an account with several users in it, I cannot restrict the use of an IAM role to a particular group or individuals within that account. This inability prevents me from blocking anyone in that account to spin an instance using that IAM role.
So my dilemma is, if I have given S3 access based on EC2 Role and cannot lock down the users within an account who can use that role, this opens my S3 bucket to everyone in the account.
Please let me know if there is a way I can, either
(1) Restrict EC2 instances getting spun up using a particular role, OR,
(2) Restrict S3 access based on EC2 Role AND user logged into the instance.
Launching an Amazon EC2 instance with an assigned requires the PassRole permission, which can further specify which roles can be passed to the instance.
By default, you should not give anybody the PassRole permission. You could then assign it to appropriate Users/Groups, specifying exactly which roles they can use.
This avoids the chance that a User within limited permissions can gain extra permissions by launching an instance with a Role, and then using the temporary credentials granted to the instance to do activities beyond their assigned permissions.
This is similar to the AssumeRole permission, which controls who is allowed to assume which roles.
For more information, see: Granting Permission to Launch EC2 Instances with IAM Roles (PassRole Permission)