AWS::IAM::Policy for any user - amazon-web-services

Is there any way to attach some policy for any user in cloudfromation? When you create a stack via aws js you can pass stack policy document with Principal as "*". But if you create a AWS::IAM::Policy inside cloudformation template, you must provide Role, User or Group, and "*" doesn't work.
Or how can I attach policy document for nested stack?

Nested CloudFormation stacks use the same stack policy document as the parent stack, which you specify in the AWS Console or via the API when creating/updating a stack (e.g., using the AWS SDK for JS, as you mentioned). As documented, for stack policy documents the Principal element is required, but supports only the wild card (*).
You can further restrict actions on nested stacks by adding statements with a Condition where ResourceType equals AWS::CloudFormation::Stack, as outlined in the Prevent Updates to Nested Stacks example in the documentation:
{
"Statement" : [
{
"Effect" : "Deny",
"Action" : "Update:*",
"Principal": "*",
"Resource" : "*",
"Condition" : {
"StringEquals" : {
"ResourceType" : ["AWS::CloudFormation::Stack"]
}
}
},
{
"Effect" : "Allow",
"Action" : "Update:*",
"Principal": "*",
"Resource" : "*"
}
]
}
The AWS::IAM::Policy resource is unrelated to the specific use-case of specifying a policy for a nested stack, but for reference, AWS::IAM::Policy creates a Policy that you attach to Users or Groups, which do not allow the Principal element to be specified, as outlined in the documentation:
Do not use the Principal element in policies that you attach to IAM users and groups. Similarly, you do not specify a principal in the access policy for an IAM role. In those cases, the principal is implicitly the user that the policy is attached to (for IAM users) or the user who assumes the role (for role access policies). When the policy is attached to an IAM group, the principal is the IAM user in that group who is making the request.

What I do, is trust relationship policy to the same (or different) account. It says root but is actually applied to the whole account:
{
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123ACCNO4567:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"Bool": {
"aws:MultiFactorAuthPresent": "true"
}
}
}
]
}

Related

Restricting access to an AWS resource using a specific pattern of AWS roles

I want all roles of my AWS account having a specific pattern to be able to access a Secrets Manager secret. I know I can use Condition block and wildcard matching for that.
However, the Principal field is required in a resource policy.
Will the following policy restrict access to just the roles matching the pattern?
{
"Statement": [
{
"Action": [
"secretsmanager:UpdateSecret",
"secretsmanager:GetSecretValue"
],
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::12345678910:role/my_role_*"
}
},
"Principal": { "AWS": "arn:aws:iam::12345678910:root" },
"Effect": "Allow",
"Resource": "arn:aws:secretsmanager:us-east-1:12345678910:secret:some-secret-1234",
"Sid": "rp1"
}
],
"Version": "2012-10-17"
}
Use the wildcard "All Principal": {"AWS": "*"}. The combination of a same-account Account Principal + wildcard condition works in role *trust* policies1 but apparently not in *resource* policies2.
The IAM docs say:
You can specify the role principal as the principal in a resource-based policy or create a broad-permission policy [with a wildcard Principal] that uses the aws:PrincipalArn condition key.
Because the condition contains the account number, the All Principal is no more permissive than the Account Principal would be. Also, because the policy is always tied to a specific secret resource, the wildcard "*" Resoure is no more permissive than the secret name. Finally, while an ArnLike condition is not always equivalent to StringLike, it is identical in this case.
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal" : { "AWS" : "*" },
"Action" : [ "secretsmanager:DescribeSecret", "secretsmanager:GetSecretValue" ],
"Resource" : "arn:aws:secretsmanager:us-east-1:12345678910:secret:some-secret-1234",
"Condition" : {
"ArnLike" : {
"aws:PrincipalArn" : "arn:aws:iam::12345678910:role/my_role_*"
}
}
} ]
}
See the wildcard permissions section of the AWS blog post How to use trust policies with IAM roles for a trust policy example.
Error using a Lambda role + secrets manager resource policy with a same-account Account Principal: ...no identity-based policy allows the secretsmanager:GetSecretValue action.

Glue Job Cross-Account secret access failing despite policies

Note: I have reviewed other questions and believe this is unique because it specifically pertains to cross-account secrets access using a glue job.
I am having an issue where a glue job, assuming a service role in one account, is unable to access a secret stored in another account, despite my policies which I believe should allow it to do so.
Error I'm seeing (with redacted values): An error occurred (AccessDeniedException) when calling the GetSecretValue operation: Access to KMS is not allowed. This version of secret is not encrypted with the current KMS key.
Question
What about the below setup is causing the permission failure?
Diagram of Current Situation
My Understanding of What Needs to be Done
Based on the AWS docs and a 2018 blog post, I think what we have to do is:
Add a Policy on the secret to allow access to service role
Add a Policy on the CMK to allow service role to decrypt
Add a Policy on Service role to allow access to secret
Add a Policy on Service role to allow CMK decryption
Current Policies
Policy on Secret
{
"Version" : "2012-10-17",
"Statement" : [ {
"Effect" : "Allow",
"Principal" : {
"AWS" : "arn:aws:iam::GLUE_ACCOUNT:role/GLUE_SERVICE_ROLE"
},
"Action" : "secretsmanager:GetSecretValue",
"Resource" : "*",
"Condition" : {
"ForAnyValue:StringEquals" : {
"secretsmanager:VersionStage" : "AWSCURRENT"
}
}
} ]
}
Policy on CMK
Note that the redacted SECRET_NAME below contains the few characters that AWS appends in the ARN, which it seems we need to include.
{
"Sid": "AllowUseOfTheKey",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::GLUE_ACCOUNT:role/GLUE_SERVICE_ROLE"
},
"Action": ["kms:Decrypt","kms:DescribeKey"],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.us-east-1.amazonaws.com"
},
"StringLike": {
"kms:EncryptionContext:SecretARN": "arn:aws:secretsmanager:us-east-1:SECRET_ACCOUNT:secret:SECRET_NAME"
}
}
}
Policy Statements Attached to Glue Service Role in Glue Account
{
"Sid": "AllowGetSecretValue",
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:secretsmanager:us-east-1:SECRET_ACCOUNT:secret:SECRET_NAME"
]
},
{
"Sid": "AllowKMSDecrypt",
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:us-east-1:SECRET_ACCOUNT:key/CMK_KEY_ID"
]
},
Trust policy on the service role
Just to confirm that the glue job does indeed seem to have the authority to assume the service role:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "glue.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
Possible Next Steps
As thought experiments, I'm considering doing the below just to see if it works:
Removing the condition in the secret policy
Removing the conditions in the CMK policy
Adding kms:DescribeKey to the Service Account policy as well, though I don't think that's going to resolve things.
As sometimes happens with these involved questions, the piece of information to answer the question was found outside of the information I'd provided, despite my best efforts.
The solution was two-fold:
The authorization error that was part of the original question wasn't due to authentication access at all. It was because the code that used boto3 specified the name of the secret instead of the full ARN. Of course secrets manager wouldn't magically know that secret was in a different account.
A surprising thing in this case is that AWS threw an unauthorized exception, and not a not found exception, which would have been infinitely more useful to our efforts.
Once that was fixed, we saw the error that is currently in the ticket, around encrypting the CMK. Apparently when we changed the CMK, we did not select to automatically create a new version of the secret with that CMK. A simple edit and save of the secret by an authorized user was enough to re-encrypt it with the chosen CMK and resolve the issue.

IAM tag policy with condition to prevent resource creation

My IAM user has the below two policies attached to it.
I created the below IAM policy that prevents lambda from being created if it does not have the Project tag.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Deny",
"Action": "lambda:*",
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/Project": "true"
}
}
}
]
}
I also need to attach/create a new execution role when creating lambda so I added below
Iam policy to my IAM user.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Action": "iam:*",
"Resource": "*"
}
]
}
I logged into aws console using that IAM user's credentials and tried to create the lambda function without the tag, but it did'nt block the resource creation.I was able to create the lambda function without the required tag but with the following errors.
You are not authorized to perform: cloudformation:DescribeStackResources.
You are not authorized to perform: lambda:GetFunctionEventInvokeConfig.
User: arn:aws:iam::****:user/testuser is not authorized to perform: lambda:ListEventSourceMappings on resource: * with an explicit deny (Service: AWSLambda; Status Code: 403; Error Code: AccessDeniedException; Request ID: 199433ed*****)
How can I completely block the resource creation?
https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_example-scps.html#example-require-tag-on-create
Eventually I want to try aws:RequestTag/{TageKey} for all supported aws resources.
Not all AWS services/resources support aws:RequestTag as a condition key.
For lambda it is not allowed. Currently the supported condition keys on lambda:CreateFuncion Action are:
lambda:Layer
lambda:VpcIds
lambda:SubnetIds
lambda:SecurityGroupIds
lambda:CodeSigningConfigArn
As specified on table "Actions defined by AWS Lambda" on column "Condition keys".
https://docs.aws.amazon.com/service-authorization/latest/reference/list_awslambda.html#awslambda-actions-as-permissions
You can check that link and review any other service and validate if a specific Action support the Condition that you need.
For example, for EC2:RunInstances https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html supported conditions are:
aws:RequestTag/${TagKey}
aws:TagKeys
ec2:AvailabilityZone
ec2:EbsOptimized
ec2:InstanceMarketType
ec2:InstanceProfile
ec2:InstanceType
ec2:IsLaunchTemplateResource
ec2:LaunchTemplate
ec2:MetadataHttpEndpoint
ec2:MetadataHttpPutResponseHopLimit
ec2:MetadataHttpTokens
ec2:PlacementGroup
ec2:Region
ec2:RootDeviceType
ec2:Tenancy
So in that case you can restrict creation on new EC2 instances based on the presence of Tags but for Lambda it is not supported (for now).

AWS IAM Policy grant permissions for some EC2 instances

I want to restrict access for a specific user to see just few EC2 instances. I created a new user in IAM Roles and I attached a new Policy to it. The content of that Policy is attached below. I tried to look over documentation and to do it myself like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": [
"arn:aws:ec2:eu-west-1:ACCOUNT_ID:instance/i-INSTANCE_ID1",
"arn:aws:ec2:eu-west-1:ACCOUNT_ID:instance/i-INSTANCE_ID2"
]
}
]
}
I placed my region,ACCOUNT_ID(the owner id, not of the new user created) and instance-id, but when I connect with that user and I go to list all Instances I got this An error occurred fetching instance data: You are not authorized to perform this operation..
After I placed the code in JSON editor, in Policy Review step I got this message:
This policy defines some actions, resources, or conditions that do not
provide permissions. To grant access, policies must have an action
that has an applicable resource or condition. For details, choose Show
remaining Learn more
The AWS documentation mention exactly the same configuration or these examples.
I assume you connect as that user in the console (but it would be the same with CLI) Here is what I think is happening:
To list all the instances, the console most probably calls the DescribeInstances API. As per the list of action/resources/tags that can be used in IAM policy, this API does not support the resource filter in IAM.
This means your user has no authorization to list instances and they will not be shown in the console. You can validate this theory by using the CLI to request the details of a specific instance id, if my hypothesis is correct, it will be authorized.
As DescribeInstances can not be restricted by resource or tags, I don't think it is possible to filter the instance list for a user.
To have the console working, you'll need to add the following statement in your IAM policy
"Statement": [
{ your existing statement },
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*"
}
]
Please report if I was right :-) The example you mentioned in your question shows exactly that : Resources = * on DescribeInstances and Resources specific InstanceId on other operations.
The previous answer is wrong, you can Conditionally allow access to ec2:DescribeInstances by tag names. It's an AWS best practice as well. Also explicitly deny access to the ec2:CreateTags and ec2:DeleteTags actions to prevent users from creating or deleting tags to take control of the instance.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:DescribeInstances",
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:ResourceTag/UserName": "${aws:username}"
}
}
},
{
"Effect": "Deny",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags"
],
"Resource": "*"
}
]
}
DescribeInstances action does not support condition.
https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonec2.html

What is the ARN of an assumed role assumed by a Lambda function?

I am trying to use the NotPrincipal element in my bucket policy to explicitly deny access to my s3 bucket while whitelisting a particular lambda that accesses the bucket. I specified the role ARN and assumed role ARN for the lambda's role in the NotPrincipal element:
"arn:aws:iam::{Account ID}:role/service-role/{Lambda role name}",
"arn:aws:sts::{Account ID}:assumed-role/{Lambda role name}/{role session name}"
This doc explains the structure of the assumed role ARNs:
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-unique-ids
I can't seem to get the assumed role ARN correct. The bucket policy is valid, but it seems I can provide anything for the role session name (the last part of the assumed-role ARN), and the ARN is considered valid. What does AWS set this role session name to when Lambda or other service assumes a service role? Is it possible to list active sessions for a role or list the assumed-role ARNs? I am currently using the Lambda function name for the role session name, but this is not working (the Lambda still cannot access the bucket).
Since I can't use wildcards in the NotPrincipal element, I need the full assumed-role ARN of the Lambda once it assumes the role.
UPDATE:
I tried using two conditions to deny all requests where the ARN does not match the ARN of the Lambda role or assumed role. The Lambda role is still denied from writing to S3 using the IAM policy simulator. Here is the policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "WhitelistRegistryAPILambdaRole",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetObjectVersion",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::{bucket name}",
"arn:aws:s3:::{bucket name}/*"
],
"Condition": {
"ArnNotLike": {
"AWS:SourceARN": "arn:aws:iam::{account ID}:role/{lambda role name}"
}
}
},
{
"Sid": "WhitelistRegistryAPILambdaAssumedRole",
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetObjectVersion",
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::{bucket name}",
"arn:aws:s3:::{bucket name}/*"
],
"Condition": {
"ArnNotLike": {
"AWS:SourceARN": "arn:aws:sts::{account ID}:assumed-role/{lambda role name}/{lambda function name}"
}
}
}
]
}
TL;DR:
The Assumed Role ARN of a Lambda Function is constructed as this:
arn:aws:sts::{AccountID}:assumed-role/{RoleName}/{FunctionName}
Details:
So the "role session name" is, in your case, the lambda function name.
You can easily verify this, by trying to call an API from your Lambda (DynamoDB ListTables for example) for which you do not have permissions. The error message in the callback will also contain the assumed role ARN (note that some service such as S3 do not provide detailed error messages when an operation is denied. DynamoDB, Lambda, and most of the recently launched services, will.)
I'm not sure to understand why you need a NotPrincipal, as probably there is a better way to handle the scenario you described :) More info would be useful to provide a more precise answer.
From the AWS IAM Documentation:
Important: Very few scenarios require the use of NotPrincipal, and we
recommend that you explore other authorization options before you
decide to use NotPrincipal.