What exactly does this AWS role do?
The most relevant bits seem to be:
"Action": "sts:AssumeRole", and
"Service": "ec2.amazonaws.com"
The full role is here:
resource "aws_iam_role" "test_role" {
name = "test_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
From: https://www.terraform.io/docs/providers/aws/r/iam_role.html
To understand the meaning of this it is necessary to understand some details of how IAM Roles work.
An IAM role is similar to a user in its structure, but rather than it being accessed by a fixed set of credentials it is instead used by assuming the role, which means to request and obtain temporary API credentials that allow taking action with the privileges that are granted to the role.
The sts:AssumeRole action is the means by which such temporary credentials are obtained. To use it, a user or application calls this API using some already-obtained credentials, such as a user's fixed access key, and it returns (if permitted) a new set of credentials to act as the role. This is the mechanism by which AWS services can call into other AWS services on your behalf, by which IAM Instance Profiles work in EC2, and by which a user can temporarily switch access level or accounts within the AWS console.
The assume role policy determines which principals (users, other roles, AWS services) are permitted to call sts:AssumeRole for this role. In this example, the EC2 service itself is given access, which means that EC2 is able to take actions on your behalf using this role.
This role resource alone is not useful, since it doesn't have any IAM policies associated and thus does not grant any access. Thus an aws_iam_role resource will always be accompanied by at least one other resource to specify its access permissions. There are several ways to do this:
Use aws_iam_role_policy to attach a policy directly to the role. In this case, the policy will describe a set of AWS actions the role is permitted to execute, and optionally other constraints.
Use aws_iam_policy to create a standalone policy, and then use aws_iam_policy_attachment to associate that policy with one or more roles, users, and groups. This approach is useful if you wish to attach a single policy to multiple roles and/or users.
Use service-specific mechanisms to attach policies at the service level. This is a different way to approach the problem, where rather than attaching the policy to the role, it is instead attached to the object whose access is being controlled. The mechanism for doing this varies by service, but for example the policy attribute on aws_s3_bucket sets bucket-specific policies; the Principal element in the policy document can be used to specify which principals (e.g. roles) can take certain actions.
IAM is a flexible system that supports several different approaches to access control. Which approach is right for you will depend largely on how your organization approaches security and access control concerns: managing policies from the role perspective, with aws_iam_role_policy and aws_iam_policy_attachment, is usually appropriate for organizations that have a centralized security team that oversees access throughout an account, while service-specific policies delegate the access control decisions to the person or team responsible for each separate object. Both approaches can be combined, as part of a defense in depth strategy, such as using role- and user-level policies for "border" access controls (controlling access from outside) and service-level policies for internal access controls (controlling interactions between objects within your account).
More details on roles can be found in the AWS IAM guide IAM Roles. See also Access Management, which covers the general concepts of access control within IAM.
Related
Can a role be assumed if it does not have a Trust policy?
If a given IAM user has an attached identity based policy saying that he/she can call sts:AssumeRole for a given role (inside the same account), but the user is not described in the Trust policy of this role, will he/she be able to assume the role?
Usually only the resource based policy or the identity based policy should be enough to give rights for the user, but is it different for the roles?
Thanks
will he/she be able to assume the role?
Yes, of course she/he will be able to do it, as long the trust policy allows the account to assume the role. For example, a role has to have the trust policy of:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "<account-number>"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
This way, your IAM user does not need to be explicitly listed in the trust policy, but trust policy is required and at least you should specify the account which can assume it. But the drawback is that any IAM user or role from the <account-number> account that has sts:AssumeRole permissions can assume the role.
it does not have a Trust policy?
Trust policy is required, so you can't have a role without such such a policy.
Update
Lets assume you have a role with a trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::xxxxxx:user/UserA"
},
"Action": "sts:AssumeRole",
"Condition": {}
}
]
}
The role can be assumed only by userA. UserB will not be able to assume this policy, regardless of his permissions.
A Trust Policy specifies the "Principal" which can assume the role it is attached to. That principal can be various different types of entity, such as an AWS service (e.g. to create a role applied to EC2 instances), or the identifier of another AWS account (to grant cross-account access). It cannot be omitted or be a wildcard.
If the principal identifies an AWS account, then it is trusting the AWS account as a whole. In a sense, all users in that account have been included in the trust policy, but to assume the role they also need permission to make the appropriate AssumeRole API call. This delegates responsibility to the administrator of the other AWS account to decide which users should be able to assume the role.
This can be used to create a hierarchical arrangement of accounts:
All users are created in a single AWS account, which has no other resources.
The actual resources - EC2 instances, S3 buckets, etc - are in separate AWS accounts.
Each account defines roles granting access to some of these services, with a trust policy listing the central account as the Principal. These roles do not list individual users or groups as trusted, they just define sets of permissions.
The users in the central account are each granted AssumeRole access to an appropriate subset of the roles in the different accounts. The effect is similar to using Groups or Managed Policies to grant multiple users the same access.
I couldn't understand the use of IAM Passrole. Can anyone explain with simple example?
I am referring the page : https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_passrole.html but couldn't make much sense out it.
PassRole is a permission granted to IAM Users and resources that permits them to use an IAM Role.
For example, imagine that there is an IAM Role called Administrators. This role has powerful permissions that should not be given to most users.
Next, imagine an IAM User who has permissions to launch an Amazon EC2 instance. While launching the instance, the user can specify an IAM Role to associate with the instance. If the user — who is not an Administrator — were to launch an EC2 instance with the Administrators role, then they could login to the instance and issue commands using permissions from that role. It would be a way for them to circumvent permissions: while not being an administrator themselves, they could assign the IAM Role to a resource, and then use that resource to gain privileged access.
To prevent this scenario, IAM requires that the user be granted the iam:PassRole permission for the Administrators role. If the user does not have that permission, then they will not be permitted to launch the EC2 instance as described, or to assign that role to any other services. It gives them permission to pass a role to a service or resource.
Simply,
when the service B needs the ROLE
A has the iam:PassRole permission about the ROLE,
A can give the ROLE to B.
This is the permission granted for a user to be allowed to pass a role to a service during configuration, without this a user can not perform that binding. You can use this permission combined with resource Arns to limit what roles the user can pass to the service
If for example you have many applications with many different available IAM roles to choose from you might want to restrict the roles a user is able to pass to the service. You would be able to limit this scope using the below statements.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"iam:GetRole",
"iam:PassRole"
],
"Resource": [
"arn:aws:iam::<account-id>:role/EC2-WordpressRole",
"arn:aws:iam::<account-id>:role/EC2-DatabaseRole"
]
}]
}
In the above scenario there might also be a arn:aws:iam::<account-id>:role/EC2-AdminRole but because this role grants an EC2 host permissions this user should not be able to give to an EC2 it is withheld from the EC2 list by the person who configured the permissions.
I have two AWS accounts: an account that holds my secrets, an account for deployment of my cloudformation stack. I am using cloudformation to deploy my infrastructure as code and have a pretty simple CD pipeline:
deploy to my dev stack
wait for approval
destroy the dev stack
deploy to my production stack
EC2 instances created as part of my stack rely on the secrets during start up. I would like to add the secret ARNs to my EC2 userdata script then use the AWS command line to retrieve the secret value when the userdata script is executed.
The IAM service roles used by my EC2 instances are also created as part of my cloudformation script. As such, the IAM role ARNs are not known prior to the launch of the stack. I find myself in a bit of a catch-22: I cannot launch my stack until access is granted to my secrets, but I cannot grant access to my secrets because the Principal in the resource policy does not accept wildcards.
Does anybody know how I might be able to create a secretsmanager resource policy for my secrets which does not require the IAM role ARN to be known beforehand? Or perhaps any other ideas?
What may be a better alternative to specifying the principals in the resource policy is to use Attribute Based Access Control (ABAC, a.k.a tagging). There is a fairly detailed tutorial on setting this up for IAM policies which can be modified for resource policies.
In this approach, you would create your resource policy granting access to the other account, but only for principals with a given tag. Then when you create the roles in the other account you add tags to them for the secrets they need to access. For example, the resource policy below grants GetSecretValue to account 123456789012 only when the tag "access-project" has the same value for both the secret and the accessing role:
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal": {"AWS": "123456789012" },
"Condition": {
"StringEquals": {
"aws:ResourceTag/access-project": "${aws:PrincipalTag/access-project}"
}
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*"
} ]
}
After adding this resource policy to the secret, you would also add the tag "access-project" to both the secret and the user/role. Note that this only grants GetSecretValue. It is probably a bad idea to let the user modify the the secret or the tags on the secret, but if you need to do so you would also include the other conditions from the referenced tutorial. Of course, you could also hard code the tags in the resource policy if you do not want to add tags to the secrets.
In general, this approach is a lot easier to manage since you do not need to keep updating the resource policy every time you add or remove a user/role. You would just add or remove the tags from the users and or secrets.
The alternate way to do this is to just open up the secret to the entire account, and then within that account limit who can access the secret via IAM policies (possibly still using tags as in the tutorial). Cross account access requires both the resource policy granting access and the IAM user/role policy granting access.
What I am trying to do
Have a Lambda function access (with Read and Write permissions) a specific Bucket I own.
Just that one Bucket though, it doesn't need to access anything else.
What I've done
I set up a public Bucket (that's actually right, I actually want its contents to be accessible to anybody), named orca-resources
I created an IAM Role named lamba-s3-orca-resources. It is set up to be used by the Lambda service.
I created a Lambda function that will eventually be triggered by API Gateway
I wrote the least code I could to try and break my policies: I'm accessing another Bucket of mine, that is not explicitly allowed to be accessed by my lamba-s3-orca-resources IAM Role
Testing the function actually yields the contents of the Bucket I wish to be unavailable. Also, s3:listObjects ain't even in my Allowed Actions.
What am I overlooking?
The Lambda function
Its code:
'use strict';
const aws = require('aws-sdk');
const s3 = new aws.S3();
exports.handler = (event, context, callback) => {
s3.listObjects({Bucket: 'orca-exe'}, callback);
};
Its Execution Role:
{
"roleName": "lamba-s3-orca-resources",
"policies": [
{
"document": {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:GetObjectTagging",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::orca-resources/*",
"arn:aws:s3:::orca-resources"
]
}
]
},
"name": "orca-resources-only",
"type": "inline"
}
]
}
“AWS Lambda function seems to ignore its specified Execution Role”
In one sense, this is true and by design, because the details of the execution role aren't something that the Lambda service or your function are actually aware of. The Lambda function and the Lambda infrastructure aren't actually looking at or aware of the permissions associated with the execution role. Lambda isn't responsible for enforcing this policy.
There's a bit of black magic going on behind the scenes that stitches all of this together, and understanding how that works may help explain why the behavior you're seeing is expected and correct.
First things first, the Lambda Execution Role is an IAM Role.
Q: What is an IAM role?
An IAM role is an IAM entity that defines a set of permissions for making AWS service requests. IAM roles are not associated with a specific user or group. Instead, trusted entities assume roles, such as IAM users, applications, or AWS services such as EC2.
— https://aws.amazon.com/iam/faqs/
When you assume a role, you're issued a set of temporary credentials -- an access key and secret (similar to IAM user credentials) and a security or session token that conveys the associated privileges, all which must accompany these credentials when they are used for signing requests. In Lambda functions, this is all done automatically.
When your Lambda function is invoked, the Lambda service itself calls AssumeRole in Session Token Service.
AssumeRole
Returns a set of temporary security credentials (consisting of an access key ID, a secret access key, and a security token) that you can use to access AWS resources that you might not normally have access to.
— https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html
This action -- which is allowed by your role's trust policy -- returns a set of credentials that are dropped into the environment of your Lambda container as environment variables with names like AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN (with the specific names dependent on the environment).
The AWS SDK then automatically uses these environment variables to sign all of the requests you generate within your Lambda function.
Nothing in Lambda screens these requests against the role policy, for a couple of different reasons: that would be a much more complicated and vulnerability-prone solution, compared to simply allowing the normal authentication and authorization mechanisms of the destination service to authenticate and authorize the request... but perhaps more importantly, the Lambda service can't actually tell what actions your code is attempting via the AWS SDK because those requests are transmitted to the service endpoint over HTTPS by default, so it isn't possible for them to be inspected.
The service you're making a request against then authenticates the credentials and authorizes the request with help from IAM and STS -- determining whether the request signature is valid, the accompanying token is valid, and whether the attempted action against the specified resource is allowed.
That last bit is where your assumptions are blurry.
The question that then must be answered by the service handling the request is two-fold:
does the principal making the request have permission from its own account to make the request, and
does the principal making the request have permission from the account that owns the resource to make the request
These are two questions, but when the principal (the role) and the resource (the bucket) are owned by the same account, they can coalesce into a single question that is answered by combining the results from multiple places.
Access policy describes who has access to what. You can associate an access policy with a resource (bucket and object) or a user. Accordingly, you can categorize the available Amazon S3 access policies as follows:
Resource-based policies – Bucket policies and access control lists (ACLs) are resource-based because you attach them to your Amazon S3 resources.
User policies – You can use IAM to manage access to your Amazon S3 resources. You can create IAM users, groups, and roles in your account and attach access policies to them granting them access to AWS resources, including Amazon S3.
When Amazon S3 receives a request, it must evaluate all the access policies to determine whether to authorize or deny the request. For more information about how Amazon S3 evaluates these policies, see How Amazon S3 Authorizes a Request.
— https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-overview.html
This explains the apparently contradictory behavior, as you noted in comments:
“Also, the documentation here seems to pretty clearly indeed deny what's not explicitly allowed.”
The documentation is correct, and you're correct, except that you've failed to consider that what's explicitly allowed includes what the resource owner (the account owner for the bucket) has already explicitly allowed.
If the bucket owner has allowed everyone to perform a particular action... well, the execution role of your Lambda function is part of everyone. Therefore, a grant of access in the Lambda execution role policy would be redundant and unnecessary, because the account owner has already given that permission to everyone. The lack of an explicit Deny in the role policy means the explicit Allow in the bucket policy allows the proposed action to occur.
“Plus, the Policy Simulator does give me exactly the behaviour I expect.”
The policy simulator doesn't make real calls to real services, so it's necessary -- when a resource like a bucket has its own policies -- to explicitly include the policy for the resource itself in the simulation.
To use a resource-based policy in the simulator, you must include the resource in the simulation and select the check box to include that resource's policy in the simulation.
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html
Otherwise, you're only testing the role policy in isolation.
Note that there is some confusion in the documentation about the S3 policy for listing the objects in a bucket. The action for allowing this in IAM policies is s3:ListBucket in spite of the fact that the Node.JS SDK method call is listObjects(). There is an action in the policy simulator called ListObjects that is either part of planned/future functionality or simply an error, because at last check that didn't correspond to a valid IAM policy action for S3. In the S3 section of the IAM User Guide, s3:ListBucket is correctly hyperlinked to the List Objects action in the S3 API Reference, but s3:ListObjects is a circular hyperlink right back to the same page in the IAM User Guide (a link to nowhere). I've tried, so far without success, to find someone at AWS to explain or correct this discrepancy.
Let's assume a user-based IAM policy i.e. one that can be attached to a user, group or role.
Let's say one that gives full access to a DynamoDB table:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:us-west-2:123456789:table/Books"
}
}
Based on this policy, any user who somehow ends up with that policy attached to them (via assuming a role or directly for example) gets full access to that DynamoDB table.
Question 1: Is it worth having a resource-based policy on the other end i.e. on the DynamoDB table to complement the user-based policy?
Example:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:user/bob"},
"Action": "dynamodb:*",
"Resource": "arn:aws:dynamodb:us-west-2:123456789012:table/Books"
}
The motivation here is that the previous policy might end up being attached to someone by accident and using the resource-based one would ensure that only user Bob will ever be given these permissions.
Question 2: Is using the stricter resource-policy only preferable maybe?
Question 3: In general, are there any best practices / patterns for picking between user-based vs resource-based policies (for the services that support resource-based policies that is)?
Answer 0: DynamoDB does not support resource-based policies.
The Console GUI looks like it, but the API does not have an operation for that.
And the documentation is clear: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/access-control-overview.html#access-control-manage-access-resource-based
Answer 1: Do not use IAM and resource policies on the same resource
The challenge with access control is maintaining it over the long run:
Permissions for new hires must be set up correctly and swiftly (they want to work!)
Permissions for leavers must be removed swiftly (for whatever reason)
Someone has to regulary review the permissions and approve them
All of the 3 tasks above are much easier, if there is only a single location where to look for. And use "Effect": "Deny", if you want to restrict access.
Any "accidental assignment" would be caught by the review.
Answer 1b:
Of course it depends on the use case (e.g. 4 eyes principle can demand it). And some permissions cannot be set in IAM, ( e.g. "Everyone") and must be set on the resource. Or if you destroy/recreate the resource, the resource-based permission disappears.
Answer 2: IAM policy is easier to manage
If the situation allows both IAM and resource policy, they have the same grammar and can be made equally strict, at least in your case. Assuming all other being equal, IAM policies are much easier to manage.
Answer 3: Best practice
Unfortunately, I am not aware of a best practice issued by AWS, apart from "minimal privileges" of course. I suggest you go with the best practice in terms of maintainability as for other permissions outside of AWS.
It depends whether you are making a request within same aws account, or a cross-account request.
Within the same AWS account, meaning your user belongs to aws account that owns the resource (S3, SQS, SNS etc), you can have either identity-based (user, group, role) OR a resource-based policy (SQS, SNS, S3, API gateway). Reference: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow
However when you are delegating access to different AWS accounts. It can vary. For API gateway, you need explicit allow from identity-based role and resource-based, for example.
source: API Gateway Authorization Flow
The answer for all of your questions is it depends
Both IAM policies and Resource policies are equally important depends upon the usecase.
Let say you want to provide permission to AWS managed services like providing permissions to cloud front to read s3 bucket.. it's better to use resource policies ...
But for uploading/changing content, it's better to via IAM policies..
In simple terms it's better to use IAM policies when providing access from some user/external system/user managed instances.. and for providing access in between AWS managed services use resource policies.