EC2 instance using the wrong user when executing PHP code - amazon-web-services

I have a ec2 instance with a role attached to it. The role is called webserver and has all the relevant policies attached to it.
I am trying to invoke my lambda function from my PHP code, but I get the following error:
Failed attempt at deleting data/ account: exception 'Aws\Lambda\Exception\LambdaException' with message 'Error executing "Invoke" on "https://lambda.eu-west-2.amazonaws.com/2015-03-31/functions/blahFunction/invocations"; AWS HTTP error: Client error: `POST https://lambda.eu-west-2.amazonaws.com/2015-03-31/functions/blahFunction/invocations` resulted in a `403 Forbidden` response:
{"Message":"User: arn:aws:iam::34234324324342:user/SecretGuy is not authorized to perform: lambda:InvokeFunction on resour (truncated...)
AccessDeniedException (client): User: arn:aws:iam::34234324324342:user/SecretGuy is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:eu-west-2:34234324324342:function:blahFunction because no identity-based policy allows the lambda:InvokeFunction action - {"Message":"User: arn:aws:iam::34234324324342:user/SecretGuy is not authorized to perform: lambda:InvokeFunction on resource: arn:aws:lambda:eu-west-2:34234324324342:function:blahFunction because no identity-based policy allows the lambda:InvokeFunction action"}'
Now SecretGuy is a user I created a long time ago, and somehow my ec2 is trying to use that.
I am wondering if anyone can help with this?
Thanks

From my understanding, you are running PHP code on an EC2 instance, and your code invokes the Lambda function.
And this EC2 instance has attached IAM Role with proper permissions to invoke the Lambda function. Then you tried to run your code and faced that the EC2 instance is using an unexpected IAM identity(IAM User named SecretGuy here), not the role you attached.
There's a chance that you might have IAM credentials set by environment variables for that Linux user or static credentials set on your EC2 instance.
AWS SDK client has an order to retrieve credentials on the machine. The official docs of PHP AWS SDK say,
When you initialize a new service client without providing any credential arguments, the SDK uses the default credential provider chain to find AWS credentials. The SDK uses the first provider in the chain that returns credentials without an error.
The default provider chain looks for and uses credentials as follows, in this order:
Use credentials from environment variables.
Setting environment variables is useful if you're doing development work on a machine other than an Amazon EC2 instance.
Use the AWS shared credentials file and profiles.
This credentials file is the same one used by other SDKs and the AWS CLI. If you're already using a shared credentials file, you can use that file for this purpose.
We use this method in most of our PHP code examples.
Assume an IAM role.
IAM roles provide applications on the instance with temporary security credentials to make AWS calls. For example, IAM roles offer an easy way to distribute and manage credentials on multiple Amazon EC2 instances.
To retrieve IAM credentials from the role attached,
You can check which IAM Identity you are using to call AWS API with the below command on the EC2 instance. (as that Linux user, you are running PHP code)
aws sts get-caller-identity
Then it will show result as below,
{
"UserId": "ABCDEFGHIJKLMNOPQRSTU",
"Account": "34234324324342",
"Arn": "arn:aws:iam:: 34234324324342:user/SecretGuy"
}
Then you need to look for environment variables set or static credentials files on that EC2 instance.
My guess is maybe someone used aws CLI on that EC2 before, with SecretGuy credentials, So there would be a file $HOME/.aws/credentials.
If the file exists and is confirmed as a SecretGuy access key, you have to delete that file. (If EC2 runs some critical application, you might want to copy all permissions of SecretGuy to the IAM Role you attached before deleting it to avoid unexpected service outage)
Or, you can look for environment variables.
echo $AWS_ACCESS_KEY_ID
If the above commands return the access key id value, you might have to unset environment variables.
After that, your code will retrieve credentials from IAM Role.

Related

AWS Boto3/Botocore assume IAM role in ECS task

I'm trying to create a botocore session (that does not use my local AWS credentials on ~/.aws/credentials). In other words, I want to create a "burner AWS account". With that burner credentials/session, I want to setup an STS client and with that client, assume a role in order to access a DynamoDB database. Can someone provide some example code which accomplishes exactly this?
Because if I want my system to go into production environment, I CANNOT store the AWS credentials on Github because AWS will scan for it. I'm trying to implement a workaround such that we don't have to store ~/.aws/credentials file on Github.
The running a task in Amazon ECS, simply assign an IAM Role to the task.
Amazon ECS will then generate temporary credentials for that IAM Role. Any code that uses an AWS SDK (such as boto3 for Python) knows how to access those credentials via the metadata service.
The result is that your code using boto3 will automatically receive credentials that have the permissions associated with the IAM Role assigned to the task.
See: IAM roles for tasks - Amazon Elastic Container Service

Insufficient access AWS whilst using AWS CLI

I've been trying to access a project in AWS devicefarm using AWS CLI.
Steps taken:
Downloaded the AWS CLI tool
Configured my credentials according to: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html using aws configure command
executed aws devicefarm list-uploads --arn myProjectArn
and what i get is this error:
An error occurred (AccessDeniedException) when calling the ListUploads operation:
User: arn:aws:iam::replacingANumber:user/myUserName is not authorized to perform: devicefarm:ListUploads
on resource:
arn:aws:devicefarm:us-west-2:replacingANumber:project:replacingALongString with an explicit deny
The docs:https://docs.aws.amazon.com/eks/latest/userguide/troubleshooting_iam.html say i'm missing permissions, but devOps team in my company says i have all the permissions.
What am I missing?
Either misconfigured AWS CLI or insufficient permissions.
This can be 2 things:
Your AWS CLI is misconfigured. Make sure that when you run aws sts get-caller-identity, you get the same role as the one that the devops team claims to have the correct permission. Also, make sure that your default region is us-west-2.
If the above is correctly setup, then it comes from the permissions defined in the IAM policy. If you are able to view the policy associated with your user/role, you can check out the policy simulator to figure out which permission is missing.

Why is iam:PassRole required in this project?

I cloned this solution azure-devops-on-aws and used dotnet lambda deploy-serverless ... to deploy the MyLizardApp to my personal AWS account.
During the learning curve, I created an S3 bucket my-lizard-test, IAM user group MyLizardGroup with user lizard-user and group policy MyLizardApp-Policy. Included in the policy are these services:
API Gateway (full access, all resources)
CloudFormation (full access, all resources)
Lambda (full access, all resources)
S3 (full access, all resources)
(Eventually) the deployment succeeded and I had a Lambda application serving the simple razor page showing the time.
I then copied the LambdaEntryPoint.cs, aws-lambda-tools-defaults.json and serverless.template files to my own dotnet core webapp (also a razor project) and attempted to deploy it to the same AWS account with the same command. The only changes made were the namespace of the LambdaEntryPoint class (reflected in the serverless.template file) and the .csproj file to include:
<AWSProjectType>Lambda</AWSProjectType>
and:
<PackageReference Include="Amazon.Lambda.AspNetCoreServer" Version="5.0.0" />
The dotnet lambda deploy-serverless ... command failed with the message:
User: arn:aws:iam::123456789120:user/lizard-user is not authorized to perform: iam:PassRole on resource: arn:aws:iam::123456789120:role/MyLizardAppServiceRole (Service: AWSLambdaInternal; Status Code: 403; Error Code: AccessDeniedException; Request ID: 12345678-1234-1234-1234-123456789012; Proxy: null)
I got the command to succeed by adding the IAM service to the MyLizardApp-Policy with the PassRole (all resources).
Why was this necessary for my personal app and not the demo solution from github? If the answer is not clear, what should I be looking for as differences? My personal app is not significantly different from the demo solution and I don't think the functional differences (in C#) would matter.
Whenever an AWS Service assumes (uses) an IAM Role, the service must have iam:PassRole permission to grant permission to use the Role. This required to prevent users from gaining too much permission.
For example, imagine a normal (non-Admin) user who launches an Amazon EC2 instance. When launching the instance, they can nominate an IAM Role to be assigned to the instance. If this user was permitted to select any IAM Role, they could select an Admin role and assign it to the EC2 instance. They could then login to the instance and use the credentials to make API calls as an Admin. This is an unwanted "privilege escalation".
Similarly, when an AWS Lambda function executes, it uses an IAM Role to obtain permissions. The iam:PassRole permission is used to control which roles a user can assign to the Lambda function.
So, there is something in that project that is trying to use an IAM Role and needs appropriate permissions.
First of all, we need to know what PassRole is:
iam:PassRole is the permission that controls which users can delegate an IAM role to an AWS resource.
As I can see in the repo, there is a file for CodeDeploy which already have credentials so maybe you are using CodeDeploy.
But btw, you are using an instances to deploy a Lambda function, and you need to pass the role to that Lambda so that is what PassRole do
AWS Services cannot directly assume service-linked roles. The role must be passed to the service by a user with the iam::PassRole permission.
The role-passing needs to be done only once, when a resource (e.g. EC2 instance) is created. After that the resource can assume the role repeatedly.
EC2 Instance profile is implemented this way. When a user launches an instance, it passes a role to the instance to act as an instance profile (it in addition needs iam:AddRoleToInstanceProfile for this case).
Other service-linked roles are also passed in this way.
Do not confuse it with the iam::CreateRole permission. A user may freely create service-linked roles, but is unable to pass the role to a service when needed.
In the management console, and to some extent in the CLI commands, role-passing is implicit, so you may encounter it without clear error messages when using non-root accounts.
As for why sometimes you need this permission, ands sometimes you don't, that is because when you use the root user, it will have AdministratorAccess which basically allows all actions on all resources.
If you create a new IAM user or account with blank permissions then you will need to add this permission manually.

CodeDeploy onpremise registration failing with AccessDeniedException on Amazon Lightsail

aws deploy register-on-premises-instance --instance-name XXXXX --iam-user-arn arn:aws:iam::XXXXXXXXXXXX:user/LightSailCodeDeployUser --region ap-south-1
An error occurred (AccessDeniedException) when calling the RegisterOnPremisesInstance operation: User: arn:aws:sts::XXXXXXXXXXX:assumed-role/AmazonLightsailInstanceRole/i-XXXXXXXXXXXXXX is not authorized to perform: codedeploy:RegisterOnPremisesInstance on resource: arn:aws:codedeploy:ap-south-1:XXXXXXXXXX:instance:XXXXXXXXXXXX
I didn't even create the role AmazonLightsailInstanceRole, then how did it come in the picture. My user have all permissions on codedeploy though. I am following this link to set up. https://aws.amazon.com/blogs/compute/using-aws-codedeploy-and-aws-codepipeline-to-deploy-applications-to-amazon-lightsail/
I made the same mistake and then realized that command is meant to be run on your local machine and not the instance!
AmazonLightsailInstanceRole is a service-linked role automatically created by aws:
Service-linked roles are predefined by the service and include all the permissions that the service requires to call other AWS services on your behalf.
The error you are getting is not about you not having the codedeploy:RegisterOnPremisesInstance permission.
The error is about the AmazonLightsailInstanceRole not having it. It does not matter if you (i.e. your IAM user) has all CodeDeploy permissions.
Normally you would add the missing permissions to the role. How to work with the AmazonLightsailInstanceRole is described in the following AWS documentaiton:
Using Service-Linked Roles for Amazon Lightsail
Editing a Service-Linked Role
However, I'm not sure if you can modify the AmazonLightsailInstanceRole and add the missing permissions. Some service-linked roles can be modified, some not.
The documentation is a bit confusing. Create a new user in IAM with admin role (full privileges) and use the credentials of that user to run the command in your local machine.

execute serverless deploy with aws role

I am trying to deploy a simple lambda funtcion with the serverless framework. My IAM user doesn't have the necessary permissions to run cloudformation:
User: arn:aws:iam::xxx:user/xxx is not authorized to perform: cloudformation:DescribeStacks on resource: arn:aws:cloudformation:us-east-1:xxx:stack/xx
That's more or less intended, since our setup is using IAM roles to perform certain tasks. I have configured those roles in my ~/.aws/config
file, and for aws cli operations I can e.g. call
aws s3 ls --profile myrole
in that way I attach all policies from the role 'myrole' to my IAM user to execute the aws-cli command.
Is there any way of doing something similar for serverless, i.e. attaching a role (not a different user) to the
serverless depoly
statement?
If I change the role via export
AWS_PROFILE=myrole
or call
serverless deploy --aws-profile myrole
I get Error: Profile myrole does not exist even though the role is defined in /.aws/credentials and ~/.aws/config
OK, I found a solution to get this working. Apparently you need to set AWS_SDK_LOAD_CONFIG to a truthy value, such that the Session will be created from the configuration values from the shared config (~/.aws/config) and shared credentials (~/.aws/credentials) files.
export AWS_SDK_LOAD_CONFIG=1
then execute with
serverless deploy --aws-profile myrole